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