xref: /haiku/src/servers/index/IndexServer.cpp (revision 820dca4df6c7bf955c46e8f6521b9408f50b2900)
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 			&parameterLength) == 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