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