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 (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., 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* 46 get_machine_uuid (void) 47 { 48 return machine_uuid; 49 } 50 51 static void 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 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 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 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 * 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 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 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 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 270 write_pid (int fd, 271 pid_t pid) 272 { 273 do_write (fd, &pid, sizeof (pid)); 274 } 275 276 static int 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 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 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 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 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 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 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