2007-07-13 Havoc Pennington <hp@redhat.com>
[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       if (bourne_shell_syntax)
334         printf ("export DBUS_SESSION_BUS_ADDRESS;\n");
335       printf ("DBUS_SESSION_BUS_PID=%ld;\n", (long) bus_pid);
336       if (bus_wid)
337         printf ("DBUS_SESSION_BUS_WINDOWID=%ld;\n", (long) bus_wid);
338       fflush (stdout);
339     }
340   else
341     {
342       printf ("DBUS_SESSION_BUS_ADDRESS=%s\n", bus_address);
343       printf ("DBUS_SESSION_BUS_PID=%ld\n", (long) bus_pid);
344       if (bus_wid)
345         printf ("DBUS_SESSION_BUS_WINDOWID=%ld\n", (long) bus_wid);
346       fflush (stdout);
347     }
348 }
349
350 static int got_sighup = FALSE;
351
352 static void
353 signal_handler (int sig)
354 {
355   switch (sig)
356     {
357     case SIGHUP:
358     case SIGTERM:
359       got_sighup = TRUE;
360       break;
361     }
362 }
363
364 static void
365 kill_bus_when_session_ends (void)
366 {
367   int tty_fd;
368   int x_fd;
369   fd_set read_set;
370   fd_set err_set;
371   struct sigaction act;
372   sigset_t empty_mask;
373   
374   /* install SIGHUP handler */
375   got_sighup = FALSE;
376   sigemptyset (&empty_mask);
377   act.sa_handler = signal_handler;
378   act.sa_mask    = empty_mask;
379   act.sa_flags   = 0;
380   sigaction (SIGHUP,  &act, NULL);
381   sigaction (SIGTERM,  &act, NULL);
382   
383 #ifdef DBUS_BUILD_X11
384   x11_init();
385   if (xdisplay != NULL)
386     {
387       x_fd = ConnectionNumber (xdisplay);
388     }
389   else
390     x_fd = -1;
391 #else
392   x_fd = -1;
393 #endif
394
395   if (isatty (0))
396     tty_fd = 0;
397   else
398     tty_fd = -1;
399
400   if (tty_fd >= 0)
401     verbose ("stdin isatty(), monitoring it\n");
402   else
403     verbose ("stdin was not a TTY, not monitoring it\n");  
404   
405   if (tty_fd < 0 && x_fd < 0)
406     {
407       fprintf (stderr, "No terminal on standard input and no X display; cannot attach message bus to session lifetime\n");
408       exit (1);
409     }
410   
411   while (TRUE)
412     {
413       FD_ZERO (&read_set);
414       FD_ZERO (&err_set);
415
416       if (tty_fd >= 0)
417         {
418           FD_SET (tty_fd, &read_set);
419           FD_SET (tty_fd, &err_set);
420         }
421
422       if (x_fd >= 0)
423         {
424           FD_SET (x_fd, &read_set);
425           FD_SET (x_fd, &err_set);
426         }
427       
428       select (MAX (tty_fd, x_fd) + 1,
429               &read_set, NULL, &err_set, NULL);
430
431       if (got_sighup)
432         {
433           verbose ("Got SIGHUP, exiting\n");
434           kill_bus_and_exit (0);
435         }
436       
437 #ifdef DBUS_BUILD_X11
438       /* Dump events on the floor, and let
439        * IO error handler run if we lose
440        * the X connection
441        */
442       if (x_fd >= 0)
443         verbose ("X fd condition reading = %d error = %d\n",
444                  FD_ISSET (x_fd, &read_set),
445                  FD_ISSET (x_fd, &err_set));
446       x11_handle_event ();
447 #endif
448
449       if (tty_fd >= 0)
450         {
451           if (FD_ISSET (tty_fd, &read_set))
452             {
453               int bytes_read;
454               char discard[512];
455
456               verbose ("TTY ready for reading\n");
457               
458               bytes_read = read (tty_fd, discard, sizeof (discard));
459
460               verbose ("Read %d bytes from TTY errno = %d\n",
461                        bytes_read, errno);
462               
463               if (bytes_read == 0)
464                 kill_bus_and_exit (0); /* EOF */
465               else if (bytes_read < 0 && errno != EINTR)
466                 {
467                   /* This shouldn't happen I don't think; to avoid
468                    * spinning on the fd forever we exit.
469                    */
470                   fprintf (stderr, "dbus-launch: error reading from stdin: %s\n",
471                            strerror (errno));
472                   kill_bus_and_exit (0);
473                 }
474             }
475           else if (FD_ISSET (tty_fd, &err_set))
476             {
477               verbose ("TTY has error condition\n");
478               
479               kill_bus_and_exit (0);
480             }
481         }
482     }
483 }
484
485 static void
486 babysit (int   exit_with_session,
487          pid_t child_pid,
488          int   read_bus_pid_fd)  /* read pid from here */
489 {
490   int ret;
491   int dev_null_fd;
492   const char *s;
493
494   verbose ("babysitting, exit_with_session = %d, child_pid = %ld, read_bus_pid_fd = %d\n",
495            exit_with_session, (long) child_pid, read_bus_pid_fd);
496   
497   /* We chdir ("/") since we are persistent and daemon-like, and fork
498    * again so dbus-launch can reap the parent.  However, we don't
499    * setsid() or close fd 0 because the idea is to remain attached
500    * to the tty and the X server in order to kill the message bus
501    * when the session ends.
502    */
503
504   if (chdir ("/") < 0)
505     {
506       fprintf (stderr, "Could not change to root directory: %s\n",
507                strerror (errno));
508       exit (1);
509     }
510
511   /* Close stdout/stderr so we don't block an "eval" or otherwise
512    * lock up. stdout is still chaining through to dbus-launch
513    * and in turn to the parent shell.
514    */
515   dev_null_fd = open ("/dev/null", O_RDWR);
516   if (dev_null_fd >= 0)
517     {
518       if (!exit_with_session)
519         dup2 (dev_null_fd, 0);
520       dup2 (dev_null_fd, 1);
521       s = getenv ("DBUS_DEBUG_OUTPUT");
522       if (s == NULL || *s == '\0')
523         dup2 (dev_null_fd, 2);
524     }
525   else
526     {
527       fprintf (stderr, "Failed to open /dev/null: %s\n",
528                strerror (errno));
529       /* continue, why not */
530     }
531   
532   ret = fork ();
533
534   if (ret < 0)
535     {
536       fprintf (stderr, "fork() failed in babysitter: %s\n",
537                strerror (errno));
538       exit (1);
539     }
540
541   if (ret > 0)
542     {
543       /* Parent reaps pre-fork part of bus daemon, then exits and is
544        * reaped so the babysitter isn't a zombie
545        */
546
547       verbose ("=== Babysitter's intermediate parent continues again\n");
548       
549       if (do_waitpid (child_pid) < 0)
550         {
551           /* shouldn't happen */
552           fprintf (stderr, "Failed waitpid() waiting for bus daemon's parent\n");
553           exit (1);
554         }
555
556       verbose ("Babysitter's intermediate parent exiting\n");
557       
558       exit (0);
559     }
560
561   /* Child continues */
562   verbose ("=== Babysitter process created\n");
563
564   verbose ("Reading PID from bus\n");
565       
566   switch (read_pid (read_bus_pid_fd, &bus_pid_to_kill))
567     {
568     case READ_STATUS_OK:
569       break;
570     case READ_STATUS_EOF:
571       fprintf (stderr, "EOF in dbus-launch reading PID from bus daemon\n");
572       exit (1);
573       break;
574     case READ_STATUS_ERROR:
575       fprintf (stderr, "Error in dbus-launch reading PID from bus daemon: %s\n",
576                strerror (errno));
577       exit (1);
578       break;
579     }
580
581   verbose ("Got PID %ld from daemon\n",
582            (long) bus_pid_to_kill);
583   
584   if (exit_with_session)
585     {
586       /* Bus is now started and launcher has needed info;
587        * we connect to X display and tty and wait to
588        * kill bus if requested.
589        */
590       
591       kill_bus_when_session_ends ();
592     }
593
594   verbose ("Babysitter exiting\n");
595   
596   exit (0);
597 }
598
599 static void
600 do_close_stderr (void)
601 {
602   int fd;
603
604   fflush (stderr);
605
606   /* dbus-launch is a Unix-only program, so we can rely on /dev/null being there.
607    * We're including unistd.h and we're dealing with sh/csh launch sequences...
608    */
609   fd = open ("/dev/null", O_RDWR);
610   if (fd == -1)
611     {
612       fprintf (stderr, "Internal error: cannot open /dev/null: %s", strerror (errno));
613       exit (1);
614     }
615
616   close (2);
617   if (dup2 (fd, 2) == -1)
618     // error; we can't report an error anymore...
619     exit (1);
620   close (fd);
621 }
622
623 #define READ_END  0
624 #define WRITE_END 1
625
626 int
627 main (int argc, char **argv)
628 {
629   const char *prev_arg;
630   const char *shname;
631   const char *runprog = NULL;
632   int remaining_args = 0;
633   int exit_with_session;
634   int binary_syntax = FALSE;
635   int c_shell_syntax = FALSE;
636   int bourne_shell_syntax = FALSE;
637   int auto_shell_syntax = FALSE;
638   int autolaunch = FALSE;
639   int requires_arg = FALSE;
640   int close_stderr = FALSE;
641   int i;
642   int ret;
643   int bus_pid_to_launcher_pipe[2];
644   int bus_pid_to_babysitter_pipe[2];
645   int bus_address_to_launcher_pipe[2];
646   char *config_file;
647   
648   exit_with_session = FALSE;
649   config_file = NULL;
650   
651   prev_arg = NULL;
652   i = 1;
653   while (i < argc)
654     {
655       const char *arg = argv[i];
656  
657       if (strcmp (arg, "--help") == 0 ||
658           strcmp (arg, "-h") == 0 ||
659           strcmp (arg, "-?") == 0)
660         usage (0);
661       else if (strcmp (arg, "--auto-syntax") == 0)
662         auto_shell_syntax = TRUE;
663       else if (strcmp (arg, "-c") == 0 ||
664                strcmp (arg, "--csh-syntax") == 0)
665         c_shell_syntax = TRUE;
666       else if (strcmp (arg, "-s") == 0 ||
667                strcmp (arg, "--sh-syntax") == 0)
668         bourne_shell_syntax = TRUE;
669       else if (strcmp (arg, "--binary-syntax") == 0)
670         binary_syntax = TRUE;
671       else if (strcmp (arg, "--version") == 0)
672         version ();
673       else if (strcmp (arg, "--exit-with-session") == 0)
674         exit_with_session = TRUE;
675       else if (strcmp (arg, "--close-stderr") == 0)
676         close_stderr = TRUE;
677       else if (strstr (arg, "--autolaunch=") == arg)
678         {
679           const char *s;
680
681           if (autolaunch)
682             {
683               fprintf (stderr, "--autolaunch given twice\n");
684               exit (1);
685             }
686           
687           autolaunch = TRUE;
688
689           s = strchr (arg, '=');
690           ++s;
691
692           save_machine_uuid (s);
693         }
694       else if (prev_arg &&
695                strcmp (prev_arg, "--autolaunch") == 0)
696         {
697           if (autolaunch)
698             {
699               fprintf (stderr, "--autolaunch given twice\n");
700               exit (1);
701             }
702           
703           autolaunch = TRUE;
704
705           save_machine_uuid (arg);
706           requires_arg = FALSE;
707         }
708       else if (strcmp (arg, "--autolaunch") == 0)
709         requires_arg = TRUE;
710       else if (strstr (arg, "--config-file=") == arg)
711         {
712           const char *file;
713
714           if (config_file != NULL)
715             {
716               fprintf (stderr, "--config-file given twice\n");
717               exit (1);
718             }
719           
720           file = strchr (arg, '=');
721           ++file;
722
723           config_file = xstrdup (file);
724         }
725       else if (prev_arg &&
726                strcmp (prev_arg, "--config-file") == 0)
727         {
728           if (config_file != NULL)
729             {
730               fprintf (stderr, "--config-file given twice\n");
731               exit (1);
732             }
733
734           config_file = xstrdup (arg);
735           requires_arg = FALSE;
736         }
737       else if (strcmp (arg, "--config-file") == 0)
738         requires_arg = TRUE;
739       else if (arg[0] == '-')
740         {
741           if (strcmp (arg, "--") != 0)
742             {
743               fprintf (stderr, "Option `%s' is unknown.\n", arg);
744               exit (1);
745             }
746           else
747             {
748               runprog = argv[i+1];
749               remaining_args = i+2;
750               break;
751             }
752         }
753       else
754         {
755           runprog = arg;
756           remaining_args = i+1;
757           break;
758         }
759       
760       prev_arg = arg;
761       
762       ++i;
763     }
764   if (requires_arg)
765     {
766       fprintf (stderr, "Option `%s' requires an argument.\n", prev_arg);
767       exit (1);
768     }
769
770   if (auto_shell_syntax)
771     {
772       if ((shname = getenv ("SHELL")) != NULL)
773        {
774          if (!strncmp (shname + strlen (shname) - 3, "csh", 3))
775            c_shell_syntax = TRUE;
776          else
777            bourne_shell_syntax = TRUE;
778        }
779       else
780        bourne_shell_syntax = TRUE;
781     }  
782
783   if (exit_with_session)
784     verbose ("--exit-with-session enabled\n");
785
786   if (autolaunch)
787     {      
788 #ifndef DBUS_BUILD_X11
789       fprintf (stderr, "Autolaunch requested, but X11 support not compiled in.\n"
790                "Cannot continue.\n");
791       exit (1);
792 #else
793       char *address;
794       pid_t pid;
795       long wid;
796       
797       if (get_machine_uuid () == NULL)
798         {
799           fprintf (stderr, "Machine UUID not provided as arg to --autolaunch\n");
800           exit (1);
801         }
802
803       /* FIXME right now autolaunch always does print_variables(), but it should really
804        * exec the child program instead if a child program was specified. For now
805        * we just exit if this conflict arises.
806        */
807       if (runprog)
808         {
809           fprintf (stderr, "Currently --autolaunch does not support running a program\n");
810           exit (1);
811         }
812       
813       verbose ("Autolaunch enabled (using X11).\n");
814       if (!exit_with_session)
815         {
816           verbose ("--exit-with-session automatically enabled\n");
817           exit_with_session = TRUE;
818         }
819
820       if (!x11_init ())
821         {
822           fprintf (stderr, "Autolaunch error: X11 initialization failed.\n");
823           exit (1);
824         }
825
826       if (!x11_get_address (&address, &pid, &wid))
827         {
828           fprintf (stderr, "Autolaunch error: X11 communication error.\n");
829           exit (1);
830         }
831
832       if (address != NULL)
833         {          
834           verbose ("dbus-daemon is already running. Returning existing parameters.\n");
835           print_variables (address, pid, wid, c_shell_syntax,
836                            bourne_shell_syntax, binary_syntax);
837           exit (0);
838         }
839 #endif
840     }
841
842   if (pipe (bus_pid_to_launcher_pipe) < 0 ||
843       pipe (bus_address_to_launcher_pipe) < 0 ||
844       pipe (bus_pid_to_babysitter_pipe) < 0)
845     {
846       fprintf (stderr,
847                "Failed to create pipe: %s\n",
848                strerror (errno));
849       exit (1);
850     }
851
852   ret = fork ();
853   if (ret < 0)
854     {
855       fprintf (stderr, "Failed to fork: %s\n",
856                strerror (errno));
857       exit (1);
858     }
859
860   if (ret == 0)
861     {
862       /* Child */
863 #define MAX_FD_LEN 64
864       char write_pid_fd_as_string[MAX_FD_LEN];
865       char write_address_fd_as_string[MAX_FD_LEN];
866
867       if (close_stderr)
868         do_close_stderr ();
869
870       verbose ("=== Babysitter's intermediate parent created\n");
871
872       /* Fork once more to create babysitter */
873       
874       ret = fork ();
875       if (ret < 0)
876         {
877           fprintf (stderr, "Failed to fork: %s\n",
878                    strerror (errno));
879           exit (1);
880         }
881       
882       if (ret > 0)
883         {
884           /* In babysitter */
885           verbose ("=== Babysitter's intermediate parent continues\n");
886           
887           close (bus_pid_to_launcher_pipe[READ_END]);
888           close (bus_pid_to_launcher_pipe[WRITE_END]);
889           close (bus_address_to_launcher_pipe[READ_END]);
890           close (bus_address_to_launcher_pipe[WRITE_END]);
891           close (bus_pid_to_babysitter_pipe[WRITE_END]);
892
893           /* babysit() will fork *again*
894            * and will also reap the pre-forked bus
895            * daemon
896            */
897           babysit (exit_with_session, ret,
898                    bus_pid_to_babysitter_pipe[READ_END]);
899           exit (0);
900         }
901
902       verbose ("=== Bus exec process created\n");
903       
904       /* Now we are the bus process (well, almost;
905        * dbus-daemon itself forks again)
906        */
907       close (bus_pid_to_launcher_pipe[READ_END]);
908       close (bus_address_to_launcher_pipe[READ_END]);
909       close (bus_pid_to_babysitter_pipe[READ_END]);
910       close (bus_pid_to_babysitter_pipe[WRITE_END]);
911
912       sprintf (write_pid_fd_as_string,
913                "%d", bus_pid_to_launcher_pipe[WRITE_END]);
914
915       sprintf (write_address_fd_as_string,
916                "%d", bus_address_to_launcher_pipe[WRITE_END]);
917
918       verbose ("Calling exec()\n");
919  
920 #ifdef DBUS_BUILD_TESTS 
921       /* exec from testdir */
922       if (getenv("DBUS_USE_TEST_BINARY") != NULL)
923         {
924           execl (TEST_BUS_BINARY,
925                  TEST_BUS_BINARY,
926                  "--fork",
927                  "--print-pid", write_pid_fd_as_string,
928                  "--print-address", write_address_fd_as_string,
929                  config_file ? "--config-file" : "--session",
930                  config_file, /* has to be last in this varargs list */
931                  NULL); 
932
933           fprintf (stderr,
934                    "Failed to execute test message bus daemon %s: %s. Will try again with the system path.\n",
935                    TEST_BUS_BINARY, strerror (errno));
936         }
937  #endif /* DBUS_BUILD_TESTS */
938
939       execl (DBUS_DAEMONDIR"/dbus-daemon",
940              DBUS_DAEMONDIR"/dbus-daemon",
941              "--fork",
942              "--print-pid", write_pid_fd_as_string,
943              "--print-address", write_address_fd_as_string,
944              config_file ? "--config-file" : "--session",
945              config_file, /* has to be last in this varargs list */
946              NULL);
947
948       fprintf (stderr,
949                "Failed to execute message bus daemon %s: %s.  Will try again without full path.\n",
950                DBUS_DAEMONDIR"/dbus-daemon", strerror (errno));
951       
952       /*
953        * If it failed, try running without full PATH.  Note this is needed
954        * because the build process builds the run-with-tmp-session-bus.conf
955        * file and the dbus-daemon will not be in the install location during
956        * build time.
957        */
958       execlp ("dbus-daemon",
959               "dbus-daemon",
960               "--fork",
961               "--print-pid", write_pid_fd_as_string,
962               "--print-address", write_address_fd_as_string,
963               config_file ? "--config-file" : "--session",
964               config_file, /* has to be last in this varargs list */
965               NULL);
966
967       fprintf (stderr,
968                "Failed to execute message bus daemon: %s\n",
969                strerror (errno));
970       exit (1);
971     }
972   else
973     {
974       /* Parent */
975 #define MAX_PID_LEN 64
976       pid_t bus_pid;  
977       char bus_address[MAX_ADDR_LEN];
978       char buf[MAX_PID_LEN];
979       char *end;
980       long wid = 0;
981       long val;
982       int ret2;
983
984       verbose ("=== Parent dbus-launch continues\n");
985       
986       close (bus_pid_to_launcher_pipe[WRITE_END]);
987       close (bus_address_to_launcher_pipe[WRITE_END]);
988       close (bus_pid_to_babysitter_pipe[READ_END]);
989
990       verbose ("Waiting for babysitter's intermediate parent\n");
991       
992       /* Immediately reap parent of babysitter
993        * (which was created just for us to reap)
994        */
995       if (do_waitpid (ret) < 0)
996         {
997           fprintf (stderr, "Failed to waitpid() for babysitter intermediate process: %s\n",
998                    strerror (errno));
999           exit (1);
1000         }
1001
1002       verbose ("Reading address from bus\n");
1003       
1004       /* Read the pipe data, print, and exit */
1005       switch (read_line (bus_address_to_launcher_pipe[READ_END],
1006                          bus_address, MAX_ADDR_LEN))
1007         {
1008         case READ_STATUS_OK:
1009           break;
1010         case READ_STATUS_EOF:
1011           fprintf (stderr, "EOF in dbus-launch reading address from bus daemon\n");
1012           exit (1);
1013           break;
1014         case READ_STATUS_ERROR:
1015           fprintf (stderr, "Error in dbus-launch reading address from bus daemon: %s\n",
1016                    strerror (errno));
1017           exit (1);
1018           break;
1019         }
1020         
1021       close (bus_address_to_launcher_pipe[READ_END]);
1022
1023       verbose ("Reading PID from daemon\n");
1024       /* Now read data */
1025       switch (read_line (bus_pid_to_launcher_pipe[READ_END], buf, MAX_PID_LEN))
1026         {
1027         case READ_STATUS_OK:
1028           break;
1029         case READ_STATUS_EOF:
1030           fprintf (stderr, "EOF reading PID from bus daemon\n");
1031           exit (1);
1032           break;
1033         case READ_STATUS_ERROR:
1034           fprintf (stderr, "Error reading PID from bus daemon: %s\n",
1035                    strerror (errno));
1036           exit (1);
1037           break;
1038         }
1039
1040       end = NULL;
1041       val = strtol (buf, &end, 0);
1042       if (buf == end || end == NULL)
1043         {
1044           fprintf (stderr, "Failed to parse bus PID \"%s\": %s\n",
1045                    buf, strerror (errno));
1046           exit (1);
1047         }
1048
1049       bus_pid = val;
1050
1051       close (bus_pid_to_launcher_pipe[READ_END]);
1052
1053 #ifdef DBUS_BUILD_X11
1054       /* FIXME the runprog == NULL is broken - we need to launch the runprog with the existing bus,
1055        * instead of just doing print_variables() if there's an existing bus.
1056        */
1057       if (xdisplay != NULL && runprog == NULL)
1058         {
1059           ret2 = x11_save_address (bus_address, bus_pid, &wid);
1060           if (ret2 == 0)
1061             {
1062               /* another window got added. Return its address */
1063               char *address;
1064               pid_t pid;
1065               long wid;
1066               
1067               if (x11_get_address (&address, &pid, &wid) && address != NULL)
1068                 {
1069                   verbose ("dbus-daemon is already running. Returning existing parameters.\n");
1070                   print_variables (address, pid, wid, c_shell_syntax,
1071                                    bourne_shell_syntax, binary_syntax);
1072                   free (address);
1073                   
1074                   bus_pid_to_kill = bus_pid;
1075                   kill_bus_and_exit (0);
1076                 }
1077               
1078               /* if failed, fall through */
1079             }
1080           if (ret2 <= 0)
1081             {
1082               fprintf (stderr, "Error saving bus information.\n");
1083               bus_pid_to_kill = bus_pid;
1084               kill_bus_and_exit (1);
1085             }
1086         }
1087 #endif
1088
1089       /* Forward the pid to the babysitter */
1090       write_pid (bus_pid_to_babysitter_pipe[WRITE_END], bus_pid);
1091       close (bus_pid_to_babysitter_pipe[WRITE_END]);
1092
1093       if (runprog)
1094         {
1095           char *envvar;
1096           char **args;
1097
1098           envvar = malloc (strlen ("DBUS_SESSION_BUS_ADDRESS=") + strlen (bus_address) + 1);
1099           args = malloc (sizeof (char *) * ((argc-remaining_args)+2));
1100
1101           if (envvar == NULL || args == NULL)
1102             goto oom;
1103
1104           args[0] = xstrdup (runprog);
1105           if (!args[0])
1106             goto oom;
1107           for (i = 1; i <= (argc-remaining_args); i++)
1108             {
1109               size_t len = strlen (argv[remaining_args+i-1])+1;
1110               args[i] = malloc (len);
1111               if (!args[i])
1112                 goto oom;
1113               strncpy (args[i], argv[remaining_args+i-1], len);
1114             }
1115           args[i] = NULL;
1116
1117           strcpy (envvar, "DBUS_SESSION_BUS_ADDRESS=");
1118           strcat (envvar, bus_address);
1119           putenv (envvar);
1120
1121           execvp (runprog, args);
1122           fprintf (stderr, "Couldn't exec %s: %s\n", runprog, strerror (errno));
1123           exit (1);
1124         }
1125       else
1126         {
1127           print_variables (bus_address, bus_pid, wid, c_shell_syntax,
1128                            bourne_shell_syntax, binary_syntax);
1129         }
1130           
1131       verbose ("dbus-launch exiting\n");
1132
1133       fflush (stdout);
1134       fflush (stderr);
1135       close (1);
1136       close (2);
1137       
1138       exit (0);
1139     } 
1140   
1141   return 0;
1142  oom:
1143   fprintf (stderr, "Out of memory!");
1144   exit (1);
1145 }