1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25: #include "activation.h"
26: #include "desktop-file.h"
27: #include "services.h"
28: #include "test.h"
29: #include "utils.h"
30: #include <dbus/dbus-internals.h>
31: #include <dbus/dbus-hash.h>
32: #include <dbus/dbus-list.h>
33: #include <dbus/dbus-shell.h>
34: #include <dbus/dbus-spawn.h>
35: #include <dbus/dbus-timeout.h>
36: #include <dbus/dbus-sysdeps.h>
37: #include <dirent.h>
38: #include <errno.h>
39:
40: #define DBUS_SERVICE_SECTION "D-BUS Service"
41: #define DBUS_SERVICE_NAME "Name"
42: #define DBUS_SERVICE_EXEC "Exec"
43:
44: struct BusActivation
45: {
46: int refcount;
47: DBusHashTable *entries;
48: DBusHashTable *pending_activations;
49: char *server_address;
50: BusContext *context;
51: int n_pending_activations;
52:
53:
54:
55: DBusHashTable *directories;
56: };
57:
58: typedef struct
59: {
60: int refcount;
61: char *dir_c;
62: DBusHashTable *entries;
63: } BusServiceDirectory;
64:
65: typedef struct
66: {
67: int refcount;
68: char *name;
69: char *exec;
70: unsigned long mtime;
71: BusServiceDirectory *s_dir;
72: char *filename;
73: } BusActivationEntry;
74:
75: typedef struct BusPendingActivationEntry BusPendingActivationEntry;
76:
77: struct BusPendingActivationEntry
78: {
79: DBusMessage *activation_message;
80: DBusConnection *connection;
81:
82: dbus_bool_t auto_activation;
83: };
84:
85: typedef struct
86: {
87: int refcount;
88: BusActivation *activation;
89: char *service_name;
90: char *exec;
91: DBusList *entries;
92: int n_entries;
93: DBusBabysitter *babysitter;
94: DBusTimeout *timeout;
95: unsigned int timeout_added : 1;
96: } BusPendingActivation;
97:
98: #if 0
99: static BusServiceDirectory *
100: bus_service_directory_ref (BusServiceDirectory *dir)
101: {
102: _dbus_assert (dir->refcount);
103:
104: dir->refcount++;
105:
106: return dir;
107: }
108: #endif
109:
110: static void
111: bus_service_directory_unref (BusServiceDirectory *dir)
112: {
113: if (dir == NULL)
114: return;
115:
116: _dbus_assert (dir->refcount > 0);
117: dir->refcount--;
118:
119: if (dir->refcount > 0)
120: return;
121:
122: if (dir->entries)
123: _dbus_hash_table_unref (dir->entries);
124:
125: dbus_free (dir->dir_c);
126: dbus_free (dir);
127: }
128:
129: static void
130: bus_pending_activation_entry_free (BusPendingActivationEntry *entry)
131: {
132: if (entry->activation_message)
133: dbus_message_unref (entry->activation_message);
134:
135: if (entry->connection)
136: dbus_connection_unref (entry->connection);
137:
138: dbus_free (entry);
139: }
140:
141: static void
142: handle_timeout_callback (DBusTimeout *timeout,
143: void *data)
144: {
145: BusPendingActivation *pending_activation = data;
146:
147: while (!dbus_timeout_handle (pending_activation->timeout))
148: _dbus_wait_for_memory ();
149: }
150:
151: static BusPendingActivation *
152: bus_pending_activation_ref (BusPendingActivation *pending_activation)
153: {
154: _dbus_assert (pending_activation->refcount > 0);
155: pending_activation->refcount += 1;
156:
157: return pending_activation;
158: }
159:
160: static void
161: bus_pending_activation_unref (BusPendingActivation *pending_activation)
162: {
163: DBusList *link;
164:
165: if (pending_activation == NULL)
166: return;
167:
168: _dbus_assert (pending_activation->refcount > 0);
169: pending_activation->refcount -= 1;
170:
171: if (pending_activation->refcount > 0)
172: return;
173:
174: if (pending_activation->timeout_added)
175: {
176: _dbus_loop_remove_timeout (bus_context_get_loop (pending_activation->activation->context),
177: pending_activation->timeout,
178: handle_timeout_callback, pending_activation);
179: pending_activation->timeout_added = FALSE;
180: }
181:
182: if (pending_activation->timeout)
183: _dbus_timeout_unref (pending_activation->timeout);
184:
185: if (pending_activation->babysitter)
186: {
187: if (!_dbus_babysitter_set_watch_functions (pending_activation->babysitter,
188: NULL, NULL, NULL,
189: pending_activation->babysitter,
190: NULL))
191: _dbus_assert_not_reached ("setting watch functions to NULL failed");
192:
193: _dbus_babysitter_unref (pending_activation->babysitter);
194: }
195:
196: dbus_free (pending_activation->service_name);
197: dbus_free (pending_activation->exec);
198:
199: link = _dbus_list_get_first_link (&pending_activation->entries);
200:
201: while (link != NULL)
202: {
203: BusPendingActivationEntry *entry = link->data;
204:
205: bus_pending_activation_entry_free (entry);
206:
207: link = _dbus_list_get_next_link (&pending_activation->entries, link);
208: }
209: _dbus_list_clear (&pending_activation->entries);
210:
211: pending_activation->activation->n_pending_activations -=
212: pending_activation->n_entries;
213:
214: _dbus_assert (pending_activation->activation->n_pending_activations >= 0);
215:
216: dbus_free (pending_activation);
217: }
218:
219: static BusActivationEntry *
220: bus_activation_entry_ref (BusActivationEntry *entry)
221: {
222: _dbus_assert (entry->refcount > 0);
223: entry->refcount++;
224:
225: return entry;
226: }
227:
228: static void
229: bus_activation_entry_unref (BusActivationEntry *entry)
230: {
231: if (entry == NULL)
232: return;
233:
234: _dbus_assert (entry->refcount > 0);
235: entry->refcount--;
236:
237: if (entry->refcount > 0)
238: return;
239:
240: dbus_free (entry->name);
241: dbus_free (entry->exec);
242: dbus_free (entry->filename);
243:
244: dbus_free (entry);
245: }
246:
247: static dbus_bool_t
248: update_desktop_file_entry (BusActivation *activation,
249: BusServiceDirectory *s_dir,
250: DBusString *filename,
251: BusDesktopFile *desktop_file,
252: DBusError *error)
253: {
254: char *name, *exec;
255: BusActivationEntry *entry;
256: DBusStat stat_buf;
257: DBusString file_path;
258:
259: _DBUS_ASSERT_ERROR_IS_CLEAR (error);
260:
261: name = NULL;
262: exec = NULL;
263: entry = NULL;
264:
265: if (!_dbus_string_init (&file_path))
266: {
267: BUS_SET_OOM (error);
268: return FALSE;
269: }
270:
271: if (!_dbus_string_append (&file_path, s_dir->dir_c) ||
272: !_dbus_concat_dir_and_file (&file_path, filename))
273: {
274: BUS_SET_OOM (error);
275: goto failed;
276: }
277:
278: if (!_dbus_stat (&file_path, &stat_buf, NULL))
279: {
280: dbus_set_error (error, DBUS_ERROR_FAILED,
281: "Can't stat the service file\n");
282: goto failed;
283: }
284:
285: if (!bus_desktop_file_get_string (desktop_file,
286: DBUS_SERVICE_SECTION,
287: DBUS_SERVICE_NAME,
288: &name,
289: error))
290: goto failed;
291:
292: if (!bus_desktop_file_get_string (desktop_file,
293: DBUS_SERVICE_SECTION,
294: DBUS_SERVICE_EXEC,
295: &exec,
296: error))
297: goto failed;
298:
299: entry = _dbus_hash_table_lookup_string (s_dir->entries,
300: _dbus_string_get_const_data (filename));
301: if (entry == NULL)
302: {
303:
304:
305:
306: if (_dbus_hash_table_lookup_string (activation->entries, name))
307: {
308: dbus_set_error (error, DBUS_ERROR_FAILED,
309: "Service %s already exists in activation entry list\n", name);
310: goto failed;
311: }
312:
313: entry = dbus_new0 (BusActivationEntry, 1);
314: if (entry == NULL)
315: {
316: BUS_SET_OOM (error);
317: goto failed;
318: }
319:
320: entry->name = name;
321: entry->exec = exec;
322: entry->refcount = 1;
323:
324: entry->s_dir = s_dir;
325: entry->filename = _dbus_strdup (_dbus_string_get_const_data (filename));
326: if (!entry->filename)
327: {
328: BUS_SET_OOM (error);
329: goto failed;
330: }
331:
332: if (!_dbus_hash_table_insert_string (activation->entries, entry->name, bus_activation_entry_ref (entry)))
333: {
334: BUS_SET_OOM (error);
335: goto failed;
336: }
337:
338: if (!_dbus_hash_table_insert_string (s_dir->entries, entry->filename, bus_activation_entry_ref (entry)))
339: {
340:
341: _dbus_hash_table_remove_string (activation->entries, entry->name);
342: BUS_SET_OOM (error);
343: goto failed;
344: }
345:
346: _dbus_verbose ("Added \"%s\" to list of services\n", entry->name);
347: }
348: else
349: {
350: bus_activation_entry_ref (entry);
351: _dbus_hash_table_remove_string (activation->entries, entry->name);
352:
353: if (_dbus_hash_table_lookup_string (activation->entries, name))
354: {
355: _dbus_verbose ("The new service name \"%s\" of service file \"%s\" already in cache, ignoring\n",
356: name, _dbus_string_get_const_data (&file_path));
357: goto failed;
358: }
359:
360: dbus_free (entry->name);
361: dbus_free (entry->exec);
362: entry->name = name;
363: entry->exec = exec;
364: if (!_dbus_hash_table_insert_string (activation->entries,
365: entry->name, bus_activation_entry_ref(entry)))
366: {
367: BUS_SET_OOM (error);
368:
369:
370: _dbus_hash_table_remove_string (entry->s_dir->entries,
371: entry->filename);
372: bus_activation_entry_unref (entry);
373: return FALSE;
374: }
375: }
376:
377: entry->mtime = stat_buf.mtime;
378:
379: _dbus_string_free (&file_path);
380: bus_activation_entry_unref (entry);
381:
382: return TRUE;
383:
384: failed:
385: dbus_free (name);
386: dbus_free (exec);
387: _dbus_string_free (&file_path);
388:
389: if (entry)
390: bus_activation_entry_unref (entry);
391:
392: return FALSE;
393: }
394:
395: static dbus_bool_t
396: check_service_file (BusActivation *activation,
397: BusActivationEntry *entry,
398: BusActivationEntry **updated_entry,
399: DBusError *error)
400: {
401: DBusStat stat_buf;
402: dbus_bool_t retval;
403: BusActivationEntry *tmp_entry;
404: DBusString file_path;
405: DBusString filename;
406:
407: retval = TRUE;
408: tmp_entry = entry;
409:
410: _dbus_string_init_const (&filename, entry->filename);
411:
412: if (!_dbus_string_init (&file_path))
413: {
414: BUS_SET_OOM (error);
415: return FALSE;
416: }
417:
418: if (!_dbus_string_append (&file_path, entry->s_dir->dir_c) ||
419: !_dbus_concat_dir_and_file (&file_path, &filename))
420: {
421: BUS_SET_OOM (error);
422: retval = FALSE;
423: goto out;
424: }
425:
426: if (!_dbus_stat (&file_path, &stat_buf, NULL))
427: {
428: _dbus_verbose ("****** Can't stat file \"%s\", removing from cache\n",
429: _dbus_string_get_const_data (&file_path));
430:
431: _dbus_hash_table_remove_string (activation->entries, entry->name);
432: _dbus_hash_table_remove_string (entry->s_dir->entries, entry->filename);
433:
434: tmp_entry = NULL;
435: retval = TRUE;
436: goto out;
437: }
438: else
439: {
440: if (stat_buf.mtime > entry->mtime)
441: {
442: BusDesktopFile *desktop_file;
443: DBusError tmp_error;
444:
445: dbus_error_init (&tmp_error);
446:
447: desktop_file = bus_desktop_file_load (&file_path, &tmp_error);
448: if (desktop_file == NULL)
449: {
450: _dbus_verbose ("Could not load %s: %s\n",
451: _dbus_string_get_const_data (&file_path),
452: tmp_error.message);
453: if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
454: {
455: dbus_move_error (&tmp_error, error);
456: retval = FALSE;
457: goto out;
458: }
459: dbus_error_free (&tmp_error);
460: retval = TRUE;
461: goto out;
462: }
463:
464:
465:
466:
467: if (!update_desktop_file_entry (activation, entry->s_dir, &filename, desktop_file, &tmp_error))
468: {
469: bus_desktop_file_free (desktop_file);
470: if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
471: {
472: dbus_move_error (&tmp_error, error);
473: retval = FALSE;
474: goto out;
475: }
476: dbus_error_free (&tmp_error);
477: retval = TRUE;
478: goto out;
479: }
480:
481: bus_desktop_file_free (desktop_file);
482: retval = TRUE;
483: }
484: }
485:
486: out:
487: _dbus_string_free (&file_path);
488:
489: if (updated_entry != NULL)
490: *updated_entry = tmp_entry;
491: return retval;
492: }
493:
494:
495:
496:
497:
498: static dbus_bool_t
499: update_directory (BusActivation *activation,
500: BusServiceDirectory *s_dir,
501: DBusError *error)
502: {
503: DBusDirIter *iter;
504: DBusString dir, filename;
505: BusDesktopFile *desktop_file;
506: DBusError tmp_error;
507: dbus_bool_t retval;
508: BusActivationEntry *entry;
509: DBusString full_path;
510:
511: _DBUS_ASSERT_ERROR_IS_CLEAR (error);
512:
513: iter = NULL;
514: desktop_file = NULL;
515:
516: _dbus_string_init_const (&dir, s_dir->dir_c);
517:
518: if (!_dbus_string_init (&filename))
519: {
520: BUS_SET_OOM (error);
521: return FALSE;
522: }
523:
524: if (!_dbus_string_init (&full_path))
525: {
526: BUS_SET_OOM (error);
527: _dbus_string_free (&filename);
528: return FALSE;
529: }
530:
531: retval = FALSE;
532:
533:
534:
535: iter = _dbus_directory_open (&dir, error);
536: if (iter == NULL)
537: {
538: _dbus_verbose ("Failed to open directory %s: %s\n",
539: s_dir->dir_c,
540: error ? error->message : "unknown");
541: goto out;
542: }
543:
544:
545: dbus_error_init (&tmp_error);
546: while (_dbus_directory_get_next_file (iter, &filename, &tmp_error))
547: {
548: _dbus_assert (!dbus_error_is_set (&tmp_error));
549:
550: _dbus_string_set_length (&full_path, 0);
551:
552: if (!_dbus_string_ends_with_c_str (&filename, ".service"))
553: {
554: _dbus_verbose ("Skipping non-.service file %s\n",
555: _dbus_string_get_const_data (&filename));
556: continue;
557: }
558:
559: entry = _dbus_hash_table_lookup_string (s_dir->entries, _dbus_string_get_const_data (&filename));
560: if (entry)
561: {
562: if (!check_service_file (activation, entry, NULL, error))
563: goto out;
564:
565: continue;
566: }
567:
568: if (!_dbus_string_append (&full_path, s_dir->dir_c) ||
569: !_dbus_concat_dir_and_file (&full_path, &filename))
570: {
571: BUS_SET_OOM (error);
572: goto out;
573: }
574:
575:
576: desktop_file = bus_desktop_file_load (&full_path, &tmp_error);
577: if (desktop_file == NULL)
578: {
579: _dbus_verbose ("Could not load %s: %s\n",
580: _dbus_string_get_const_data (&full_path),
581: tmp_error.message);
582:
583: if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
584: {
585: dbus_move_error (&tmp_error, error);
586: goto out;
587: }
588:
589: dbus_error_free (&tmp_error);
590: continue;
591: }
592:
593:
594:
595:
596: if (!update_desktop_file_entry (activation, s_dir, &filename, desktop_file, &tmp_error))
597: {
598: bus_desktop_file_free (desktop_file);
599: desktop_file = NULL;
600:
601: _dbus_verbose ("Could not add %s to activation entry list: %s\n",
602: _dbus_string_get_const_data (&full_path), tmp_error.message);
603:
604: if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
605: {
606: dbus_move_error (&tmp_error, error);
607: goto out;
608: }
609:
610: dbus_error_free (&tmp_error);
611: continue;
612: }
613: else
614: {
615: bus_desktop_file_free (desktop_file);
616: desktop_file = NULL;
617: continue;
618: }
619: }
620:
621: if (dbus_error_is_set (&tmp_error))
622: {
623: dbus_move_error (&tmp_error, error);