dbus-launch.c revision 2abdb13ebe737e39653b79fecd93477e156b9db1
1/* -*- mode: C; c-file-style: "gnu" -*- */
2/* dbus-launch.c  dbus-launch utility
3 *
4 * Copyright (C) 2003 Red Hat, Inc.
5 *
6 * Licensed under the Academic Free License version 2.1
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21 *
22 */
23#include <config.h>
24#include <stdlib.h>
25#include <unistd.h>
26#include <fcntl.h>
27#include <signal.h>
28#include <sys/wait.h>
29#include <errno.h>
30#include <stdio.h>
31#include <string.h>
32#include <signal.h>
33#include <stdarg.h>
34#ifdef DBUS_BUILD_X11
35#include <X11/Xlib.h>
36#endif
37
38#ifndef TRUE
39#define TRUE (1)
40#endif
41
42#ifndef FALSE
43#define FALSE (0)
44#endif
45
46#undef	MAX
47#define MAX(a, b)  (((a) > (b)) ? (a) : (b))
48
49static void
50verbose (const char *format,
51         ...)
52{
53  va_list args;
54  static int verbose = TRUE;
55  static int verbose_initted = FALSE;
56
57  /* things are written a bit oddly here so that
58   * in the non-verbose case we just have the one
59   * conditional and return immediately.
60   */
61  if (!verbose)
62    return;
63
64  if (!verbose_initted)
65    {
66      verbose = getenv ("DBUS_VERBOSE") != NULL;
67      verbose_initted = TRUE;
68      if (!verbose)
69        return;
70    }
71
72  fprintf (stderr, "%lu: ", (unsigned long) getpid ());
73
74  va_start (args, format);
75  vfprintf (stderr, format, args);
76  va_end (args);
77}
78
79static void
80usage (int ecode)
81{
82  fprintf (stderr, "dbus-launch [--version] [--help] [--sh-syntax] [--csh-syntax] [--auto-syntax] [--exit-with-session]\n");
83  exit (ecode);
84}
85
86static void
87version (void)
88{
89  printf ("D-BUS Message Bus Launcher %s\n"
90          "Copyright (C) 2003 Red Hat, Inc.\n"
91          "This is free software; see the source for copying conditions.\n"
92          "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
93          VERSION);
94  exit (0);
95}
96
97static char *
98xstrdup (const char *str)
99{
100  int len;
101  char *copy;
102
103  if (str == NULL)
104    return NULL;
105
106  len = strlen (str);
107
108  copy = malloc (len + 1);
109  if (copy == NULL)
110    return NULL;
111
112  memcpy (copy, str, len + 1);
113
114  return copy;
115}
116
117typedef enum
118{
119  READ_STATUS_OK,    /**< Read succeeded */
120  READ_STATUS_ERROR, /**< Some kind of error */
121  READ_STATUS_EOF    /**< EOF returned */
122} ReadStatus;
123
124static ReadStatus
125read_line (int        fd,
126           char      *buf,
127           size_t     maxlen)
128{
129  size_t bytes = 0;
130  ReadStatus retval;
131
132  memset (buf, '\0', maxlen);
133  maxlen -= 1; /* ensure nul term */
134
135  retval = READ_STATUS_OK;
136
137  while (TRUE)
138    {
139      size_t chunk;
140      size_t to_read;
141
142    again:
143      to_read = maxlen - bytes;
144
145      if (to_read == 0)
146        break;
147
148      chunk = read (fd,
149                    buf + bytes,
150                    to_read);
151      if (chunk < 0 && errno == EINTR)
152        goto again;
153
154      if (chunk < 0)
155        {
156          retval = READ_STATUS_ERROR;
157          break;
158        }
159      else if (chunk == 0)
160        {
161          retval = READ_STATUS_EOF;
162          break; /* EOF */
163        }
164      else /* chunk > 0 */
165	bytes += chunk;
166    }
167
168  if (retval == READ_STATUS_EOF &&
169      bytes > 0)
170    retval = READ_STATUS_OK;
171
172  /* whack newline */
173  if (retval != READ_STATUS_ERROR &&
174      bytes > 0 &&
175      buf[bytes-1] == '\n')
176    buf[bytes-1] = '\0';
177
178  return retval;
179}
180
181static ReadStatus
182read_pid (int        fd,
183          pid_t     *buf)
184{
185  size_t bytes = 0;
186  ReadStatus retval;
187
188  retval = READ_STATUS_OK;
189
190  while (TRUE)
191    {
192      size_t chunk;
193      size_t to_read;
194
195    again:
196      to_read = sizeof (pid_t) - bytes;
197
198      if (to_read == 0)
199        break;
200
201      chunk = read (fd,
202                    ((char*)buf) + bytes,
203                    to_read);
204      if (chunk < 0 && errno == EINTR)
205        goto again;
206
207      if (chunk < 0)
208        {
209          retval = READ_STATUS_ERROR;
210          break;
211        }
212      else if (chunk == 0)
213        {
214          retval = READ_STATUS_EOF;
215          break; /* EOF */
216        }
217      else /* chunk > 0 */
218	bytes += chunk;
219    }
220
221  return retval;
222}
223
224static void
225do_write (int fd, const void *buf, size_t count)
226{
227  size_t bytes_written;
228  int ret;
229
230  bytes_written = 0;
231
232 again:
233
234  ret = write (fd, ((const char*)buf) + bytes_written, count - bytes_written);
235
236  if (ret < 0)
237    {
238      if (errno == EINTR)
239        goto again;
240      else
241        {
242          fprintf (stderr, "Failed to write data to pipe! %s\n",
243                   strerror (errno));
244          exit (1); /* give up, we suck */
245        }
246    }
247  else
248    bytes_written += ret;
249
250  if (bytes_written < count)
251    goto again;
252}
253
254static void
255write_pid (int   fd,
256           pid_t pid)
257{
258  do_write (fd, &pid, sizeof (pid));
259}
260
261static int
262do_waitpid (pid_t pid)
263{
264  int ret;
265
266 again:
267  ret = waitpid (pid, NULL, 0);
268
269  if (ret < 0 &&
270      errno == EINTR)
271    goto again;
272
273  return ret;
274}
275
276static pid_t bus_pid_to_kill = -1;
277
278static void
279kill_bus_and_exit (void)
280{
281  verbose ("Killing message bus and exiting babysitter\n");
282
283  /* in case these point to any NFS mounts, get rid of them immediately */
284  close (0);
285  close (1);
286  close (2);
287
288  kill (bus_pid_to_kill, SIGTERM);
289  sleep (3);
290  kill (bus_pid_to_kill, SIGKILL);
291
292  exit (0);
293}
294
295#ifdef DBUS_BUILD_X11
296static int
297x_io_error_handler (Display *xdisplay)
298{
299  verbose ("X IO error\n");
300  kill_bus_and_exit ();
301  return 0;
302}
303#endif
304
305static int got_sighup = FALSE;
306
307static void
308signal_handler (int sig)
309{
310  switch (sig)
311    {
312    case SIGHUP:
313      got_sighup = TRUE;
314      break;
315    }
316}
317
318static void
319kill_bus_when_session_ends (void)
320{
321  int tty_fd;
322  int x_fd;
323  fd_set read_set;
324  fd_set err_set;
325  int ret;
326  struct sigaction act;
327  sigset_t empty_mask;
328#ifdef DBUS_BUILD_X11
329  Display *xdisplay;
330#endif
331
332  /* install SIGHUP handler */
333  got_sighup = FALSE;
334  sigemptyset (&empty_mask);
335  act.sa_handler = signal_handler;
336  act.sa_mask    = empty_mask;
337  act.sa_flags   = 0;
338  sigaction (SIGHUP,  &act, 0);
339
340#ifdef DBUS_BUILD_X11
341  xdisplay = XOpenDisplay (NULL);
342  if (xdisplay != NULL)
343    {
344      verbose ("Successfully opened X display\n");
345      x_fd = ConnectionNumber (xdisplay);
346      XSetIOErrorHandler (x_io_error_handler);
347    }
348  else
349    x_fd = -1;
350#else
351  verbose ("Compiled without X11 support\n");
352  x_fd = -1;
353#endif
354
355  if (isatty (0))
356    tty_fd = 0;
357  else
358    tty_fd = -1;
359
360  if (tty_fd >= 0)
361    verbose ("stdin isatty(), monitoring it\n");
362  else
363    verbose ("stdin was not a TTY, not monitoring it\n");
364
365  if (tty_fd < 0 && x_fd < 0)
366    {
367      fprintf (stderr, "No terminal on standard input and no X display; cannot attach message bus to session lifetime\n");
368      exit (1);
369    }
370
371  while (TRUE)
372    {
373      FD_ZERO (&read_set);
374      FD_ZERO (&err_set);
375
376      if (tty_fd >= 0)
377        {
378          FD_SET (tty_fd, &read_set);
379          FD_SET (tty_fd, &err_set);
380        }
381
382      if (x_fd >= 0)
383        {
384          FD_SET (x_fd, &read_set);
385          FD_SET (x_fd, &err_set);
386        }
387
388      ret = select (MAX (tty_fd, x_fd) + 1,
389                    &read_set, NULL, &err_set, NULL);
390
391      if (got_sighup)
392        {
393          verbose ("Got SIGHUP, exiting\n");
394          kill_bus_and_exit ();
395        }
396
397#ifdef DBUS_BUILD_X11
398      /* Dump events on the floor, and let
399       * IO error handler run if we lose
400       * the X connection
401       */
402      if (x_fd >= 0)
403        verbose ("X fd condition reading = %d error = %d\n",
404                 FD_ISSET (x_fd, &read_set),
405                 FD_ISSET (x_fd, &err_set));
406
407      if (xdisplay != NULL)
408        {
409          while (XPending (xdisplay))
410            {
411              XEvent ignored;
412              XNextEvent (xdisplay, &ignored);
413            }
414        }
415#endif
416
417      if (tty_fd >= 0)
418        {
419          if (FD_ISSET (tty_fd, &read_set))
420            {
421              int bytes_read;
422              char discard[512];
423
424              verbose ("TTY ready for reading\n");
425
426              bytes_read = read (tty_fd, discard, sizeof (discard));
427
428              verbose ("Read %d bytes from TTY errno = %d\n",
429                       bytes_read, errno);
430
431              if (bytes_read == 0)
432                kill_bus_and_exit (); /* EOF */
433              else if (bytes_read < 0 && errno != EINTR)
434                {
435                  /* This shouldn't happen I don't think; to avoid
436                   * spinning on the fd forever we exit.
437                   */
438                  fprintf (stderr, "dbus-launch: error reading from stdin: %s\n",
439                           strerror (errno));
440                  kill_bus_and_exit ();
441                }
442            }
443          else if (FD_ISSET (tty_fd, &err_set))
444            {
445              verbose ("TTY has error condition\n");
446
447              kill_bus_and_exit ();
448            }
449        }
450    }
451}
452
453static void
454babysit (int   exit_with_session,
455         pid_t child_pid,
456         int   read_bus_pid_fd,  /* read pid from here */
457         int   write_bus_pid_fd) /* forward pid to here */
458{
459  int ret;
460#define MAX_PID_LEN 64
461  char buf[MAX_PID_LEN];
462  long val;
463  char *end;
464  int dev_null_fd;
465  const char *s;
466
467  verbose ("babysitting, exit_with_session = %d, child_pid = %ld, read_bus_pid_fd = %d, write_bus_pid_fd = %d\n",
468           exit_with_session, (long) child_pid, read_bus_pid_fd, write_bus_pid_fd);
469
470  /* We chdir ("/") since we are persistent and daemon-like, and fork
471   * again so dbus-launch can reap the parent.  However, we don't
472   * setsid() or close fd 0 because the idea is to remain attached
473   * to the tty and the X server in order to kill the message bus
474   * when the session ends.
475   */
476
477  if (chdir ("/") < 0)
478    {
479      fprintf (stderr, "Could not change to root directory: %s\n",
480               strerror (errno));
481      exit (1);
482    }
483
484  /* Close stdout/stderr so we don't block an "eval" or otherwise
485   * lock up. stdout is still chaining through to dbus-launch
486   * and in turn to the parent shell.
487   */
488  dev_null_fd = open ("/dev/null", O_RDWR);
489  if (dev_null_fd >= 0)
490    {
491      if (!exit_with_session)
492        dup2 (dev_null_fd, 0);
493      dup2 (dev_null_fd, 1);
494      s = getenv ("DBUS_DEBUG_OUTPUT");
495      if (s == NULL || *s == '\0')
496        dup2 (dev_null_fd, 2);
497    }
498  else
499    {
500      fprintf (stderr, "Failed to open /dev/null: %s\n",
501               strerror (errno));
502      /* continue, why not */
503    }
504
505  ret = fork ();
506
507  if (ret < 0)
508    {
509      fprintf (stderr, "fork() failed in babysitter: %s\n",
510               strerror (errno));
511      exit (1);
512    }
513
514  if (ret > 0)
515    {
516      /* Parent reaps pre-fork part of bus daemon, then exits and is
517       * reaped so the babysitter isn't a zombie
518       */
519
520      verbose ("=== Babysitter's intermediate parent continues again\n");
521
522      if (do_waitpid (child_pid) < 0)
523        {
524          /* shouldn't happen */
525          fprintf (stderr, "Failed waitpid() waiting for bus daemon's parent\n");
526          exit (1);
527        }
528
529      verbose ("Babysitter's intermediate parent exiting\n");
530
531      exit (0);
532    }
533
534  /* Child continues */
535  verbose ("=== Babysitter process created\n");
536
537  verbose ("Reading PID from daemon\n");
538  /* Now read data */
539  switch (read_line (read_bus_pid_fd, buf, MAX_PID_LEN))
540    {
541    case READ_STATUS_OK:
542      break;
543    case READ_STATUS_EOF:
544      fprintf (stderr, "EOF reading PID from bus daemon\n");
545      exit (1);
546      break;
547    case READ_STATUS_ERROR:
548      fprintf (stderr, "Error reading PID from bus daemon: %s\n",
549               strerror (errno));
550      exit (1);
551      break;
552    }
553
554  end = NULL;
555  val = strtol (buf, &end, 0);
556  if (buf == end || end == NULL)
557    {
558      fprintf (stderr, "Failed to parse bus PID \"%s\": %s\n",
559               buf, strerror (errno));
560      exit (1);
561    }
562
563  bus_pid_to_kill = val;
564
565  verbose ("Got PID %ld from daemon\n",
566           (long) bus_pid_to_kill);
567
568  /* Write data to launcher */
569  write_pid (write_bus_pid_fd, bus_pid_to_kill);
570  close (write_bus_pid_fd);
571
572  if (exit_with_session)
573    {
574      /* Bus is now started and launcher has needed info;
575       * we connect to X display and tty and wait to
576       * kill bus if requested.
577       */
578
579      kill_bus_when_session_ends ();
580    }
581
582  verbose ("Babysitter exiting\n");
583
584  exit (0);
585}
586
587#define READ_END  0
588#define WRITE_END 1
589
590int
591main (int argc, char **argv)
592{
593  const char *prev_arg;
594  const char *shname;
595  const char *runprog = NULL;
596  int remaining_args = 0;
597  int exit_with_session;
598  int c_shell_syntax = FALSE;
599  int bourne_shell_syntax = FALSE;
600  int auto_shell_syntax = FALSE;
601  int i;
602  int ret;
603  int bus_pid_to_launcher_pipe[2];
604  int bus_pid_to_babysitter_pipe[2];
605  int bus_address_to_launcher_pipe[2];
606  char *config_file;
607
608  exit_with_session = FALSE;
609  config_file = NULL;
610
611  prev_arg = NULL;
612  i = 1;
613  while (i < argc)
614    {
615      const char *arg = argv[i];
616
617      if (strcmp (arg, "--help") == 0 ||
618          strcmp (arg, "-h") == 0 ||
619          strcmp (arg, "-?") == 0)
620        usage (0);
621      else if (strcmp (arg, "--auto-syntax") == 0)
622        auto_shell_syntax = TRUE;
623      else if (strcmp (arg, "-c") == 0 ||
624	       strcmp (arg, "--csh-syntax") == 0)
625        c_shell_syntax = TRUE;
626      else if (strcmp (arg, "-s") == 0 ||
627	       strcmp (arg, "--sh-syntax") == 0)
628        bourne_shell_syntax = TRUE;
629      else if (strcmp (arg, "--version") == 0)
630        version ();
631      else if (strcmp (arg, "--exit-with-session") == 0)
632        exit_with_session = TRUE;
633      else if (strstr (arg, "--config-file=") == arg)
634        {
635          const char *file;
636
637          if (config_file != NULL)
638            {
639              fprintf (stderr, "--config-file given twice\n");
640              exit (1);
641            }
642
643          file = strchr (arg, '=');
644          ++file;
645
646          config_file = xstrdup (file);
647        }
648      else if (prev_arg &&
649               strcmp (prev_arg, "--config-file") == 0)
650        {
651          if (config_file != NULL)
652            {
653              fprintf (stderr, "--config-file given twice\n");
654              exit (1);
655            }
656
657          config_file = xstrdup (arg);
658        }
659      else if (strcmp (arg, "--config-file") == 0)
660        ; /* wait for next arg */
661      else
662	{
663	  runprog = arg;
664	  remaining_args = i+1;
665	  break;
666	}
667
668      prev_arg = arg;
669
670      ++i;
671    }
672
673  if (exit_with_session)
674    verbose ("--exit-with-session enabled\n");
675
676  if (auto_shell_syntax)
677    {
678      if ((shname = getenv ("SHELL")) != NULL)
679       {
680         if (!strncmp (shname + strlen (shname) - 3, "csh", 3))
681           c_shell_syntax = TRUE;
682         else
683           bourne_shell_syntax = TRUE;
684       }
685      else
686       bourne_shell_syntax = TRUE;
687    }
688
689  if (pipe (bus_pid_to_launcher_pipe) < 0 ||
690      pipe (bus_address_to_launcher_pipe) < 0)
691    {
692      fprintf (stderr,
693               "Failed to create pipe: %s\n",
694               strerror (errno));
695      exit (1);
696    }
697
698  bus_pid_to_babysitter_pipe[READ_END] = -1;
699  bus_pid_to_babysitter_pipe[WRITE_END] = -1;
700
701  ret = fork ();
702  if (ret < 0)
703    {
704      fprintf (stderr, "Failed to fork: %s\n",
705               strerror (errno));
706      exit (1);
707    }
708
709  if (ret == 0)
710    {
711      /* Child */
712#define MAX_FD_LEN 64
713      char write_pid_fd_as_string[MAX_FD_LEN];
714      char write_address_fd_as_string[MAX_FD_LEN];
715
716      verbose ("=== Babysitter's intermediate parent created\n");
717
718      /* Fork once more to create babysitter */
719
720      if (pipe (bus_pid_to_babysitter_pipe) < 0)
721        {
722          fprintf (stderr,
723                   "Failed to create pipe: %s\n",
724                   strerror (errno));
725          exit (1);
726        }
727
728      ret = fork ();
729      if (ret < 0)
730        {
731          fprintf (stderr, "Failed to fork: %s\n",
732                   strerror (errno));
733          exit (1);
734        }
735
736      if (ret > 0)
737        {
738          /* In babysitter */
739          verbose ("=== Babysitter's intermediate parent continues\n");
740
741          close (bus_pid_to_launcher_pipe[READ_END]);
742          close (bus_address_to_launcher_pipe[READ_END]);
743          close (bus_address_to_launcher_pipe[WRITE_END]);
744          close (bus_pid_to_babysitter_pipe[WRITE_END]);
745
746          /* babysit() will fork *again*
747           * and will also reap the pre-forked bus
748           * daemon
749           */
750          babysit (exit_with_session, ret,
751                   bus_pid_to_babysitter_pipe[READ_END],
752                   bus_pid_to_launcher_pipe[WRITE_END]);
753          exit (0);
754        }
755
756      verbose ("=== Bus exec process created\n");
757
758      /* Now we are the bus process (well, almost;
759       * dbus-daemon itself forks again)
760       */
761      close (bus_pid_to_launcher_pipe[READ_END]);
762      close (bus_address_to_launcher_pipe[READ_END]);
763      close (bus_pid_to_babysitter_pipe[READ_END]);
764      close (bus_pid_to_launcher_pipe[WRITE_END]);
765
766      sprintf (write_pid_fd_as_string,
767               "%d", bus_pid_to_babysitter_pipe[WRITE_END]);
768
769      sprintf (write_address_fd_as_string,
770               "%d", bus_address_to_launcher_pipe[WRITE_END]);
771
772      verbose ("Calling exec()\n");
773
774      execlp ("dbus-daemon",
775              "dbus-daemon",
776              "--fork",
777              "--print-pid", write_pid_fd_as_string,
778              "--print-address", write_address_fd_as_string,
779              config_file ? "--config-file" : "--session",
780              config_file, /* has to be last in this varargs list */
781              NULL);
782
783      fprintf (stderr,
784               "Failed to execute message bus daemon: %s\n",
785               strerror (errno));
786      exit (1);
787    }
788  else
789    {
790      /* Parent */
791#define MAX_ADDR_LEN 512
792      pid_t bus_pid;
793      char bus_address[MAX_ADDR_LEN];
794
795      verbose ("=== Parent dbus-launch continues\n");
796
797      close (bus_pid_to_launcher_pipe[WRITE_END]);
798      close (bus_address_to_launcher_pipe[WRITE_END]);
799
800      verbose ("Waiting for babysitter's intermediate parent\n");
801
802      /* Immediately reap parent of babysitter
803       * (which was created just for us to reap)
804       */
805      if (do_waitpid (ret) < 0)
806        {
807          fprintf (stderr, "Failed to waitpid() for babysitter intermediate process: %s\n",
808                   strerror (errno));
809          exit (1);
810        }
811
812      verbose ("Reading address from bus\n");
813
814      /* Read the pipe data, print, and exit */
815      switch (read_line (bus_address_to_launcher_pipe[READ_END],
816                         bus_address, MAX_ADDR_LEN))
817        {
818        case READ_STATUS_OK:
819          break;
820        case READ_STATUS_EOF:
821          fprintf (stderr, "EOF in dbus-launch reading address from bus daemon\n");
822          exit (1);
823          break;
824        case READ_STATUS_ERROR:
825          fprintf (stderr, "Error in dbus-launch reading address from bus daemon: %s\n",
826                   strerror (errno));
827          exit (1);
828          break;
829        }
830
831      close (bus_address_to_launcher_pipe[READ_END]);
832
833      verbose ("Reading PID from babysitter\n");
834
835      switch (read_pid (bus_pid_to_launcher_pipe[READ_END], &bus_pid))
836        {
837        case READ_STATUS_OK:
838          break;
839        case READ_STATUS_EOF:
840          fprintf (stderr, "EOF in dbus-launch reading address from bus daemon\n");
841          exit (1);
842          break;
843        case READ_STATUS_ERROR:
844          fprintf (stderr, "Error in dbus-launch reading address from bus daemon: %s\n",
845                   strerror (errno));
846          exit (1);
847          break;
848        }
849
850      close (bus_pid_to_launcher_pipe[READ_END]);
851
852      if (runprog)
853	{
854	  char *envvar;
855	  char **args;
856
857	  envvar = malloc (strlen ("DBUS_SESSION_BUS_ADDRESS=") + strlen (bus_address) + 1);
858	  args = malloc (sizeof (char *) * ((argc-remaining_args)+2));
859
860	  if (envvar == NULL || args == NULL)
861	    goto oom;
862
863	  args[0] = xstrdup (runprog);
864	  if (!args[0])
865	    goto oom;
866	  for (i = 1; i <= (argc-remaining_args); i++)
867	    {
868	      size_t len = strlen (argv[remaining_args+i-1])+1;
869	      args[i] = malloc (len);
870	      if (!args[i])
871		goto oom;
872	      strncpy (args[i], argv[remaining_args+i-1], len);
873	    }
874	  args[i] = NULL;
875
876	  strcpy (envvar, "DBUS_SESSION_BUS_ADDRESS=");
877	  strcat (envvar, bus_address);
878	  putenv (envvar);
879
880	  execvp (runprog, args);
881	  fprintf (stderr, "Couldn't exec %s: %s\n", runprog, strerror (errno));
882	  exit (1);
883	}
884      else
885	{
886	  if (c_shell_syntax)
887	    printf ("setenv DBUS_SESSION_BUS_ADDRESS '%s'\n", bus_address);
888	  else
889	    {
890	      printf ("DBUS_SESSION_BUS_ADDRESS='%s'\n", bus_address);
891	      if (bourne_shell_syntax)
892		printf ("export DBUS_SESSION_BUS_ADDRESS\n");
893	    }
894	  if (c_shell_syntax)
895	    printf ("set DBUS_SESSION_BUS_PID=%ld\n", (long) bus_pid);
896	  else
897	    printf ("DBUS_SESSION_BUS_PID=%ld\n", (long) bus_pid);
898	}
899
900      verbose ("dbus-launch exiting\n");
901
902      fflush (stdout);
903      fflush (stderr);
904      close (1);
905      close (2);
906
907      exit (0);
908    }
909
910  return 0;
911 oom:
912  fprintf (stderr, "Out of memory!");
913  exit (1);
914}
915