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