From b7917663804d45a112700dc6112a2def378a0f74 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Wed, 18 Nov 2015 23:35:46 +0100 Subject: [PATCH] Add windows implementation of dbus-run-session helper tool. The implementation requires a dbus-daemon configured with 'autolaunch:scope=*install-path' listen address, which let the client find the session bus address from shared memory. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=92899 --- cmake/tools/CMakeLists.txt | 3 + dbus/dbus-spawn-win.c | 19 ++- dbus/dbus-spawn.h | 3 + tools/dbus-run-session.c | 320 +++++++++++++++++++++++++++------------------ 4 files changed, 217 insertions(+), 128 deletions(-) diff --git a/cmake/tools/CMakeLists.txt b/cmake/tools/CMakeLists.txt index 6a2e999..75cc240 100644 --- a/cmake/tools/CMakeLists.txt +++ b/cmake/tools/CMakeLists.txt @@ -77,5 +77,8 @@ add_executable(dbus-monitor ${dbus_monitor_SOURCES}) target_link_libraries(dbus-monitor ${DBUS_LIBRARIES}) install_targets(/bin dbus-monitor ) +add_executable(dbus-run-session ../../tools/dbus-run-session.c) +target_link_libraries(dbus-run-session ${DBUS_LIBRARIES} dbus-internal) + # create the /var/lib/dbus directory for dbus-uuidgen install(DIRECTORY DESTINATION var/lib/dbus) diff --git a/dbus/dbus-spawn-win.c b/dbus/dbus-spawn-win.c index c58bf3c..31f2b92 100644 --- a/dbus/dbus-spawn-win.c +++ b/dbus/dbus-spawn-win.c @@ -538,8 +538,9 @@ build_env_string (char** envp) return compose_string (envp, '\0'); } -static HANDLE -spawn_program (char* name, char** argv, char** envp) + +HANDLE +_dbus_spawn_program (char* name, char** argv, char** envp) { PROCESS_INFORMATION pi = { NULL, 0, 0, 0 }; STARTUPINFOA si; @@ -561,6 +562,15 @@ spawn_program (char* name, char** argv, char** envp) memset (&si, 0, sizeof (si)); si.cb = sizeof (si); + +#ifdef DBUS_ENABLE_VERBOSE_MODE + { + char *s = compose_string (envp, ';'); + _dbus_verbose ("spawning '%s'' with args: '%s' env: '%s'\n", name, arg_string, s); + free (s); + } +#endif + #ifdef DBUS_WINCE result = CreateProcessA (name, arg_string, NULL, NULL, FALSE, 0, #else @@ -578,6 +588,11 @@ spawn_program (char* name, char** argv, char** envp) return pi.hProcess; } +static HANDLE +spawn_program (char* name, char** argv, char** envp) +{ + return _dbus_spawn_program (name, argv, envp); +} static DWORD __stdcall babysitter (void *parameter) diff --git a/dbus/dbus-spawn.h b/dbus/dbus-spawn.h index e6baae9..7786da0 100644 --- a/dbus/dbus-spawn.h +++ b/dbus/dbus-spawn.h @@ -63,6 +63,9 @@ dbus_bool_t _dbus_babysitter_set_watch_functions (DBusBabysitter *si void *data, DBusFreeFunction free_data_function); +HANDLE +_dbus_spawn_program (char* name, char** argv, char** envp); + DBUS_END_DECLS #endif /* DBUS_SPAWN_H */ diff --git a/tools/dbus-run-session.c b/tools/dbus-run-session.c index 105ab3b..503c5d2 100644 --- a/tools/dbus-run-session.c +++ b/tools/dbus-run-session.c @@ -4,6 +4,7 @@ * Copyright © 2003-2006 Red Hat, Inc. * Copyright © 2006 Thiago Macieira * Copyright © 2011-2012 Nokia Corporation + * Copyright © 2015 Ralf Habacker * * Licensed under the Academic Free License version 2.1 * @@ -33,10 +34,12 @@ #include #include +#ifdef DBUS_UNIX #include #include - +#endif #include "dbus/dbus.h" +#include #define MAX_ADDR_LEN 512 #define PIPE_READ_END 0 @@ -88,6 +91,7 @@ version (void) "Copyright (C) 2003-2006 Red Hat, Inc.\n" "Copyright (C) 2006 Thiago Macieira\n" "Copyright © 2011-2012 Nokia Corporation\n" + "Copyright © 2015 Ralf Habacker\n" "\n" "This is free software; see the source for copying conditions.\n" "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n", @@ -201,19 +205,204 @@ exec_app (int prog_arg, char **argv) exit (1); } +static int +run_session(char *dbus_daemon, char *config_file, char *bus_address, char **argv, int prog_arg) +{ +#ifdef DBUS_UNIX + pid_t bus_pid; + pid_t app_pid; + int bus_address_pipe[2] = { 0, 0 }; + + if (pipe (bus_address_pipe) < 0) + { + fprintf (stderr, "%s: failed to create pipe: %s\n", me, strerror (errno)); + return 127; + } + + bus_pid = fork (); + + if (bus_pid < 0) + { + fprintf (stderr, "%s: failed to fork: %s\n", me, strerror (errno)); + return 127; + } + + if (bus_pid == 0) + { + /* child */ + exec_dbus_daemon (dbus_daemon, bus_address_pipe, config_file); + /* not reached */ + return 127; + } + + close (bus_address_pipe[PIPE_WRITE_END]); + + switch (read_line (bus_address_pipe[PIPE_READ_END], bus_address, MAX_ADDR_LEN)) + { + case READ_STATUS_OK: + break; + + case READ_STATUS_EOF: + fprintf (stderr, "%s: EOF reading address from bus daemon\n", me); + return 127; + break; + + case READ_STATUS_ERROR: + fprintf (stderr, "%s: error reading address from bus daemon: %s\n", + me, strerror (errno)); + return 127; + break; + } + + close (bus_address_pipe[PIPE_READ_END]); + + if (!dbus_setenv ("DBUS_SESSION_BUS_ADDRESS", bus_address) || + !dbus_setenv ("DBUS_SESSION_BUS_PID", NULL) || + !dbus_setenv ("DBUS_SESSION_BUS_WINDOWID", NULL) || + !dbus_setenv ("DBUS_STARTER_ADDRESS", NULL) || + !dbus_setenv ("DBUS_STARTER_BUS_TYPE", NULL)) + oom (); + + app_pid = fork (); + + if (app_pid < 0) + { + fprintf (stderr, "%s: failed to fork: %s\n", me, strerror (errno)); + return 127; + } + + if (app_pid == 0) + { + /* child */ + exec_app (prog_arg, argv); + /* not reached */ + return 127; + } + + while (1) + { + int child_status; + pid_t child_pid = waitpid (-1, &child_status, 0); + + if (child_pid == (pid_t) -1) + { + int errsv = errno; + + if (errsv == EINTR) + continue; + + /* shouldn't happen: the only other documented errors are ECHILD, + * which shouldn't happen because we terminate when all our children + * have died, and EINVAL, which would indicate programming error */ + fprintf (stderr, "%s: waitpid() failed: %s\n", me, strerror (errsv)); + return 127; + } + else if (child_pid == bus_pid) + { + /* no need to kill it, now */ + bus_pid = 0; + + if (WIFEXITED (child_status)) + fprintf (stderr, "%s: dbus-daemon exited with code %d\n", + me, WEXITSTATUS (child_status)); + else if (WIFSIGNALED (child_status)) + fprintf (stderr, "%s: dbus-daemon terminated by signal %d\n", + me, WTERMSIG (child_status)); + else + fprintf (stderr, "%s: dbus-daemon died or something\n", me); + } + else if (child_pid == app_pid) + { + if (bus_pid != 0) + kill (bus_pid, SIGTERM); + + if (WIFEXITED (child_status)) + return WEXITSTATUS (child_status); + + /* if it died from a signal, behave like sh(1) */ + if (WIFSIGNALED (child_status)) + return 128 + WTERMSIG (child_status); + + /* I give up (this should never be reached) */ + fprintf (stderr, "%s: child process died or something\n", me); + return 127; + } + else + { + fprintf (stderr, "%s: ignoring unknown child process %ld\n", me, + (long) child_pid); + } + } + + return 0; +#else + char buffer[2][MAX_PATH]; + char *argv2[5]; + char *env[3]; + int ret = 127; + char *s; + HANDLE hProcess; + HANDLE hChild; + DWORD exitCode; + + snprintf (buffer[0], sizeof(buffer[0]), "%s", dbus_daemon); + snprintf (buffer[1], sizeof(buffer[1]), "--config-file=%s", config_file); + argv2[0] = buffer[0]; + argv2[1] = buffer[1]; + argv2[2] = 0; + + /* use env from parent */ + env[0] = 0; + + hProcess = _dbus_spawn_program (dbus_daemon, argv2, env); + if (!hProcess) + { + fprintf (stderr, "%s: could not be started error=%ld\n", dbus_daemon, GetLastError ()); + goto out; + } + + snprintf (buffer[0], sizeof(buffer[0]), "DBUS_SESSION_BUS_ADDRESS=autolaunch:scope=*install-path"); + env[0] = buffer[0]; + env[1] = 0; + + s = getenv("DBUS_VERBOSE"); + if (s) + { + snprintf (buffer[1], sizeof (buffer[1]), "DBUS_VERBOSE=%s", s && *s == '1' ? "1" : "0"); + env[1] = buffer[1]; + env[2] = 0; + } + + hChild = _dbus_spawn_program (argv[prog_arg], argv + prog_arg, env); + if (!hChild) + { + fprintf (stderr, "%s: child process died or something error=%ld\n", argv[prog_arg], GetLastError ()); + goto out; + } + + WaitForSingleObject (hChild, INFINITE); + if (!GetExitCodeProcess (hChild, &exitCode)) + goto out; + ret = exitCode; + +out: + TerminateProcess (hProcess, 0); + CloseHandle (hProcess); + CloseHandle (hChild); + return ret; +#endif +} + int main (int argc, char **argv) { int prog_arg = 0; - int bus_address_pipe[2] = { 0, 0 }; const char *config_file = NULL; const char *dbus_daemon = NULL; char bus_address[MAX_ADDR_LEN] = { 0 }; const char *prev_arg = NULL; int i = 1; int requires_arg = 0; - pid_t bus_pid; - pid_t app_pid; while (i < argc) { @@ -339,126 +528,5 @@ main (int argc, char **argv) if (dbus_daemon == NULL) dbus_daemon = "dbus-daemon"; - if (pipe (bus_address_pipe) < 0) - { - fprintf (stderr, "%s: failed to create pipe: %s\n", me, strerror (errno)); - return 127; - } - - bus_pid = fork (); - - if (bus_pid < 0) - { - fprintf (stderr, "%s: failed to fork: %s\n", me, strerror (errno)); - return 127; - } - - if (bus_pid == 0) - { - /* child */ - exec_dbus_daemon (dbus_daemon, bus_address_pipe, config_file); - /* not reached */ - return 127; - } - - close (bus_address_pipe[PIPE_WRITE_END]); - - switch (read_line (bus_address_pipe[PIPE_READ_END], bus_address, MAX_ADDR_LEN)) - { - case READ_STATUS_OK: - break; - - case READ_STATUS_EOF: - fprintf (stderr, "%s: EOF reading address from bus daemon\n", me); - return 127; - break; - - case READ_STATUS_ERROR: - fprintf (stderr, "%s: error reading address from bus daemon: %s\n", - me, strerror (errno)); - return 127; - break; - } - - close (bus_address_pipe[PIPE_READ_END]); - - if (!dbus_setenv ("DBUS_SESSION_BUS_ADDRESS", bus_address) || - !dbus_setenv ("DBUS_SESSION_BUS_PID", NULL) || - !dbus_setenv ("DBUS_SESSION_BUS_WINDOWID", NULL) || - !dbus_setenv ("DBUS_STARTER_ADDRESS", NULL) || - !dbus_setenv ("DBUS_STARTER_BUS_TYPE", NULL)) - oom (); - - app_pid = fork (); - - if (app_pid < 0) - { - fprintf (stderr, "%s: failed to fork: %s\n", me, strerror (errno)); - return 127; - } - - if (app_pid == 0) - { - /* child */ - exec_app (prog_arg, argv); - /* not reached */ - return 127; - } - - while (1) - { - int child_status; - pid_t child_pid = waitpid (-1, &child_status, 0); - - if (child_pid == (pid_t) -1) - { - int errsv = errno; - - if (errsv == EINTR) - continue; - - /* shouldn't happen: the only other documented errors are ECHILD, - * which shouldn't happen because we terminate when all our children - * have died, and EINVAL, which would indicate programming error */ - fprintf (stderr, "%s: waitpid() failed: %s\n", me, strerror (errsv)); - return 127; - } - else if (child_pid == bus_pid) - { - /* no need to kill it, now */ - bus_pid = 0; - - if (WIFEXITED (child_status)) - fprintf (stderr, "%s: dbus-daemon exited with code %d\n", - me, WEXITSTATUS (child_status)); - else if (WIFSIGNALED (child_status)) - fprintf (stderr, "%s: dbus-daemon terminated by signal %d\n", - me, WTERMSIG (child_status)); - else - fprintf (stderr, "%s: dbus-daemon died or something\n", me); - } - else if (child_pid == app_pid) - { - if (bus_pid != 0) - kill (bus_pid, SIGTERM); - - if (WIFEXITED (child_status)) - return WEXITSTATUS (child_status); - - /* if it died from a signal, behave like sh(1) */ - if (WIFSIGNALED (child_status)) - return 128 + WTERMSIG (child_status); - - /* I give up (this should never be reached) */ - fprintf (stderr, "%s: child process died or something\n", me); - return 127; - } - else - { - fprintf (stderr, "%s: ignoring unknown child process %ld\n", me, - (long) child_pid); - } - } - - return 0; + return run_session (dbus_daemon, config_file, bus_address, argv, prog_arg); } -- 1.8.4.5