2005-01-15 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / bus / activation.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* activation.c  Activation of services
3  *
4  * Copyright (C) 2003  CodeFactory AB
5  * Copyright (C) 2003  Red Hat, Inc.
6  * 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-spawn.h>
34 #include <dbus/dbus-timeout.h>
35 #include <dirent.h>
36 #include <errno.h>
37
38 #define DBUS_SERVICE_SECTION "D-BUS Service"
39 #define DBUS_SERVICE_NAME "Name"
40 #define DBUS_SERVICE_EXEC "Exec"
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     {
288       dbus_set_error (error, DBUS_ERROR_FAILED,
289                       "No \""DBUS_SERVICE_NAME"\" key in .service file\n");
290       goto failed;
291     }
292
293   if (!bus_desktop_file_get_string (desktop_file,
294                                     DBUS_SERVICE_SECTION,
295                                     DBUS_SERVICE_EXEC,
296                                     &exec))
297     {
298       dbus_set_error (error, DBUS_ERROR_FAILED,
299                       "No \""DBUS_SERVICE_EXEC"\" key in .service file\n");
300       goto failed;
301     }
302
303   entry = _dbus_hash_table_lookup_string (s_dir->entries, 
304                                           _dbus_string_get_const_data (filename));
305   if (entry == NULL) /* New file */
306     { 
307       /* FIXME we need a better-defined algorithm for which service file to
308        * pick than "whichever one is first in the directory listing"
309        */
310       if (_dbus_hash_table_lookup_string (activation->entries, name))
311         {
312           dbus_set_error (error, DBUS_ERROR_FAILED,
313                           "Service %s already exists in activation entry list\n", name);
314           goto failed;
315         }
316       
317       entry = dbus_new0 (BusActivationEntry, 1);
318       if (entry == NULL)
319         {
320           BUS_SET_OOM (error);
321           goto failed;
322         }
323      
324       entry->name = name;
325       entry->exec = exec;
326       entry->refcount = 1;
327     
328       entry->s_dir = s_dir;
329       entry->filename = _dbus_strdup (_dbus_string_get_const_data (filename));
330       if (!entry->filename)
331         {
332           BUS_SET_OOM (error);
333           goto failed;
334         }
335
336       if (!_dbus_hash_table_insert_string (activation->entries, entry->name, bus_activation_entry_ref (entry)))
337         {
338           BUS_SET_OOM (error);
339           goto failed;
340         }
341      
342       if (!_dbus_hash_table_insert_string (s_dir->entries, entry->filename, bus_activation_entry_ref (entry)))
343         {
344           /* Revert the insertion in the entries table */
345           _dbus_hash_table_remove_string (activation->entries, entry->name);
346           BUS_SET_OOM (error);
347           goto failed;
348         }
349
350       _dbus_verbose ("Added \"%s\" to list of services\n", entry->name);
351     }
352   else /* Just update the entry */
353     {
354       bus_activation_entry_ref (entry);
355       _dbus_hash_table_remove_string (activation->entries, entry->name);
356
357       if (_dbus_hash_table_lookup_string (activation->entries, name))
358         {
359           _dbus_verbose ("The new service name \"%s\" of service file \"%s\" already in cache, ignoring\n",
360                          name, _dbus_string_get_const_data (&file_path));
361           goto failed;
362         }
363  
364       dbus_free (entry->name);
365       dbus_free (entry->exec);
366       entry->name = name;
367       entry->exec = exec;
368       if (!_dbus_hash_table_insert_string (activation->entries,
369                                            entry->name, bus_activation_entry_ref(entry)))
370         {
371           BUS_SET_OOM (error);
372           /* Also remove path to entries hash since we want this in sync with
373            * the entries hash table */
374           _dbus_hash_table_remove_string (entry->s_dir->entries, 
375                                           entry->filename);
376           bus_activation_entry_unref (entry);
377           return FALSE;
378         }
379     }
380   
381   entry->mtime = stat_buf.mtime;
382   
383   _dbus_string_free (&file_path);
384   bus_activation_entry_unref (entry);
385
386   return TRUE;
387
388 failed:
389   dbus_free (name);
390   dbus_free (exec);
391   _dbus_string_free (&file_path);
392
393   if (entry)
394     bus_activation_entry_unref (entry);
395   
396   return FALSE;
397 }
398
399 static dbus_bool_t
400 check_service_file (BusActivation       *activation,
401                     BusActivationEntry  *entry,
402                     BusActivationEntry **updated_entry,
403                     DBusError           *error)
404 {
405   DBusStat stat_buf;
406   dbus_bool_t retval;
407   BusActivationEntry *tmp_entry;
408   DBusString file_path;
409   DBusString filename;
410
411   retval = TRUE;
412   tmp_entry = entry;
413   
414   _dbus_string_init_const (&filename, entry->filename);
415   
416   if (!_dbus_string_init (&file_path))
417     {
418       BUS_SET_OOM (error);
419       return FALSE;
420     }
421  
422   if (!_dbus_string_append (&file_path, entry->s_dir->dir_c) ||
423       !_dbus_concat_dir_and_file (&file_path, &filename))
424     {
425       BUS_SET_OOM (error);
426       retval = FALSE;
427       goto out;
428     }
429   
430   if (!_dbus_stat (&file_path, &stat_buf, NULL))
431     {
432       _dbus_verbose ("****** Can't stat file \"%s\", removing from cache\n",
433                      _dbus_string_get_const_data (&file_path));
434
435       _dbus_hash_table_remove_string (activation->entries, entry->name);
436       _dbus_hash_table_remove_string (entry->s_dir->entries, entry->filename);
437
438       tmp_entry = NULL;
439       retval = TRUE;
440       goto out;
441     }
442   else 
443     {
444       if (stat_buf.mtime > entry->mtime) 
445         {
446           BusDesktopFile *desktop_file;
447           DBusError tmp_error;
448           
449           dbus_error_init (&tmp_error);
450           
451           desktop_file = bus_desktop_file_load (&file_path, &tmp_error);
452           if (desktop_file == NULL)
453             {
454               _dbus_verbose ("Could not load %s: %s\n",
455                              _dbus_string_get_const_data (&file_path), 
456                              tmp_error.message);
457               if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
458                 {
459                   dbus_move_error (&tmp_error, error);
460                   retval = FALSE;
461                   goto out;
462                 }
463               dbus_error_free (&tmp_error);
464               retval = TRUE;
465               goto out;
466             }
467           
468           if (!update_desktop_file_entry (activation, entry->s_dir, &filename, desktop_file, &tmp_error))
469             {
470               bus_desktop_file_free (desktop_file);
471               if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
472                 {
473                   dbus_move_error (&tmp_error, error);
474                   retval = FALSE;
475                   goto out;
476                 }
477               dbus_error_free (&tmp_error);
478               retval = TRUE;
479               goto out;
480             }
481          
482           bus_desktop_file_free (desktop_file);
483           retval = TRUE;
484         }
485     }
486   
487 out:
488   _dbus_string_free (&file_path);
489
490   if (updated_entry != NULL)
491     *updated_entry = tmp_entry;
492   return retval;
493 }
494
495
496 /* warning: this doesn't fully "undo" itself on failure, i.e. doesn't strip
497  * hash entries it already added.
498  */
499 static dbus_bool_t
500 update_directory (BusActivation       *activation,
501                   BusServiceDirectory *s_dir,
502                   DBusError           *error)
503 {
504   DBusDirIter *iter;
505   DBusString dir, filename;
506   BusDesktopFile *desktop_file;
507   DBusError tmp_error;
508   dbus_bool_t retval;
509   BusActivationEntry *entry;
510   DBusString full_path;
511   
512   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
513   
514   iter = NULL;
515   desktop_file = NULL;
516   
517   _dbus_string_init_const (&dir, s_dir->dir_c);
518   
519   if (!_dbus_string_init (&filename))
520     {
521       BUS_SET_OOM (error);
522       return FALSE;
523     }
524
525   if (!_dbus_string_init (&full_path))
526     {
527       BUS_SET_OOM (error);
528       _dbus_string_free (&filename);
529       return FALSE;
530     }
531
532   retval = FALSE;
533
534   /* from this point it's safe to "goto out" */
535   
536   iter = _dbus_directory_open (&dir, error);
537   if (iter == NULL)
538     {
539       _dbus_verbose ("Failed to open directory %s: %s\n",
540                      s_dir->dir_c, 
541                      error ? error->message : "unknown");
542       goto out;
543     }
544   
545   /* Now read the files */
546   dbus_error_init (&tmp_error);
547   while (_dbus_directory_get_next_file (iter, &filename, &tmp_error))
548     {
549       _dbus_assert (!dbus_error_is_set (&tmp_error));
550       
551       _dbus_string_set_length (&full_path, 0);
552       
553       if (!_dbus_string_ends_with_c_str (&filename, ".service"))
554         {
555           _dbus_verbose ("Skipping non-.service file %s\n",
556                          _dbus_string_get_const_data (&filename));
557           continue;
558         }
559
560       entry = _dbus_hash_table_lookup_string (s_dir->entries, _dbus_string_get_const_data (&filename));
561       if (entry) /* Already has this service file in the cache */ 
562         {
563           if (!check_service_file (activation, entry, NULL, error))
564             goto out;
565
566           continue;
567         }
568       
569       if (!_dbus_string_append (&full_path, s_dir->dir_c) ||
570           !_dbus_concat_dir_and_file (&full_path, &filename))
571         {
572           BUS_SET_OOM (error);
573           goto out;
574         }
575           
576       /* New file */
577       desktop_file = bus_desktop_file_load (&full_path, &tmp_error);
578       if (desktop_file == NULL)
579         {
580           _dbus_verbose ("Could not load %s: %s\n",
581                          _dbus_string_get_const_data (&full_path),
582                          tmp_error.message);
583
584           if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
585             {
586               dbus_move_error (&tmp_error, error);
587               goto out;
588             }
589           
590           dbus_error_free (&tmp_error);
591           continue;
592         }
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   if (desktop_file)
636     bus_desktop_file_free (desktop_file);
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_ACTIVATION_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_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_ACTIVATION_REPLY_ACTIVATED;
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_owner (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 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_ACTIVATE_SERVICE_NOT_FOUND,
1284                       "The service %s was not found in the activation entry list",
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[2];
1307   dbus_bool_t retval;
1308   DBusHashIter iter;
1309   dbus_bool_t activated;
1310   
1311   activated = TRUE;
1312
1313   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
1314
1315   if (activation->n_pending_activations >=
1316       bus_context_get_max_pending_activations (activation->context))
1317     {
1318       dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
1319                       "The maximum number of pending activations has been reached, activation of %s failed",
1320                       service_name);
1321       return FALSE;
1322     }
1323
1324   entry = activation_find_entry (activation, service_name, error);
1325   if (!entry) 
1326     return FALSE;
1327
1328   /* Bypass the registry lookup if we're auto-activating, bus_dispatch would not
1329    * call us if the service is already active.
1330    */
1331   if (!auto_activation)
1332     {
1333       /* Check if the service is active */
1334       _dbus_string_init_const (&service_str, service_name);
1335       if (bus_registry_lookup (bus_context_get_registry (activation->context), &service_str) != NULL)
1336         {
1337           dbus_uint32_t result;
1338           
1339           _dbus_verbose ("Service \"%s\" is already active\n", service_name);
1340       
1341           message = dbus_message_new_method_return (activation_message);
1342
1343           if (!message)
1344             {
1345               _dbus_verbose ("No memory to create reply to activate message\n");
1346               BUS_SET_OOM (error);
1347               return FALSE;
1348             }
1349
1350           result = DBUS_ACTIVATION_REPLY_ALREADY_ACTIVE;
1351           
1352           if (!dbus_message_append_args (message,
1353                                          DBUS_TYPE_UINT32, &result,
1354                                          DBUS_TYPE_INVALID))
1355             {
1356               _dbus_verbose ("No memory to set args of reply to activate message\n");
1357               BUS_SET_OOM (error);
1358               dbus_message_unref (message);
1359               return FALSE;
1360             }
1361
1362           retval = bus_transaction_send_from_driver (transaction, connection, message);
1363           dbus_message_unref (message);
1364           if (!retval)
1365             {
1366               _dbus_verbose ("Failed to send reply\n");
1367               BUS_SET_OOM (error);
1368             }
1369
1370           return retval;
1371         }
1372     }
1373
1374   pending_activation_entry = dbus_new0 (BusPendingActivationEntry, 1);
1375   if (!pending_activation_entry)
1376     {
1377       _dbus_verbose ("Failed to create pending activation entry\n");
1378       BUS_SET_OOM (error);
1379       return FALSE;
1380     }
1381
1382   pending_activation_entry->auto_activation = auto_activation;
1383
1384   pending_activation_entry->activation_message = activation_message;
1385   dbus_message_ref (activation_message);
1386   pending_activation_entry->connection = connection;
1387   dbus_connection_ref (connection);
1388   
1389   /* Check if the service is being activated */
1390   pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, service_name);
1391   if (pending_activation)
1392     {
1393       if (!_dbus_list_append (&pending_activation->entries, pending_activation_entry))
1394         {
1395           _dbus_verbose ("Failed to append a new entry to pending activation\n");
1396           
1397           BUS_SET_OOM (error);
1398           bus_pending_activation_entry_free (pending_activation_entry);
1399           return FALSE;
1400         }
1401
1402       pending_activation->n_entries += 1;
1403       pending_activation->activation->n_pending_activations += 1;
1404     }
1405   else
1406     {
1407       pending_activation = dbus_new0 (BusPendingActivation, 1);
1408       if (!pending_activation)
1409         {
1410           _dbus_verbose ("Failed to create pending activation\n");
1411           
1412           BUS_SET_OOM (error);
1413           bus_pending_activation_entry_free (pending_activation_entry);   
1414           return FALSE;
1415         }
1416
1417       pending_activation->activation = activation;
1418       pending_activation->refcount = 1;
1419       
1420       pending_activation->service_name = _dbus_strdup (service_name);
1421       if (!pending_activation->service_name)
1422         {
1423           _dbus_verbose ("Failed to copy service name for pending activation\n");
1424           
1425           BUS_SET_OOM (error);
1426           bus_pending_activation_unref (pending_activation);
1427           bus_pending_activation_entry_free (pending_activation_entry);   
1428           return FALSE;
1429         }
1430
1431       pending_activation->exec = _dbus_strdup (entry->exec);
1432       if (!pending_activation->exec)
1433         {
1434           _dbus_verbose ("Failed to copy service exec for pending activation\n");
1435           BUS_SET_OOM (error);
1436           bus_pending_activation_unref (pending_activation);
1437           bus_pending_activation_entry_free (pending_activation_entry);
1438           return FALSE;
1439         }
1440
1441       pending_activation->timeout =
1442         _dbus_timeout_new (bus_context_get_activation_timeout (activation->context),
1443                            pending_activation_timed_out,
1444                            pending_activation,
1445                            NULL);
1446       if (!pending_activation->timeout)
1447         {
1448           _dbus_verbose ("Failed to create timeout for pending activation\n");
1449           
1450           BUS_SET_OOM (error);
1451           bus_pending_activation_unref (pending_activation);
1452           bus_pending_activation_entry_free (pending_activation_entry);   
1453           return FALSE;
1454         }
1455
1456       if (!_dbus_loop_add_timeout (bus_context_get_loop (activation->context),
1457                                    pending_activation->timeout,
1458                                    handle_timeout_callback,
1459                                    pending_activation,
1460                                    NULL))
1461         {
1462           _dbus_verbose ("Failed to add timeout for pending activation\n");
1463           
1464           BUS_SET_OOM (error);
1465           bus_pending_activation_unref (pending_activation);
1466           bus_pending_activation_entry_free (pending_activation_entry);   
1467           return FALSE;
1468         }
1469
1470       pending_activation->timeout_added = TRUE;
1471       
1472       if (!_dbus_list_append (&pending_activation->entries, pending_activation_entry))
1473         {
1474           _dbus_verbose ("Failed to add entry to just-created pending activation\n");
1475           
1476           BUS_SET_OOM (error);
1477           bus_pending_activation_unref (pending_activation);
1478           bus_pending_activation_entry_free (pending_activation_entry);   
1479           return FALSE;
1480         }
1481
1482       pending_activation->n_entries += 1;
1483       pending_activation->activation->n_pending_activations += 1;
1484     
1485       activated = FALSE;
1486       _dbus_hash_iter_init (activation->pending_activations, &iter);
1487       while (_dbus_hash_iter_next (&iter))
1488         {
1489           BusPendingActivation *p = _dbus_hash_iter_get_value (&iter);
1490           
1491           if (strcmp (p->exec, entry->exec) == 0) 
1492             {
1493               activated = TRUE;
1494               break;
1495             }
1496         }
1497      
1498       if (!_dbus_hash_table_insert_string (activation->pending_activations,
1499                                            pending_activation->service_name,
1500                                            pending_activation))
1501         {
1502           _dbus_verbose ("Failed to put pending activation in hash table\n");
1503           
1504           BUS_SET_OOM (error);
1505           bus_pending_activation_unref (pending_activation);
1506           return FALSE;
1507         }
1508     }
1509   
1510   if (!add_cancel_pending_to_transaction (transaction, pending_activation))
1511     {
1512       _dbus_verbose ("Failed to add pending activation cancel hook to transaction\n");
1513       BUS_SET_OOM (error);
1514       _dbus_hash_table_remove_string (activation->pending_activations,
1515                                       pending_activation->service_name);
1516       return FALSE;
1517     }
1518   
1519   /* FIXME we need to support a full command line, not just a single
1520    * argv[0]
1521    */
1522
1523   if (activated)
1524     return TRUE;
1525
1526   /* Now try to spawn the process */
1527   argv[0] = entry->exec;
1528   argv[1] = NULL;
1529
1530   if (!_dbus_spawn_async_with_babysitter (&pending_activation->babysitter, argv,
1531                                           child_setup, activation, 
1532                                           error))
1533     {
1534       _dbus_verbose ("Failed to spawn child\n");
1535       _DBUS_ASSERT_ERROR_IS_SET (error);
1536       return FALSE;
1537     }
1538
1539   _dbus_assert (pending_activation->babysitter != NULL);
1540   
1541   if (!_dbus_babysitter_set_watch_functions (pending_activation->babysitter,
1542                                              add_babysitter_watch,
1543                                              remove_babysitter_watch,
1544                                              NULL,
1545                                              pending_activation,
1546                                              NULL))
1547     {
1548       BUS_SET_OOM (error);
1549       _dbus_verbose ("Failed to set babysitter watch functions\n");
1550       return FALSE;
1551     }
1552   
1553   return TRUE;
1554 }
1555
1556 #ifdef DBUS_BUILD_TESTS
1557
1558 #include <stdio.h>
1559
1560 #define SERVICE_NAME_1 "MyService1"
1561 #define SERVICE_NAME_2 "MyService2"
1562 #define SERVICE_NAME_3 "MyService3"
1563
1564 #define SERVICE_FILE_1 "service-1.service"
1565 #define SERVICE_FILE_2 "service-2.service"
1566 #define SERVICE_FILE_3 "service-3.service"
1567
1568 static dbus_bool_t
1569 test_create_service_file (DBusString *dir,
1570                           const char *filename, 
1571                           const char *name, 
1572                           const char *exec)
1573 {
1574   DBusString  file_name, full_path;
1575   FILE        *file;
1576   dbus_bool_t  ret_val;
1577
1578   ret_val = TRUE;
1579   _dbus_string_init_const (&file_name, filename);
1580
1581   if (!_dbus_string_init (&full_path))
1582     return FALSE;
1583
1584   if (!_dbus_string_append (&full_path, _dbus_string_get_const_data (dir)) ||
1585       !_dbus_concat_dir_and_file (&full_path, &file_name))
1586     {
1587       ret_val = FALSE;
1588       goto out;
1589     }
1590   
1591   file = fopen (_dbus_string_get_const_data (&full_path), "w");
1592   if (!file)
1593     {
1594       ret_val = FALSE;
1595       goto out;
1596     }
1597
1598   fprintf (file, "[D-BUS Service]\nName=%s\nExec=%s\n", name, exec);
1599   fclose (file);
1600
1601 out:
1602   _dbus_string_free (&full_path);
1603   return ret_val;
1604 }
1605
1606 static dbus_bool_t
1607 test_remove_service_file (DBusString *dir, const char *filename)
1608 {
1609   DBusString  file_name, full_path;
1610   dbus_bool_t ret_val;
1611   
1612   ret_val = TRUE;
1613  
1614   _dbus_string_init_const (&file_name, filename);
1615
1616   if (!_dbus_string_init (&full_path))
1617     return FALSE;
1618
1619   if (!_dbus_string_append (&full_path, _dbus_string_get_const_data (dir)) ||
1620       !_dbus_concat_dir_and_file (&full_path, &file_name))
1621     {
1622       ret_val = FALSE;
1623       goto out;
1624     }
1625
1626   if (!_dbus_delete_file (&full_path, NULL))
1627     {
1628       ret_val = FALSE;
1629       goto out;
1630     }
1631
1632 out:
1633   _dbus_string_free (&full_path);
1634   return ret_val;
1635 }
1636
1637 static dbus_bool_t
1638 test_remove_directory (DBusString *dir)
1639 {
1640   DBusDirIter *iter;
1641   DBusString   filename, full_path;
1642   dbus_bool_t  ret_val;
1643   
1644   ret_val = TRUE;
1645   
1646   if (!_dbus_string_init (&filename))
1647     return FALSE;
1648
1649   if (!_dbus_string_init (&full_path))
1650     {
1651       _dbus_string_free (&filename);
1652       return FALSE;
1653     }
1654     
1655   iter = _dbus_directory_open (dir, NULL);
1656   if (iter == NULL)
1657     {
1658       ret_val = FALSE;
1659       goto out;
1660     }
1661   
1662   while (_dbus_directory_get_next_file (iter, &filename, NULL)) 
1663     {
1664       if (!test_remove_service_file (dir, _dbus_string_get_const_data (&filename)))
1665         {
1666           ret_val = FALSE;
1667           goto out;
1668         }
1669     }
1670   _dbus_directory_close (iter);
1671
1672   if (!_dbus_delete_directory (dir, NULL))
1673     {
1674       ret_val = FALSE;
1675       goto out;
1676     }
1677
1678 out:
1679   _dbus_string_free (&filename);
1680   _dbus_string_free (&full_path);
1681
1682   return ret_val;
1683 }
1684
1685 static dbus_bool_t
1686 init_service_reload_test (DBusString *dir)
1687 {
1688   DBusStat stat_buf;
1689  
1690   if (!_dbus_stat (dir, &stat_buf, NULL))
1691     {
1692       if (!_dbus_create_directory (dir, NULL))
1693         return FALSE;
1694     }
1695   else 
1696     {
1697       if (!test_remove_directory (dir))
1698         return FALSE;
1699
1700       if (!_dbus_create_directory (dir, NULL))
1701         return FALSE;
1702     }
1703
1704   /* Create one initial file */
1705   if (!test_create_service_file (dir, SERVICE_FILE_1, SERVICE_NAME_1, "exec-1"))
1706     return FALSE;
1707
1708   return TRUE;
1709 }
1710
1711 static dbus_bool_t
1712 cleanup_service_reload_test (DBusString *dir)
1713 {
1714   if (!test_remove_directory (dir))
1715     return FALSE;
1716
1717   return TRUE;
1718 }
1719
1720 typedef struct 
1721 {
1722   BusActivation *activation;
1723   const char    *service_name;
1724   dbus_bool_t    expecting_find;
1725 } CheckData;
1726
1727 static dbus_bool_t
1728 check_func (void *data)
1729 {
1730   CheckData          *d;
1731   BusActivationEntry *entry;
1732   DBusError           error;
1733   dbus_bool_t         ret_val;
1734   
1735   ret_val = TRUE;
1736   d = data;
1737   
1738   dbus_error_init (&error);
1739  
1740   entry = activation_find_entry (d->activation, d->service_name, &error);
1741   if (entry == NULL)
1742     {
1743       if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY)) 
1744         {
1745           ret_val = TRUE;
1746         }
1747       else
1748         {
1749           if (d->expecting_find)
1750             ret_val = FALSE;
1751         }
1752       
1753       dbus_error_free (&error);
1754     }
1755   else 
1756     {
1757       if (!d->expecting_find)
1758         ret_val = FALSE;
1759     }
1760
1761   return ret_val;
1762 }
1763
1764 static dbus_bool_t
1765 do_test (const char *description, dbus_bool_t oom_test, CheckData *data)
1766 {
1767   dbus_bool_t err;
1768
1769   if (oom_test)
1770     err = !_dbus_test_oom_handling (description, check_func, data);
1771   else
1772     err = !check_func (data);
1773
1774   if (err) 
1775     _dbus_assert_not_reached ("Test failed");
1776
1777   return TRUE;
1778 }
1779
1780 static dbus_bool_t
1781 do_service_reload_test (DBusString *dir, dbus_bool_t oom_test)
1782 {
1783   BusActivation *activation;
1784   DBusString     address;
1785   DBusList      *directories;
1786   CheckData      d;
1787   
1788   directories = NULL;
1789   _dbus_string_init_const (&address, "");
1790  
1791   if (!_dbus_list_append (&directories, _dbus_string_get_data (dir)))
1792     return FALSE; 
1793
1794   activation = bus_activation_new (NULL, &address, &directories, NULL);
1795   if (!activation)
1796     return FALSE;
1797
1798   d.activation = activation;
1799   
1800   /* Check for existing service file */
1801   d.expecting_find = TRUE;
1802   d.service_name = SERVICE_NAME_1;
1803
1804   if (!do_test ("Existing service file", oom_test, &d))
1805     return FALSE;
1806
1807   /* Check for non-existing service file */
1808   d.expecting_find = FALSE;
1809   d.service_name = SERVICE_NAME_3;
1810
1811   if (!do_test ("Nonexisting service file", oom_test, &d))
1812     return FALSE;
1813
1814   /* Check for added service file */
1815   if (!test_create_service_file (dir, SERVICE_FILE_2, SERVICE_NAME_2, "exec-2"))
1816     return FALSE;
1817
1818   d.expecting_find = TRUE;
1819   d.service_name = SERVICE_NAME_2;
1820   
1821   if (!do_test ("Added service file", oom_test, &d))
1822     return FALSE;
1823   
1824   /* Check for removed service file */
1825   if (!test_remove_service_file (dir, SERVICE_FILE_2))
1826     return FALSE;
1827
1828   d.expecting_find = FALSE;
1829   d.service_name = SERVICE_FILE_2;
1830
1831   if (!do_test ("Removed service file", oom_test, &d))
1832     return FALSE;
1833   
1834   /* Check for updated service file */
1835   
1836   _dbus_sleep_milliseconds (1000); /* Sleep a second to make sure the mtime is updated */
1837
1838   if (!test_create_service_file (dir, SERVICE_FILE_1, SERVICE_NAME_3, "exec-3"))
1839     return FALSE;
1840
1841   d.expecting_find = TRUE;
1842   d.service_name = SERVICE_NAME_3;
1843
1844   if (!do_test ("Updated service file, part 1", oom_test, &d))
1845     return FALSE;
1846
1847   d.expecting_find = FALSE;
1848   d.service_name = SERVICE_NAME_1;
1849
1850   if (!do_test ("Updated service file, part 2", oom_test, &d))
1851     return FALSE; 
1852
1853   bus_activation_unref (activation);
1854   _dbus_list_clear (&directories);
1855
1856   return TRUE;
1857 }
1858
1859 dbus_bool_t
1860 bus_activation_service_reload_test (const DBusString *test_data_dir)
1861 {
1862   DBusString directory;
1863
1864   if (!_dbus_string_init (&directory))
1865     return FALSE;
1866
1867   if (!_dbus_string_append (&directory, "/tmp/dbus-reload-test-") ||
1868       !_dbus_generate_random_ascii (&directory, 6))
1869      {
1870        return FALSE;
1871      }
1872    
1873   /* Do normal tests */
1874   if (!init_service_reload_test (&directory))
1875     _dbus_assert_not_reached ("could not initiate service reload test");
1876  
1877   if (!do_service_reload_test (&directory, FALSE));
1878   
1879   /* Do OOM tests */
1880   if (!init_service_reload_test (&directory))
1881     _dbus_assert_not_reached ("could not initiate service reload test");
1882  
1883   if (!do_service_reload_test (&directory, TRUE));
1884  
1885   /* Cleanup test directory */
1886   if (!cleanup_service_reload_test (&directory))
1887     return FALSE;
1888   
1889   _dbus_string_free (&directory);
1890   
1891   return TRUE;
1892 }
1893
1894 #endif /* DBUS_BUILD_TESTS */