fd.o bug #12547 remove superfluous if
[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     // error; we can't report an error anymore...
618     exit (1);
619   close (fd);
620 }
621
622 #define READ_END  0
623 #define WRITE_END 1
624
625 int
626 main (int argc, char **argv)
627 {
628   const char *prev_arg;
629   const char *shname;
630   const char *runprog = NULL;
631   int remaining_args = 0;
632   int exit_with_session;
633   int binary_syntax = FALSE;
634   int c_shell_syntax = FALSE;
635   int bourne_shell_syntax = FALSE;
636   int auto_shell_syntax = FALSE;
637   int autolaunch = FALSE;
638   int requires_arg = FALSE;
639   int close_stderr = FALSE;
640   int i;
641   int ret;
642   int bus_pid_to_launcher_pipe[2];
643   int bus_pid_to_babysitter_pipe[2];
644   int bus_address_to_launcher_pipe[2];
645   char *config_file;
646   
647   exit_with_session = FALSE;
648   config_file = NULL;
649   
650   prev_arg = NULL;
651   i = 1;
652   while (i < argc)
653     {
654       const char *arg = argv[i];
655  
656       if (strcmp (arg, "--help") == 0 ||
657           strcmp (arg, "-h") == 0 ||
658           strcmp (arg, "-?") == 0)
659         usage (0);
660       else if (strcmp (arg, "--auto-syntax") == 0)
661         auto_shell_syntax = TRUE;
662       else if (strcmp (arg, "-c") == 0 ||
663                strcmp (arg, "--csh-syntax") == 0)
664         c_shell_syntax = TRUE;
665       else if (strcmp (arg, "-s") == 0 ||
666                strcmp (arg, "--sh-syntax") == 0)
667         bourne_shell_syntax = TRUE;
668       else if (strcmp (arg, "--binary-syntax") == 0)
669         binary_syntax = TRUE;
670       else if (strcmp (arg, "--version") == 0)
671         version ();
672       else if (strcmp (arg, "--exit-with-session") == 0)
673         exit_with_session = TRUE;
674       else if (strcmp (arg, "--close-stderr") == 0)
675         close_stderr = TRUE;
676       else if (strstr (arg, "--autolaunch=") == arg)
677         {
678           const char *s;
679
680           if (autolaunch)
681             {
682               fprintf (stderr, "--autolaunch given twice\n");
683               exit (1);
684             }
685           
686           autolaunch = TRUE;
687
688           s = strchr (arg, '=');
689           ++s;
690
691           save_machine_uuid (s);
692         }
693       else if (prev_arg &&
694                strcmp (prev_arg, "--autolaunch") == 0)
695         {
696           if (autolaunch)
697             {
698               fprintf (stderr, "--autolaunch given twice\n");
699               exit (1);
700             }
701           
702           autolaunch = TRUE;
703
704           save_machine_uuid (arg);
705           requires_arg = FALSE;
706         }
707       else if (strcmp (arg, "--autolaunch") == 0)
708         requires_arg = TRUE;
709       else if (strstr (arg, "--config-file=") == arg)
710         {
711           const char *file;
712
713           if (config_file != NULL)
714             {
715               fprintf (stderr, "--config-file given twice\n");
716               exit (1);
717             }
718           
719           file = strchr (arg, '=');
720           ++file;
721
722           config_file = xstrdup (file);
723         }
724       else if (prev_arg &&
725                strcmp (prev_arg, "--config-file") == 0)
726         {
727           if (config_file != NULL)
728             {
729               fprintf (stderr, "--config-file given twice\n");
730               exit (1);
731             }
732
733           config_file = xstrdup (arg);
734           requires_arg = FALSE;
735         }
736       else if (strcmp (arg, "--config-file") == 0)
737         requires_arg = TRUE;
738       else if (arg[0] == '-')
739         {
740           if (strcmp (arg, "--") != 0)
741             {
742               fprintf (stderr, "Option `%s' is unknown.\n", arg);
743               exit (1);
744             }
745           else
746             {
747               runprog = argv[i+1];
748               remaining_args = i+2;
749               break;
750             }
751         }
752       else
753         {
754           runprog = arg;
755           remaining_args = i+1;
756           break;
757         }
758       
759       prev_arg = arg;
760       
761       ++i;
762     }
763   if (requires_arg)
764     {
765       fprintf (stderr, "Option `%s' requires an argument.\n", prev_arg);
766       exit (1);
767     }
768
769   if (auto_shell_syntax)
770     {
771       if ((shname = getenv ("SHELL")) != NULL)
772        {
773          if (!strncmp (shname + strlen (shname) - 3, "csh", 3))
774            c_shell_syntax = TRUE;
775          else
776            bourne_shell_syntax = TRUE;
777        }
778       else
779        bourne_shell_syntax = TRUE;
780     }  
781
782   if (exit_with_session)
783     verbose ("--exit-with-session enabled\n");
784
785   if (autolaunch)
786     {      
787 #ifndef DBUS_BUILD_X11
788       fprintf (stderr, "Autolaunch requested, but X11 support not compiled in.\n"
789                "Cannot continue.\n");
790       exit (1);
791 #else
792       char *address;
793       pid_t pid;
794       long wid;
795       
796       if (get_machine_uuid () == NULL)
797         {
798           fprintf (stderr, "Machine UUID not provided as arg to --autolaunch\n");
799           exit (1);
800         }
801
802       /* FIXME right now autolaunch always does print_variables(), but it should really
803        * exec the child program instead if a child program was specified. For now
804        * we just exit if this conflict arises.
805        */
806       if (runprog)
807         {
808           fprintf (stderr, "Currently --autolaunch does not support running a program\n");
809           exit (1);
810         }
811       
812       verbose ("Autolaunch enabled (using X11).\n");
813       if (!exit_with_session)
814         {
815           verbose ("--exit-with-session automatically enabled\n");
816           exit_with_session = TRUE;
817         }
818
819       if (!x11_init ())
820         {
821           fprintf (stderr, "Autolaunch error: X11 initialization failed.\n");
822           exit (1);
823         }
824
825       if (!x11_get_address (&address, &pid, &wid))
826         {
827           fprintf (stderr, "Autolaunch error: X11 communication error.\n");
828           exit (1);
829         }
830
831       if (address != NULL)
832         {          
833           verbose ("dbus-daemon is already running. Returning existing parameters.\n");
834           print_variables (address, pid, wid, c_shell_syntax,
835                            bourne_shell_syntax, binary_syntax);
836           exit (0);
837         }
838 #endif
839     }
840
841   if (pipe (bus_pid_to_launcher_pipe) < 0 ||
842       pipe (bus_address_to_launcher_pipe) < 0 ||
843       pipe (bus_pid_to_babysitter_pipe) < 0)
844     {
845       fprintf (stderr,
846                "Failed to create pipe: %s\n",
847                strerror (errno));
848       exit (1);
849     }
850
851   ret = fork ();
852   if (ret < 0)
853     {
854       fprintf (stderr, "Failed to fork: %s\n",
855                strerror (errno));
856       exit (1);
857     }
858
859   if (ret == 0)
860     {
861       /* Child */
862 #define MAX_FD_LEN 64
863       char write_pid_fd_as_string[MAX_FD_LEN];
864       char write_address_fd_as_string[MAX_FD_LEN];
865
866       if (close_stderr)
867         do_close_stderr ();
868
869       verbose ("=== Babysitter's intermediate parent created\n");
870
871       /* Fork once more to create babysitter */
872       
873       ret = fork ();
874       if (ret < 0)
875         {
876           fprintf (stderr, "Failed to fork: %s\n",
877                    strerror (errno));
878           exit (1);
879         }
880       
881       if (ret > 0)
882         {
883           /* In babysitter */
884           verbose ("=== Babysitter's intermediate parent continues\n");
885           
886           close (bus_pid_to_launcher_pipe[READ_END]);
887           close (bus_pid_to_launcher_pipe[WRITE_END]);
888           close (bus_address_to_launcher_pipe[READ_END]);
889           close (bus_address_to_launcher_pipe[WRITE_END]);
890           close (bus_pid_to_babysitter_pipe[WRITE_END]);
891
892           /* babysit() will fork *again*
893            * and will also reap the pre-forked bus
894            * daemon
895            */
896           babysit (exit_with_session, ret,
897                    bus_pid_to_babysitter_pipe[READ_END]);
898           exit (0);
899         }
900
901       verbose ("=== Bus exec process created\n");
902       
903       /* Now we are the bus process (well, almost;
904        * dbus-daemon itself forks again)
905        */
906       close (bus_pid_to_launcher_pipe[READ_END]);
907       close (bus_address_to_launcher_pipe[READ_END]);
908       close (bus_pid_to_babysitter_pipe[READ_END]);
909       close (bus_pid_to_babysitter_pipe[WRITE_END]);
910
911       sprintf (write_pid_fd_as_string,
912                "%d", bus_pid_to_launcher_pipe[WRITE_END]);
913
914       sprintf (write_address_fd_as_string,
915                "%d", bus_address_to_launcher_pipe[WRITE_END]);
916
917       verbose ("Calling exec()\n");
918  
919 #ifdef DBUS_BUILD_TESTS 
920       /* exec from testdir */
921       if (getenv("DBUS_USE_TEST_BINARY") != NULL)
922         {
923           execl (TEST_BUS_BINARY,
924                  TEST_BUS_BINARY,
925                  "--fork",
926                  "--print-pid", write_pid_fd_as_string,
927                  "--print-address", write_address_fd_as_string,
928                  config_file ? "--config-file" : "--session",
929                  config_file, /* has to be last in this varargs list */
930                  NULL); 
931
932           fprintf (stderr,
933                    "Failed to execute test message bus daemon %s: %s. Will try again with the system path.\n",
934                    TEST_BUS_BINARY, strerror (errno));
935         }
936  #endif /* DBUS_BUILD_TESTS */
937
938       execl (DBUS_DAEMONDIR"/dbus-daemon",
939              DBUS_DAEMONDIR"/dbus-daemon",
940              "--fork",
941              "--print-pid", write_pid_fd_as_string,
942              "--print-address", write_address_fd_as_string,
943              config_file ? "--config-file" : "--session",
944              config_file, /* has to be last in this varargs list */
945              NULL);
946
947       fprintf (stderr,
948                "Failed to execute message bus daemon %s: %s.  Will try again without full path.\n",
949                DBUS_DAEMONDIR"/dbus-daemon", strerror (errno));
950       
951       /*
952        * If it failed, try running without full PATH.  Note this is needed
953        * because the build process builds the run-with-tmp-session-bus.conf
954        * file and the dbus-daemon will not be in the install location during
955        * build time.
956        */
957       execlp ("dbus-daemon",
958               "dbus-daemon",
959               "--fork",
960               "--print-pid", write_pid_fd_as_string,
961               "--print-address", write_address_fd_as_string,
962               config_file ? "--config-file" : "--session",
963               config_file, /* has to be last in this varargs list */
964               NULL);
965
966       fprintf (stderr,
967                "Failed to execute message bus daemon: %s\n",
968                strerror (errno));
969       exit (1);
970     }
971   else
972     {
973       /* Parent */
974 #define MAX_PID_LEN 64
975       pid_t bus_pid;  
976       char bus_address[MAX_ADDR_LEN];
977       char buf[MAX_PID_LEN];
978       char *end;
979       long wid = 0;
980       long val;
981       int ret2;
982
983       verbose ("=== Parent dbus-launch continues\n");
984       
985       close (bus_pid_to_launcher_pipe[WRITE_END]);
986       close (bus_address_to_launcher_pipe[WRITE_END]);
987       close (bus_pid_to_babysitter_pipe[READ_END]);
988
989       verbose ("Waiting for babysitter's intermediate parent\n");
990       
991       /* Immediately reap parent of babysitter
992        * (which was created just for us to reap)
993        */
994       if (do_waitpid (ret) < 0)
995         {
996           fprintf (stderr, "Failed to waitpid() for babysitter intermediate process: %s\n",
997                    strerror (errno));
998           exit (1);
999         }
1000
1001       verbose ("Reading address from bus\n");
1002       
1003       /* Read the pipe data, print, and exit */
1004       switch (read_line (bus_address_to_launcher_pipe[READ_END],
1005                          bus_address, MAX_ADDR_LEN))
1006         {
1007         case READ_STATUS_OK:
1008           break;
1009         case READ_STATUS_EOF:
1010           fprintf (stderr, "EOF in dbus-launch reading address from bus daemon\n");
1011           exit (1);
1012           break;
1013         case READ_STATUS_ERROR:
1014           fprintf (stderr, "Error in dbus-launch reading address from bus daemon: %s\n",
1015                    strerror (errno));
1016           exit (1);
1017           break;
1018         }
1019         
1020       close (bus_address_to_launcher_pipe[READ_END]);
1021
1022       verbose ("Reading PID from daemon\n");
1023       /* Now read data */
1024       switch (read_line (bus_pid_to_launcher_pipe[READ_END], buf, MAX_PID_LEN))
1025         {
1026         case READ_STATUS_OK:
1027           break;
1028         case READ_STATUS_EOF:
1029           fprintf (stderr, "EOF reading PID from bus daemon\n");
1030           exit (1);
1031           break;
1032         case READ_STATUS_ERROR:
1033           fprintf (stderr, "Error reading PID from bus daemon: %s\n",
1034                    strerror (errno));
1035           exit (1);
1036           break;
1037         }
1038
1039       end = NULL;
1040       val = strtol (buf, &end, 0);
1041       if (buf == end || end == NULL)
1042         {
1043           fprintf (stderr, "Failed to parse bus PID \"%s\": %s\n",
1044                    buf, strerror (errno));
1045           exit (1);
1046         }
1047
1048       bus_pid = val;
1049
1050       close (bus_pid_to_launcher_pipe[READ_END]);
1051
1052 #ifdef DBUS_BUILD_X11
1053       /* FIXME the runprog == NULL is broken - we need to launch the runprog with the existing bus,
1054        * instead of just doing print_variables() if there's an existing bus.
1055        */
1056       if (xdisplay != NULL && runprog == NULL)
1057         {
1058           ret2 = x11_save_address (bus_address, bus_pid, &wid);
1059           if (ret2 == 0)
1060             {
1061               /* another window got added. Return its address */
1062               char *address;
1063               pid_t pid;
1064               long wid;
1065               
1066               if (x11_get_address (&address, &pid, &wid) && address != NULL)
1067                 {
1068                   verbose ("dbus-daemon is already running. Returning existing parameters.\n");
1069                   print_variables (address, pid, wid, c_shell_syntax,
1070                                    bourne_shell_syntax, binary_syntax);
1071                   free (address);
1072                   
1073                   bus_pid_to_kill = bus_pid;
1074                   kill_bus_and_exit (0);
1075                 }
1076               
1077               /* if failed, fall through */
1078             }
1079           if (ret2 <= 0)
1080             {
1081               fprintf (stderr, "Error saving bus information.\n");
1082               bus_pid_to_kill = bus_pid;
1083               kill_bus_and_exit (1);
1084             }
1085         }
1086 #endif
1087
1088       /* Forward the pid to the babysitter */
1089       write_pid (bus_pid_to_babysitter_pipe[WRITE_END], bus_pid);
1090       close (bus_pid_to_babysitter_pipe[WRITE_END]);
1091
1092       if (runprog)
1093         {
1094           char *envvar;
1095           char **args;
1096
1097           envvar = malloc (strlen ("DBUS_SESSION_BUS_ADDRESS=") + strlen (bus_address) + 1);
1098           args = malloc (sizeof (char *) * ((argc-remaining_args)+2));
1099
1100           if (envvar == NULL || args == NULL)
1101             goto oom;
1102
1103           args[0] = xstrdup (runprog);
1104           if (!args[0])
1105             goto oom;
1106           for (i = 1; i <= (argc-remaining_args); i++)
1107             {
1108               size_t len = strlen (argv[remaining_args+i-1])+1;
1109               args[i] = malloc (len);
1110               if (!args[i])
1111                 goto oom;
1112               strncpy (args[i], argv[remaining_args+i-1], len);
1113             }
1114           args[i] = NULL;
1115
1116           strcpy (envvar, "DBUS_SESSION_BUS_ADDRESS=");
1117           strcat (envvar, bus_address);
1118           putenv (envvar);
1119
1120           execvp (runprog, args);
1121           fprintf (stderr, "Couldn't exec %s: %s\n", runprog, strerror (errno));
1122           exit (1);
1123         }
1124       else
1125         {
1126           print_variables (bus_address, bus_pid, wid, c_shell_syntax,
1127                            bourne_shell_syntax, binary_syntax);
1128         }
1129           
1130       verbose ("dbus-launch exiting\n");
1131
1132       fflush (stdout);
1133       fflush (stderr);
1134       close (1);
1135       close (2);
1136       
1137       exit (0);
1138     } 
1139   
1140   return 0;
1141  oom:
1142   fprintf (stderr, "Out of memory!");
1143   exit (1);
1144 }