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