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