1 /*
2 * Copyright 2005-2009, Haiku Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT license.
4 *
5 * Authors:
6 * Ficus Kirkpatrick (ficus@ior.com)
7 * Jérôme Duval
8 * Axel Dörfler, axeld@pinc-software.de
9 */
10
11
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16
17 #include <Application.h>
18 #include <Entry.h>
19 #include <NodeMonitor.h>
20 #include <Path.h>
21 #include <Query.h>
22 #include <Volume.h>
23 #include <VolumeRoster.h>
24 #include <String.h>
25
26 #include <ObjectList.h>
27
28
29 static const uint32 kMsgAddQuery = 'adqu';
30
31 extern const char *__progname;
32 static const char *kProgramName = __progname;
33
34 // Option variables.
35 static bool sAllVolumes = false; // Query all volumes?
36 static bool sEscapeMetaChars = true; // Escape metacharacters?
37 static bool sFilesOnly = false; // Show only files?
38
39
40 class LiveQuery : public BApplication {
41 public:
42 LiveQuery();
43 virtual ~LiveQuery();
44
45 virtual void ArgvReceived(int32 argc, char** argv);
46 virtual void ReadyToRun();
47
48 virtual void MessageReceived(BMessage* message);
49
50 private:
51 void _PrintUsage();
52 void _AddQuery(BVolume& volume,
53 const char* predicate);
54 void _PerformQuery(BQuery& query);
55
56 BObjectList<BQuery> fQueries;
57 bool fArgsReceived;
58 };
59
60
LiveQuery()61 LiveQuery::LiveQuery()
62 :
63 BApplication("application/x-vnd.test-live-query"),
64 fQueries(10, true),
65 fArgsReceived(false)
66 {
67 }
68
69
~LiveQuery()70 LiveQuery::~LiveQuery()
71 {
72 }
73
74
75 void
ArgvReceived(int32 argc,char ** argv)76 LiveQuery::ArgvReceived(int32 argc, char** argv)
77 {
78 fArgsReceived = true;
79
80 // Which volume do we make the query on?
81 // Default to the current volume.
82 char volumePath[B_FILE_NAME_LENGTH];
83 strcpy(volumePath, ".");
84
85 // Parse command-line arguments.
86 int opt;
87 while ((opt = getopt(argc, argv, "efav:")) != -1) {
88 switch (opt) {
89 case 'e':
90 sEscapeMetaChars = false;
91 break;
92 case 'f':
93 sFilesOnly = true;
94 break;
95 case 'a':
96 sAllVolumes = true;
97 break;
98 case 'v':
99 strncpy(volumePath, optarg, B_FILE_NAME_LENGTH);
100 break;
101
102 default:
103 _PrintUsage();
104 break;
105 }
106 }
107
108 BVolume volume;
109
110 if (!sAllVolumes) {
111 // Find the volume that the query should be performed on,
112 // and set the query to it.
113 BEntry entry(volumePath);
114 if (entry.InitCheck() != B_OK) {
115 fprintf(stderr, "%s: \"%s\" is not a valid file\n", kProgramName,
116 volumePath);
117 exit(1);
118 }
119
120 status_t status = entry.GetVolume(&volume);
121 if (status != B_OK) {
122 fprintf(stderr, "%s: could not get volume: %s\n", kProgramName,
123 strerror(status));
124 exit(1);
125 }
126
127 if (!volume.KnowsQuery()) {
128 fprintf(stderr, "%s: volume containing %s is not query-enabled\n",
129 kProgramName, volumePath);
130 } else
131 _AddQuery(volume, argv[optind]);
132 } else {
133 // Okay, we want to query all the disks -- so iterate over
134 // them, one by one, running the query.
135 BVolumeRoster volumeRoster;
136 while (volumeRoster.GetNextVolume(&volume) == B_OK) {
137 // We don't print errors here -- this will catch /pipe and
138 // other filesystems we don't care about.
139 if (volume.KnowsQuery())
140 _AddQuery(volume, argv[optind]);
141 }
142 }
143 }
144
145
146 void
ReadyToRun()147 LiveQuery::ReadyToRun()
148 {
149 if (!fArgsReceived)
150 _PrintUsage();
151 }
152
153
154 void
MessageReceived(BMessage * message)155 LiveQuery::MessageReceived(BMessage* message)
156 {
157 switch (message->what) {
158 case kMsgAddQuery:
159 {
160 int32 device;
161 const char* predicate;
162 if (message->FindInt32("volume", &device) != B_OK
163 || message->FindString("predicate", &predicate) != B_OK)
164 break;
165
166 BVolume volume(device);
167 BQuery* query = new BQuery;
168
169 // Set up the volume and predicate for the query.
170 query->SetVolume(&volume);
171 query->SetPredicate(predicate);
172 query->SetTarget(this);
173
174 fQueries.AddItem(query);
175 _PerformQuery(*query);
176 break;
177 }
178
179 case B_QUERY_UPDATE:
180 {
181 int32 what;
182 message->FindInt32("opcode", &what);
183
184 int32 device;
185 int64 directory;
186 int64 node;
187 const char* name;
188 message->FindInt32("device", &device);
189 message->FindInt64("directory", &directory);
190 message->FindInt64("node", &node);
191 message->FindString("name", &name);
192
193 switch (what) {
194 case B_ENTRY_CREATED:
195 {
196 printf("CREATED %s\n", name);
197 break;
198 }
199 case B_ENTRY_REMOVED:
200 printf("REMOVED %s\n", name);
201 break;
202 }
203 break;
204 }
205
206 default:
207 BApplication::MessageReceived(message);
208 break;
209 }
210 }
211
212
213 void
_PrintUsage()214 LiveQuery::_PrintUsage()
215 {
216 printf("usage: %s [ -ef ] [ -a || -v <path-to-volume> ] expression\n"
217 " -e\t\tdon't escape meta-characters\n"
218 " -f\t\tshow only files (ie. no directories or symbolic links)\n"
219 " -a\t\tperform the query on all volumes\n"
220 " -v <file>\tperform the query on just one volume; <file> can be any\n"
221 "\t\tfile on that volume. Defaults to the current volume.\n"
222 " Hint: '%s name=bar' will find files named \"bar\"\n",
223 kProgramName, kProgramName);
224
225 Quit();
226 }
227
228
229 void
_AddQuery(BVolume & volume,const char * predicate)230 LiveQuery::_AddQuery(BVolume& volume, const char* predicate)
231 {
232 BMessage add(kMsgAddQuery);
233 add.AddInt32("volume", volume.Device());
234 add.AddString("predicate", predicate);
235
236 PostMessage(&add);
237 }
238
239
240 void
_PerformQuery(BQuery & query)241 LiveQuery::_PerformQuery(BQuery& query)
242 {
243 status_t status = query.Fetch();
244 if (status != B_OK) {
245 fprintf(stderr, "%s: bad query expression\n", kProgramName);
246 return;
247 }
248
249 int32 count = 0;
250
251 BEntry entry;
252 BPath path;
253 while (query.GetNextEntry(&entry) == B_OK) {
254 if (sFilesOnly && !entry.IsFile())
255 continue;
256
257 if (entry.GetPath(&path) != B_OK) {
258 fprintf(stderr, "%s: could not get path for entry\n", kProgramName);
259 continue;
260 }
261
262 printf("%s\n", sEscapeMetaChars ? BString().CharacterEscape(
263 path.Path(), " ()?*&\"'[]^\\~|;!<>*$\t", '\\').String()
264 : path.Path());
265
266 count++;
267 }
268
269 printf("FOUND %ld entries\n", count);
270 }
271
272
273 // #pragma mark -
274
275
276 int
main(int argc,char ** argv)277 main(int argc, char** argv)
278 {
279 LiveQuery query;
280 query.Run();
281
282 return 0;
283 }
284