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