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 20VolumeObserverHandler::VolumeObserverHandler(IndexServer* indexServer) 21 : 22 fIndexServer(indexServer) 23{ 24 25} 26 27 28void 29VolumeObserverHandler::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 51AnalyserMonitorHandler::AnalyserMonitorHandler(IndexServer* indexServer) 52 : 53 fIndexServer(indexServer) 54{ 55 56} 57 58 59void 60AnalyserMonitorHandler::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 69void 70AnalyserMonitorHandler::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 79IndexServer::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 92IndexServer::~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 112void 113IndexServer::ReadyToRun() 114{ 115 _StartWatchingAddOns(); 116 _StartWatchingVolumes(); 117} 118 119 120void 121IndexServer::MessageReceived(BMessage *message) 122{ 123 BApplication::MessageReceived(message); 124} 125 126 127bool 128IndexServer::QuitRequested() 129{ 130 _StopWatchingVolumes(); 131 return BApplication::QuitRequested(); 132} 133 134 135void 136IndexServer::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 164void 165IndexServer::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 185void 186IndexServer::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 227void 228IndexServer::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 243FileAnalyser* 244IndexServer::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 258void 259IndexServer::_StartWatchingVolumes() 260{ 261 BVolume volume; 262 while (fVolumeRoster.GetNextVolume(&volume) != B_BAD_VALUE) 263 AddVolume(volume); 264 fVolumeRoster.StartWatching(this); 265} 266 267 268void 269IndexServer::_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 282void 283IndexServer::_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 296FileAnalyser* 297IndexServer::_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 314void 315IndexServer::_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 355IndexServerAddOn* 356IndexServer::_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