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