• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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