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