Home | History | Annotate | Download | only in tools
      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 (at) 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 #define READ_END  0
    600 #define WRITE_END 1
    601 
    602 int
    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