dbus-launch: convert C++-style comment to C-style, add {} for clarity
[platform/upstream/dbus.git] / tools / dbus-launch.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-launch.c  dbus-launch utility
3  *
4  * Copyright (C) 2003, 2006 Red Hat, Inc.
5  * Copyright (C) 2006 Thiago Macieira <thiago@kde.org>
6  *
7  * Licensed under the Academic Free License version 2.1
8  * 
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  * 
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  */
24 #include "dbus-launch.h"
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <signal.h>
29 #include <sys/wait.h>
30 #include <errno.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <signal.h>
34 #include <stdarg.h>
35 #include <sys/select.h>
36 #include <time.h>
37
38 #ifdef DBUS_BUILD_X11
39 #include <X11/Xlib.h>
40 extern Display *xdisplay;
41 #endif
42
43 static char* machine_uuid = NULL;
44
45 const char*
46 get_machine_uuid (void)
47 {
48   return machine_uuid;
49 }
50
51 static void
52 save_machine_uuid (const char *uuid_arg)
53 {
54   if (strlen (uuid_arg) != 32)
55     {
56       fprintf (stderr, "machine ID '%s' looks like it's the wrong length, should be 32 hex digits",
57                uuid_arg);
58       exit (1);
59     }
60
61   machine_uuid = xstrdup (uuid_arg);
62 }
63
64 void
65 verbose (const char *format,
66          ...)
67 {
68   va_list args;
69   static int verbose = TRUE;
70   static int verbose_initted = FALSE;
71   
72   /* things are written a bit oddly here so that
73    * in the non-verbose case we just have the one
74    * conditional and return immediately.
75    */
76   if (!verbose)
77     return;
78   
79   if (!verbose_initted)
80     {
81       verbose = getenv ("DBUS_VERBOSE") != NULL;
82       verbose_initted = TRUE;
83       if (!verbose)
84         return;
85     }
86
87   fprintf (stderr, "%lu: ", (unsigned long) getpid ());
88   
89   va_start (args, format);
90   vfprintf (stderr, format, args);
91   va_end (args);
92 }
93
94 static void
95 usage (int ecode)
96 {
97   fprintf (stderr, "dbus-launch [--version] [--help] [--sh-syntax] [--csh-syntax] [--auto-syntax] [--exit-with-session]\n");
98   exit (ecode);
99 }
100
101 static void
102 version (void)
103 {
104   printf ("D-Bus Message Bus Launcher %s\n"
105           "Copyright (C) 2003 Red Hat, Inc.\n"
106           "This is free software; see the source for copying conditions.\n"
107           "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
108           VERSION);
109   exit (0);
110 }
111
112 char *
113 xstrdup (const char *str)
114 {
115   int len;
116   char *copy;
117   
118   if (str == NULL)
119     return NULL;
120   
121   len = strlen (str);
122
123   copy = malloc (len + 1);
124   if (copy == NULL)
125     return NULL;
126
127   memcpy (copy, str, len + 1);
128   
129   return copy;
130 }
131
132 typedef enum
133 {
134   READ_STATUS_OK,    /**< Read succeeded */
135   READ_STATUS_ERROR, /**< Some kind of error */
136   READ_STATUS_EOF    /**< EOF returned */
137 } ReadStatus;
138
139 static ReadStatus
140 read_line (int        fd,
141            char      *buf,
142            size_t     maxlen)
143 {
144   size_t bytes = 0;
145   ReadStatus retval;
146
147   memset (buf, '\0', maxlen);
148   maxlen -= 1; /* ensure nul term */
149   
150   retval = READ_STATUS_OK;
151   
152   while (TRUE)
153     {
154       ssize_t chunk;    
155       size_t to_read;
156       
157     again:
158       to_read = maxlen - bytes;
159
160       if (to_read == 0)
161         break;
162       
163       chunk = read (fd,
164                     buf + bytes,
165                     to_read);
166       if (chunk < 0 && errno == EINTR)
167         goto again;
168           
169       if (chunk < 0)
170         {
171           retval = READ_STATUS_ERROR;
172           break;
173         }
174       else if (chunk == 0)
175         {
176           retval = READ_STATUS_EOF;
177           break; /* EOF */
178         }
179       else /* chunk > 0 */
180         bytes += chunk;
181     }
182
183   if (retval == READ_STATUS_EOF &&
184       bytes > 0)
185     retval = READ_STATUS_OK;
186   
187   /* whack newline */
188   if (retval != READ_STATUS_ERROR &&
189       bytes > 0 &&
190       buf[bytes-1] == '\n')
191     buf[bytes-1] = '\0';
192   
193   return retval;
194 }
195
196 static ReadStatus
197 read_pid (int        fd,
198           pid_t     *buf)
199 {
200   size_t bytes = 0;
201   ReadStatus retval;
202
203   retval = READ_STATUS_OK;
204   
205   while (TRUE)
206     {
207       ssize_t chunk;    
208       size_t to_read;
209       
210     again:
211       to_read = sizeof (pid_t) - bytes;
212
213       if (to_read == 0)
214         break;
215       
216       chunk = read (fd,
217                     ((char*)buf) + bytes,
218                     to_read);
219       if (chunk < 0 && errno == EINTR)
220         goto again;
221           
222       if (chunk < 0)
223         {
224           retval = READ_STATUS_ERROR;
225           break;
226         }
227       else if (chunk == 0)
228         {
229           retval = READ_STATUS_EOF;
230           break; /* EOF */
231         }
232       else /* chunk > 0 */
233         bytes += chunk;
234     }
235
236   return retval;
237 }
238
239 static void
240 do_write (int fd, const void *buf, size_t count)
241 {
242   size_t bytes_written;
243   int ret;
244   
245   bytes_written = 0;
246   
247  again:
248   
249   ret = write (fd, ((const char*)buf) + bytes_written, count - bytes_written);
250
251   if (ret < 0)
252     {
253       if (errno == EINTR)
254         goto again;
255       else
256         {
257           fprintf (stderr, "Failed to write data to pipe! %s\n",
258                    strerror (errno));
259           exit (1); /* give up, we suck */
260         }
261     }
262   else
263     bytes_written += ret;
264   
265   if (bytes_written < count)
266     goto again;
267 }
268
269 static void
270 write_pid (int   fd,
271            pid_t pid)
272 {
273   do_write (fd, &pid, sizeof (pid));
274 }
275
276 static int
277 do_waitpid (pid_t pid)
278 {
279   int ret;
280   
281  again:
282   ret = waitpid (pid, NULL, 0);
283
284   if (ret < 0 &&
285       errno == EINTR)
286     goto again;
287
288   return ret;
289 }
290
291 static pid_t bus_pid_to_kill = -1;
292
293 void
294 kill_bus_and_exit (int exitcode)
295 {
296   verbose ("Killing message bus and exiting babysitter\n");
297   
298   /* in case these point to any NFS mounts, get rid of them immediately */
299   close (0);
300   close (1);
301   close (2);
302
303   kill (bus_pid_to_kill, SIGTERM);
304   sleep (3);
305   kill (bus_pid_to_kill, SIGKILL);
306
307   exit (exitcode);
308 }
309
310 static void
311 print_variables (const char *bus_address, pid_t bus_pid, long bus_wid,
312                  int c_shell_syntax, int bourne_shell_syntax,
313                  int binary_syntax)
314 {
315   if (binary_syntax)
316     {
317       write (1, bus_address, strlen (bus_address) + 1);
318       write (1, &bus_pid, sizeof bus_pid);
319       write (1, &bus_wid, sizeof bus_wid);
320       return;
321     }
322   else if (c_shell_syntax)
323     {
324       printf ("setenv DBUS_SESSION_BUS_ADDRESS '%s';\n", bus_address);  
325       printf ("set DBUS_SESSION_BUS_PID=%ld;\n", (long) bus_pid);
326       if (bus_wid)
327         printf ("set DBUS_SESSION_BUS_WINDOWID=%ld;\n", (long) bus_wid);
328       fflush (stdout);
329     }
330   else if (bourne_shell_syntax)
331     {
332       printf ("DBUS_SESSION_BUS_ADDRESS='%s';\n", bus_address);
333       printf ("export DBUS_SESSION_BUS_ADDRESS;\n");
334       printf ("DBUS_SESSION_BUS_PID=%ld;\n", (long) bus_pid);
335       if (bus_wid)
336         printf ("DBUS_SESSION_BUS_WINDOWID=%ld;\n", (long) bus_wid);
337       fflush (stdout);
338     }
339   else
340     {
341       printf ("DBUS_SESSION_BUS_ADDRESS=%s\n", bus_address);
342       printf ("DBUS_SESSION_BUS_PID=%ld\n", (long) bus_pid);
343       if (bus_wid)
344         printf ("DBUS_SESSION_BUS_WINDOWID=%ld\n", (long) bus_wid);
345       fflush (stdout);
346     }
347 }
348
349 static int got_sighup = FALSE;
350
351 static void
352 signal_handler (int sig)
353 {
354   switch (sig)
355     {
356     case SIGHUP:
357     case SIGTERM:
358       got_sighup = TRUE;
359       break;
360     }
361 }
362
363 static void
364 kill_bus_when_session_ends (void)
365 {
366   int tty_fd;
367   int x_fd;
368   fd_set read_set;
369   fd_set err_set;
370   struct sigaction act;
371   sigset_t empty_mask;
372   
373   /* install SIGHUP handler */
374   got_sighup = FALSE;
375   sigemptyset (&empty_mask);
376   act.sa_handler = signal_handler;
377   act.sa_mask    = empty_mask;
378   act.sa_flags   = 0;
379   sigaction (SIGHUP,  &act, NULL);
380   sigaction (SIGTERM,  &act, NULL);
381   
382 #ifdef DBUS_BUILD_X11
383   x11_init();
384   if (xdisplay != NULL)
385     {
386       x_fd = ConnectionNumber (xdisplay);
387     }
388   else
389     x_fd = -1;
390 #else
391   x_fd = -1;
392 #endif
393
394   if (isatty (0))
395     tty_fd = 0;
396   else
397     tty_fd = -1;
398
399   if (tty_fd >= 0)
400     verbose ("stdin isatty(), monitoring it\n");
401   else
402     verbose ("stdin was not a TTY, not monitoring it\n");  
403   
404   if (tty_fd < 0 && x_fd < 0)
405     {
406       fprintf (stderr, "No terminal on standard input and no X display; cannot attach message bus to session lifetime\n");
407       exit (1);
408     }
409   
410   while (TRUE)
411     {
412       FD_ZERO (&read_set);
413       FD_ZERO (&err_set);
414
415       if (tty_fd >= 0)
416         {
417           FD_SET (tty_fd, &read_set);
418           FD_SET (tty_fd, &err_set);
419         }
420
421       if (x_fd >= 0)
422         {
423           FD_SET (x_fd, &read_set);
424           FD_SET (x_fd, &err_set);
425         }
426       
427       select (MAX (tty_fd, x_fd) + 1,
428               &read_set, NULL, &err_set, NULL);
429
430       if (got_sighup)
431         {
432           verbose ("Got SIGHUP, exiting\n");
433           kill_bus_and_exit (0);
434         }
435       
436 #ifdef DBUS_BUILD_X11
437       /* Dump events on the floor, and let
438        * IO error handler run if we lose
439        * the X connection
440        */
441       if (x_fd >= 0)
442         verbose ("X fd condition reading = %d error = %d\n",
443                  FD_ISSET (x_fd, &read_set),
444                  FD_ISSET (x_fd, &err_set));
445       x11_handle_event ();
446 #endif
447
448       if (tty_fd >= 0)
449         {
450           if (FD_ISSET (tty_fd, &read_set))
451             {
452               int bytes_read;
453               char discard[512];
454
455               verbose ("TTY ready for reading\n");
456               
457               bytes_read = read (tty_fd, discard, sizeof (discard));
458
459               verbose ("Read %d bytes from TTY errno = %d\n",
460                        bytes_read, errno);
461               
462               if (bytes_read == 0)
463                 kill_bus_and_exit (0); /* EOF */
464               else if (bytes_read < 0 && errno != EINTR)
465                 {
466                   /* This shouldn't happen I don't think; to avoid
467                    * spinning on the fd forever we exit.
468                    */
469                   fprintf (stderr, "dbus-launch: error reading from stdin: %s\n",
470                            strerror (errno));
471                   kill_bus_and_exit (0);
472                 }
473             }
474           else if (FD_ISSET (tty_fd, &err_set))
475             {
476               verbose ("TTY has error condition\n");
477               
478               kill_bus_and_exit (0);
479             }
480         }
481     }
482 }
483
484 static void
485 babysit (int   exit_with_session,
486          pid_t child_pid,
487          int   read_bus_pid_fd)  /* read pid from here */
488 {
489   int ret;
490   int dev_null_fd;
491   const char *s;
492
493   verbose ("babysitting, exit_with_session = %d, child_pid = %ld, read_bus_pid_fd = %d\n",
494            exit_with_session, (long) child_pid, read_bus_pid_fd);
495   
496   /* We chdir ("/") since we are persistent and daemon-like, and fork
497    * again so dbus-launch can reap the parent.  However, we don't
498    * setsid() or close fd 0 because the idea is to remain attached
499    * to the tty and the X server in order to kill the message bus
500    * when the session ends.
501    */
502
503   if (chdir ("/") < 0)
504     {
505       fprintf (stderr, "Could not change to root directory: %s\n",
506                strerror (errno));
507       exit (1);
508     }
509
510   /* Close stdout/stderr so we don't block an "eval" or otherwise
511    * lock up. stdout is still chaining through to dbus-launch
512    * and in turn to the parent shell.
513    */
514   dev_null_fd = open ("/dev/null", O_RDWR);
515   if (dev_null_fd >= 0)
516     {
517       if (!exit_with_session)
518         dup2 (dev_null_fd, 0);
519       dup2 (dev_null_fd, 1);
520       s = getenv ("DBUS_DEBUG_OUTPUT");
521       if (s == NULL || *s == '\0')
522         dup2 (dev_null_fd, 2);
523     }
524   else
525     {
526       fprintf (stderr, "Failed to open /dev/null: %s\n",
527                strerror (errno));
528       /* continue, why not */
529     }
530   
531   ret = fork ();
532
533   if (ret < 0)
534     {
535       fprintf (stderr, "fork() failed in babysitter: %s\n",
536                strerror (errno));
537       exit (1);
538     }
539
540   if (ret > 0)
541     {
542       /* Parent reaps pre-fork part of bus daemon, then exits and is
543        * reaped so the babysitter isn't a zombie
544        */
545
546       verbose ("=== Babysitter's intermediate parent continues again\n");
547       
548       if (do_waitpid (child_pid) < 0)
549         {
550           /* shouldn't happen */
551           fprintf (stderr, "Failed waitpid() waiting for bus daemon's parent\n");
552           exit (1);
553         }
554
555       verbose ("Babysitter's intermediate parent exiting\n");
556       
557       exit (0);
558     }
559
560   /* Child continues */
561   verbose ("=== Babysitter process created\n");
562
563   verbose ("Reading PID from bus\n");
564       
565   switch (read_pid (read_bus_pid_fd, &bus_pid_to_kill))
566     {
567     case READ_STATUS_OK:
568       break;
569     case READ_STATUS_EOF:
570       fprintf (stderr, "EOF in dbus-launch reading PID from bus daemon\n");
571       exit (1);
572       break;
573     case READ_STATUS_ERROR:
574       fprintf (stderr, "Error in dbus-launch reading PID from bus daemon: %s\n",
575                strerror (errno));
576       exit (1);
577       break;
578     }
579
580   verbose ("Got PID %ld from daemon\n",
581            (long) bus_pid_to_kill);
582   
583   if (exit_with_session)
584     {
585       /* Bus is now started and launcher has needed info;
586        * we connect to X display and tty and wait to
587        * kill bus if requested.
588        */
589       
590       kill_bus_when_session_ends ();
591     }
592
593   verbose ("Babysitter exiting\n");
594   
595   exit (0);
596 }
597
598 static void
599 do_close_stderr (void)
600 {
601   int fd;
602
603   fflush (stderr);
604
605   /* dbus-launch is a Unix-only program, so we can rely on /dev/null being there.
606    * We're including unistd.h and we're dealing with sh/csh launch sequences...
607    */
608   fd = open ("/dev/null", O_RDWR);
609   if (fd == -1)
610     {
611       fprintf (stderr, "Internal error: cannot open /dev/null: %s", strerror (errno));
612       exit (1);
613     }
614
615   close (2);
616   if (dup2 (fd, 2) == -1)
617     {
618       /* error; we can't report an error anymore... */
619       exit (1);
620     }
621   close (fd);
622 }
623
624 #define READ_END  0
625 #define WRITE_END 1
626
627 int
628 main (int argc, char **argv)
629 {
630   const char *prev_arg;
631   const char *shname;
632   const char *runprog = NULL;
633   int remaining_args = 0;
634   int exit_with_session;
635   int binary_syntax = FALSE;
636   int c_shell_syntax = FALSE;
637   int bourne_shell_syntax = FALSE;
638   int auto_shell_syntax = FALSE;
639   int autolaunch = FALSE;
640   int requires_arg = FALSE;
641   int close_stderr = FALSE;
642   int i;
643   int ret;
644   int bus_pid_to_launcher_pipe[2];
645   int bus_pid_to_babysitter_pipe[2];
646   int bus_address_to_launcher_pipe[2];
647   char *config_file;
648   
649   exit_with_session = FALSE;
650   config_file = NULL;
651   
652   prev_arg = NULL;
653   i = 1;
654   while (i < argc)
655     {
656       const char *arg = argv[i];
657  
658       if (strcmp (arg, "--help") == 0 ||
659           strcmp (arg, "-h") == 0 ||
660           strcmp (arg, "-?") == 0)
661         usage (0);
662       else if (strcmp (arg, "--auto-syntax") == 0)
663         auto_shell_syntax = TRUE;
664       else if (strcmp (arg, "-c") == 0 ||
665                strcmp (arg, "--csh-syntax") == 0)
666         c_shell_syntax = TRUE;
667       else if (strcmp (arg, "-s") == 0 ||
668                strcmp (arg, "--sh-syntax") == 0)
669         bourne_shell_syntax = TRUE;
670       else if (strcmp (arg, "--binary-syntax") == 0)
671         binary_syntax = TRUE;
672       else if (strcmp (arg, "--version") == 0)
673         version ();
674       else if (strcmp (arg, "--exit-with-session") == 0)
675         exit_with_session = TRUE;
676       else if (strcmp (arg, "--close-stderr") == 0)
677         close_stderr = TRUE;
678       else if (strstr (arg, "--autolaunch=") == arg)
679         {
680           const char *s;
681
682           if (autolaunch)
683             {
684               fprintf (stderr, "--autolaunch given twice\n");
685               exit (1);
686             }
687           
688           autolaunch = TRUE;
689
690           s = strchr (arg, '=');
691           ++s;
692
693           save_machine_uuid (s);
694         }
695       else if (prev_arg &&
696                strcmp (prev_arg, "--autolaunch") == 0)
697         {
698           if (autolaunch)
699             {
700               fprintf (stderr, "--autolaunch given twice\n");
701               exit (1);
702             }
703           
704           autolaunch = TRUE;
705
706           save_machine_uuid (arg);
707           requires_arg = FALSE;
708         }
709       else if (strcmp (arg, "--autolaunch") == 0)
710         requires_arg = TRUE;
711       else if (strstr (arg, "--config-file=") == arg)
712         {
713           const char *file;
714
715           if (config_file != NULL)
716             {
717               fprintf (stderr, "--config-file given twice\n");
718               exit (1);
719             }
720           
721           file = strchr (arg, '=');
722           ++file;
723
724           config_file = xstrdup (file);
725         }
726       else if (prev_arg &&
727                strcmp (prev_arg, "--config-file") == 0)
728         {
729           if (config_file != NULL)
730             {
731               fprintf (stderr, "--config-file given twice\n");
732               exit (1);
733             }
734
735           config_file = xstrdup (arg);
736           requires_arg = FALSE;
737         }
738       else if (strcmp (arg, "--config-file") == 0)
739         requires_arg = TRUE;
740       else if (arg[0] == '-')
741         {
742           if (strcmp (arg, "--") != 0)
743             {
744               fprintf (stderr, "Option `%s' is unknown.\n", arg);
745               exit (1);
746             }
747           else
748             {
749               runprog = argv[i+1];
750               remaining_args = i+2;
751               break;
752             }
753         }
754       else
755         {
756           runprog = arg;
757           remaining_args = i+1;
758           break;
759         }
760       
761       prev_arg = arg;
762       
763       ++i;
764     }
765   if (requires_arg)
766     {
767       fprintf (stderr, "Option `%s' requires an argument.\n", prev_arg);
768       exit (1);
769     }
770
771   if (auto_shell_syntax)
772     {
773       if ((shname = getenv ("SHELL")) != NULL)
774        {
775          if (!strncmp (shname + strlen (shname) - 3, "csh", 3))
776            c_shell_syntax = TRUE;
777          else
778            bourne_shell_syntax = TRUE;
779        }
780       else
781        bourne_shell_syntax = TRUE;
782     }  
783
784   if (exit_with_session)
785     verbose ("--exit-with-session enabled\n");
786
787   if (autolaunch)
788     {      
789 #ifndef DBUS_BUILD_X11
790       fprintf (stderr, "Autolaunch requested, but X11 support not compiled in.\n"
791                "Cannot continue.\n");
792       exit (1);
793 #else
794       char *address;
795       pid_t pid;
796       long wid;
797       
798       if (get_machine_uuid () == NULL)
799         {
800           fprintf (stderr, "Machine UUID not provided as arg to --autolaunch\n");
801           exit (1);
802         }
803
804       /* FIXME right now autolaunch always does print_variables(), but it should really
805        * exec the child program instead if a child program was specified. For now
806        * we just exit if this conflict arises.
807        */
808       if (runprog)
809         {
810           fprintf (stderr, "Currently --autolaunch does not support running a program\n");
811           exit (1);
812         }
813       
814       verbose ("Autolaunch enabled (using X11).\n");
815       if (!exit_with_session)
816         {
817           verbose ("--exit-with-session automatically enabled\n");
818           exit_with_session = TRUE;
819         }
820
821       if (!x11_init ())
822         {
823           fprintf (stderr, "Autolaunch error: X11 initialization failed.\n");
824           exit (1);
825         }
826
827       if (!x11_get_address (&address, &pid, &wid))
828         {
829           fprintf (stderr, "Autolaunch error: X11 communication error.\n");
830           exit (1);
831         }
832
833       if (address != NULL)
834         {          
835           verbose ("dbus-daemon is already running. Returning existing parameters.\n");
836           print_variables (address, pid, wid, c_shell_syntax,
837                            bourne_shell_syntax, binary_syntax);
838           exit (0);
839         }
840 #endif
841     }
842
843   if (pipe (bus_pid_to_launcher_pipe) < 0 ||
844       pipe (bus_address_to_launcher_pipe) < 0 ||
845       pipe (bus_pid_to_babysitter_pipe) < 0)
846     {
847       fprintf (stderr,
848                "Failed to create pipe: %s\n",
849                strerror (errno));
850       exit (1);
851     }
852
853   ret = fork ();
854   if (ret < 0)
855     {
856       fprintf (stderr, "Failed to fork: %s\n",
857                strerror (errno));
858       exit (1);
859     }
860
861   if (ret == 0)
862     {
863       /* Child */
864 #define MAX_FD_LEN 64
865       char write_pid_fd_as_string[MAX_FD_LEN];
866       char write_address_fd_as_string[MAX_FD_LEN];
867
868       if (close_stderr)
869         do_close_stderr ();
870
871       verbose ("=== Babysitter's intermediate parent created\n");
872
873       /* Fork once more to create babysitter */
874       
875       ret = fork ();
876       if (ret < 0)
877         {
878           fprintf (stderr, "Failed to fork: %s\n",
879                    strerror (errno));
880           exit (1);
881         }
882       
883       if (ret > 0)
884         {
885           /* In babysitter */
886           verbose ("=== Babysitter's intermediate parent continues\n");
887           
888           close (bus_pid_to_launcher_pipe[READ_END]);
889           close (bus_pid_to_launcher_pipe[WRITE_END]);
890           close (bus_address_to_launcher_pipe[READ_END]);
891           close (bus_address_to_launcher_pipe[WRITE_END]);
892           close (bus_pid_to_babysitter_pipe[WRITE_END]);
893
894           /* babysit() will fork *again*
895            * and will also reap the pre-forked bus
896            * daemon
897            */
898           babysit (exit_with_session, ret,
899                    bus_pid_to_babysitter_pipe[READ_END]);
900           exit (0);
901         }
902
903       verbose ("=== Bus exec process created\n");
904       
905       /* Now we are the bus process (well, almost;
906        * dbus-daemon itself forks again)
907        */
908       close (bus_pid_to_launcher_pipe[READ_END]);
909       close (bus_address_to_launcher_pipe[READ_END]);
910       close (bus_pid_to_babysitter_pipe[READ_END]);
911       close (bus_pid_to_babysitter_pipe[WRITE_END]);
912
913       sprintf (write_pid_fd_as_string,
914                "%d", bus_pid_to_launcher_pipe[WRITE_END]);
915
916       sprintf (write_address_fd_as_string,
917                "%d", bus_address_to_launcher_pipe[WRITE_END]);
918
919       verbose ("Calling exec()\n");
920  
921 #ifdef DBUS_BUILD_TESTS 
922       /* exec from testdir */
923       if (getenv("DBUS_USE_TEST_BINARY") != NULL)
924         {
925           execl (TEST_BUS_BINARY,
926                  TEST_BUS_BINARY,
927                  "--fork",
928                  "--print-pid", write_pid_fd_as_string,
929                  "--print-address", write_address_fd_as_string,
930                  config_file ? "--config-file" : "--session",
931                  config_file, /* has to be last in this varargs list */
932                  NULL); 
933
934           fprintf (stderr,
935                    "Failed to execute test message bus daemon %s: %s. Will try again with the system path.\n",
936                    TEST_BUS_BINARY, strerror (errno));
937         }
938  #endif /* DBUS_BUILD_TESTS */
939
940       execl (DBUS_DAEMONDIR"/dbus-daemon",
941              DBUS_DAEMONDIR"/dbus-daemon",
942              "--fork",
943              "--print-pid", write_pid_fd_as_string,
944              "--print-address", write_address_fd_as_string,
945              config_file ? "--config-file" : "--session",
946              config_file, /* has to be last in this varargs list */
947              NULL);
948
949       fprintf (stderr,
950                "Failed to execute message bus daemon %s: %s.  Will try again without full path.\n",
951                DBUS_DAEMONDIR"/dbus-daemon", strerror (errno));
952       
953       /*
954        * If it failed, try running without full PATH.  Note this is needed
955        * because the build process builds the run-with-tmp-session-bus.conf
956        * file and the dbus-daemon will not be in the install location during
957        * build time.
958        */
959       execlp ("dbus-daemon",
960               "dbus-daemon",
961               "--fork",
962               "--print-pid", write_pid_fd_as_string,
963               "--print-address", write_address_fd_as_string,
964               config_file ? "--config-file" : "--session",
965               config_file, /* has to be last in this varargs list */
966               NULL);
967
968       fprintf (stderr,
969                "Failed to execute message bus daemon: %s\n",
970                strerror (errno));
971       exit (1);
972     }
973   else
974     {
975       /* Parent */
976 #define MAX_PID_LEN 64
977       pid_t bus_pid;  
978       char bus_address[MAX_ADDR_LEN];
979       char buf[MAX_PID_LEN];
980       char *end;
981       long wid = 0;
982       long val;
983       int ret2;
984
985       verbose ("=== Parent dbus-launch continues\n");
986       
987       close (bus_pid_to_launcher_pipe[WRITE_END]);
988       close (bus_address_to_launcher_pipe[WRITE_END]);
989       close (bus_pid_to_babysitter_pipe[READ_END]);
990
991       verbose ("Waiting for babysitter's intermediate parent\n");
992       
993       /* Immediately reap parent of babysitter
994        * (which was created just for us to reap)
995        */
996       if (do_waitpid (ret) < 0)
997         {
998           fprintf (stderr, "Failed to waitpid() for babysitter intermediate process: %s\n",
999                    strerror (errno));
1000           exit (1);
1001         }
1002
1003       verbose ("Reading address from bus\n");
1004       
1005       /* Read the pipe data, print, and exit */
1006       switch (read_line (bus_address_to_launcher_pipe[READ_END],
1007                          bus_address, MAX_ADDR_LEN))
1008         {
1009         case READ_STATUS_OK:
1010           break;
1011         case READ_STATUS_EOF:
1012           fprintf (stderr, "EOF in dbus-launch reading address from bus daemon\n");
1013           exit (1);
1014           break;
1015         case READ_STATUS_ERROR:
1016           fprintf (stderr, "Error in dbus-launch reading address from bus daemon: %s\n",
1017                    strerror (errno));
1018           exit (1);
1019           break;
1020         }
1021         
1022       close (bus_address_to_launcher_pipe[READ_END]);
1023
1024       verbose ("Reading PID from daemon\n");
1025       /* Now read data */
1026       switch (read_line (bus_pid_to_launcher_pipe[READ_END], buf, MAX_PID_LEN))
1027         {
1028         case READ_STATUS_OK:
1029           break;
1030         case READ_STATUS_EOF:
1031           fprintf (stderr, "EOF reading PID from bus daemon\n");
1032           exit (1);
1033           break;
1034         case READ_STATUS_ERROR:
1035           fprintf (stderr, "Error reading PID from bus daemon: %s\n",
1036                    strerror (errno));
1037           exit (1);
1038           break;
1039         }
1040
1041       end = NULL;
1042       val = strtol (buf, &end, 0);
1043       if (buf == end || end == NULL)
1044         {
1045           fprintf (stderr, "Failed to parse bus PID \"%s\": %s\n",
1046                    buf, strerror (errno));
1047           exit (1);
1048         }
1049
1050       bus_pid = val;
1051
1052       close (bus_pid_to_launcher_pipe[READ_END]);
1053
1054 #ifdef DBUS_BUILD_X11
1055       /* FIXME the runprog == NULL is broken - we need to launch the runprog with the existing bus,
1056        * instead of just doing print_variables() if there's an existing bus.
1057        */
1058       if (xdisplay != NULL && runprog == NULL)
1059         {
1060           ret2 = x11_save_address (bus_address, bus_pid, &wid);
1061           if (ret2 == 0)
1062             {
1063               /* another window got added. Return its address */
1064               char *address;
1065               pid_t pid;
1066               long wid;
1067               
1068               if (x11_get_address (&address, &pid, &wid) && address != NULL)
1069                 {
1070                   verbose ("dbus-daemon is already running. Returning existing parameters.\n");
1071                   print_variables (address, pid, wid, c_shell_syntax,
1072                                    bourne_shell_syntax, binary_syntax);
1073                   free (address);
1074                   
1075                   bus_pid_to_kill = bus_pid;
1076                   kill_bus_and_exit (0);
1077                 }
1078               
1079               /* if failed, fall through */
1080             }
1081           if (ret2 <= 0)
1082             {
1083               fprintf (stderr, "Error saving bus information.\n");
1084               bus_pid_to_kill = bus_pid;
1085               kill_bus_and_exit (1);
1086             }
1087         }
1088 #endif
1089
1090       /* Forward the pid to the babysitter */
1091       write_pid (bus_pid_to_babysitter_pipe[WRITE_END], bus_pid);
1092       close (bus_pid_to_babysitter_pipe[WRITE_END]);
1093
1094       if (runprog)
1095         {
1096           char *envvar;
1097           char **args;
1098
1099           envvar = malloc (strlen ("DBUS_SESSION_BUS_ADDRESS=") + strlen (bus_address) + 1);
1100           args = malloc (sizeof (char *) * ((argc-remaining_args)+2));
1101
1102           if (envvar == NULL || args == NULL)
1103             goto oom;
1104
1105           args[0] = xstrdup (runprog);
1106           if (!args[0])
1107             goto oom;
1108           for (i = 1; i <= (argc-remaining_args); i++)
1109             {
1110               size_t len = strlen (argv[remaining_args+i-1])+1;
1111               args[i] = malloc (len);
1112               if (!args[i])
1113                 goto oom;
1114               strncpy (args[i], argv[remaining_args+i-1], len);
1115             }
1116           args[i] = NULL;
1117
1118           strcpy (envvar, "DBUS_SESSION_BUS_ADDRESS=");
1119           strcat (envvar, bus_address);
1120           putenv (envvar);
1121
1122           execvp (runprog, args);
1123           fprintf (stderr, "Couldn't exec %s: %s\n", runprog, strerror (errno));
1124           exit (1);
1125         }
1126       else
1127         {
1128           print_variables (bus_address, bus_pid, wid, c_shell_syntax,
1129                            bourne_shell_syntax, binary_syntax);
1130         }
1131           
1132       verbose ("dbus-launch exiting\n");
1133
1134       fflush (stdout);
1135       fflush (stderr);
1136       close (1);
1137       close (2);
1138       
1139       exit (0);
1140     } 
1141   
1142   return 0;
1143  oom:
1144   fprintf (stderr, "Out of memory!");
1145   exit (1);
1146 }