* doc/TODO, various source files: Audited todo's and FIXME's and
[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  * 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
111 bus_service_directory_unref (BusServiceDirectory *dir)
112 {
113   if (dir == NULL) 
114     return; 
115
116   _dbus_assert (dir->refcount > 0);
117   dir->refcount--;
118
119   if (dir->refcount > 0)
120     return;
121
122   if (dir->entries)
123     _dbus_hash_table_unref (dir->entries);
124
125   dbus_free (dir->dir_c);
126   dbus_free (dir);
127 }
128
129 static void
130 bus_pending_activation_entry_free (BusPendingActivationEntry *entry)
131 {
132   if (entry->activation_message)
133     dbus_message_unref (entry->activation_message);
134   
135   if (entry->connection)
136     dbus_connection_unref (entry->connection);
137   
138   dbus_free (entry);
139 }
140
141 static void
142 handle_timeout_callback (DBusTimeout   *timeout,
143                          void          *data)
144 {
145   BusPendingActivation *pending_activation = data;
146
147   while (!dbus_timeout_handle (pending_activation->timeout))
148     _dbus_wait_for_memory ();
149 }
150
151 static BusPendingActivation * 
152 bus_pending_activation_ref (BusPendingActivation *pending_activation)
153 {
154   _dbus_assert (pending_activation->refcount > 0);
155   pending_activation->refcount += 1;
156
157   return pending_activation;
158 }
159
160 static void
161 bus_pending_activation_unref (BusPendingActivation *pending_activation)
162 {
163   DBusList *link;
164   
165   if (pending_activation == NULL) /* 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 *
220 bus_activation_entry_ref (BusActivationEntry *entry)
221 {
222   _dbus_assert (entry->refcount > 0);
223   entry->refcount++;
224
225   return entry;
226 }
227
228 static void
229 bus_activation_entry_unref (BusActivationEntry *entry)
230 {
231   if (entry == NULL) /* 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
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     {
290       dbus_set_error (error, DBUS_ERROR_FAILED,
291                       "No \""DBUS_SERVICE_NAME"\" key in .service file\n");
292       goto failed;
293     }
294
295   if (!bus_desktop_file_get_string (desktop_file,
296                                     DBUS_SERVICE_SECTION,
297                                     DBUS_SERVICE_EXEC,
298                                     &exec))
299     {
300       dbus_set_error (error, DBUS_ERROR_FAILED,
301                       "No \""DBUS_SERVICE_EXEC"\" key in .service file\n");
302       goto failed;
303     }
304
305   entry = _dbus_hash_table_lookup_string (s_dir->entries, 
306                                           _dbus_string_get_const_data (filename));
307   if (entry == NULL) /* New file */
308     { 
309       /* FIXME we need a better-defined algorithm for which service file to
310        * pick than "whichever one is first in the directory listing"
311        */
312       if (_dbus_hash_table_lookup_string (activation->entries, name))
313         {
314           dbus_set_error (error, DBUS_ERROR_FAILED,
315                           "Service %s already exists in activation entry list\n", name);
316           goto failed;
317         }
318       
319       entry = dbus_new0 (BusActivationEntry, 1);
320       if (entry == NULL)
321         {
322           BUS_SET_OOM (error);
323           goto failed;
324         }
325      
326       entry->name = name;
327       entry->exec = exec;
328       entry->refcount = 1;
329     
330       entry->s_dir = s_dir;
331       entry->filename = _dbus_strdup (_dbus_string_get_const_data (filename));
332       if (!entry->filename)
333         {
334           BUS_SET_OOM (error);
335           goto failed;
336         }
337
338       if (!_dbus_hash_table_insert_string (activation->entries, entry->name, bus_activation_entry_ref (entry)))
339         {
340           BUS_SET_OOM (error);
341           goto failed;
342         }
343      
344       if (!_dbus_hash_table_insert_string (s_dir->entries, entry->filename, bus_activation_entry_ref (entry)))
345         {
346           /* Revert the insertion in the entries table */
347           _dbus_hash_table_remove_string (activation->entries, entry->name);
348           BUS_SET_OOM (error);
349           goto failed;
350         }
351
352       _dbus_verbose ("Added \"%s\" to list of services\n", entry->name);
353     }
354   else /* Just update the entry */
355     {
356       bus_activation_entry_ref (entry);
357       _dbus_hash_table_remove_string (activation->entries, entry->name);
358
359       if (_dbus_hash_table_lookup_string (activation->entries, name))
360         {
361           _dbus_verbose ("The new service name \"%s\" of service file \"%s\" already in cache, ignoring\n",
362                          name, _dbus_string_get_const_data (&file_path));
363           goto failed;
364         }
365  
366       dbus_free (entry->name);
367       dbus_free (entry->exec);
368       entry->name = name;
369       entry->exec = exec;
370       if (!_dbus_hash_table_insert_string (activation->entries,
371                                            entry->name, bus_activation_entry_ref(entry)))
372         {
373           BUS_SET_OOM (error);
374           /* Also remove path to entries hash since we want this in sync with
375            * the entries hash table */
376           _dbus_hash_table_remove_string (entry->s_dir->entries, 
377                                           entry->filename);
378           bus_activation_entry_unref (entry);
379           return FALSE;
380         }
381     }
382   
383   entry->mtime = stat_buf.mtime;
384   
385   _dbus_string_free (&file_path);
386   bus_activation_entry_unref (entry);
387
388   return TRUE;
389
390 failed:
391   dbus_free (name);
392   dbus_free (exec);
393   _dbus_string_free (&file_path);
394
395   if (entry)
396     bus_activation_entry_unref (entry);
397   
398   return FALSE;
399 }
400
401 static dbus_bool_t
402 check_service_file (BusActivation       *activation,
403                     BusActivationEntry  *entry,
404                     BusActivationEntry **updated_entry,
405                     DBusError           *error)
406 {
407   DBusStat stat_buf;
408   dbus_bool_t retval;
409   BusActivationEntry *tmp_entry;
410   DBusString file_path;
411   DBusString filename;
412
413   retval = TRUE;
414   tmp_entry = entry;
415   
416   _dbus_string_init_const (&filename, entry->filename);
417   
418   if (!_dbus_string_init (&file_path))
419     {
420       BUS_SET_OOM (error);
421       return FALSE;
422     }
423  
424   if (!_dbus_string_append (&file_path, entry->s_dir->dir_c) ||
425       !_dbus_concat_dir_and_file (&file_path, &filename))
426     {
427       BUS_SET_OOM (error);
428       retval = FALSE;
429       goto out;
430     }
431   
432   if (!_dbus_stat (&file_path, &stat_buf, NULL))
433     {
434       _dbus_verbose ("****** Can't stat file \"%s\", removing from cache\n",
435                      _dbus_string_get_const_data (&file_path));
436
437       _dbus_hash_table_remove_string (activation->entries, entry->name);
438       _dbus_hash_table_remove_string (entry->s_dir->entries, entry->filename);
439
440       tmp_entry = NULL;
441       retval = TRUE;
442       goto out;
443     }
444   else 
445     {
446       if (stat_buf.mtime > entry->mtime) 
447         {
448           BusDesktopFile *desktop_file;
449           DBusError tmp_error;
450           
451           dbus_error_init (&tmp_error);
452           
453           desktop_file = bus_desktop_file_load (&file_path, &tmp_error);
454           if (desktop_file == NULL)
455             {
456               _dbus_verbose ("Could not load %s: %s\n",
457                              _dbus_string_get_const_data (&file_path), 
458                              tmp_error.message);
459               if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
460                 {
461                   dbus_move_error (&tmp_error, error);
462                   retval = FALSE;
463                   goto out;
464                 }
465               dbus_error_free (&tmp_error);
466               retval = TRUE;
467               goto out;
468             }
469           
470           if (!update_desktop_file_entry (activation, entry->s_dir, &filename, desktop_file, &tmp_error))
471             {
472               bus_desktop_file_free (desktop_file);
473               if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
474                 {
475                   dbus_move_error (&tmp_error, error);
476                   retval = FALSE;
477                   goto out;
478                 }
479               dbus_error_free (&tmp_error);
480               retval = TRUE;
481               goto out;
482             }
483          
484           bus_desktop_file_free (desktop_file);
485           retval = TRUE;
486         }
487     }
488   
489 out:
490   _dbus_string_free (&file_path);
491
492   if (updated_entry != NULL)
493     *updated_entry = tmp_entry;
494   return retval;
495 }
496
497
498 /* warning: this doesn't fully "undo" itself on failure, i.e. doesn't strip
499  * hash entries it already added.
500  */
501 static dbus_bool_t
502 update_directory (BusActivation       *activation,
503                   BusServiceDirectory *s_dir,
504                   DBusError           *error)
505 {
506   DBusDirIter *iter;
507   DBusString dir, filename;
508   BusDesktopFile *desktop_file;
509   DBusError tmp_error;
510   dbus_bool_t retval;
511   BusActivationEntry *entry;
512   DBusString full_path;
513   
514   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
515   
516   iter = NULL;
517   desktop_file = NULL;
518   
519   _dbus_string_init_const (&dir, s_dir->dir_c);
520   
521   if (!_dbus_string_init (&filename))
522     {
523       BUS_SET_OOM (error);
524       return FALSE;
525     }
526
527   if (!_dbus_string_init (&full_path))
528     {
529       BUS_SET_OOM (error);
530       _dbus_string_free (&filename);
531       return FALSE;
532     }
533
534   retval = FALSE;
535
536   /* from this point it's safe to "goto out" */
537   
538   iter = _dbus_directory_open (&dir, error);
539   if (iter == NULL)
540     {
541       _dbus_verbose ("Failed to open directory %s: %s\n",
542                      s_dir->dir_c, 
543                      error ? error->message : "unknown");
544       goto out;
545     }
546   
547   /* Now read the files */
548   dbus_error_init (&tmp_error);
549   while (_dbus_directory_get_next_file (iter, &filename, &tmp_error))
550     {
551       _dbus_assert (!dbus_error_is_set (&tmp_error));
552       
553       _dbus_string_set_length (&full_path, 0);
554       
555       if (!_dbus_string_ends_with_c_str (&filename, ".service"))
556         {
557           _dbus_verbose ("Skipping non-.service file %s\n",
558                          _dbus_string_get_const_data (&filename));
559           continue;
560         }
561
562       entry = _dbus_hash_table_lookup_string (s_dir->entries, _dbus_string_get_const_data (&filename));
563       if (entry) /* Already has this service file in the cache */ 
564         {
565           if (!check_service_file (activation, entry, NULL, error))
566             goto out;
567
568           continue;
569         }
570       
571       if (!_dbus_string_append (&full_path, s_dir->dir_c) ||
572           !_dbus_concat_dir_and_file (&full_path, &filename))
573         {
574           BUS_SET_OOM (error);
575           goto out;
576         }
577           
578       /* New file */
579       desktop_file = bus_desktop_file_load (&full_path, &tmp_error);
580       if (desktop_file == NULL)
581         {
582           _dbus_verbose ("Could not load %s: %s\n",
583                          _dbus_string_get_const_data (&full_path),
584                          tmp_error.message);
585
586           if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
587             {
588               dbus_move_error (&tmp_error, error);
589               goto out;
590             }
591           
592           dbus_error_free (&tmp_error);
593           continue;
594         }
595
596       if (!update_desktop_file_entry (activation, s_dir, &filename, desktop_file, &tmp_error))
597         {
598           bus_desktop_file_free (desktop_file);
599           desktop_file = NULL;
600           
601           _dbus_verbose ("Could not add %s to activation entry list: %s\n",
602                          _dbus_string_get_const_data (&full_path), tmp_error.message);
603
604           if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
605             {
606               dbus_move_error (&tmp_error, error);
607               goto out;
608             }
609
610           dbus_error_free (&tmp_error);
611           continue;
612         }
613       else
614         {
615           bus_desktop_file_free (desktop_file);
616           desktop_file = NULL;
617           continue;
618         }
619     }
620
621   if (dbus_error_is_set (&tmp_error))
622     {
623       dbus_move_error (&tmp_error, error);
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*
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       if (!update_directory (activation, s_dir, error))
740         goto failed;
741       
742       link = _dbus_list_get_next_link (directories, link);
743     }
744
745   return activation;
746   
747  failed:
748   bus_activation_unref (activation);  
749   return NULL;
750 }
751
752 BusActivation *
753 bus_activation_ref (BusActivation *activation)
754 {
755   _dbus_assert (activation->refcount > 0);
756   
757   activation->refcount += 1;
758
759   return activation;
760 }
761
762 void
763 bus_activation_unref (BusActivation *activation)
764 {
765   _dbus_assert (activation->refcount > 0);
766
767   activation->refcount -= 1;
768
769   if (activation->refcount > 0)
770     return;
771   
772   dbus_free (activation->server_address);
773   if (activation->entries)
774     _dbus_hash_table_unref (activation->entries);
775   if (activation->pending_activations)
776     _dbus_hash_table_unref (activation->pending_activations);
777   if (activation->directories)  
778     _dbus_hash_table_unref (activation->directories);
779   
780   dbus_free (activation);
781 }
782
783 static void
784 child_setup (void *data)
785 {
786   BusActivation *activation = data;
787   const char *type;
788   
789   /* If no memory, we simply have the child exit, so it won't try
790    * to connect to the wrong thing.
791    */
792   if (!_dbus_setenv ("DBUS_STARTER_ADDRESS", activation->server_address))
793     _dbus_exit (1);
794   
795   type = bus_context_get_type (activation->context);
796   if (type != NULL)
797     {
798       if (!_dbus_setenv ("DBUS_STARTER_BUS_TYPE", type))
799         _dbus_exit (1);
800
801       if (strcmp (type, "session") == 0)
802         {
803           if (!_dbus_setenv ("DBUS_SESSION_BUS_ADDRESS",
804                              activation->server_address))
805             _dbus_exit (1);
806         }
807       else if (strcmp (type, "system") == 0)
808         {
809           if (!_dbus_setenv ("DBUS_SYSTEM_BUS_ADDRESS",
810                              activation->server_address))
811             _dbus_exit (1);
812         }
813     }
814 }
815
816 typedef struct
817 {
818   BusPendingActivation *pending_activation;
819   DBusPreallocatedHash *hash_entry;
820 } RestorePendingData;
821
822 static void
823 restore_pending (void *data)
824 {
825   RestorePendingData *d = data;
826
827   _dbus_assert (d->pending_activation != NULL);
828   _dbus_assert (d->hash_entry != NULL);
829
830   _dbus_verbose ("Restoring pending activation for service %s, has timeout = %d\n",
831                  d->pending_activation->service_name,
832                  d->pending_activation->timeout_added);
833   
834   _dbus_hash_table_insert_string_preallocated (d->pending_activation->activation->pending_activations,
835                                                d->hash_entry,
836                                                d->pending_activation->service_name, d->pending_activation);
837
838   bus_pending_activation_ref (d->pending_activation);
839   
840   d->hash_entry = NULL;
841 }
842
843 static void
844 free_pending_restore_data (void *data)
845 {
846   RestorePendingData *d = data;
847
848   if (d->hash_entry)
849     _dbus_hash_table_free_preallocated_entry (d->pending_activation->activation->pending_activations,
850                                               d->hash_entry);
851
852   bus_pending_activation_unref (d->pending_activation);
853   
854   dbus_free (d);
855 }
856
857 static dbus_bool_t
858 add_restore_pending_to_transaction (BusTransaction       *transaction,
859                                     BusPendingActivation *pending_activation)
860 {
861   RestorePendingData *d;
862
863   d = dbus_new (RestorePendingData, 1);
864   if (d == NULL)
865     return FALSE;
866   
867   d->pending_activation = pending_activation;
868   d->hash_entry = _dbus_hash_table_preallocate_entry (d->pending_activation->activation->pending_activations);
869   
870   bus_pending_activation_ref (d->pending_activation);
871   
872   if (d->hash_entry == NULL ||
873       !bus_transaction_add_cancel_hook (transaction, restore_pending, d,
874                                         free_pending_restore_data))
875     {
876       free_pending_restore_data (d);
877       return FALSE;
878     }
879
880   _dbus_verbose ("Saved pending activation to be restored if the transaction fails\n");
881   
882   return TRUE;
883 }
884
885 dbus_bool_t
886 bus_activation_service_created (BusActivation  *activation,
887                                 const char     *service_name,
888                                 BusTransaction *transaction,
889                                 DBusError      *error)
890 {
891   BusPendingActivation *pending_activation;
892   DBusMessage *message;
893   DBusList *link;
894
895   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
896   
897   /* Check if it's a pending activation */
898   pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, service_name);
899
900   if (!pending_activation)
901     return TRUE;
902
903   link = _dbus_list_get_first_link (&pending_activation->entries);
904   while (link != NULL)
905     {
906       BusPendingActivationEntry *entry = link->data;
907       DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link);
908       
909       if (dbus_connection_get_is_connected (entry->connection))
910         {
911           /* Only send activation replies to regular activation requests. */
912           if (!entry->auto_activation)
913             {
914               dbus_uint32_t result;
915               
916               message = dbus_message_new_method_return (entry->activation_message);
917               if (!message)
918                 {
919                   BUS_SET_OOM (error);
920                   goto error;
921                 }
922
923               result = DBUS_START_REPLY_SUCCESS;
924               
925               if (!dbus_message_append_args (message,
926                                              DBUS_TYPE_UINT32, &result,
927                                              DBUS_TYPE_INVALID))
928                 {
929                   dbus_message_unref (message);
930                   BUS_SET_OOM (error);
931                   goto error;
932                 }
933               
934               if (!bus_transaction_send_from_driver (transaction, entry->connection, message))
935                 {
936                   dbus_message_unref (message);
937                   BUS_SET_OOM (error);
938                   goto error;
939                 }
940               
941               dbus_message_unref (message);
942             }
943         }
944       
945       link = next;
946     }
947
948   return TRUE;
949
950  error:
951   return FALSE;
952 }
953
954 dbus_bool_t
955 bus_activation_send_pending_auto_activation_messages (BusActivation  *activation,
956                                                       BusService     *service,
957                                                       BusTransaction *transaction,
958                                                       DBusError      *error)
959 {
960   BusPendingActivation *pending_activation;
961   DBusList *link;
962
963   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
964   
965   /* Check if it's a pending activation */
966   pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations,
967                                                        bus_service_get_name (service));
968
969   if (!pending_activation)
970     return TRUE;
971
972   link = _dbus_list_get_first_link (&pending_activation->entries);
973   while (link != NULL)
974     {
975       BusPendingActivationEntry *entry = link->data;
976       DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link);
977
978       if (entry->auto_activation && dbus_connection_get_is_connected (entry->connection))
979         {
980           DBusConnection *addressed_recipient;
981           
982           addressed_recipient = bus_service_get_primary_owners_connection (service);
983
984           /* Check the security policy, which has the side-effect of adding an
985            * expected pending reply.
986            */
987           if (!bus_context_check_security_policy (activation->context, transaction,
988                                                   entry->connection,
989                                                   addressed_recipient,
990                                                   addressed_recipient,
991                                                   entry->activation_message, error))
992             goto error;
993
994           if (!bus_transaction_send (transaction, addressed_recipient, entry->activation_message))
995             {
996               BUS_SET_OOM (error);
997               goto error;
998             }
999         }
1000
1001       link = next;
1002     }
1003
1004   if (!add_restore_pending_to_transaction (transaction, pending_activation))
1005     {
1006       _dbus_verbose ("Could not add cancel hook to transaction to revert removing pending activation\n");
1007       BUS_SET_OOM (error);
1008       goto error;
1009     }
1010   
1011   _dbus_hash_table_remove_string (activation->pending_activations, bus_service_get_name (service));
1012
1013   return TRUE;
1014
1015  error:
1016   return FALSE;
1017 }
1018
1019 /**
1020  * FIXME @todo 1.0? the error messages here would ideally be preallocated
1021  * so we don't need to allocate memory to send them.
1022  * Using the usual tactic, prealloc an OOM message, then
1023  * if we can't alloc the real error send the OOM error instead.
1024  */
1025 static dbus_bool_t
1026 try_send_activation_failure (BusPendingActivation *pending_activation,
1027                              const DBusError      *how)
1028 {
1029   BusActivation *activation;
1030   DBusList *link;
1031   BusTransaction *transaction;
1032   
1033   activation = pending_activation->activation;
1034
1035   transaction = bus_transaction_new (activation->context);
1036   if (transaction == NULL)
1037     return FALSE;
1038   
1039   link = _dbus_list_get_first_link (&pending_activation->entries);
1040   while (link != NULL)
1041     {
1042       BusPendingActivationEntry *entry = link->data;
1043       DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link);
1044       
1045       if (dbus_connection_get_is_connected (entry->connection))
1046         {
1047           if (!bus_transaction_send_error_reply (transaction,
1048                                                  entry->connection,
1049                                                  how,
1050                                                  entry->activation_message))
1051             goto error;
1052         }
1053       
1054       link = next;
1055     }
1056
1057   bus_transaction_execute_and_free (transaction);
1058   
1059   return TRUE;
1060
1061  error:
1062   if (transaction)
1063     bus_transaction_cancel_and_free (transaction);
1064   return FALSE;
1065 }
1066
1067 /**
1068  * Free the pending activation and send an error message to all the
1069  * connections that were waiting for it.
1070  */
1071 static void
1072 pending_activation_failed (BusPendingActivation *pending_activation,
1073                            const DBusError      *how)
1074 {
1075   /* FIXME use preallocated OOM messages instead of bus_wait_for_memory() */
1076   while (!try_send_activation_failure (pending_activation, how))
1077     _dbus_wait_for_memory ();
1078
1079   /* Destroy this pending activation */
1080   _dbus_hash_table_remove_string (pending_activation->activation->pending_activations,
1081                                   pending_activation->service_name);
1082 }
1083
1084 static dbus_bool_t
1085 babysitter_watch_callback (DBusWatch     *watch,
1086                            unsigned int   condition,
1087                            void          *data)
1088 {
1089   BusPendingActivation *pending_activation = data;
1090   dbus_bool_t retval;
1091   DBusBabysitter *babysitter;
1092
1093   babysitter = pending_activation->babysitter;
1094   
1095   _dbus_babysitter_ref (babysitter);
1096   
1097   retval = dbus_watch_handle (watch, condition);
1098
1099   /* FIXME this is broken in the same way that
1100    * connection watches used to be; there should be
1101    * a separate callback for status change, instead
1102    * of doing "if we handled a watch status might
1103    * have changed"
1104    *
1105    * Fixing this lets us move dbus_watch_handle
1106    * calls into dbus-mainloop.c
1107    */
1108   
1109   if (_dbus_babysitter_get_child_exited (babysitter))
1110     {
1111       DBusError error;
1112       DBusHashIter iter;
1113       
1114       dbus_error_init (&error);
1115       _dbus_babysitter_set_child_exit_error (babysitter, &error);
1116
1117       /* Destroy all pending activations with the same exec */
1118       _dbus_hash_iter_init (pending_activation->activation->pending_activations,
1119                             &iter);
1120       while (_dbus_hash_iter_next (&iter))
1121         {
1122           BusPendingActivation *p = _dbus_hash_iter_get_value (&iter);
1123          
1124           if (p != pending_activation && strcmp (p->exec, pending_activation->exec) == 0)
1125             pending_activation_failed (p, &error);
1126         }
1127       
1128       /* Destroys the pending activation */
1129       pending_activation_failed (pending_activation, &error);
1130
1131       dbus_error_free (&error);
1132     }
1133   
1134   _dbus_babysitter_unref (babysitter);
1135
1136   return retval;
1137 }
1138
1139 static dbus_bool_t
1140 add_babysitter_watch (DBusWatch      *watch,
1141                       void           *data)
1142 {
1143   BusPendingActivation *pending_activation = data;
1144
1145   return _dbus_loop_add_watch (bus_context_get_loop (pending_activation->activation->context),
1146                                watch, babysitter_watch_callback, pending_activation,
1147                                NULL);
1148 }
1149
1150 static void
1151 remove_babysitter_watch (DBusWatch      *watch,
1152                          void           *data)
1153 {
1154   BusPendingActivation *pending_activation = data;
1155   
1156   _dbus_loop_remove_watch (bus_context_get_loop (pending_activation->activation->context),
1157                            watch, babysitter_watch_callback, pending_activation);
1158 }
1159
1160 static dbus_bool_t
1161 pending_activation_timed_out (void *data)
1162 {
1163   BusPendingActivation *pending_activation = data;
1164   DBusError error;
1165   
1166   /* Kill the spawned process, since it sucks
1167    * (not sure this is what we want to do, but
1168    * may as well try it for now)
1169    */
1170   if (pending_activation->babysitter) 
1171     _dbus_babysitter_kill_child (pending_activation->babysitter);
1172
1173   dbus_error_init (&error);
1174
1175   dbus_set_error (&error, DBUS_ERROR_TIMED_OUT,
1176                   "Activation of %s timed out",
1177                   pending_activation->service_name);
1178
1179   pending_activation_failed (pending_activation, &error);
1180
1181   dbus_error_free (&error);
1182
1183   return TRUE;
1184 }
1185
1186 static void
1187 cancel_pending (void *data)
1188 {
1189   BusPendingActivation *pending_activation = data;
1190
1191   _dbus_verbose ("Canceling pending activation of %s\n",
1192                  pending_activation->service_name);
1193
1194   if (pending_activation->babysitter)
1195     _dbus_babysitter_kill_child (pending_activation->babysitter);
1196   
1197   _dbus_hash_table_remove_string (pending_activation->activation->pending_activations,
1198                                   pending_activation->service_name);
1199 }
1200
1201 static void
1202 free_pending_cancel_data (void *data)
1203 {
1204   BusPendingActivation *pending_activation = data;
1205   
1206   bus_pending_activation_unref (pending_activation);
1207 }
1208
1209 static dbus_bool_t
1210 add_cancel_pending_to_transaction (BusTransaction       *transaction,
1211                                    BusPendingActivation *pending_activation)
1212 {  
1213   if (!bus_transaction_add_cancel_hook (transaction, cancel_pending,
1214                                         pending_activation,
1215                                         free_pending_cancel_data))
1216     return FALSE;
1217
1218   bus_pending_activation_ref (pending_activation); 
1219   
1220   _dbus_verbose ("Saved pending activation to be canceled if the transaction fails\n");
1221   
1222   return TRUE;
1223 }
1224
1225 static dbus_bool_t 
1226 update_service_cache (BusActivation *activation, DBusError *error)
1227 {
1228   DBusHashIter iter;
1229  
1230   _dbus_hash_iter_init (activation->directories, &iter);
1231   while (_dbus_hash_iter_next (&iter))
1232     {
1233       DBusError tmp_error;
1234       BusServiceDirectory *s_dir;
1235
1236       s_dir = _dbus_hash_iter_get_value (&iter);
1237
1238       dbus_error_init (&tmp_error);
1239       if (!update_directory (activation, s_dir, &tmp_error))
1240         {
1241           if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
1242             {
1243               dbus_move_error (&tmp_error, error);
1244               return FALSE;
1245             }
1246
1247           dbus_error_free (&tmp_error);
1248           continue;
1249         }
1250     }
1251   
1252   return TRUE;
1253 }
1254
1255 static BusActivationEntry *
1256 activation_find_entry (BusActivation *activation, 
1257                        const char    *service_name,
1258                        DBusError     *error)
1259 {
1260   BusActivationEntry *entry;
1261   
1262   entry = _dbus_hash_table_lookup_string (activation->entries, service_name);
1263   if (!entry)
1264     { 
1265       if (!update_service_cache (activation, error)) 
1266         return NULL;
1267
1268       entry = _dbus_hash_table_lookup_string (activation->entries,
1269                                               service_name);
1270     }
1271   else 
1272     {
1273       BusActivationEntry *updated_entry;
1274
1275       if (!check_service_file (activation, entry, &updated_entry, error)) 
1276         return NULL;
1277
1278       entry = updated_entry;
1279     }
1280
1281   if (!entry) 
1282     {
1283       dbus_set_error (error, DBUS_ERROR_SERVICE_UNKNOWN,
1284                       "The name %s was not provided by any .service files",
1285                       service_name);
1286       return NULL;
1287     }
1288
1289   return entry;
1290 }
1291
1292 dbus_bool_t
1293 bus_activation_activate_service (BusActivation  *activation,
1294                                  DBusConnection *connection,
1295                                  BusTransaction *transaction,
1296                                  dbus_bool_t     auto_activation,
1297                                  DBusMessage    *activation_message,
1298                                  const char     *service_name,
1299                                  DBusError      *error)
1300 {
1301   BusActivationEntry *entry;
1302   BusPendingActivation *pending_activation;
1303   BusPendingActivationEntry *pending_activation_entry;
1304   DBusMessage *message;
1305   DBusString service_str;
1306   char **argv;
1307   int argc;
1308   dbus_bool_t retval;
1309   DBusHashIter iter;
1310   dbus_bool_t activated;
1311   
1312   activated = TRUE;
1313
1314   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1315
1316   if (activation->n_pending_activations >=
1317       bus_context_get_max_pending_activations (activation->context))
1318     {
1319       dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
1320                       "The maximum number of pending activations has been reached, activation of %s failed",
1321                       service_name);
1322       return FALSE;
1323     }
1324
1325   entry = activation_find_entry (activation, service_name, error);
1326   if (!entry) 
1327     return FALSE;
1328
1329   /* Bypass the registry lookup if we're auto-activating, bus_dispatch would not
1330    * call us if the service is already active.
1331    */
1332   if (!auto_activation)
1333     {
1334       /* Check if the service is active */
1335       _dbus_string_init_const (&service_str, service_name);
1336       if (bus_registry_lookup (bus_context_get_registry (activation->context), &service_str) != NULL)
1337         {
1338           dbus_uint32_t result;
1339           
1340           _dbus_verbose ("Service \"%s\" is already active\n", service_name);
1341       
1342           message = dbus_message_new_method_return (activation_message);
1343
1344           if (!message)
1345             {
1346               _dbus_verbose ("No memory to create reply to activate message\n");
1347               BUS_SET_OOM (error);
1348               return FALSE;
1349             }
1350
1351           result = DBUS_START_REPLY_ALREADY_RUNNING;
1352           
1353           if (!dbus_message_append_args (message,
1354                                          DBUS_TYPE_UINT32, &result,
1355                                          DBUS_TYPE_INVALID))
1356             {
1357               _dbus_verbose ("No memory to set args of reply to activate message\n");
1358               BUS_SET_OOM (error);
1359               dbus_message_unref (message);
1360               return FALSE;
1361             }
1362
1363           retval = bus_transaction_send_from_driver (transaction, connection, message);
1364           dbus_message_unref (message);
1365           if (!retval)
1366             {
1367               _dbus_verbose ("Failed to send reply\n");
1368               BUS_SET_OOM (error);
1369             }
1370
1371           return retval;
1372         }
1373     }
1374   
1375   pending_activation_entry = dbus_new0 (BusPendingActivationEntry, 1);
1376   if (!pending_activation_entry)
1377     {
1378       _dbus_verbose ("Failed to create pending activation entry\n");
1379       BUS_SET_OOM (error);
1380       return FALSE;
1381     }
1382
1383   pending_activation_entry->auto_activation = auto_activation;
1384
1385   pending_activation_entry->activation_message = activation_message;
1386   dbus_message_ref (activation_message);
1387   pending_activation_entry->connection = connection;
1388   dbus_connection_ref (connection);
1389   
1390   /* Check if the service is being activated */
1391   pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, service_name);
1392   if (pending_activation)
1393     {
1394       if (!_dbus_list_append (&pending_activation->entries, pending_activation_entry))
1395         {
1396           _dbus_verbose ("Failed to append a new entry to pending activation\n");
1397           
1398           BUS_SET_OOM (error);
1399           bus_pending_activation_entry_free (pending_activation_entry);
1400           return FALSE;
1401         }
1402
1403       pending_activation->n_entries += 1;
1404       pending_activation->activation->n_pending_activations += 1;
1405     }
1406   else
1407     {
1408       pending_activation = dbus_new0 (BusPendingActivation, 1);
1409       if (!pending_activation)
1410         {
1411           _dbus_verbose ("Failed to create pending activation\n");
1412           
1413           BUS_SET_OOM (error);
1414           bus_pending_activation_entry_free (pending_activation_entry);          
1415           return FALSE;
1416         }
1417
1418       pending_activation->activation = activation;
1419       pending_activation->refcount = 1;
1420       
1421       pending_activation->service_name = _dbus_strdup (service_name);
1422       if (!pending_activation->service_name)
1423         {
1424           _dbus_verbose ("Failed to copy service name for pending activation\n");
1425           
1426           BUS_SET_OOM (error);
1427           bus_pending_activation_unref (pending_activation);
1428           bus_pending_activation_entry_free (pending_activation_entry);          
1429           return FALSE;
1430         }
1431
1432       pending_activation->exec = _dbus_strdup (entry->exec);
1433       if (!pending_activation->exec)
1434         {
1435           _dbus_verbose ("Failed to copy service exec for pending activation\n");
1436           BUS_SET_OOM (error);
1437           bus_pending_activation_unref (pending_activation);
1438           bus_pending_activation_entry_free (pending_activation_entry);
1439           return FALSE;
1440         }
1441
1442       pending_activation->timeout =
1443         _dbus_timeout_new (bus_context_get_activation_timeout (activation->context),
1444                            pending_activation_timed_out,
1445                            pending_activation,
1446                            NULL);
1447       if (!pending_activation->timeout)
1448         {
1449           _dbus_verbose ("Failed to create timeout for pending activation\n");
1450           
1451           BUS_SET_OOM (error);
1452           bus_pending_activation_unref (pending_activation);
1453           bus_pending_activation_entry_free (pending_activation_entry);
1454           return FALSE;
1455         }
1456
1457       if (!_dbus_loop_add_timeout (bus_context_get_loop (activation->context),
1458                                    pending_activation->timeout,
1459                                    handle_timeout_callback,
1460                                    pending_activation,
1461                                    NULL))
1462         {
1463           _dbus_verbose ("Failed to add timeout for pending activation\n");
1464           
1465           BUS_SET_OOM (error);
1466           bus_pending_activation_unref (pending_activation);
1467           bus_pending_activation_entry_free (pending_activation_entry);          
1468           return FALSE;
1469         }
1470
1471       pending_activation->timeout_added = TRUE;
1472       
1473       if (!_dbus_list_append (&pending_activation->entries, pending_activation_entry))
1474         {
1475           _dbus_verbose ("Failed to add entry to just-created pending activation\n");
1476           
1477           BUS_SET_OOM (error);
1478           bus_pending_activation_unref (pending_activation);
1479           bus_pending_activation_entry_free (pending_activation_entry);          
1480           return FALSE;
1481         }
1482
1483       pending_activation->n_entries += 1;
1484       pending_activation->activation->n_pending_activations += 1;
1485     
1486       activated = FALSE;
1487       _dbus_hash_iter_init (activation->pending_activations, &iter);
1488       while (_dbus_hash_iter_next (&iter))
1489         {
1490           BusPendingActivation *p = _dbus_hash_iter_get_value (&iter);
1491           
1492           if (strcmp (p->exec, entry->exec) == 0) 
1493             {
1494               activated = TRUE;
1495               break;
1496             }
1497         }
1498      
1499       if (!_dbus_hash_table_insert_string (activation->pending_activations,
1500                                            pending_activation->service_name,
1501                                            pending_activation))
1502         {
1503           _dbus_verbose ("Failed to put pending activation in hash table\n");
1504           
1505           BUS_SET_OOM (error);
1506           bus_pending_activation_unref (pending_activation);
1507           return FALSE;
1508         }
1509     }
1510   
1511   if (!add_cancel_pending_to_transaction (transaction, pending_activation))
1512     {
1513       _dbus_verbose ("Failed to add pending activation cancel hook to transaction\n");
1514       BUS_SET_OOM (error);
1515       _dbus_hash_table_remove_string (activation->pending_activations,
1516                                       pending_activation->service_name);
1517
1518       return FALSE;
1519     }
1520   
1521   if (activated)
1522     return TRUE;
1523
1524   /* Now try to spawn the process */
1525   if (!_dbus_shell_parse_argv (entry->exec, &argc, &argv, error))
1526     {
1527       _dbus_verbose ("Failed to parse command line: %s\n", entry->exec);
1528       _DBUS_ASSERT_ERROR_IS_SET (error);
1529       
1530       _dbus_hash_table_remove_string (activation->pending_activations,
1531                                       pending_activation->service_name);
1532
1533       return FALSE;
1534     }
1535
1536   _dbus_verbose ("Spawning %s ...\n", argv[0]);
1537   if (!_dbus_spawn_async_with_babysitter (&pending_activation->babysitter, argv,
1538                                           child_setup, activation, 
1539                                           error))
1540     {
1541       _dbus_verbose ("Failed to spawn child\n");
1542       _DBUS_ASSERT_ERROR_IS_SET (error);
1543       dbus_free_string_array (argv);
1544
1545       return FALSE;
1546     }
1547
1548   dbus_free_string_array (argv);
1549
1550   _dbus_assert (pending_activation->babysitter != NULL);
1551   
1552   if (!_dbus_babysitter_set_watch_functions (pending_activation->babysitter,
1553                                              add_babysitter_watch,
1554                                              remove_babysitter_watch,
1555                                              NULL,
1556                                              pending_activation,
1557                                              NULL))
1558     {
1559       BUS_SET_OOM (error);
1560       _dbus_verbose ("Failed to set babysitter watch functions\n");
1561       return FALSE;
1562     }
1563   
1564   return TRUE;
1565 }
1566
1567 dbus_bool_t
1568 bus_activation_list_services (BusActivation *activation,
1569                               char        ***listp,
1570                               int           *array_len)
1571 {
1572   int i, j, len;
1573   char **retval;
1574   DBusHashIter iter;
1575
1576   len = _dbus_hash_table_get_n_entries (activation->entries);
1577   retval = dbus_new (char *, len + 1);
1578
1579   if (retval == NULL)
1580     return FALSE;
1581
1582   _dbus_hash_iter_init (activation->entries, &iter);
1583   i = 0;
1584   while (_dbus_hash_iter_next (&iter))
1585     {
1586       BusActivationEntry *entry = _dbus_hash_iter_get_value (&iter);
1587
1588       retval[i] = _dbus_strdup (entry->name);
1589       if (retval[i] == NULL)
1590         goto error;
1591
1592       i++;
1593     }
1594
1595   retval[i] = NULL;
1596
1597   if (array_len)
1598     *array_len = len;
1599
1600   *listp = retval;
1601   return TRUE;
1602
1603  error:
1604   for (j = 0; j < i; j++)
1605     dbus_free (retval[i]);
1606   dbus_free (retval);
1607
1608   return FALSE;
1609 }
1610   
1611
1612 #ifdef DBUS_BUILD_TESTS
1613
1614 #include <stdio.h>
1615
1616 #define SERVICE_NAME_1 "MyService1"
1617 #define SERVICE_NAME_2 "MyService2"
1618 #define SERVICE_NAME_3 "MyService3"
1619
1620 #define SERVICE_FILE_1 "service-1.service"
1621 #define SERVICE_FILE_2 "service-2.service"
1622 #define SERVICE_FILE_3 "service-3.service"
1623
1624 static dbus_bool_t
1625 test_create_service_file (DBusString *dir,
1626                           const char *filename, 
1627                           const char *name, 
1628                           const char *exec)
1629 {
1630   DBusString  file_name, full_path;
1631   FILE        *file;
1632   dbus_bool_t  ret_val;
1633
1634   ret_val = TRUE;
1635   _dbus_string_init_const (&file_name, filename);
1636
1637   if (!_dbus_string_init (&full_path))
1638     return FALSE;
1639
1640   if (!_dbus_string_append (&full_path, _dbus_string_get_const_data (dir)) ||
1641       !_dbus_concat_dir_and_file (&full_path, &file_name))
1642     {
1643       ret_val = FALSE;
1644       goto out;
1645     }
1646   
1647   file = fopen (_dbus_string_get_const_data (&full_path), "w");
1648   if (!file)
1649     {
1650       ret_val = FALSE;
1651       goto out;
1652     }
1653
1654   fprintf (file, "[D-BUS Service]\nName=%s\nExec=%s\n", name, exec);
1655   fclose (file);
1656
1657 out:
1658   _dbus_string_free (&full_path);
1659   return ret_val;
1660 }
1661
1662 static dbus_bool_t
1663 test_remove_service_file (DBusString *dir, const char *filename)
1664 {
1665   DBusString  file_name, full_path;
1666   dbus_bool_t ret_val;
1667   
1668   ret_val = TRUE;
1669  
1670   _dbus_string_init_const (&file_name, filename);
1671
1672   if (!_dbus_string_init (&full_path))
1673     return FALSE;
1674
1675   if (!_dbus_string_append (&full_path, _dbus_string_get_const_data (dir)) ||
1676       !_dbus_concat_dir_and_file (&full_path, &file_name))
1677     {
1678       ret_val = FALSE;
1679       goto out;
1680     }
1681
1682   if (!_dbus_delete_file (&full_path, NULL))
1683     {
1684       ret_val = FALSE;
1685       goto out;
1686     }
1687
1688 out:
1689   _dbus_string_free (&full_path);
1690   return ret_val;
1691 }
1692
1693 static dbus_bool_t
1694 test_remove_directory (DBusString *dir)
1695 {
1696   DBusDirIter *iter;
1697   DBusString   filename, full_path;
1698   dbus_bool_t  ret_val;
1699   
1700   ret_val = TRUE;
1701   
1702   if (!_dbus_string_init (&filename))
1703     return FALSE;
1704
1705   if (!_dbus_string_init (&full_path))
1706     {
1707       _dbus_string_free (&filename);
1708       return FALSE;
1709     }
1710     
1711   iter = _dbus_directory_open (dir, NULL);
1712   if (iter == NULL)
1713     {
1714       ret_val = FALSE;
1715       goto out;
1716     }
1717   
1718   while (_dbus_directory_get_next_file (iter, &filename, NULL)) 
1719     {
1720       if (!test_remove_service_file (dir, _dbus_string_get_const_data (&filename)))
1721         {
1722           ret_val = FALSE;
1723           goto out;
1724         }
1725     }
1726   _dbus_directory_close (iter);
1727
1728   if (!_dbus_delete_directory (dir, NULL))
1729     {
1730       ret_val = FALSE;
1731       goto out;
1732     }
1733
1734 out:
1735   _dbus_string_free (&filename);
1736   _dbus_string_free (&full_path);
1737
1738   return ret_val;
1739 }
1740
1741 static dbus_bool_t
1742 init_service_reload_test (DBusString *dir)
1743 {
1744   DBusStat stat_buf;
1745  
1746   if (!_dbus_stat (dir, &stat_buf, NULL))
1747     {
1748       if (!_dbus_create_directory (dir, NULL))
1749         return FALSE;
1750     }
1751   else 
1752     {
1753       if (!test_remove_directory (dir))
1754         return FALSE;
1755
1756       if (!_dbus_create_directory (dir, NULL))
1757         return FALSE;
1758     }
1759
1760   /* Create one initial file */
1761   if (!test_create_service_file (dir, SERVICE_FILE_1, SERVICE_NAME_1, "exec-1"))
1762     return FALSE;
1763
1764   return TRUE;
1765 }
1766
1767 static dbus_bool_t
1768 cleanup_service_reload_test (DBusString *dir)
1769 {
1770   if (!test_remove_directory (dir))
1771     return FALSE;
1772
1773   return TRUE;
1774 }
1775
1776 typedef struct 
1777 {
1778   BusActivation *activation;
1779   const char    *service_name;
1780   dbus_bool_t    expecting_find;
1781 } CheckData;
1782
1783 static dbus_bool_t
1784 check_func (void *data)
1785 {
1786   CheckData          *d;
1787   BusActivationEntry *entry;
1788   DBusError           error;
1789   dbus_bool_t         ret_val;
1790   
1791   ret_val = TRUE;
1792   d = data;
1793   
1794   dbus_error_init (&error);
1795  
1796   entry = activation_find_entry (d->activation, d->service_name, &error);
1797   if (entry == NULL)
1798     {
1799       if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) 
1800         {
1801           ret_val = TRUE;
1802         }
1803       else
1804         {
1805           if (d->expecting_find)
1806             ret_val = FALSE;
1807         }
1808       
1809       dbus_error_free (&error);
1810     }
1811   else 
1812     {
1813       if (!d->expecting_find)
1814         ret_val = FALSE;
1815     }
1816
1817   return ret_val;
1818 }
1819
1820 static dbus_bool_t
1821 do_test (const char *description, dbus_bool_t oom_test, CheckData *data)
1822 {
1823   dbus_bool_t err;
1824
1825   if (oom_test)
1826     err = !_dbus_test_oom_handling (description, check_func, data);
1827   else
1828     err = !check_func (data);
1829
1830   if (err) 
1831     _dbus_assert_not_reached ("Test failed");
1832
1833   return TRUE;
1834 }
1835
1836 static dbus_bool_t
1837 do_service_reload_test (DBusString *dir, dbus_bool_t oom_test)
1838 {
1839   BusActivation *activation;
1840   DBusString     address;
1841   DBusList      *directories;
1842   CheckData      d;
1843   
1844   directories = NULL;
1845   _dbus_string_init_const (&address, "");
1846  
1847   if (!_dbus_list_append (&directories, _dbus_string_get_data (dir)))
1848     return FALSE; 
1849
1850   activation = bus_activation_new (NULL, &address, &directories, NULL);
1851   if (!activation)
1852     return FALSE;
1853
1854   d.activation = activation;
1855   
1856   /* Check for existing service file */
1857   d.expecting_find = TRUE;
1858   d.service_name = SERVICE_NAME_1;
1859
1860   if (!do_test ("Existing service file", oom_test, &d))
1861     return FALSE;
1862
1863   /* Check for non-existing service file */
1864   d.expecting_find = FALSE;
1865   d.service_name = SERVICE_NAME_3;
1866
1867   if (!do_test ("Nonexisting service file", oom_test, &d))
1868     return FALSE;
1869
1870   /* Check for added service file */
1871   if (!test_create_service_file (dir, SERVICE_FILE_2, SERVICE_NAME_2, "exec-2"))
1872     return FALSE;
1873
1874   d.expecting_find = TRUE;
1875   d.service_name = SERVICE_NAME_2;
1876   
1877   if (!do_test ("Added service file", oom_test, &d))
1878     return FALSE;
1879   
1880   /* Check for removed service file */
1881   if (!test_remove_service_file (dir, SERVICE_FILE_2))
1882     return FALSE;
1883
1884   d.expecting_find = FALSE;
1885   d.service_name = SERVICE_FILE_2;
1886
1887   if (!do_test ("Removed service file", oom_test, &d))
1888     return FALSE;
1889   
1890   /* Check for updated service file */
1891   
1892   _dbus_sleep_milliseconds (1000); /* Sleep a second to make sure the mtime is updated */
1893
1894   if (!test_create_service_file (dir, SERVICE_FILE_1, SERVICE_NAME_3, "exec-3"))
1895     return FALSE;
1896
1897   d.expecting_find = TRUE;
1898   d.service_name = SERVICE_NAME_3;
1899
1900   if (!do_test ("Updated service file, part 1", oom_test, &d))
1901     return FALSE;
1902
1903   d.expecting_find = FALSE;
1904   d.service_name = SERVICE_NAME_1;
1905
1906   if (!do_test ("Updated service file, part 2", oom_test, &d))
1907     return FALSE; 
1908
1909   bus_activation_unref (activation);
1910   _dbus_list_clear (&directories);
1911
1912   return TRUE;
1913 }
1914
1915 dbus_bool_t
1916 bus_activation_service_reload_test (const DBusString *test_data_dir)
1917 {
1918   DBusString directory;
1919
1920   if (!_dbus_string_init (&directory))
1921     return FALSE;
1922   
1923   if (!_dbus_string_append (&directory, _dbus_get_tmpdir()))
1924     return FALSE;
1925   
1926   if (!_dbus_string_append (&directory, "/dbus-reload-test-") ||
1927       !_dbus_generate_random_ascii (&directory, 6))
1928      {
1929        return FALSE;
1930      }
1931    
1932   /* Do normal tests */
1933   if (!init_service_reload_test (&directory))
1934     _dbus_assert_not_reached ("could not initiate service reload test");
1935  
1936   if (!do_service_reload_test (&directory, FALSE))
1937     ; /* Do nothing? */
1938   
1939   /* Do OOM tests */
1940   if (!init_service_reload_test (&directory))
1941     _dbus_assert_not_reached ("could not initiate service reload test");
1942  
1943   if (!do_service_reload_test (&directory, TRUE))
1944     ; /* Do nothing? */
1945  
1946   /* Cleanup test directory */
1947   if (!cleanup_service_reload_test (&directory))
1948     return FALSE;
1949   
1950   _dbus_string_free (&directory);
1951   
1952   return TRUE;
1953 }
1954
1955 #endif /* DBUS_BUILD_TESTS */