/* * Saves the session address in session file. Returns TRUE on * success, FALSE if an error occurs. */ static int set_address_in_file (char *address, pid_t pid, Window wid) { char *session_file; FILE *f; ensure_session_directory (); session_file = get_session_file(); if (session_file == NULL) return FALSE; f = fopen (session_file, "w"); if (f == NULL) return FALSE; /* some kind of error */ fprintf (f, "# This file allows processes on the machine with id %s using \n" "# display %s to find the D-Bus session bus with the below address.\n" "# If the DBUS_SESSION_BUS_ADDRESS environment variable is set, it will\n" "# be used rather than this file.\n" "# See \"man dbus-launch\" for more details.\n" "DBUS_SESSION_BUS_ADDRESS=%s\n" "DBUS_SESSION_BUS_PID=%ld\n" "DBUS_SESSION_BUS_WINDOWID=%ld\n", get_machine_uuid (), getenv ("DISPLAY"), address, (long)pid, (long)wid); fclose (f); free (session_file); return TRUE; }
static int init_x_atoms (Display *display) { static const char selection_prefix[] = "_DBUS_SESSION_BUS_SELECTION_"; static const char address_prefix[] = "_DBUS_SESSION_BUS_ADDRESS"; static const char pid_prefix[] = "_DBUS_SESSION_BUS_PID"; static int init = FALSE; char *atom_name; const char *machine; char *user_name; struct passwd *user; if (init) return TRUE; machine = get_machine_uuid (); if (machine == NULL) return FALSE; user = getpwuid (getuid ()); if (user == NULL) { verbose ("Could not determine the user informations; aborting X11 integration.\n"); return FALSE; } user_name = xstrdup(user->pw_name); atom_name = malloc (strlen (machine) + strlen (user_name) + 2 + MAX (strlen (selection_prefix), MAX (strlen (address_prefix), strlen (pid_prefix)))); if (atom_name == NULL) { verbose ("Could not create X11 atoms; aborting X11 integration.\n"); free (user_name); return FALSE; } /* create the selection atom */ strcpy (atom_name, selection_prefix); strcat (atom_name, user_name); strcat (atom_name, "_"); strcat (atom_name, machine); selection_atom = XInternAtom (display, atom_name, FALSE); /* create the address property atom */ strcpy (atom_name, address_prefix); address_atom = XInternAtom (display, atom_name, FALSE); /* create the PID property atom */ strcpy (atom_name, pid_prefix); pid_atom = XInternAtom (display, atom_name, FALSE); free (atom_name); free (user_name); init = TRUE; return TRUE; }
int main (int argc, char **argv) { const char *prev_arg; const char *shname; const char *runprog = NULL; int remaining_args = 0; int exit_with_session; int binary_syntax = FALSE; int c_shell_syntax = FALSE; int bourne_shell_syntax = FALSE; int auto_shell_syntax = FALSE; int autolaunch = FALSE; int requires_arg = FALSE; int close_stderr = FALSE; int i; int ret; int bus_pid_to_launcher_pipe[2]; int bus_pid_to_babysitter_pipe[2]; int bus_address_to_launcher_pipe[2]; char *config_file; exit_with_session = FALSE; config_file = NULL; prev_arg = NULL; i = 1; while (i < argc) { const char *arg = argv[i]; if (strcmp (arg, "--help") == 0 || strcmp (arg, "-h") == 0 || strcmp (arg, "-?") == 0) usage (0); else if (strcmp (arg, "--auto-syntax") == 0) auto_shell_syntax = TRUE; else if (strcmp (arg, "-c") == 0 || strcmp (arg, "--csh-syntax") == 0) c_shell_syntax = TRUE; else if (strcmp (arg, "-s") == 0 || strcmp (arg, "--sh-syntax") == 0) bourne_shell_syntax = TRUE; else if (strcmp (arg, "--binary-syntax") == 0) binary_syntax = TRUE; else if (strcmp (arg, "--version") == 0) version (); else if (strcmp (arg, "--exit-with-session") == 0) exit_with_session = TRUE; else if (strcmp (arg, "--close-stderr") == 0) close_stderr = TRUE; else if (strstr (arg, "--autolaunch=") == arg) { const char *s; if (autolaunch) { fprintf (stderr, "--autolaunch given twice\n"); exit (1); } autolaunch = TRUE; s = strchr (arg, '='); ++s; save_machine_uuid (s); } else if (prev_arg && strcmp (prev_arg, "--autolaunch") == 0) { if (autolaunch) { fprintf (stderr, "--autolaunch given twice\n"); exit (1); } autolaunch = TRUE; save_machine_uuid (arg); requires_arg = FALSE; } else if (strcmp (arg, "--autolaunch") == 0) requires_arg = TRUE; else if (strstr (arg, "--config-file=") == arg) { const char *file; if (config_file != NULL) { fprintf (stderr, "--config-file given twice\n"); exit (1); } file = strchr (arg, '='); ++file; config_file = xstrdup (file); } else if (prev_arg && strcmp (prev_arg, "--config-file") == 0) { if (config_file != NULL) { fprintf (stderr, "--config-file given twice\n"); exit (1); } config_file = xstrdup (arg); requires_arg = FALSE; } else if (strcmp (arg, "--config-file") == 0) requires_arg = TRUE; else if (arg[0] == '-') { if (strcmp (arg, "--") != 0) { fprintf (stderr, "Option `%s' is unknown.\n", arg); exit (1); } else { runprog = argv[i+1]; remaining_args = i+2; break; } } else { runprog = arg; remaining_args = i+1; break; } prev_arg = arg; ++i; } if (requires_arg) { fprintf (stderr, "Option `%s' requires an argument.\n", prev_arg); exit (1); } if (auto_shell_syntax) { if ((shname = getenv ("SHELL")) != NULL) { if (!strncmp (shname + strlen (shname) - 3, "csh", 3)) c_shell_syntax = TRUE; else bourne_shell_syntax = TRUE; } else bourne_shell_syntax = TRUE; } if (exit_with_session) verbose ("--exit-with-session enabled\n"); if (autolaunch) { #ifndef DBUS_BUILD_X11 fprintf (stderr, "Autolaunch requested, but X11 support not compiled in.\n" "Cannot continue.\n"); exit (1); #else char *address; pid_t pid; long wid; if (get_machine_uuid () == NULL) { fprintf (stderr, "Machine UUID not provided as arg to --autolaunch\n"); exit (1); } /* FIXME right now autolaunch always does print_variables(), but it should really * exec the child program instead if a child program was specified. For now * we just exit if this conflict arises. */ if (runprog) { fprintf (stderr, "Currently --autolaunch does not support running a program\n"); exit (1); } verbose ("Autolaunch enabled (using X11).\n"); if (!exit_with_session) { verbose ("--exit-with-session automatically enabled\n"); exit_with_session = TRUE; } if (!x11_init ()) { fprintf (stderr, "Autolaunch error: X11 initialization failed.\n"); exit (1); } if (!x11_get_address (&address, &pid, &wid)) { fprintf (stderr, "Autolaunch error: X11 communication error.\n"); exit (1); } if (address != NULL) { verbose ("dbus-daemon is already running. Returning existing parameters.\n"); print_variables (address, pid, wid, c_shell_syntax, bourne_shell_syntax, binary_syntax); exit (0); } #endif } if (pipe (bus_pid_to_launcher_pipe) < 0 || pipe (bus_address_to_launcher_pipe) < 0 || pipe (bus_pid_to_babysitter_pipe) < 0) { fprintf (stderr, "Failed to create pipe: %s\n", strerror (errno)); exit (1); } ret = fork (); if (ret < 0) { fprintf (stderr, "Failed to fork: %s\n", strerror (errno)); exit (1); } if (ret == 0) { /* Child */ #define MAX_FD_LEN 64 char write_pid_fd_as_string[MAX_FD_LEN]; char write_address_fd_as_string[MAX_FD_LEN]; if (close_stderr) do_close_stderr (); verbose ("=== Babysitter's intermediate parent created\n"); /* Fork once more to create babysitter */ ret = fork (); if (ret < 0) { fprintf (stderr, "Failed to fork: %s\n", strerror (errno)); exit (1); } if (ret > 0) { /* In babysitter */ verbose ("=== Babysitter's intermediate parent continues\n"); close (bus_pid_to_launcher_pipe[READ_END]); close (bus_pid_to_launcher_pipe[WRITE_END]); close (bus_address_to_launcher_pipe[READ_END]); close (bus_address_to_launcher_pipe[WRITE_END]); close (bus_pid_to_babysitter_pipe[WRITE_END]); /* babysit() will fork *again* * and will also reap the pre-forked bus * daemon */ babysit (exit_with_session, ret, bus_pid_to_babysitter_pipe[READ_END]); exit (0); } verbose ("=== Bus exec process created\n"); /* Now we are the bus process (well, almost; * dbus-daemon itself forks again) */ close (bus_pid_to_launcher_pipe[READ_END]); close (bus_address_to_launcher_pipe[READ_END]); close (bus_pid_to_babysitter_pipe[READ_END]); close (bus_pid_to_babysitter_pipe[WRITE_END]); sprintf (write_pid_fd_as_string, "%d", bus_pid_to_launcher_pipe[WRITE_END]); sprintf (write_address_fd_as_string, "%d", bus_address_to_launcher_pipe[WRITE_END]); verbose ("Calling exec()\n"); #ifdef DBUS_BUILD_TESTS /* exec from testdir */ if (getenv("DBUS_USE_TEST_BINARY") != NULL) { execl (TEST_BUS_BINARY, TEST_BUS_BINARY, "--fork", "--print-pid", write_pid_fd_as_string, "--print-address", write_address_fd_as_string, config_file ? "--config-file" : "--session", config_file, /* has to be last in this varargs list */ NULL); fprintf (stderr, "Failed to execute test message bus daemon %s: %s. Will try again with the system path.\n", TEST_BUS_BINARY, strerror (errno)); } #endif /* DBUS_BUILD_TESTS */ execl (DBUS_DAEMONDIR"/dbus-daemon", DBUS_DAEMONDIR"/dbus-daemon", "--fork", "--print-pid", write_pid_fd_as_string, "--print-address", write_address_fd_as_string, config_file ? "--config-file" : "--session", config_file, /* has to be last in this varargs list */ NULL); fprintf (stderr, "Failed to execute message bus daemon %s: %s. Will try again without full path.\n", DBUS_DAEMONDIR"/dbus-daemon", strerror (errno)); /* * If it failed, try running without full PATH. Note this is needed * because the build process builds the run-with-tmp-session-bus.conf * file and the dbus-daemon will not be in the install location during * build time. */ execlp ("dbus-daemon", "dbus-daemon", "--fork", "--print-pid", write_pid_fd_as_string, "--print-address", write_address_fd_as_string, config_file ? "--config-file" : "--session", config_file, /* has to be last in this varargs list */ NULL); fprintf (stderr, "Failed to execute message bus daemon: %s\n", strerror (errno)); exit (1); } else { /* Parent */ #define MAX_PID_LEN 64 pid_t bus_pid; char bus_address[MAX_ADDR_LEN]; char buf[MAX_PID_LEN]; char *end; long wid = 0; long val; int ret2; verbose ("=== Parent dbus-launch continues\n"); close (bus_pid_to_launcher_pipe[WRITE_END]); close (bus_address_to_launcher_pipe[WRITE_END]); close (bus_pid_to_babysitter_pipe[READ_END]); verbose ("Waiting for babysitter's intermediate parent\n"); /* Immediately reap parent of babysitter * (which was created just for us to reap) */ if (do_waitpid (ret) < 0) { fprintf (stderr, "Failed to waitpid() for babysitter intermediate process: %s\n", strerror (errno)); exit (1); } verbose ("Reading address from bus\n"); /* Read the pipe data, print, and exit */ switch (read_line (bus_address_to_launcher_pipe[READ_END], bus_address, MAX_ADDR_LEN)) { case READ_STATUS_OK: break; case READ_STATUS_EOF: fprintf (stderr, "EOF in dbus-launch reading address from bus daemon\n"); exit (1); break; case READ_STATUS_ERROR: fprintf (stderr, "Error in dbus-launch reading address from bus daemon: %s\n", strerror (errno)); exit (1); break; } close (bus_address_to_launcher_pipe[READ_END]); verbose ("Reading PID from daemon\n"); /* Now read data */ switch (read_line (bus_pid_to_launcher_pipe[READ_END], buf, MAX_PID_LEN)) { case READ_STATUS_OK: break; case READ_STATUS_EOF: fprintf (stderr, "EOF reading PID from bus daemon\n"); exit (1); break; case READ_STATUS_ERROR: fprintf (stderr, "Error reading PID from bus daemon: %s\n", strerror (errno)); exit (1); break; } end = NULL; val = strtol (buf, &end, 0); if (buf == end || end == NULL) { fprintf (stderr, "Failed to parse bus PID \"%s\": %s\n", buf, strerror (errno)); exit (1); } bus_pid = val; close (bus_pid_to_launcher_pipe[READ_END]); #ifdef DBUS_BUILD_X11 /* FIXME the runprog == NULL is broken - we need to launch the runprog with the existing bus, * instead of just doing print_variables() if there's an existing bus. */ if (xdisplay != NULL && runprog == NULL) { ret2 = x11_save_address (bus_address, bus_pid, &wid); if (ret2 == 0) { /* another window got added. Return its address */ char *address; pid_t pid; long wid; if (x11_get_address (&address, &pid, &wid) && address != NULL) { verbose ("dbus-daemon is already running. Returning existing parameters.\n"); print_variables (address, pid, wid, c_shell_syntax, bourne_shell_syntax, binary_syntax); free (address); bus_pid_to_kill = bus_pid; kill_bus_and_exit (0); } /* if failed, fall through */ } if (ret2 <= 0) { fprintf (stderr, "Error saving bus information.\n"); bus_pid_to_kill = bus_pid; kill_bus_and_exit (1); } } #endif /* Forward the pid to the babysitter */ write_pid (bus_pid_to_babysitter_pipe[WRITE_END], bus_pid); close (bus_pid_to_babysitter_pipe[WRITE_END]); if (runprog) { char *envvar; char **args; envvar = malloc (strlen ("DBUS_SESSION_BUS_ADDRESS=") + strlen (bus_address) + 1); args = malloc (sizeof (char *) * ((argc-remaining_args)+2)); if (envvar == NULL || args == NULL) goto oom; args[0] = xstrdup (runprog); if (!args[0]) goto oom; for (i = 1; i <= (argc-remaining_args); i++) { size_t len = strlen (argv[remaining_args+i-1])+1; args[i] = malloc (len); if (!args[i]) goto oom; strncpy (args[i], argv[remaining_args+i-1], len); } args[i] = NULL; strcpy (envvar, "DBUS_SESSION_BUS_ADDRESS="); strcat (envvar, bus_address); putenv (envvar); execvp (runprog, args); fprintf (stderr, "Couldn't exec %s: %s\n", runprog, strerror (errno)); exit (1); } else { print_variables (bus_address, bus_pid, wid, c_shell_syntax, bourne_shell_syntax, binary_syntax); } verbose ("dbus-launch exiting\n"); fflush (stdout); fflush (stderr); close (1); close (2); exit (0); } return 0; oom: fprintf (stderr, "Out of memory!"); exit (1); }
static char * get_session_file (void) { static const char prefix[] = "/" DBUS_DIR "/" DBUS_SESSION_BUS_DIR "/"; const char *machine; const char *home; char *display; char *result; char *p; machine = get_machine_uuid (); if (machine == NULL) return NULL; display = xstrdup (getenv ("DISPLAY")); if (display == NULL) { verbose ("X11 integration disabled because X11 is not running\n"); return NULL; } /* remove the screen part of the display name */ p = strrchr (display, ':'); if (p != NULL) { for ( ; *p; ++p) { if (*p == '.') { *p = '\0'; break; } } } /* Note that we leave the hostname in the display most of the * time. The idea is that we want to be per-(machine,display,user) * triplet to be extra-sure we get a bus we can connect to. Ideally * we'd recognize when the hostname matches the machine we're on in * all cases; we do try to drop localhost and localhost.localdomain * as a special common case so that alternate spellings of DISPLAY * don't result in extra bus instances. * * We also kill the ":" if there's nothing in front of it. This * avoids an ugly double underscore in the filename. */ remove_prefix (display, "localhost.localdomain:"); remove_prefix (display, "localhost:"); remove_prefix (display, ":"); /* replace the : in the display with _ if the : is still there. * use _ instead of - since it can't be in hostnames. */ for (p = display; *p; ++p) { if (*p == ':') *p = '_'; } home = get_homedir (); result = malloc (strlen (home) + strlen (prefix) + strlen (machine) + strlen (display) + 2); if (result == NULL) { /* out of memory */ free (display); return NULL; } strcpy (result, home); strcat (result, prefix); strcat (result, machine); strcat (result, "-"); strcat (result, display); free (display); verbose ("session file: %s\n", result); return result; }