1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* activation.c Activation of services
3 *
4 * Copyright (C) 2003 CodeFactory AB
5 * Copyright (C) 2003 Red Hat, Inc.
6 * Copyright (C) 2004 Imendio HB
7 *
8 * Licensed under the Academic Free License version 2.1
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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; /**< This is in fact the number of BusPendingActivationEntry,
52 * i.e. number of pending activation requests, not pending
53 * activations per se
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
bus_service_directory_unref(BusServiceDirectory * dir)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
bus_pending_activation_entry_free(BusPendingActivationEntry * entry)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
handle_timeout_callback(DBusTimeout * timeout,void * data)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 *
bus_pending_activation_ref(BusPendingActivation * pending_activation)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
bus_pending_activation_unref(BusPendingActivation * pending_activation)161 bus_pending_activation_unref (BusPendingActivation *pending_activation)
162 {
163 DBusList *link;
164
165 if (pending_activation == NULL) /* hash table requires this */
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 *
bus_activation_entry_ref(BusActivationEntry * entry)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
bus_activation_entry_unref(BusActivationEntry * entry)229 bus_activation_entry_unref (BusActivationEntry *entry)
230 {
231 if (entry == NULL) /* hash table requires this */
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
update_desktop_file_entry(BusActivation * activation,BusServiceDirectory * s_dir,DBusString * filename,BusDesktopFile * desktop_file,DBusError * error)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) /* New file */
302 {
303 /* FIXME we need a better-defined algorithm for which service file to
304 * pick than "whichever one is first in the directory listing"
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 /* Revert the insertion in the entries table */
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 /* Just update the entry */
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 /* Also remove path to entries hash since we want this in sync with
369 * the entries hash table */
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
check_service_file(BusActivation * activation,BusActivationEntry * entry,BusActivationEntry ** updated_entry,DBusError * error)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 /* @todo We can return OOM or a DBUS_ERROR_FAILED error
465 * Handle these both better
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 /* warning: this doesn't fully "undo" itself on failure, i.e. doesn't strip
496 * hash entries it already added.
497 */
498 static dbus_bool_t
update_directory(BusActivation * activation,BusServiceDirectory * s_dir,DBusError * error)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 /* from this point it's safe to "goto out" */
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 /* Now read the files */
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) /* Already has this service file in the cache */
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 /* New file */
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 /* @todo We can return OOM or a DBUS_ERROR_FAILED error
594 * Handle these both better
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);
624 goto out;
625 }
626
627 retval = TRUE;
628
629 out:
630 if (!retval)
631 _DBUS_ASSERT_ERROR_IS_SET (error);
632 else
633 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
634
635 if (iter != NULL)
636 _dbus_directory_close (iter);
637 _dbus_string_free (&filename);
638 _dbus_string_free (&full_path);
639
640 return retval;
641 }
642
643 BusActivation*
bus_activation_new(BusContext * context,const DBusString * address,DBusList ** directories,DBusError * error)644 bus_activation_new (BusContext *context,
645 const DBusString *address,
646 DBusList **directories,
647 DBusError *error)
648 {
649 BusActivation *activation;
650 DBusList *link;
651 char *dir;
652
653 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
654
655 activation = dbus_new0 (BusActivation, 1);
656 if (activation == NULL)
657 {
658 BUS_SET_OOM (error);
659 return NULL;
660 }
661
662 activation->refcount = 1;
663 activation->context = context;
664 activation->n_pending_activations = 0;
665
666 if (!_dbus_string_copy_data (address, &activation->server_address))
667 {
668 BUS_SET_OOM (error);
669 goto failed;
670 }
671
672 activation->entries = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
673 (DBusFreeFunction)bus_activation_entry_unref);
674 if (activation->entries == NULL)
675 {
676 BUS_SET_OOM (error);
677 goto failed;
678 }
679
680 activation->pending_activations = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
681 (DBusFreeFunction)bus_pending_activation_unref);
682
683 if (activation->pending_activations == NULL)
684 {
685 BUS_SET_OOM (error);
686 goto failed;
687 }
688
689 activation->directories = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
690 (DBusFreeFunction)bus_service_directory_unref);
691
692 if (activation->directories == NULL)
693 {
694 BUS_SET_OOM (error);
695 goto failed;
696 }
697
698 /* Load service files */
699 link = _dbus_list_get_first_link (directories);
700 while (link != NULL)
701 {
702 BusServiceDirectory *s_dir;
703
704 dir = _dbus_strdup ((const char *) link->data);
705 if (!dir)
706 {
707 BUS_SET_OOM (error);
708 goto failed;
709 }
710
711 s_dir = dbus_new0 (BusServiceDirectory, 1);
712 if (!s_dir)
713 {
714 dbus_free (dir);
715 BUS_SET_OOM (error);
716 goto failed;
717 }
718
719 s_dir->refcount = 1;
720 s_dir->dir_c = dir;
721
722 s_dir->entries = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
723 (DBusFreeFunction)bus_activation_entry_unref);
724
725 if (!s_dir->entries)
726 {
727 bus_service_directory_unref (s_dir);
728 BUS_SET_OOM (error);
729 goto failed;
730 }
731
732 if (!_dbus_hash_table_insert_string (activation->directories, s_dir->dir_c, s_dir))
733 {
734 bus_service_directory_unref (s_dir);
735 BUS_SET_OOM (error);
736 goto failed;
737 }
738
739 /* only fail on OOM, it is ok if we can't read the directory */
740 if (!update_directory (activation, s_dir, error))
741 {
742 if (dbus_error_has_name (error, DBUS_ERROR_NO_MEMORY))
743 goto failed;
744 else
745 dbus_error_free (error);
746 }
747
748 link = _dbus_list_get_next_link (directories, link);
749 }
750
751 return activation;
752
753 failed:
754 bus_activation_unref (activation);
755 return NULL;
756 }
757
758 BusActivation *
bus_activation_ref(BusActivation * activation)759 bus_activation_ref (BusActivation *activation)
760 {
761 _dbus_assert (activation->refcount > 0);
762
763 activation->refcount += 1;
764
765 return activation;
766 }
767
768 void
bus_activation_unref(BusActivation * activation)769 bus_activation_unref (BusActivation *activation)
770 {
771 _dbus_assert (activation->refcount > 0);
772
773 activation->refcount -= 1;
774
775 if (activation->refcount > 0)
776 return;
777
778 dbus_free (activation->server_address);
779 if (activation->entries)
780 _dbus_hash_table_unref (activation->entries);
781 if (activation->pending_activations)
782 _dbus_hash_table_unref (activation->pending_activations);
783 if (activation->directories)
784 _dbus_hash_table_unref (activation->directories);
785
786 dbus_free (activation);
787 }
788
789 static void
child_setup(void * data)790 child_setup (void *data)
791 {
792 BusActivation *activation = data;
793 const char *type;
794
795 /* If no memory, we simply have the child exit, so it won't try
796 * to connect to the wrong thing.
797 */
798 if (!_dbus_setenv ("DBUS_STARTER_ADDRESS", activation->server_address))
799 _dbus_exit (1);
800
801 type = bus_context_get_type (activation->context);
802 if (type != NULL)
803 {
804 if (!_dbus_setenv ("DBUS_STARTER_BUS_TYPE", type))
805 _dbus_exit (1);
806
807 if (strcmp (type, "session") == 0)
808 {
809 if (!_dbus_setenv ("DBUS_SESSION_BUS_ADDRESS",
810 activation->server_address))
811 _dbus_exit (1);
812 }
813 else if (strcmp (type, "system") == 0)
814 {
815 if (!_dbus_setenv ("DBUS_SYSTEM_BUS_ADDRESS",
816 activation->server_address))
817 _dbus_exit (1);
818 }
819 }
820 }
821
822 typedef struct
823 {
824 BusPendingActivation *pending_activation;
825 DBusPreallocatedHash *hash_entry;
826 } RestorePendingData;
827
828 static void
restore_pending(void * data)829 restore_pending (void *data)
830 {
831 RestorePendingData *d = data;
832
833 _dbus_assert (d->pending_activation != NULL);
834 _dbus_assert (d->hash_entry != NULL);
835
836 _dbus_verbose ("Restoring pending activation for service %s, has timeout = %d\n",
837 d->pending_activation->service_name,
838 d->pending_activation->timeout_added);
839
840 _dbus_hash_table_insert_string_preallocated (d->pending_activation->activation->pending_activations,
841 d->hash_entry,
842 d->pending_activation->service_name, d->pending_activation);
843
844 bus_pending_activation_ref (d->pending_activation);
845
846 d->hash_entry = NULL;
847 }
848
849 static void
free_pending_restore_data(void * data)850 free_pending_restore_data (void *data)
851 {
852 RestorePendingData *d = data;
853
854 if (d->hash_entry)
855 _dbus_hash_table_free_preallocated_entry (d->pending_activation->activation->pending_activations,
856 d->hash_entry);
857
858 bus_pending_activation_unref (d->pending_activation);
859
860 dbus_free (d);
861 }
862
863 static dbus_bool_t
add_restore_pending_to_transaction(BusTransaction * transaction,BusPendingActivation * pending_activation)864 add_restore_pending_to_transaction (BusTransaction *transaction,
865 BusPendingActivation *pending_activation)
866 {
867 RestorePendingData *d;
868
869 d = dbus_new (RestorePendingData, 1);
870 if (d == NULL)
871 return FALSE;
872
873 d->pending_activation = pending_activation;
874 d->hash_entry = _dbus_hash_table_preallocate_entry (d->pending_activation->activation->pending_activations);
875
876 bus_pending_activation_ref (d->pending_activation);
877
878 if (d->hash_entry == NULL ||
879 !bus_transaction_add_cancel_hook (transaction, restore_pending, d,
880 free_pending_restore_data))
881 {
882 free_pending_restore_data (d);
883 return FALSE;
884 }
885
886 _dbus_verbose ("Saved pending activation to be restored if the transaction fails\n");
887
888 return TRUE;
889 }
890
891 dbus_bool_t
bus_activation_service_created(BusActivation * activation,const char * service_name,BusTransaction * transaction,DBusError * error)892 bus_activation_service_created (BusActivation *activation,
893 const char *service_name,
894 BusTransaction *transaction,
895 DBusError *error)
896 {
897 BusPendingActivation *pending_activation;
898 DBusMessage *message;
899 DBusList *link;
900
901 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
902
903 /* Check if it's a pending activation */
904 pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, service_name);
905
906 if (!pending_activation)
907 return TRUE;
908
909 link = _dbus_list_get_first_link (&pending_activation->entries);
910 while (link != NULL)
911 {
912 BusPendingActivationEntry *entry = link->data;
913 DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link);
914
915 if (dbus_connection_get_is_connected (entry->connection))
916 {
917 /* Only send activation replies to regular activation requests. */
918 if (!entry->auto_activation)
919 {
920 dbus_uint32_t result;
921
922 message = dbus_message_new_method_return (entry->activation_message);
923 if (!message)
924 {
925 BUS_SET_OOM (error);
926 goto error;
927 }
928
929 result = DBUS_START_REPLY_SUCCESS;
930
931 if (!dbus_message_append_args (message,
932 DBUS_TYPE_UINT32, &result,
933 DBUS_TYPE_INVALID))
934 {
935 dbus_message_unref (message);
936 BUS_SET_OOM (error);
937 goto error;
938 }
939
940 if (!bus_transaction_send_from_driver (transaction, entry->connection, message))
941 {
942 dbus_message_unref (message);
943 BUS_SET_OOM (error);
944 goto error;
945 }
946
947 dbus_message_unref (message);
948 }
949 }
950
951 link = next;
952 }
953
954 return TRUE;
955
956 error:
957 return FALSE;
958 }
959
960 dbus_bool_t
bus_activation_send_pending_auto_activation_messages(BusActivation * activation,BusService * service,BusTransaction * transaction,DBusError * error)961 bus_activation_send_pending_auto_activation_messages (BusActivation *activation,
962 BusService *service,
963 BusTransaction *transaction,
964 DBusError *error)
965 {
966 BusPendingActivation *pending_activation;
967 DBusList *link;
968
969 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
970
971 /* Check if it's a pending activation */
972 pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations,
973 bus_service_get_name (service));
974
975 if (!pending_activation)
976 return TRUE;
977
978 link = _dbus_list_get_first_link (&pending_activation->entries);
979 while (link != NULL)
980 {
981 BusPendingActivationEntry *entry = link->data;
982 DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link);
983
984 if (entry->auto_activation && dbus_connection_get_is_connected (entry->connection))
985 {
986 DBusConnection *addressed_recipient;
987
988 addressed_recipient = bus_service_get_primary_owners_connection (service);
989
990 /* Check the security policy, which has the side-effect of adding an
991 * expected pending reply.
992 */
993 if (!bus_context_check_security_policy (activation->context, transaction,
994 entry->connection,
995 addressed_recipient,
996 addressed_recipient,
997 entry->activation_message, error))
998 goto error;
999
1000 if (!bus_transaction_send (transaction, addressed_recipient, entry->activation_message))
1001 {
1002 BUS_SET_OOM (error);
1003 goto error;
1004 }
1005 }
1006
1007 link = next;
1008 }
1009
1010 if (!add_restore_pending_to_transaction (transaction, pending_activation))
1011 {
1012 _dbus_verbose ("Could not add cancel hook to transaction to revert removing pending activation\n");
1013 BUS_SET_OOM (error);
1014 goto error;
1015 }
1016
1017 _dbus_hash_table_remove_string (activation->pending_activations, bus_service_get_name (service));
1018
1019 return TRUE;
1020
1021 error:
1022 return FALSE;
1023 }
1024
1025 /**
1026 * FIXME @todo the error messages here would ideally be preallocated
1027 * so we don't need to allocate memory to send them.
1028 * Using the usual tactic, prealloc an OOM message, then
1029 * if we can't alloc the real error send the OOM error instead.
1030 */
1031 static dbus_bool_t
try_send_activation_failure(BusPendingActivation * pending_activation,const DBusError * how)1032 try_send_activation_failure (BusPendingActivation *pending_activation,
1033 const DBusError *how)
1034 {
1035 BusActivation *activation;
1036 DBusList *link;
1037 BusTransaction *transaction;
1038
1039 activation = pending_activation->activation;
1040
1041 transaction = bus_transaction_new (activation->context);
1042 if (transaction == NULL)
1043 return FALSE;
1044
1045 link = _dbus_list_get_first_link (&pending_activation->entries);
1046 while (link != NULL)
1047 {
1048 BusPendingActivationEntry *entry = link->data;
1049 DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link);
1050
1051 if (dbus_connection_get_is_connected (entry->connection))
1052 {
1053 if (!bus_transaction_send_error_reply (transaction,
1054 entry->connection,
1055 how,
1056 entry->activation_message))
1057 goto error;
1058 }
1059
1060 link = next;
1061 }
1062
1063 bus_transaction_execute_and_free (transaction);
1064
1065 return TRUE;
1066
1067 error:
1068 if (transaction)
1069 bus_transaction_cancel_and_free (transaction);
1070 return FALSE;
1071 }
1072
1073 /**
1074 * Free the pending activation and send an error message to all the
1075 * connections that were waiting for it.
1076 */
1077 static void
pending_activation_failed(BusPendingActivation * pending_activation,const DBusError * how)1078 pending_activation_failed (BusPendingActivation *pending_activation,
1079 const DBusError *how)
1080 {
1081 /* FIXME use preallocated OOM messages instead of bus_wait_for_memory() */
1082 while (!try_send_activation_failure (pending_activation, how))
1083 _dbus_wait_for_memory ();
1084
1085 /* Destroy this pending activation */
1086 _dbus_hash_table_remove_string (pending_activation->activation->pending_activations,
1087 pending_activation->service_name);
1088 }
1089
1090 static dbus_bool_t
babysitter_watch_callback(DBusWatch * watch,unsigned int condition,void * data)1091 babysitter_watch_callback (DBusWatch *watch,
1092 unsigned int condition,
1093 void *data)
1094 {
1095 BusPendingActivation *pending_activation = data;
1096 dbus_bool_t retval;
1097 DBusBabysitter *babysitter;
1098
1099 babysitter = pending_activation->babysitter;
1100
1101 _dbus_babysitter_ref (babysitter);
1102
1103 retval = dbus_watch_handle (watch, condition);
1104
1105 /* FIXME this is broken in the same way that
1106 * connection watches used to be; there should be
1107 * a separate callback for status change, instead
1108 * of doing "if we handled a watch status might
1109 * have changed"
1110 *
1111 * Fixing this lets us move dbus_watch_handle
1112 * calls into dbus-mainloop.c
1113 */
1114
1115 if (_dbus_babysitter_get_child_exited (babysitter))
1116 {
1117 DBusError error;
1118 DBusHashIter iter;
1119
1120 dbus_error_init (&error);
1121 _dbus_babysitter_set_child_exit_error (babysitter, &error);
1122
1123 /* Destroy all pending activations with the same exec */
1124 _dbus_hash_iter_init (pending_activation->activation->pending_activations,
1125 &iter);
1126 while (_dbus_hash_iter_next (&iter))
1127 {
1128 BusPendingActivation *p = _dbus_hash_iter_get_value (&iter);
1129
1130 if (p != pending_activation && strcmp (p->exec, pending_activation->exec) == 0)
1131 pending_activation_failed (p, &error);
1132 }
1133
1134 /* Destroys the pending activation */
1135 pending_activation_failed (pending_activation, &error);
1136
1137 dbus_error_free (&error);
1138 }
1139
1140 _dbus_babysitter_unref (babysitter);
1141
1142 return retval;
1143 }
1144
1145 static dbus_bool_t
add_babysitter_watch(DBusWatch * watch,void * data)1146 add_babysitter_watch (DBusWatch *watch,
1147 void *data)
1148 {
1149 BusPendingActivation *pending_activation = data;
1150
1151 return _dbus_loop_add_watch (bus_context_get_loop (pending_activation->activation->context),
1152 watch, babysitter_watch_callback, pending_activation,
1153 NULL);
1154 }
1155
1156 static void
remove_babysitter_watch(DBusWatch * watch,void * data)1157 remove_babysitter_watch (DBusWatch *watch,
1158 void *data)
1159 {
1160 BusPendingActivation *pending_activation = data;
1161
1162 _dbus_loop_remove_watch (bus_context_get_loop (pending_activation->activation->context),
1163 watch, babysitter_watch_callback, pending_activation);
1164 }
1165
1166 static dbus_bool_t
pending_activation_timed_out(void * data)1167 pending_activation_timed_out (void *data)
1168 {
1169 BusPendingActivation *pending_activation = data;
1170 DBusError error;
1171
1172 /* Kill the spawned process, since it sucks
1173 * (not sure this is what we want to do, but
1174 * may as well try it for now)
1175 */
1176 if (pending_activation->babysitter)
1177 _dbus_babysitter_kill_child (pending_activation->babysitter);
1178
1179 dbus_error_init (&error);
1180
1181 dbus_set_error (&error, DBUS_ERROR_TIMED_OUT,
1182 "Activation of %s timed out",
1183 pending_activation->service_name);
1184
1185 pending_activation_failed (pending_activation, &error);
1186
1187 dbus_error_free (&error);
1188
1189 return TRUE;
1190 }
1191
1192 static void
cancel_pending(void * data)1193 cancel_pending (void *data)
1194 {
1195 BusPendingActivation *pending_activation = data;
1196
1197 _dbus_verbose ("Canceling pending activation of %s\n",
1198 pending_activation->service_name);
1199
1200 if (pending_activation->babysitter)
1201 _dbus_babysitter_kill_child (pending_activation->babysitter);
1202
1203 _dbus_hash_table_remove_string (pending_activation->activation->pending_activations,
1204 pending_activation->service_name);
1205 }
1206
1207 static void
free_pending_cancel_data(void * data)1208 free_pending_cancel_data (void *data)
1209 {
1210 BusPendingActivation *pending_activation = data;
1211
1212 bus_pending_activation_unref (pending_activation);
1213 }
1214
1215 static dbus_bool_t
add_cancel_pending_to_transaction(BusTransaction * transaction,BusPendingActivation * pending_activation)1216 add_cancel_pending_to_transaction (BusTransaction *transaction,
1217 BusPendingActivation *pending_activation)
1218 {
1219 if (!bus_transaction_add_cancel_hook (transaction, cancel_pending,
1220 pending_activation,
1221 free_pending_cancel_data))
1222 return FALSE;
1223
1224 bus_pending_activation_ref (pending_activation);
1225
1226 _dbus_verbose ("Saved pending activation to be canceled if the transaction fails\n");
1227
1228 return TRUE;
1229 }
1230
1231 static dbus_bool_t
update_service_cache(BusActivation * activation,DBusError * error)1232 update_service_cache (BusActivation *activation, DBusError *error)
1233 {
1234 DBusHashIter iter;
1235
1236 _dbus_hash_iter_init (activation->directories, &iter);
1237 while (_dbus_hash_iter_next (&iter))
1238 {
1239 DBusError tmp_error;
1240 BusServiceDirectory *s_dir;
1241
1242 s_dir = _dbus_hash_iter_get_value (&iter);
1243
1244 dbus_error_init (&tmp_error);
1245 if (!update_directory (activation, s_dir, &tmp_error))
1246 {
1247 if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
1248 {
1249 dbus_move_error (&tmp_error, error);
1250 return FALSE;
1251 }
1252
1253 dbus_error_free (&tmp_error);
1254 continue;
1255 }
1256 }
1257
1258 return TRUE;
1259 }
1260
1261 static BusActivationEntry *
activation_find_entry(BusActivation * activation,const char * service_name,DBusError * error)1262 activation_find_entry (BusActivation *activation,
1263 const char *service_name,
1264 DBusError *error)
1265 {
1266 BusActivationEntry *entry;
1267
1268 entry = _dbus_hash_table_lookup_string (activation->entries, service_name);
1269 if (!entry)
1270 {
1271 if (!update_service_cache (activation, error))
1272 return NULL;
1273
1274 entry = _dbus_hash_table_lookup_string (activation->entries,
1275 service_name);
1276 }
1277 else
1278 {
1279 BusActivationEntry *updated_entry;
1280
1281 if (!check_service_file (activation, entry, &updated_entry, error))
1282 return NULL;
1283
1284 entry = updated_entry;
1285 }
1286
1287 if (!entry)
1288 {
1289 dbus_set_error (error, DBUS_ERROR_SERVICE_UNKNOWN,
1290 "The name %s was not provided by any .service files",
1291 service_name);
1292 return NULL;
1293 }
1294
1295 return entry;
1296 }
1297
1298 dbus_bool_t
bus_activation_activate_service(BusActivation * activation,DBusConnection * connection,BusTransaction * transaction,dbus_bool_t auto_activation,DBusMessage * activation_message,const char * service_name,DBusError * error)1299 bus_activation_activate_service (BusActivation *activation,
1300 DBusConnection *connection,
1301 BusTransaction *transaction,
1302 dbus_bool_t auto_activation,
1303 DBusMessage *activation_message,
1304 const char *service_name,
1305 DBusError *error)
1306 {
1307 BusActivationEntry *entry;
1308 BusPendingActivation *pending_activation;
1309 BusPendingActivationEntry *pending_activation_entry;
1310 DBusMessage *message;
1311 DBusString service_str;
1312 char **argv;
1313 int argc;
1314 dbus_bool_t retval;
1315 DBusHashIter iter;
1316 dbus_bool_t activated;
1317
1318 activated = TRUE;
1319
1320 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1321
1322 if (activation->n_pending_activations >=
1323 bus_context_get_max_pending_activations (activation->context))
1324 {
1325 dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
1326 "The maximum number of pending activations has been reached, activation of %s failed",
1327 service_name);
1328 return FALSE;
1329 }
1330
1331 entry = activation_find_entry (activation, service_name, error);
1332 if (!entry)
1333 return FALSE;
1334
1335 /* Bypass the registry lookup if we're auto-activating, bus_dispatch would not
1336 * call us if the service is already active.
1337 */
1338 if (!auto_activation)
1339 {
1340 /* Check if the service is active */
1341 _dbus_string_init_const (&service_str, service_name);
1342 if (bus_registry_lookup (bus_context_get_registry (activation->context), &service_str) != NULL)
1343 {
1344 dbus_uint32_t result;
1345
1346 _dbus_verbose ("Service \"%s\" is already active\n", service_name);
1347
1348 message = dbus_message_new_method_return (activation_message);
1349
1350 if (!message)
1351 {
1352 _dbus_verbose ("No memory to create reply to activate message\n");
1353 BUS_SET_OOM (error);
1354 return FALSE;
1355 }
1356
1357 result = DBUS_START_REPLY_ALREADY_RUNNING;
1358
1359 if (!dbus_message_append_args (message,
1360 DBUS_TYPE_UINT32, &result,
1361 DBUS_TYPE_INVALID))
1362 {
1363 _dbus_verbose ("No memory to set args of reply to activate message\n");
1364 BUS_SET_OOM (error);
1365 dbus_message_unref (message);
1366 return FALSE;
1367 }
1368
1369 retval = bus_transaction_send_from_driver (transaction, connection, message);
1370 dbus_message_unref (message);
1371 if (!retval)
1372 {
1373 _dbus_verbose ("Failed to send reply\n");
1374 BUS_SET_OOM (error);
1375 }
1376
1377 return retval;
1378 }
1379 }
1380
1381 pending_activation_entry = dbus_new0 (BusPendingActivationEntry, 1);
1382 if (!pending_activation_entry)
1383 {
1384 _dbus_verbose ("Failed to create pending activation entry\n");
1385 BUS_SET_OOM (error);
1386 return FALSE;
1387 }
1388
1389 pending_activation_entry->auto_activation = auto_activation;
1390
1391 pending_activation_entry->activation_message = activation_message;
1392 dbus_message_ref (activation_message);
1393 pending_activation_entry->connection = connection;
1394 dbus_connection_ref (connection);
1395
1396 /* Check if the service is being activated */
1397 pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, service_name);
1398 if (pending_activation)
1399 {
1400 if (!_dbus_list_append (&pending_activation->entries, pending_activation_entry))
1401 {
1402 _dbus_verbose ("Failed to append a new entry to pending activation\n");
1403
1404 BUS_SET_OOM (error);
1405 bus_pending_activation_entry_free (pending_activation_entry);
1406 return FALSE;
1407 }
1408
1409 pending_activation->n_entries += 1;
1410 pending_activation->activation->n_pending_activations += 1;
1411 }
1412 else
1413 {
1414 pending_activation = dbus_new0 (BusPendingActivation, 1);
1415 if (!pending_activation)
1416 {
1417 _dbus_verbose ("Failed to create pending activation\n");
1418
1419 BUS_SET_OOM (error);
1420 bus_pending_activation_entry_free (pending_activation_entry);
1421 return FALSE;
1422 }
1423
1424 pending_activation->activation = activation;
1425 pending_activation->refcount = 1;
1426
1427 pending_activation->service_name = _dbus_strdup (service_name);
1428 if (!pending_activation->service_name)
1429 {
1430 _dbus_verbose ("Failed to copy service name for pending activation\n");
1431
1432 BUS_SET_OOM (error);
1433 bus_pending_activation_unref (pending_activation);
1434 bus_pending_activation_entry_free (pending_activation_entry);
1435 return FALSE;
1436 }
1437
1438 pending_activation->exec = _dbus_strdup (entry->exec);
1439 if (!pending_activation->exec)
1440 {
1441 _dbus_verbose ("Failed to copy service exec for pending activation\n");
1442 BUS_SET_OOM (error);
1443 bus_pending_activation_unref (pending_activation);
1444 bus_pending_activation_entry_free (pending_activation_entry);
1445 return FALSE;
1446 }
1447
1448 pending_activation->timeout =
1449 _dbus_timeout_new (bus_context_get_activation_timeout (activation->context),
1450 pending_activation_timed_out,
1451 pending_activation,
1452 NULL);
1453 if (!pending_activation->timeout)
1454 {
1455 _dbus_verbose ("Failed to create timeout for pending activation\n");
1456
1457 BUS_SET_OOM (error);
1458 bus_pending_activation_unref (pending_activation);
1459 bus_pending_activation_entry_free (pending_activation_entry);
1460 return FALSE;
1461 }
1462
1463 if (!_dbus_loop_add_timeout (bus_context_get_loop (activation->context),
1464 pending_activation->timeout,
1465 handle_timeout_callback,
1466 pending_activation,
1467 NULL))
1468 {
1469 _dbus_verbose ("Failed to add timeout for pending activation\n");
1470
1471 BUS_SET_OOM (error);
1472 bus_pending_activation_unref (pending_activation);
1473 bus_pending_activation_entry_free (pending_activation_entry);
1474 return FALSE;
1475 }
1476
1477 pending_activation->timeout_added = TRUE;
1478
1479 if (!_dbus_list_append (&pending_activation->entries, pending_activation_entry))
1480 {
1481 _dbus_verbose ("Failed to add entry to just-created pending activation\n");
1482
1483 BUS_SET_OOM (error);
1484 bus_pending_activation_unref (pending_activation);
1485 bus_pending_activation_entry_free (pending_activation_entry);
1486 return FALSE;
1487 }
1488
1489 pending_activation->n_entries += 1;
1490 pending_activation->activation->n_pending_activations += 1;
1491
1492 activated = FALSE;
1493 _dbus_hash_iter_init (activation->pending_activations, &iter);
1494 while (_dbus_hash_iter_next (&iter))
1495 {
1496 BusPendingActivation *p = _dbus_hash_iter_get_value (&iter);
1497
1498 if (strcmp (p->exec, entry->exec) == 0)
1499 {
1500 activated = TRUE;
1501 break;
1502 }
1503 }
1504
1505 if (!_dbus_hash_table_insert_string (activation->pending_activations,
1506 pending_activation->service_name,
1507 pending_activation))
1508 {
1509 _dbus_verbose ("Failed to put pending activation in hash table\n");
1510
1511 BUS_SET_OOM (error);
1512 bus_pending_activation_unref (pending_activation);
1513 return FALSE;
1514 }
1515 }
1516
1517 if (!add_cancel_pending_to_transaction (transaction, pending_activation))
1518 {
1519 _dbus_verbose ("Failed to add pending activation cancel hook to transaction\n");
1520 BUS_SET_OOM (error);
1521 _dbus_hash_table_remove_string (activation->pending_activations,
1522 pending_activation->service_name);
1523
1524 return FALSE;
1525 }
1526
1527 if (activated)
1528 return TRUE;
1529
1530 /* Now try to spawn the process */
1531 if (!_dbus_shell_parse_argv (entry->exec, &argc, &argv, error))
1532 {
1533 _dbus_verbose ("Failed to parse command line: %s\n", entry->exec);
1534 _DBUS_ASSERT_ERROR_IS_SET (error);
1535
1536 _dbus_hash_table_remove_string (activation->pending_activations,
1537 pending_activation->service_name);
1538
1539 return FALSE;
1540 }
1541
1542 _dbus_verbose ("Spawning %s ...\n", argv[0]);
1543 if (!_dbus_spawn_async_with_babysitter (&pending_activation->babysitter, argv,
1544 child_setup, activation,
1545 error))
1546 {
1547 _dbus_verbose ("Failed to spawn child\n");
1548 _DBUS_ASSERT_ERROR_IS_SET (error);
1549 dbus_free_string_array (argv);
1550
1551 return FALSE;
1552 }
1553
1554 dbus_free_string_array (argv);
1555
1556 _dbus_assert (pending_activation->babysitter != NULL);
1557
1558 if (!_dbus_babysitter_set_watch_functions (pending_activation->babysitter,
1559 add_babysitter_watch,
1560 remove_babysitter_watch,
1561 NULL,
1562 pending_activation,
1563 NULL))
1564 {
1565 BUS_SET_OOM (error);
1566 _dbus_verbose ("Failed to set babysitter watch functions\n");
1567 return FALSE;
1568 }
1569
1570 return TRUE;
1571 }
1572
1573 dbus_bool_t
bus_activation_list_services(BusActivation * activation,char *** listp,int * array_len)1574 bus_activation_list_services (BusActivation *activation,
1575 char ***listp,
1576 int *array_len)
1577 {
1578 int i, j, len;
1579 char **retval;
1580 DBusHashIter iter;
1581
1582 len = _dbus_hash_table_get_n_entries (activation->entries);
1583 retval = dbus_new (char *, len + 1);
1584
1585 if (retval == NULL)
1586 return FALSE;
1587
1588 _dbus_hash_iter_init (activation->entries, &iter);
1589 i = 0;
1590 while (_dbus_hash_iter_next (&iter))
1591 {
1592 BusActivationEntry *entry = _dbus_hash_iter_get_value (&iter);
1593
1594 retval[i] = _dbus_strdup (entry->name);
1595 if (retval[i] == NULL)
1596 goto error;
1597
1598 i++;
1599 }
1600
1601 retval[i] = NULL;
1602
1603 if (array_len)
1604 *array_len = len;
1605
1606 *listp = retval;
1607 return TRUE;
1608
1609 error:
1610 for (j = 0; j < i; j++)
1611 dbus_free (retval[i]);
1612 dbus_free (retval);
1613
1614 return FALSE;
1615 }
1616
1617
1618 #ifdef DBUS_BUILD_TESTS
1619
1620 #include <stdio.h>
1621
1622 #define SERVICE_NAME_1 "MyService1"
1623 #define SERVICE_NAME_2 "MyService2"
1624 #define SERVICE_NAME_3 "MyService3"
1625
1626 #define SERVICE_FILE_1 "service-1.service"
1627 #define SERVICE_FILE_2 "service-2.service"
1628 #define SERVICE_FILE_3 "service-3.service"
1629
1630 static dbus_bool_t
test_create_service_file(DBusString * dir,const char * filename,const char * name,const char * exec)1631 test_create_service_file (DBusString *dir,
1632 const char *filename,
1633 const char *name,
1634 const char *exec)
1635 {
1636 DBusString file_name, full_path;
1637 FILE *file;
1638 dbus_bool_t ret_val;
1639
1640 ret_val = TRUE;
1641 _dbus_string_init_const (&file_name, filename);
1642
1643 if (!_dbus_string_init (&full_path))
1644 return FALSE;
1645
1646 if (!_dbus_string_append (&full_path, _dbus_string_get_const_data (dir)) ||
1647 !_dbus_concat_dir_and_file (&full_path, &file_name))
1648 {
1649 ret_val = FALSE;
1650 goto out;
1651 }
1652
1653 file = fopen (_dbus_string_get_const_data (&full_path), "w");
1654 if (!file)
1655 {
1656 ret_val = FALSE;
1657 goto out;
1658 }
1659
1660 fprintf (file, "[D-BUS Service]\nName=%s\nExec=%s\n", name, exec);
1661 fclose (file);
1662
1663 out:
1664 _dbus_string_free (&full_path);
1665 return ret_val;
1666 }
1667
1668 static dbus_bool_t
test_remove_service_file(DBusString * dir,const char * filename)1669 test_remove_service_file (DBusString *dir, const char *filename)
1670 {
1671 DBusString file_name, full_path;
1672 dbus_bool_t ret_val;
1673
1674 ret_val = TRUE;
1675
1676 _dbus_string_init_const (&file_name, filename);
1677
1678 if (!_dbus_string_init (&full_path))
1679 return FALSE;
1680
1681 if (!_dbus_string_append (&full_path, _dbus_string_get_const_data (dir)) ||
1682 !_dbus_concat_dir_and_file (&full_path, &file_name))
1683 {
1684 ret_val = FALSE;
1685 goto out;
1686 }
1687
1688 if (!_dbus_delete_file (&full_path, NULL))
1689 {
1690 ret_val = FALSE;
1691 goto out;
1692 }
1693
1694 out:
1695 _dbus_string_free (&full_path);
1696 return ret_val;
1697 }
1698
1699 static dbus_bool_t
test_remove_directory(DBusString * dir)1700 test_remove_directory (DBusString *dir)
1701 {
1702 DBusDirIter *iter;
1703 DBusString filename, full_path;
1704 dbus_bool_t ret_val;
1705
1706 ret_val = TRUE;
1707
1708 if (!_dbus_string_init (&filename))
1709 return FALSE;
1710
1711 if (!_dbus_string_init (&full_path))
1712 {
1713 _dbus_string_free (&filename);
1714 return FALSE;
1715 }
1716
1717 iter = _dbus_directory_open (dir, NULL);
1718 if (iter == NULL)
1719 {
1720 ret_val = FALSE;
1721 goto out;
1722 }
1723
1724 while (_dbus_directory_get_next_file (iter, &filename, NULL))
1725 {
1726 if (!test_remove_service_file (dir, _dbus_string_get_const_data (&filename)))
1727 {
1728 ret_val = FALSE;
1729 goto out;
1730 }
1731 }
1732 _dbus_directory_close (iter);
1733
1734 if (!_dbus_delete_directory (dir, NULL))
1735 {
1736 ret_val = FALSE;
1737 goto out;
1738 }
1739
1740 out:
1741 _dbus_string_free (&filename);
1742 _dbus_string_free (&full_path);
1743
1744 return ret_val;
1745 }
1746
1747 static dbus_bool_t
init_service_reload_test(DBusString * dir)1748 init_service_reload_test (DBusString *dir)
1749 {
1750 DBusStat stat_buf;
1751
1752 if (!_dbus_stat (dir, &stat_buf, NULL))
1753 {
1754 if (!_dbus_create_directory (dir, NULL))
1755 return FALSE;
1756 }
1757 else
1758 {
1759 if (!test_remove_directory (dir))
1760 return FALSE;
1761
1762 if (!_dbus_create_directory (dir, NULL))
1763 return FALSE;
1764 }
1765
1766 /* Create one initial file */
1767 if (!test_create_service_file (dir, SERVICE_FILE_1, SERVICE_NAME_1, "exec-1"))
1768 return FALSE;
1769
1770 return TRUE;
1771 }
1772
1773 static dbus_bool_t
cleanup_service_reload_test(DBusString * dir)1774 cleanup_service_reload_test (DBusString *dir)
1775 {
1776 if (!test_remove_directory (dir))
1777 return FALSE;
1778
1779 return TRUE;
1780 }
1781
1782 typedef struct
1783 {
1784 BusActivation *activation;
1785 const char *service_name;
1786 dbus_bool_t expecting_find;
1787 } CheckData;
1788
1789 static dbus_bool_t
check_func(void * data)1790 check_func (void *data)
1791 {
1792 CheckData *d;
1793 BusActivationEntry *entry;
1794 DBusError error;
1795 dbus_bool_t ret_val;
1796
1797 ret_val = TRUE;
1798 d = data;
1799
1800 dbus_error_init (&error);
1801
1802 entry = activation_find_entry (d->activation, d->service_name, &error);
1803 if (entry == NULL)
1804 {
1805 if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
1806 {
1807 ret_val = TRUE;
1808 }
1809 else
1810 {
1811 if (d->expecting_find)
1812 ret_val = FALSE;
1813 }
1814
1815 dbus_error_free (&error);
1816 }
1817 else
1818 {
1819 if (!d->expecting_find)
1820 ret_val = FALSE;
1821 }
1822
1823 return ret_val;
1824 }
1825
1826 static dbus_bool_t
do_test(const char * description,dbus_bool_t oom_test,CheckData * data)1827 do_test (const char *description, dbus_bool_t oom_test, CheckData *data)
1828 {
1829 dbus_bool_t err;
1830
1831 if (oom_test)
1832 err = !_dbus_test_oom_handling (description, check_func, data);
1833 else
1834 err = !check_func (data);
1835
1836 if (err)
1837 _dbus_assert_not_reached ("Test failed");
1838
1839 return TRUE;
1840 }
1841
1842 static dbus_bool_t
do_service_reload_test(DBusString * dir,dbus_bool_t oom_test)1843 do_service_reload_test (DBusString *dir, dbus_bool_t oom_test)
1844 {
1845 BusActivation *activation;
1846 DBusString address;
1847 DBusList *directories;
1848 CheckData d;
1849
1850 directories = NULL;
1851 _dbus_string_init_const (&address, "");
1852
1853 if (!_dbus_list_append (&directories, _dbus_string_get_data (dir)))
1854 return FALSE;
1855
1856 activation = bus_activation_new (NULL, &address, &directories, NULL);
1857 if (!activation)
1858 return FALSE;
1859
1860 d.activation = activation;
1861
1862 /* Check for existing service file */
1863 d.expecting_find = TRUE;
1864 d.service_name = SERVICE_NAME_1;
1865
1866 if (!do_test ("Existing service file", oom_test, &d))
1867 return FALSE;
1868
1869 /* Check for non-existing service file */
1870 d.expecting_find = FALSE;
1871 d.service_name = SERVICE_NAME_3;
1872
1873 if (!do_test ("Nonexisting service file", oom_test, &d))
1874 return FALSE;
1875
1876 /* Check for added service file */
1877 if (!test_create_service_file (dir, SERVICE_FILE_2, SERVICE_NAME_2, "exec-2"))
1878 return FALSE;
1879
1880 d.expecting_find = TRUE;
1881 d.service_name = SERVICE_NAME_2;
1882
1883 if (!do_test ("Added service file", oom_test, &d))
1884 return FALSE;
1885
1886 /* Check for removed service file */
1887 if (!test_remove_service_file (dir, SERVICE_FILE_2))
1888 return FALSE;
1889
1890 d.expecting_find = FALSE;
1891 d.service_name = SERVICE_FILE_2;
1892
1893 if (!do_test ("Removed service file", oom_test, &d))
1894 return FALSE;
1895
1896 /* Check for updated service file */
1897
1898 _dbus_sleep_milliseconds (1000); /* Sleep a second to make sure the mtime is updated */
1899
1900 if (!test_create_service_file (dir, SERVICE_FILE_1, SERVICE_NAME_3, "exec-3"))
1901 return FALSE;
1902
1903 d.expecting_find = TRUE;
1904 d.service_name = SERVICE_NAME_3;
1905
1906 if (!do_test ("Updated service file, part 1", oom_test, &d))
1907 return FALSE;
1908
1909 d.expecting_find = FALSE;
1910 d.service_name = SERVICE_NAME_1;
1911
1912 if (!do_test ("Updated service file, part 2", oom_test, &d))
1913 return FALSE;
1914
1915 bus_activation_unref (activation);
1916 _dbus_list_clear (&directories);
1917
1918 return TRUE;
1919 }
1920
1921 dbus_bool_t
bus_activation_service_reload_test(const DBusString * test_data_dir)1922 bus_activation_service_reload_test (const DBusString *test_data_dir)
1923 {
1924 DBusString directory;
1925
1926 if (!_dbus_string_init (&directory))
1927 return FALSE;
1928
1929 if (!_dbus_string_append (&directory, _dbus_get_tmpdir()))
1930 return FALSE;
1931
1932 if (!_dbus_string_append (&directory, "/dbus-reload-test-") ||
1933 !_dbus_generate_random_ascii (&directory, 6))
1934 {
1935 return FALSE;
1936 }
1937
1938 /* Do normal tests */
1939 if (!init_service_reload_test (&directory))
1940 _dbus_assert_not_reached ("could not initiate service reload test");
1941
1942 if (!do_service_reload_test (&directory, FALSE))
1943 ; /* Do nothing? */
1944
1945 /* Do OOM tests */
1946 if (!init_service_reload_test (&directory))
1947 _dbus_assert_not_reached ("could not initiate service reload test");
1948
1949 if (!do_service_reload_test (&directory, TRUE))
1950 ; /* Do nothing? */
1951
1952 /* Cleanup test directory */
1953 if (!cleanup_service_reload_test (&directory))
1954 return FALSE;
1955
1956 _dbus_string_free (&directory);
1957
1958 return TRUE;
1959 }
1960
1961 #endif /* DBUS_BUILD_TESTS */
1962