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