From 21e311cc1226c3cc74f0be3da2051c849f7473cc Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Wed, 18 Nov 2015 23:35:46 +0100 Subject: [PATCH 5/8] Add windows implementation of dbus-run-session helper tool. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=92899 Signed-off-by: Ralf Habacker --- cmake/tools/CMakeLists.txt | 3 + dbus/dbus-hash.c | 96 ++++++------ dbus/dbus-hash.h | 2 + dbus/dbus-spawn-win.c | 18 ++- dbus/dbus-sysdeps-win.c | 11 ++ dbus/dbus-sysdeps-win.h | 9 +- tools/Makefile.am | 4 +- tools/dbus-run-session.c | 361 +++++++++++++++++++++++++++++---------------- 8 files changed, 328 insertions(+), 176 deletions(-) diff --git a/cmake/tools/CMakeLists.txt b/cmake/tools/CMakeLists.txt index 6a2e999..bf979aa 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-internal) + # create the /var/lib/dbus directory for dbus-uuidgen install(DIRECTORY DESTINATION var/lib/dbus) diff --git a/dbus/dbus-hash.c b/dbus/dbus-hash.c index 26ac4c2..acaef6c 100644 --- a/dbus/dbus-hash.c +++ b/dbus/dbus-hash.c @@ -336,6 +336,59 @@ _dbus_hash_table_new (DBusHashType type, return table; } +/** + * Destroy a hash table + * @param table the hash table to destroy + */ +dbus_bool_t +_dbus_hash_table_free (DBusHashTable *table) +{ + if (table == NULL) + return FALSE; +#if 0 + DBusHashEntry *entry; + DBusHashEntry *next; + int i; + + /* Free the entries in the table. */ + for (i = 0; i < table->n_buckets; i++) + { + entry = table->buckets[i]; + while (entry != NULL) + { + next = entry->next; + + free_entry (table, entry); + + entry = next; + } + } +#else + DBusHashEntry *entry; + int i; + + /* Free the entries in the table. */ + for (i = 0; i < table->n_buckets; i++) + { + entry = table->buckets[i]; + while (entry != NULL) + { + free_entry_data (table, entry); + + entry = entry->next; + } + } + /* We can do this very quickly with memory pools ;-) */ + _dbus_mem_pool_free (table->entry_pool); +#endif + + /* Free the bucket array, if it was dynamically allocated. */ + if (table->buckets != table->static_buckets) + dbus_free (table->buckets); + + dbus_free (table); + return TRUE; +} /** * Increments the reference count for a hash table. @@ -364,48 +417,7 @@ _dbus_hash_table_unref (DBusHashTable *table) if (table->refcount == 0) { -#if 0 - DBusHashEntry *entry; - DBusHashEntry *next; - int i; - - /* Free the entries in the table. */ - for (i = 0; i < table->n_buckets; i++) - { - entry = table->buckets[i]; - while (entry != NULL) - { - next = entry->next; - - free_entry (table, entry); - - entry = next; - } - } -#else - DBusHashEntry *entry; - int i; - - /* Free the entries in the table. */ - for (i = 0; i < table->n_buckets; i++) - { - entry = table->buckets[i]; - while (entry != NULL) - { - free_entry_data (table, entry); - - entry = entry->next; - } - } - /* We can do this very quickly with memory pools ;-) */ - _dbus_mem_pool_free (table->entry_pool); -#endif - - /* Free the bucket array, if it was dynamically allocated. */ - if (table->buckets != table->static_buckets) - dbus_free (table->buckets); - - dbus_free (table); + _dbus_hash_table_free (table); } } diff --git a/dbus/dbus-hash.h b/dbus/dbus-hash.h index 93f717a..98e1ee4 100644 --- a/dbus/dbus-hash.h +++ b/dbus/dbus-hash.h @@ -75,6 +75,8 @@ DBUS_PRIVATE_EXPORT DBusHashTable* _dbus_hash_table_new (DBusHashType type, DBusFreeFunction key_free_function, DBusFreeFunction value_free_function); +DBUS_PRIVATE_EXPORT +dbus_bool_t _dbus_hash_table_free (DBusHashTable *table); DBusHashTable* _dbus_hash_table_ref (DBusHashTable *table); DBUS_PRIVATE_EXPORT void _dbus_hash_table_unref (DBusHashTable *table); diff --git a/dbus/dbus-spawn-win.c b/dbus/dbus-spawn-win.c index 43fafd5..d92d67d 100644 --- a/dbus/dbus-spawn-win.c +++ b/dbus/dbus-spawn-win.c @@ -536,8 +536,8 @@ build_env_string (char** envp) return compose_string (envp, '\0'); } -static HANDLE -spawn_program (char* name, char** argv, char** envp) +HANDLE +_dbus_spawn_program (const char* name, char** argv, char** envp) { PROCESS_INFORMATION pi = { NULL, 0, 0, 0 }; STARTUPINFOA si; @@ -559,6 +559,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 @@ -576,7 +585,6 @@ spawn_program (char* name, char** argv, char** envp) return pi.hProcess; } - static DWORD __stdcall babysitter (void *parameter) { @@ -589,8 +597,8 @@ babysitter (void *parameter) _dbus_verbose ("babysitter: spawning %s\n", sitter->log_name); PING(); - sitter->child_handle = spawn_program (sitter->log_name, - sitter->argv, sitter->envp); + sitter->child_handle = _dbus_spawn_program (sitter->log_name, + sitter->argv, sitter->envp); PING(); if (sitter->child_handle == (HANDLE) -1) diff --git a/dbus/dbus-sysdeps-win.c b/dbus/dbus-sysdeps-win.c index 1a35a89..4f6ccf0 100644 --- a/dbus/dbus-sysdeps-win.c +++ b/dbus/dbus-sysdeps-win.c @@ -3569,6 +3569,17 @@ _dbus_win_warn_win_error (const char *message, dbus_error_free (&error); } +void +_dbus_win_stderr_win_error (const char *app, const char *message, unsigned long code) +{ + DBusError error; + + dbus_error_init (&error); + _dbus_win_set_error_from_win_error (&error, code); + fprintf (stderr, "%s: %s: %s\n", app, message, error.message); + dbus_error_free (&error); +} + /** * Removes a directory; Directory must be empty * diff --git a/dbus/dbus-sysdeps-win.h b/dbus/dbus-sysdeps-win.h index 0b5d8f0..1682fe9 100644 --- a/dbus/dbus-sysdeps-win.h +++ b/dbus/dbus-sysdeps-win.h @@ -44,9 +44,13 @@ DBUS_PRIVATE_EXPORT const char* _dbus_win_error_from_last_error (void); dbus_bool_t _dbus_win_startup_winsock (void); +DBUS_PRIVATE_EXPORT void _dbus_win_warn_win_error (const char *message, unsigned long code); - +DBUS_PRIVATE_EXPORT +void _dbus_win_stderr_win_error (const char *app, + const char *message, + unsigned long code); DBUS_PRIVATE_EXPORT char * _dbus_win_error_string (int error_number); DBUS_PRIVATE_EXPORT @@ -92,6 +96,9 @@ void _dbus_threads_windows_ensure_ctor_linked (void); DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_getsid(char **sid, dbus_pid_t process_id); + +HANDLE _dbus_spawn_program (const char* name, char** argv, char** envp); + #endif /** @} end of sysdeps-win.h */ diff --git a/tools/Makefile.am b/tools/Makefile.am index 56a0b7f..8425252 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -12,6 +12,7 @@ AM_LDFLAGS = @R_DYNAMIC_LDFLAG@ bin_PROGRAMS = \ dbus-launch \ dbus-monitor \ + dbus-run-session \ dbus-send \ dbus-test-tool \ dbus-update-activation-environment \ @@ -20,7 +21,6 @@ bin_PROGRAMS = \ if DBUS_UNIX bin_PROGRAMS += \ dbus-cleanup-sockets \ - dbus-run-session \ dbus-uuidgen \ $(NULL) endif @@ -65,7 +65,7 @@ dbus_run_session_SOURCES = \ dbus-run-session.c dbus_run_session_LDADD = \ - $(top_builddir)/dbus/libdbus-1.la \ + $(top_builddir)/dbus/libdbus-internal.la \ $(NULL) endif diff --git a/tools/dbus-run-session.c b/tools/dbus-run-session.c index 105ab3b..6cab198 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 © 2016 Ralf Habacker * * Licensed under the Academic Free License version 2.1 * @@ -33,9 +34,13 @@ #include #include +#ifdef DBUS_UNIX #include #include - +#else +#include +#include +#endif #include "dbus/dbus.h" #define MAX_ADDR_LEN 512 @@ -88,6 +93,7 @@ version (void) "Copyright (C) 2003-2006 Red Hat, Inc.\n" "Copyright (C) 2006 Thiago Macieira\n" "Copyright © 2011-2012 Nokia Corporation\n" + "Copyright © 2016 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", @@ -102,6 +108,7 @@ oom (void) exit (1); } +#ifndef DBUS_WIN typedef enum { READ_STATUS_OK, /**< Read succeeded */ @@ -200,20 +207,243 @@ exec_app (int prog_arg, char **argv) strerror (errno)); exit (1); } +#endif + +static int +run_session(const char *dbus_daemon, const char *config_file, const 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 *dbus_daemon_argv[4]; + int ret = 127; + HANDLE server_handle; + HANDLE app_handle; + DWORD exit_code; + DBusString argv_strings[4]; + char **env = NULL; + DBusHashTable *env_table; + long sec,usec; + dbus_bool_t result = TRUE; + + if (!_dbus_string_init (&argv_strings[0])) + result = FALSE; + if (!_dbus_string_init (&argv_strings[1])) + result = FALSE; + if (!_dbus_string_init (&argv_strings[2])) + result = FALSE; + if (!_dbus_string_init (&argv_strings[3])) + result = FALSE; + if (result == FALSE) + goto out; + + /* run dbus daemon */ + _dbus_get_real_time (&sec, &usec); + _dbus_string_append_printf (&argv_strings[3], "autolaunch:scope=dbus-tmp-session-%ld%ld-" DBUS_PID_FORMAT, sec, usec, _dbus_getpid()); + _dbus_string_append_printf (&argv_strings[0], "%s", dbus_daemon); + _dbus_string_append_printf (&argv_strings[1], "--config-file=%s", config_file); + _dbus_string_append_printf (&argv_strings[2], "--address=%s", _dbus_string_get_const_data (&argv_strings[3])); + dbus_daemon_argv[0] = _dbus_string_get_data (&argv_strings[0]); + dbus_daemon_argv[1] = _dbus_string_get_data (&argv_strings[1]); + dbus_daemon_argv[2] = _dbus_string_get_data (&argv_strings[2]); + dbus_daemon_argv[3] = NULL; + _DBUS_STATIC_ASSERT (_DBUS_N_ELEMENTS (dbus_daemon_argv) == 4); + + server_handle = _dbus_spawn_program (dbus_daemon, dbus_daemon_argv, NULL); + if (!server_handle) + { + _dbus_win_stderr_win_error (me, "Could not start dbus daemon", GetLastError ()); + goto out; + } + + /* run app */ + env = _dbus_get_environment (); + env_table = _dbus_hash_table_new (DBUS_HASH_STRING, + (DBusFreeFunction) dbus_free, + (DBusFreeFunction) dbus_free); + if (!_dbus_hash_table_from_array (env_table, env, '=')) + { + goto out; + } + dbus_free_string_array (env); + + if (!_dbus_hash_table_insert_string (env_table, "DBUS_SESSION_BUS_ADDRESS", _dbus_string_get_data (&argv_strings[3]))) + goto out; + + if (!_dbus_hash_table_remove_string (env_table, "DBUS_STARTER_ADDRESS")) + goto out; + + if (!_dbus_hash_table_remove_string (env_table, "DBUS_STARTER_BUS_TYPE")) + goto out; + + env = _dbus_hash_table_to_array (env_table, '='); + if (!env) + goto out; + + app_handle = _dbus_spawn_program (argv[prog_arg], argv + prog_arg, env); + if (!app_handle) + { + _dbus_win_stderr_win_error (me, "unable to start child process", GetLastError ()); + goto out; + } + + WaitForSingleObject (app_handle, INFINITE); + if (!GetExitCodeProcess (app_handle, &exit_code)) + { + _dbus_win_stderr_win_error (me, "could not fetch exit code", GetLastError ()); + goto out; + } + ret = exit_code; + +out: + TerminateProcess (server_handle, 0); + CloseHandle (server_handle); + CloseHandle (app_handle); + _dbus_string_free (&argv_strings[0]); + _dbus_string_free (&argv_strings[1]); + _dbus_string_free (&argv_strings[2]); + _dbus_string_free (&argv_strings[3]); + dbus_free_string_array (env); + _dbus_hash_table_free (env_table); + 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 +569,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); } -- 2.6.2