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