xref: /haiku/src/tests/system/kernel/live_query.cpp (revision 1deede7388b04dbeec5af85cae7164735ea9e70d)
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 
61 LiveQuery::LiveQuery()
62 	:
63 	BApplication("application/x-vnd.test-live-query"),
64 	fQueries(10, true),
65 	fArgsReceived(false)
66 {
67 }
68 
69 
70 LiveQuery::~LiveQuery()
71 {
72 }
73 
74 
75 void
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
147 LiveQuery::ReadyToRun()
148 {
149 	if (!fArgsReceived)
150 		_PrintUsage();
151 }
152 
153 
154 void
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
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
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
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
277 main(int argc, char** argv)
278 {
279 	LiveQuery query;
280 	query.Run();
281 
282 	return 0;
283 }
284