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 (at) 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* 90 get_machine_uuid (void) 91 { 92 return machine_uuid; 93 } 94 95 static void 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 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 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 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 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 * 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 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 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 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 357 write_pid (int fd, 358 pid_t pid) 359 { 360 do_write (fd, &pid, sizeof (pid)); 361 } 362 363 static int 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 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 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 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 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 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 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 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 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 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