1 /* 2 * Copyright 2010, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Clemens Zeidler <haiku@clemens-zeidler.de> 7 */ 8 9 #include "IndexServer.h" 10 11 #include <Directory.h> 12 #include <driver_settings.h> 13 #include <FindDirectory.h> 14 #include <Path.h> 15 #include <String.h> 16 17 #include <syscalls.h> 18 19 20 VolumeObserverHandler::VolumeObserverHandler(IndexServer* indexServer) 21 : 22 fIndexServer(indexServer) 23 { 24 25 } 26 27 28 void 29 VolumeObserverHandler::MessageReceived(BMessage* message) 30 { 31 if (message->what != B_NODE_MONITOR) 32 return; 33 34 dev_t device; 35 int32 opcode; 36 message->FindInt32("opcode", &opcode) ; 37 switch (opcode) { 38 case B_DEVICE_MOUNTED : 39 message->FindInt32("new device", &device); 40 fIndexServer->AddVolume(BVolume(device)); 41 break ; 42 43 case B_DEVICE_UNMOUNTED : 44 message->FindInt32("device", &device); 45 fIndexServer->RemoveVolume(BVolume(device)); 46 break ; 47 } 48 } 49 50 51 AnalyserMonitorHandler::AnalyserMonitorHandler(IndexServer* indexServer) 52 : 53 fIndexServer(indexServer) 54 { 55 56 } 57 58 59 void 60 AnalyserMonitorHandler::AddOnEnabled(const add_on_entry_info* entryInfo) 61 { 62 entry_ref ref; 63 make_entry_ref(entryInfo->dir_nref.device, entryInfo->dir_nref.node, 64 entryInfo->name, &ref); 65 fIndexServer->RegisterAddOn(ref); 66 }; 67 68 69 void 70 AnalyserMonitorHandler::AddOnDisabled(const add_on_entry_info* entryInfo) 71 { 72 entry_ref ref; 73 make_entry_ref(entryInfo->dir_nref.device, entryInfo->dir_nref.node, 74 entryInfo->name, &ref); 75 fIndexServer->UnregisterAddOn(ref); 76 }; 77 78 79 IndexServer::IndexServer() 80 : 81 BApplication("application/x-vnd.Haiku-index_server"), 82 83 fVolumeObserverHandler(this), 84 fAddOnMonitorHandler(this), 85 fPulseRunner(NULL) 86 { 87 AddHandler(&fVolumeObserverHandler); 88 AddHandler(&fAddOnMonitorHandler); 89 } 90 91 92 IndexServer::~IndexServer() 93 { 94 for (int i = 0; i < fAddOnList.CountItems(); i++) { 95 IndexServerAddOn* addon = fAddOnList.ItemAt(i); 96 for (int i = 0; i < fVolumeWatcherList.CountItems(); i++) 97 fVolumeWatcherList.ItemAt(i)->RemoveAnalyser(addon->Name()); 98 image_id image = addon->ImageId(); 99 delete addon; 100 unload_add_on(image); 101 } 102 103 _StopWatchingVolumes(); 104 105 delete fPulseRunner; 106 107 RemoveHandler(&fVolumeObserverHandler); 108 RemoveHandler(&fAddOnMonitorHandler); 109 } 110 111 112 void 113 IndexServer::ReadyToRun() 114 { 115 _StartWatchingAddOns(); 116 _StartWatchingVolumes(); 117 } 118 119 120 void 121 IndexServer::MessageReceived(BMessage *message) 122 { 123 BApplication::MessageReceived(message); 124 } 125 126 127 bool 128 IndexServer::QuitRequested() 129 { 130 _StopWatchingVolumes(); 131 return BApplication::QuitRequested(); 132 } 133 134 135 void 136 IndexServer::AddVolume(const BVolume& volume) 137 { 138 // ignore volumes like / or /dev 139 if (volume.Capacity() == 0) 140 return; 141 142 // check if volume is already in our list 143 for (int i = 0; i < fVolumeWatcherList.CountItems(); i++) { 144 VolumeWatcher* current = fVolumeWatcherList.ItemAt(i); 145 if (current->Volume() == volume) 146 return; 147 } 148 149 char name[256]; 150 volume.GetName(name); 151 STRACE("IndexServer::AddVolume %s\n", name); 152 153 VolumeWatcher* watcher = new VolumeWatcher(volume); 154 /* if (!watcher->Enabled()) { 155 delete watcher; 156 return; 157 }*/ 158 fVolumeWatcherList.AddItem(watcher); 159 _SetupVolumeWatcher(watcher); 160 watcher->StartWatching(); 161 } 162 163 164 void 165 IndexServer::RemoveVolume(const BVolume& volume) 166 { 167 VolumeWatcher* watcher = NULL; 168 for (int i = 0; i < fVolumeWatcherList.CountItems(); i++) { 169 VolumeWatcher* current = fVolumeWatcherList.ItemAt(i); 170 if (current->Volume() == volume) { 171 watcher = current; 172 break; 173 } 174 } 175 176 if (!watcher) 177 return; 178 179 watcher->Stop(); 180 fVolumeWatcherList.RemoveItem(watcher); 181 watcher->PostMessage(B_QUIT_REQUESTED); 182 } 183 184 185 void 186 IndexServer::RegisterAddOn(entry_ref ref) 187 { 188 STRACE("RegisterAddOn %s\n", ref.name); 189 190 BPath path(&ref); 191 image_id image = load_add_on(path.Path()); 192 if (image < 0) 193 return; 194 195 create_index_server_addon* createFunc; 196 197 // Get the instantiation function 198 status_t status = get_image_symbol(image, "instantiate_index_server_addon", 199 B_SYMBOL_TYPE_TEXT, (void**)&createFunc); 200 if (status != B_OK) { 201 unload_add_on(image); 202 return; 203 } 204 205 IndexServerAddOn* addon = createFunc(image, ref.name); 206 if (!addon) { 207 unload_add_on(image); 208 return; 209 } 210 if (!fAddOnList.AddItem(addon)) { 211 unload_add_on(image); 212 return; 213 } 214 215 for (int i = 0; i < fVolumeWatcherList.CountItems(); i++) { 216 VolumeWatcher* watcher = fVolumeWatcherList.ItemAt(i); 217 FileAnalyser* analyser = _SetupFileAnalyser(addon, watcher->Volume()); 218 if (!analyser) 219 continue; 220 if (!watcher->AddAnalyser(analyser)) 221 delete analyser; 222 } 223 224 } 225 226 227 void 228 IndexServer::UnregisterAddOn(entry_ref ref) 229 { 230 IndexServerAddOn* addon = _FindAddon(ref.name); 231 if (!addon) 232 return; 233 234 for (int i = 0; i < fVolumeWatcherList.CountItems(); i++) 235 fVolumeWatcherList.ItemAt(i)->RemoveAnalyser(addon->Name()); 236 237 fAddOnList.RemoveItem(addon); 238 unload_add_on(addon->ImageId()); 239 delete addon; 240 } 241 242 243 FileAnalyser* 244 IndexServer::CreateFileAnalyser(const BString& name, const BVolume& volume) 245 { 246 Lock(); 247 IndexServerAddOn* addon = _FindAddon(name); 248 if (!addon) { 249 Unlock(); 250 return NULL; 251 } 252 FileAnalyser* analyser = addon->CreateFileAnalyser(volume); 253 Unlock(); 254 return analyser; 255 } 256 257 258 void 259 IndexServer::_StartWatchingVolumes() 260 { 261 BVolume volume; 262 while (fVolumeRoster.GetNextVolume(&volume) != B_BAD_VALUE) 263 AddVolume(volume); 264 fVolumeRoster.StartWatching(this); 265 } 266 267 268 void 269 IndexServer::_StopWatchingVolumes() 270 { 271 STRACE("_StopWatchingVolumes\n"); 272 273 for (int i = 0; i < fVolumeWatcherList.CountItems(); i++) { 274 VolumeWatcher* watcher = fVolumeWatcherList.ItemAt(i); 275 watcher->Stop(); 276 watcher->PostMessage(B_QUIT_REQUESTED); 277 } 278 fVolumeWatcherList.MakeEmpty(); 279 } 280 281 282 void 283 IndexServer::_SetupVolumeWatcher(VolumeWatcher* watcher) 284 { 285 for (int i = 0; i < fAddOnList.CountItems(); i++) { 286 IndexServerAddOn* addon = fAddOnList.ItemAt(i); 287 FileAnalyser* analyser = _SetupFileAnalyser(addon, watcher->Volume()); 288 if (!analyser) 289 continue; 290 if (!watcher->AddAnalyser(analyser)) 291 delete analyser; 292 } 293 } 294 295 296 FileAnalyser* 297 IndexServer::_SetupFileAnalyser(IndexServerAddOn* addon, const BVolume& volume) 298 { 299 FileAnalyser* analyser = addon->CreateFileAnalyser(volume); 300 if (!analyser) 301 return NULL; 302 AnalyserSettings* settings = new AnalyserSettings(analyser->Name(), 303 analyser->Volume()); 304 BReference<AnalyserSettings> settingsRef(settings, true); 305 if (!settings) { 306 delete analyser; 307 return NULL; 308 } 309 analyser->SetSettings(settings); 310 return analyser; 311 } 312 313 314 void 315 IndexServer::_StartWatchingAddOns() 316 { 317 AddHandler(&fAddOnMonitorHandler); 318 BMessage pulse(B_PULSE); 319 fPulseRunner = new BMessageRunner(&fAddOnMonitorHandler, &pulse, 1000000LL); 320 // the monitor handler needs a pulse to check if add-ons are ready 321 322 char parameter[32]; 323 size_t parameterLength = sizeof(parameter); 324 bool safeMode = false; 325 if (_kern_get_safemode_option(B_SAFEMODE_SAFE_MODE, parameter, 326 ¶meterLength) == B_OK) { 327 if (!strcasecmp(parameter, "enabled") || !strcasecmp(parameter, "on") 328 || !strcasecmp(parameter, "true") || !strcasecmp(parameter, "yes") 329 || !strcasecmp(parameter, "enable") || !strcmp(parameter, "1")) 330 safeMode = true; 331 } 332 333 // load dormant media nodes 334 const directory_which directories[] = { 335 B_USER_ADDONS_DIRECTORY, 336 B_COMMON_ADDONS_DIRECTORY, 337 B_SYSTEM_ADDONS_DIRECTORY 338 }; 339 340 // when safemode, only B_SYSTEM_ADDONS_DIRECTORY is used 341 for (uint32 i = safeMode ? 4 : 0; 342 i < sizeof(directories) / sizeof(directory_which); i++) { 343 BDirectory directory; 344 node_ref nodeRef; 345 BPath path; 346 if (find_directory(directories[i], &path) == B_OK 347 && path.Append("index_server") == B_OK 348 && directory.SetTo(path.Path()) == B_OK 349 && directory.GetNodeRef(&nodeRef) == B_OK) 350 fAddOnMonitorHandler.AddDirectory(&nodeRef, true); 351 } 352 } 353 354 355 IndexServerAddOn* 356 IndexServer::_FindAddon(const BString& name) 357 { 358 for (int i = 0; i < fAddOnList.CountItems(); i++) { 359 IndexServerAddOn* current = fAddOnList.ItemAt(i); 360 if (current->Name() == name) 361 return current; 362 } 363 return NULL; 364 } 365