2003-11-26 Mikael Hallendal <micke@imendio.com>
[platform/upstream/dbus.git] / bus / activation.c
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  *
7  * Licensed under the Academic Free License version 1.2
8  * 
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  * 
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  */
24 #include "activation.h"
25 #include "desktop-file.h"
26 #include "services.h"
27 #include "utils.h"
28 #include <dbus/dbus-internals.h>
29 #include <dbus/dbus-hash.h>
30 #include <dbus/dbus-list.h>
31 #include <dbus/dbus-spawn.h>
32 #include <dbus/dbus-timeout.h>
33 #include <sys/types.h>
34 #include <dirent.h>
35 #include <errno.h>
36
37 #define DBUS_SERVICE_SECTION "D-BUS Service"
38 #define DBUS_SERVICE_NAME "Name"
39 #define DBUS_SERVICE_EXEC "Exec"
40
41 struct BusActivation
42 {
43   int refcount;
44   DBusHashTable *entries;
45   DBusHashTable *pending_activations;
46   char *server_address;
47   BusContext *context;
48   int n_pending_activations; /**< This is in fact the number of BusPendingActivationEntry,
49                               * i.e. number of pending activation requests, not pending
50                               * activations per se
51                               */
52 };
53
54 typedef struct
55 {
56   char *name;
57   char *exec;
58 } BusActivationEntry;
59
60 typedef struct BusPendingActivationEntry BusPendingActivationEntry;
61
62 struct BusPendingActivationEntry
63 {
64   DBusMessage *activation_message;
65   DBusConnection *connection;
66 };
67
68 typedef struct
69 {
70   int refcount;
71   BusActivation *activation;
72   char *service_name;
73   DBusList *entries;
74   int n_entries;
75   DBusBabysitter *babysitter;
76   DBusTimeout *timeout;
77   unsigned int timeout_added : 1;
78 } BusPendingActivation;
79
80 static void
81 bus_pending_activation_entry_free (BusPendingActivationEntry *entry)
82 {
83   if (entry->activation_message)
84     dbus_message_unref (entry->activation_message);
85   
86   if (entry->connection)
87     dbus_connection_unref (entry->connection);
88   
89   dbus_free (entry);
90 }
91
92 static void
93 handle_timeout_callback (DBusTimeout   *timeout,
94                          void          *data)
95 {
96   BusPendingActivation *pending_activation = data;
97
98   while (!dbus_timeout_handle (pending_activation->timeout))
99     _dbus_wait_for_memory ();
100 }
101
102 static BusPendingActivation * 
103 bus_pending_activation_ref (BusPendingActivation *pending_activation)
104 {
105   _dbus_assert (pending_activation->refcount > 0);
106   pending_activation->refcount += 1;
107
108   return pending_activation;
109 }
110
111 static void
112 bus_pending_activation_unref (BusPendingActivation *pending_activation)
113 {
114   DBusList *link;
115   
116   if (pending_activation == NULL) /* hash table requires this */
117     return;
118
119   _dbus_assert (pending_activation->refcount > 0);
120   pending_activation->refcount -= 1;
121
122   if (pending_activation->refcount > 0)
123     return;
124   
125   if (pending_activation->timeout_added)
126     {
127       _dbus_loop_remove_timeout (bus_context_get_loop (pending_activation->activation->context),
128                                  pending_activation->timeout,
129                                  handle_timeout_callback, pending_activation);
130       pending_activation->timeout_added = FALSE;
131     }
132
133   if (pending_activation->timeout)
134     _dbus_timeout_unref (pending_activation->timeout);
135   
136   if (pending_activation->babysitter)
137     {
138       if (!_dbus_babysitter_set_watch_functions (pending_activation->babysitter,
139                                                  NULL, NULL, NULL,
140                                                  pending_activation->babysitter,
141                                                  NULL))
142         _dbus_assert_not_reached ("setting watch functions to NULL failed");
143       
144       _dbus_babysitter_unref (pending_activation->babysitter);
145     }
146   
147   dbus_free (pending_activation->service_name);
148
149   link = _dbus_list_get_first_link (&pending_activation->entries);
150
151   while (link != NULL)
152     {
153       BusPendingActivationEntry *entry = link->data;
154
155       bus_pending_activation_entry_free (entry);
156
157       link = _dbus_list_get_next_link (&pending_activation->entries, link);
158     }
159   _dbus_list_clear (&pending_activation->entries);
160
161   pending_activation->activation->n_pending_activations -=
162     pending_activation->n_entries;
163
164   _dbus_assert (pending_activation->activation->n_pending_activations >= 0);
165   
166   dbus_free (pending_activation);
167 }
168
169 static void
170 bus_activation_entry_free (BusActivationEntry *entry)
171 {
172   if (!entry)
173     return;
174   
175   dbus_free (entry->name);
176   dbus_free (entry->exec);
177
178   dbus_free (entry);
179 }
180
181 static dbus_bool_t
182 add_desktop_file_entry (BusActivation  *activation,
183                         BusDesktopFile *desktop_file,
184                         DBusError      *error)
185 {
186   char *name, *exec;
187   BusActivationEntry *entry;
188
189   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
190   
191   name = NULL;
192   exec = NULL;
193   entry = NULL;
194   
195   if (!bus_desktop_file_get_string (desktop_file,
196                                     DBUS_SERVICE_SECTION,
197                                     DBUS_SERVICE_NAME,
198                                     &name))
199     {
200       dbus_set_error (error, DBUS_ERROR_FAILED,
201                       "No \""DBUS_SERVICE_NAME"\" key in .service file\n");
202       goto failed;
203     }
204
205   if (!bus_desktop_file_get_string (desktop_file,
206                                     DBUS_SERVICE_SECTION,
207                                     DBUS_SERVICE_EXEC,
208                                     &exec))
209     {
210       dbus_set_error (error, DBUS_ERROR_FAILED,
211                       "No \""DBUS_SERVICE_EXEC"\" key in .service file\n");
212       goto failed;
213     }
214
215   /* FIXME we need a better-defined algorithm for which service file to
216    * pick than "whichever one is first in the directory listing"
217    */
218   if (_dbus_hash_table_lookup_string (activation->entries, name))
219     {
220       dbus_set_error (error, DBUS_ERROR_FAILED,
221                       "Service %s already exists in activation entry list\n", name);
222       goto failed;
223     }
224   
225   entry = dbus_new0 (BusActivationEntry, 1);
226   if (entry == NULL)
227     {
228       BUS_SET_OOM (error);
229       goto failed;
230     }
231   
232   entry->name = name;
233   entry->exec = exec;
234
235   if (!_dbus_hash_table_insert_string (activation->entries, entry->name, entry))
236     {
237       BUS_SET_OOM (error);
238       goto failed;
239     }
240
241   _dbus_verbose ("Added \"%s\" to list of services\n", entry->name);
242   
243   return TRUE;
244
245  failed:
246   dbus_free (name);
247   dbus_free (exec);
248   dbus_free (entry);
249   
250   return FALSE;
251 }
252
253 /* warning: this doesn't fully "undo" itself on failure, i.e. doesn't strip
254  * hash entries it already added.
255  */
256 static dbus_bool_t
257 load_directory (BusActivation *activation,
258                 const char    *directory,
259                 DBusError     *error)
260 {
261   DBusDirIter *iter;
262   DBusString dir, filename;
263   DBusString full_path;
264   BusDesktopFile *desktop_file;
265   DBusError tmp_error;
266   dbus_bool_t retval;
267   
268   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
269   
270   _dbus_string_init_const (&dir, directory);
271
272   iter = NULL;
273   desktop_file = NULL;
274   
275   if (!_dbus_string_init (&filename))
276     {
277       BUS_SET_OOM (error);
278       return FALSE;
279     }
280
281   if (!_dbus_string_init (&full_path))
282     {
283       BUS_SET_OOM (error);
284       _dbus_string_free (&filename);
285       return FALSE;
286     }
287
288   retval = FALSE;
289   
290   /* from this point it's safe to "goto out" */
291   
292   iter = _dbus_directory_open (&dir, error);
293   if (iter == NULL)
294     {
295       _dbus_verbose ("Failed to open directory %s: %s\n",
296                      directory, error ? error->message : "unknown");
297       goto out;
298     }
299   
300   /* Now read the files */
301   dbus_error_init (&tmp_error);
302   while (_dbus_directory_get_next_file (iter, &filename, &tmp_error))
303     {
304       _dbus_assert (!dbus_error_is_set (&tmp_error));
305       
306       _dbus_string_set_length (&full_path, 0);
307       
308       if (!_dbus_string_append (&full_path, directory) ||
309           !_dbus_concat_dir_and_file (&full_path, &filename))
310         {
311           BUS_SET_OOM (error);
312           goto out;
313         }
314       
315       if (!_dbus_string_ends_with_c_str (&filename, ".service"))
316         {
317           _dbus_verbose ("Skipping non-.service file %s\n",
318                          _dbus_string_get_const_data (&filename));
319           continue;
320         }
321       
322       desktop_file = bus_desktop_file_load (&full_path, &tmp_error);
323
324       if (desktop_file == NULL)
325         {
326           _dbus_verbose ("Could not load %s: %s\n",
327                          _dbus_string_get_const_data (&full_path),
328                          tmp_error.message);
329
330           if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
331             {
332               dbus_move_error (&tmp_error, error);
333               goto out;
334             }
335           
336           dbus_error_free (&tmp_error);
337           continue;
338         }
339
340       if (!add_desktop_file_entry (activation, desktop_file, &tmp_error))
341         {
342           bus_desktop_file_free (desktop_file);
343           desktop_file = NULL;
344           
345           _dbus_verbose ("Could not add %s to activation entry list: %s\n",
346                          _dbus_string_get_const_data (&full_path), tmp_error.message);
347
348           if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
349             {
350               dbus_move_error (&tmp_error, error);
351               goto out;
352             }
353
354           dbus_error_free (&tmp_error);
355           continue;
356         }
357       else
358         {
359           bus_desktop_file_free (desktop_file);
360           desktop_file = NULL;
361           continue;
362         }
363     }
364
365   if (dbus_error_is_set (&tmp_error))
366     {
367       dbus_move_error (&tmp_error, error);
368       goto out;
369     }
370   
371   retval = TRUE;
372   
373  out:
374   if (!retval)
375     _DBUS_ASSERT_ERROR_IS_SET (error);
376   else
377     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
378   
379   if (iter != NULL)
380     _dbus_directory_close (iter);
381   if (desktop_file)
382     bus_desktop_file_free (desktop_file);
383   _dbus_string_free (&filename);
384   _dbus_string_free (&full_path);
385   
386   return retval;
387 }
388
389 BusActivation*
390 bus_activation_new (BusContext        *context,
391                     const DBusString  *address,
392                     DBusList         **directories,
393                     DBusError         *error)
394 {
395   BusActivation *activation;
396   DBusList *link;
397   
398   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
399   
400   activation = dbus_new0 (BusActivation, 1);
401   if (activation == NULL)
402     {
403       BUS_SET_OOM (error);
404       return NULL;
405     }
406   
407   activation->refcount = 1;
408   activation->context = context;
409   activation->n_pending_activations = 0;
410   
411   if (!_dbus_string_copy_data (address, &activation->server_address))
412     {
413       BUS_SET_OOM (error);
414       goto failed;
415     }
416   
417   activation->entries = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
418                                              (DBusFreeFunction)bus_activation_entry_free);
419   if (activation->entries == NULL)
420     {      
421       BUS_SET_OOM (error);
422       goto failed;
423     }
424
425   activation->pending_activations = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
426                                                           (DBusFreeFunction)bus_pending_activation_unref);
427
428   if (activation->pending_activations == NULL)
429     {
430       BUS_SET_OOM (error);
431       goto failed;
432     }
433   
434   /* Load service files */
435   link = _dbus_list_get_first_link (directories);
436   while (link != NULL)
437     {
438       if (!load_directory (activation, link->data, error))
439         goto failed;
440       link = _dbus_list_get_next_link (directories, link);
441     }
442
443   return activation;
444   
445  failed:
446   bus_activation_unref (activation);  
447   return NULL;
448 }
449
450 BusActivation *
451 bus_activation_ref (BusActivation *activation)
452 {
453   _dbus_assert (activation->refcount > 0);
454   
455   activation->refcount += 1;
456
457   return activation;
458 }
459
460 void
461 bus_activation_unref (BusActivation *activation)
462 {
463   _dbus_assert (activation->refcount > 0);
464
465   activation->refcount -= 1;
466
467   if (activation->refcount == 0)
468     {
469       dbus_free (activation->server_address);
470       if (activation->entries)
471         _dbus_hash_table_unref (activation->entries);
472       if (activation->pending_activations)
473         _dbus_hash_table_unref (activation->pending_activations);
474       dbus_free (activation);
475     }
476 }
477
478 static void
479 child_setup (void *data)
480 {
481   BusActivation *activation = data;
482   const char *type;
483   
484   /* If no memory, we simply have the child exit, so it won't try
485    * to connect to the wrong thing.
486    */
487   if (!_dbus_setenv ("DBUS_ACTIVATION_ADDRESS", activation->server_address))
488     _dbus_exit (1);
489   
490   type = bus_context_get_type (activation->context);
491   if (type != NULL)
492     {
493       if (!_dbus_setenv ("DBUS_BUS_TYPE", type))
494         _dbus_exit (1);
495
496       if (strcmp (type, "session") == 0)
497         {
498           if (!_dbus_setenv ("DBUS_SESSION_BUS_ADDRESS",
499                              activation->server_address))
500             _dbus_exit (1);
501         }
502       else if (strcmp (type, "system") == 0)
503         {
504           if (!_dbus_setenv ("DBUS_SYSTEM_BUS_ADDRESS",
505                              activation->server_address))
506             _dbus_exit (1);
507         }
508     }
509 }
510
511 typedef struct
512 {
513   BusPendingActivation *pending_activation;
514   DBusPreallocatedHash *hash_entry;
515 } RestorePendingData;
516
517 static void
518 restore_pending (void *data)
519 {
520   RestorePendingData *d = data;
521
522   _dbus_assert (d->pending_activation != NULL);
523   _dbus_assert (d->hash_entry != NULL);
524
525   _dbus_verbose ("Restoring pending activation for service %s, has timeout = %d\n",
526                  d->pending_activation->service_name,
527                  d->pending_activation->timeout_added);
528   
529   _dbus_hash_table_insert_string_preallocated (d->pending_activation->activation->pending_activations,
530                                                d->hash_entry,
531                                                d->pending_activation->service_name, d->pending_activation);
532
533   bus_pending_activation_ref (d->pending_activation);
534   
535   d->hash_entry = NULL;
536 }
537
538 static void
539 free_pending_restore_data (void *data)
540 {
541   RestorePendingData *d = data;
542
543   if (d->hash_entry)
544     _dbus_hash_table_free_preallocated_entry (d->pending_activation->activation->pending_activations,
545                                               d->hash_entry);
546
547   bus_pending_activation_unref (d->pending_activation);
548   
549   dbus_free (d);
550 }
551
552 static dbus_bool_t
553 add_restore_pending_to_transaction (BusTransaction       *transaction,
554                                     BusPendingActivation *pending_activation)
555 {
556   RestorePendingData *d;
557
558   d = dbus_new (RestorePendingData, 1);
559   if (d == NULL)
560     return FALSE;
561   
562   d->pending_activation = pending_activation;
563   d->hash_entry = _dbus_hash_table_preallocate_entry (d->pending_activation->activation->pending_activations);
564   
565   bus_pending_activation_ref (d->pending_activation);
566   
567   if (d->hash_entry == NULL ||
568       !bus_transaction_add_cancel_hook (transaction, restore_pending, d,
569                                         free_pending_restore_data))
570     {
571       free_pending_restore_data (d);
572       return FALSE;
573     }
574
575   _dbus_verbose ("Saved pending activation to be restored if the transaction fails\n");
576   
577   return TRUE;
578 }
579
580 dbus_bool_t
581 bus_activation_service_created (BusActivation  *activation,
582                                 const char     *service_name,
583                                 BusTransaction *transaction,
584                                 DBusError      *error)
585 {
586   BusPendingActivation *pending_activation;
587   DBusMessage *message;
588   DBusList *link;
589
590   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
591   
592   /* Check if it's a pending activation */
593   pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, service_name);
594
595   if (!pending_activation)
596     return TRUE;
597
598   link = _dbus_list_get_first_link (&pending_activation->entries);
599   while (link != NULL)
600     {
601       BusPendingActivationEntry *entry = link->data;
602       DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link);
603       
604       if (dbus_connection_get_is_connected (entry->connection))
605         {
606           message = dbus_message_new_method_return (entry->activation_message);
607           if (!message)
608             {
609               BUS_SET_OOM (error);
610               goto error;
611             }
612
613           if (!dbus_message_append_args (message,
614                                          DBUS_TYPE_UINT32, DBUS_ACTIVATION_REPLY_ACTIVATED,
615                                          DBUS_TYPE_INVALID))
616             {
617               dbus_message_unref (message);
618               BUS_SET_OOM (error);
619               goto error;
620             }
621           
622           if (!bus_transaction_send_from_driver (transaction, entry->connection, message))
623             {
624               dbus_message_unref (message);
625               BUS_SET_OOM (error);
626               goto error;
627             }
628           
629           dbus_message_unref (message);
630         }
631
632       link = next;
633     }
634
635   if (!add_restore_pending_to_transaction (transaction, pending_activation))
636     {
637       _dbus_verbose ("Could not add cancel hook to transaction to revert removing pending activation\n");
638       BUS_SET_OOM (error);
639       goto error;
640     }
641   
642   _dbus_hash_table_remove_string (activation->pending_activations, service_name);
643
644   return TRUE;
645
646  error:
647   return FALSE;
648 }
649
650 /**
651  * FIXME @todo the error messages here would ideally be preallocated
652  * so we don't need to allocate memory to send them.
653  * Using the usual tactic, prealloc an OOM message, then
654  * if we can't alloc the real error send the OOM error instead.
655  */
656 static dbus_bool_t
657 try_send_activation_failure (BusPendingActivation *pending_activation,
658                              const DBusError      *how)
659 {
660   BusActivation *activation;
661   DBusList *link;
662   BusTransaction *transaction;
663   
664   activation = pending_activation->activation;
665
666   transaction = bus_transaction_new (activation->context);
667   if (transaction == NULL)
668     return FALSE;
669   
670   link = _dbus_list_get_first_link (&pending_activation->entries);
671   while (link != NULL)
672     {
673       BusPendingActivationEntry *entry = link->data;
674       DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link);
675       
676       if (dbus_connection_get_is_connected (entry->connection))
677         {
678           if (!bus_transaction_send_error_reply (transaction,
679                                                  entry->connection,
680                                                  how,
681                                                  entry->activation_message))
682             goto error;
683         }
684       
685       link = next;
686     }
687
688   bus_transaction_execute_and_free (transaction);
689   
690   return TRUE;
691
692  error:
693   if (transaction)
694     bus_transaction_cancel_and_free (transaction);
695   return FALSE;
696 }
697
698 /**
699  * Free the pending activation and send an error message to all the
700  * connections that were waiting for it.
701  */
702 static void
703 pending_activation_failed (BusPendingActivation *pending_activation,
704                            const DBusError      *how)
705 {
706   /* FIXME use preallocated OOM messages instead of bus_wait_for_memory() */
707   while (!try_send_activation_failure (pending_activation, how))
708     _dbus_wait_for_memory ();
709
710   /* Destroy this pending activation */
711   _dbus_hash_table_remove_string (pending_activation->activation->pending_activations,
712                                   pending_activation->service_name);
713 }
714
715 static dbus_bool_t
716 babysitter_watch_callback (DBusWatch     *watch,
717                            unsigned int   condition,
718                            void          *data)
719 {
720   BusPendingActivation *pending_activation = data;
721   dbus_bool_t retval;
722   DBusBabysitter *babysitter;
723
724   babysitter = pending_activation->babysitter;
725   
726   _dbus_babysitter_ref (babysitter);
727   
728   retval = dbus_watch_handle (watch, condition);
729
730   /* FIXME this is broken in the same way that
731    * connection watches used to be; there should be
732    * a separate callback for status change, instead
733    * of doing "if we handled a watch status might
734    * have changed"
735    *
736    * Fixing this lets us move dbus_watch_handle
737    * calls into dbus-mainloop.c
738    */
739   
740   if (_dbus_babysitter_get_child_exited (babysitter))
741     {
742       DBusError error;
743
744       dbus_error_init (&error);
745       _dbus_babysitter_set_child_exit_error (babysitter, &error);
746
747       /* Destroys the pending activation */
748       pending_activation_failed (pending_activation, &error);
749
750       dbus_error_free (&error);
751     }
752   
753   _dbus_babysitter_unref (babysitter);
754
755   return retval;
756 }
757
758 static dbus_bool_t
759 add_babysitter_watch (DBusWatch      *watch,
760                       void           *data)
761 {
762   BusPendingActivation *pending_activation = data;
763
764   return _dbus_loop_add_watch (bus_context_get_loop (pending_activation->activation->context),
765                                watch, babysitter_watch_callback, pending_activation,
766                                NULL);
767 }
768
769 static void
770 remove_babysitter_watch (DBusWatch      *watch,
771                          void           *data)
772 {
773   BusPendingActivation *pending_activation = data;
774   
775   _dbus_loop_remove_watch (bus_context_get_loop (pending_activation->activation->context),
776                            watch, babysitter_watch_callback, pending_activation);
777 }
778
779 static dbus_bool_t
780 pending_activation_timed_out (void *data)
781 {
782   BusPendingActivation *pending_activation = data;
783   DBusError error;
784   
785   /* Kill the spawned process, since it sucks
786    * (not sure this is what we want to do, but
787    * may as well try it for now)
788    */
789   _dbus_babysitter_kill_child (pending_activation->babysitter);
790
791   dbus_error_init (&error);
792
793   dbus_set_error (&error, DBUS_ERROR_TIMED_OUT,
794                   "Activation of %s timed out",
795                   pending_activation->service_name);
796
797   pending_activation_failed (pending_activation, &error);
798
799   dbus_error_free (&error);
800
801   return TRUE;
802 }
803
804 static void
805 cancel_pending (void *data)
806 {
807   BusPendingActivation *pending_activation = data;
808
809   _dbus_verbose ("Canceling pending activation of %s\n",
810                  pending_activation->service_name);
811
812   if (pending_activation->babysitter)
813     _dbus_babysitter_kill_child (pending_activation->babysitter);
814   
815   _dbus_hash_table_remove_string (pending_activation->activation->pending_activations,
816                                   pending_activation->service_name);
817 }
818
819 static void
820 free_pending_cancel_data (void *data)
821 {
822   BusPendingActivation *pending_activation = data;
823   
824   bus_pending_activation_unref (pending_activation);
825 }
826
827 static dbus_bool_t
828 add_cancel_pending_to_transaction (BusTransaction       *transaction,
829                                    BusPendingActivation *pending_activation)
830 {  
831   if (!bus_transaction_add_cancel_hook (transaction, cancel_pending,
832                                         pending_activation,
833                                         free_pending_cancel_data))
834     return FALSE;
835
836   bus_pending_activation_ref (pending_activation); 
837   
838   _dbus_verbose ("Saved pending activation to be canceled if the transaction fails\n");
839   
840   return TRUE;
841 }
842
843 dbus_bool_t
844 bus_activation_activate_service (BusActivation  *activation,
845                                  DBusConnection *connection,
846                                  BusTransaction *transaction,
847                                  DBusMessage    *activation_message,
848                                  const char     *service_name,
849                                  DBusError      *error)
850 {
851   BusActivationEntry *entry;
852   BusPendingActivation *pending_activation;
853   BusPendingActivationEntry *pending_activation_entry;
854   DBusMessage *message;
855   DBusString service_str;
856   char *argv[2];
857   dbus_bool_t retval;
858
859   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
860
861   if (activation->n_pending_activations >=
862       bus_context_get_max_pending_activations (activation->context))
863     {
864       dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
865                       "The maximum number of pending activations has been reached, activation of %s failed",
866                       service_name);
867       return FALSE;
868     }
869   
870   entry = _dbus_hash_table_lookup_string (activation->entries, service_name);
871
872   if (!entry)
873     {
874       dbus_set_error (error, DBUS_ERROR_ACTIVATE_SERVICE_NOT_FOUND,
875                       "The service %s was not found in the activation entry list",
876                       service_name);
877       return FALSE;
878     }
879
880   /* Check if the service is active */
881   _dbus_string_init_const (&service_str, service_name);
882   if (bus_registry_lookup (bus_context_get_registry (activation->context), &service_str) != NULL)
883     {
884       _dbus_verbose ("Service \"%s\" is already active\n", service_name);
885       
886       message = dbus_message_new_method_return (activation_message);
887
888       if (!message)
889         {
890           _dbus_verbose ("No memory to create reply to activate message\n");
891           BUS_SET_OOM (error);
892           return FALSE;
893         }
894
895       if (!dbus_message_append_args (message,
896                                      DBUS_TYPE_UINT32, DBUS_ACTIVATION_REPLY_ALREADY_ACTIVE, 
897                                      DBUS_TYPE_INVALID))
898         {
899           _dbus_verbose ("No memory to set args of reply to activate message\n");
900           BUS_SET_OOM (error);
901           dbus_message_unref (message);
902           return FALSE;
903         }
904
905       retval = bus_transaction_send_from_driver (transaction, connection, message);
906       dbus_message_unref (message);
907       if (!retval)
908         {
909           _dbus_verbose ("Failed to send reply\n");
910           BUS_SET_OOM (error);
911         }
912
913       return retval;
914     }
915
916   pending_activation_entry = dbus_new0 (BusPendingActivationEntry, 1);
917   if (!pending_activation_entry)
918     {
919       _dbus_verbose ("Failed to create pending activation entry\n");
920       BUS_SET_OOM (error);
921       return FALSE;
922     }
923
924   pending_activation_entry->activation_message = activation_message;
925   dbus_message_ref (activation_message);
926   pending_activation_entry->connection = connection;
927   dbus_connection_ref (connection);
928   
929   /* Check if the service is being activated */
930   pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, service_name);
931   if (pending_activation)
932     {
933       if (!_dbus_list_append (&pending_activation->entries, pending_activation_entry))
934         {
935           _dbus_verbose ("Failed to append a new entry to pending activation\n");
936           
937           BUS_SET_OOM (error);
938           bus_pending_activation_entry_free (pending_activation_entry);
939           return FALSE;
940         }
941
942       pending_activation->n_entries += 1;
943       pending_activation->activation->n_pending_activations += 1;
944     }
945   else
946     {
947       pending_activation = dbus_new0 (BusPendingActivation, 1);
948       if (!pending_activation)
949         {
950           _dbus_verbose ("Failed to create pending activation\n");
951           
952           BUS_SET_OOM (error);
953           bus_pending_activation_entry_free (pending_activation_entry);   
954           return FALSE;
955         }
956
957       pending_activation->activation = activation;
958       pending_activation->refcount = 1;
959       
960       pending_activation->service_name = _dbus_strdup (service_name);
961       if (!pending_activation->service_name)
962         {
963           _dbus_verbose ("Failed to copy service name for pending activation\n");
964           
965           BUS_SET_OOM (error);
966           bus_pending_activation_unref (pending_activation);
967           bus_pending_activation_entry_free (pending_activation_entry);   
968           return FALSE;
969         }
970
971       pending_activation->timeout =
972         _dbus_timeout_new (bus_context_get_activation_timeout (activation->context),
973                            pending_activation_timed_out,
974                            pending_activation,
975                            NULL);
976       if (!pending_activation->timeout)
977         {
978           _dbus_verbose ("Failed to create timeout for pending activation\n");
979           
980           BUS_SET_OOM (error);
981           bus_pending_activation_unref (pending_activation);
982           bus_pending_activation_entry_free (pending_activation_entry);   
983           return FALSE;
984         }
985
986       if (!_dbus_loop_add_timeout (bus_context_get_loop (activation->context),
987                                    pending_activation->timeout,
988                                    handle_timeout_callback,
989                                    pending_activation,
990                                    NULL))
991         {
992           _dbus_verbose ("Failed to add timeout for pending activation\n");
993           
994           BUS_SET_OOM (error);
995           bus_pending_activation_unref (pending_activation);
996           bus_pending_activation_entry_free (pending_activation_entry);   
997           return FALSE;
998         }
999
1000       pending_activation->timeout_added = TRUE;
1001       
1002       if (!_dbus_list_append (&pending_activation->entries, pending_activation_entry))
1003         {
1004           _dbus_verbose ("Failed to add entry to just-created pending activation\n");
1005           
1006           BUS_SET_OOM (error);
1007           bus_pending_activation_unref (pending_activation);
1008           bus_pending_activation_entry_free (pending_activation_entry);   
1009           return FALSE;
1010         }
1011
1012       pending_activation->n_entries += 1;
1013       pending_activation->activation->n_pending_activations += 1;
1014       
1015       if (!_dbus_hash_table_insert_string (activation->pending_activations,
1016                                            pending_activation->service_name,
1017                                            pending_activation))
1018         {
1019           _dbus_verbose ("Failed to put pending activation in hash table\n");
1020           
1021           BUS_SET_OOM (error);
1022           bus_pending_activation_unref (pending_activation);
1023           return FALSE;
1024         }
1025     }
1026
1027   if (!add_cancel_pending_to_transaction (transaction, pending_activation))
1028     {
1029       _dbus_verbose ("Failed to add pending activation cancel hook to transaction\n");
1030       BUS_SET_OOM (error);
1031       _dbus_hash_table_remove_string (activation->pending_activations,
1032                                       pending_activation->service_name);
1033       return FALSE;
1034     }
1035   
1036   /* FIXME we need to support a full command line, not just a single
1037    * argv[0]
1038    */
1039   
1040   /* Now try to spawn the process */
1041   argv[0] = entry->exec;
1042   argv[1] = NULL;
1043
1044   if (!_dbus_spawn_async_with_babysitter (&pending_activation->babysitter, argv,
1045                                           child_setup, activation, 
1046                                           error))
1047     {
1048       _dbus_verbose ("Failed to spawn child\n");
1049       _DBUS_ASSERT_ERROR_IS_SET (error);
1050       return FALSE;
1051     }
1052
1053   _dbus_assert (pending_activation->babysitter != NULL);
1054   
1055   if (!_dbus_babysitter_set_watch_functions (pending_activation->babysitter,
1056                                              add_babysitter_watch,
1057                                              remove_babysitter_watch,
1058                                              NULL,
1059                                              pending_activation,
1060                                              NULL))
1061     {
1062       BUS_SET_OOM (error);
1063       _dbus_verbose ("Failed to set babysitter watch functions\n");
1064       return FALSE;
1065     }
1066   
1067   return TRUE;
1068 }