summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRalf Habacker <ralf.habacker@freenet.de>2015-11-18 23:35:46 +0100
committerRalf Habacker <ralf.habacker@freenet.de>2018-10-25 18:24:04 +0000
commitb0c0652005ce6892dd359f1b098dbdec9fb7455f (patch)
tree0e006251d6f504bb013691349080aaa784af9ae7
parentf7e9b8a7379ce28e68bf1bd57e6f8d30602b938d (diff)
downloaddbus-b0c0652005ce6892dd359f1b098dbdec9fb7455f.tar.gz
Add Windows implementation of dbus-run-session tool
Bug: https://gitlab.freedesktop.org/dbus/dbus/issues/135 Signed-off-by: Ralf Habacker <ralf.habacker@freenet.de> Reviewed-by: Simon McVittie <smcv@collabora.com>
-rw-r--r--cmake/config.h.cmake1
-rw-r--r--cmake/tools/CMakeLists.txt8
-rw-r--r--dbus/dbus-spawn-win.c17
-rw-r--r--dbus/dbus-sysdeps-util-win.c13
-rw-r--r--dbus/dbus-sysdeps-win.h7
-rw-r--r--tools/Makefile.am7
-rw-r--r--tools/dbus-run-session.c422
7 files changed, 328 insertions, 147 deletions
diff --git a/cmake/config.h.cmake b/cmake/config.h.cmake
index 1c66118e..fd193b76 100644
--- a/cmake/config.h.cmake
+++ b/cmake/config.h.cmake
@@ -242,6 +242,7 @@
#cmakedefine DBUS_USER "@DBUS_USER@"
#cmakedefine DBUS_TEST_USER "@DBUS_TEST_USER@"
+#cmakedefine DBUS_TEST_EXEC "@DBUS_TEST_EXEC@"
// system type defines
#if defined(_WIN32) || defined(_WIN64) || defined (_WIN32_WCE)
diff --git a/cmake/tools/CMakeLists.txt b/cmake/tools/CMakeLists.txt
index 64997fdc..704e3a49 100644
--- a/cmake/tools/CMakeLists.txt
+++ b/cmake/tools/CMakeLists.txt
@@ -130,11 +130,9 @@ add_executable(dbus-monitor ${dbus_monitor_SOURCES})
target_link_libraries(dbus-monitor ${DBUS_LIBRARIES})
install(TARGETS dbus-monitor ${INSTALL_TARGETS_DEFAULT_ARGS})
-if(NOT WIN32)
- add_executable(dbus-run-session ${dbus_run_session_SOURCES})
- target_link_libraries(dbus-run-session ${DBUS_LIBRARIES})
- install(TARGETS dbus-run-session ${INSTALL_TARGETS_DEFAULT_ARGS})
-endif()
+add_executable(dbus-run-session ${dbus_run_session_SOURCES})
+target_link_libraries(dbus-run-session ${DBUS_INTERNAL_LIBRARIES})
+install(TARGETS dbus-run-session ${INSTALL_TARGETS_DEFAULT_ARGS})
# 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 cc5bfc3b..aa54ba7d 100644
--- a/dbus/dbus-spawn-win.c
+++ b/dbus/dbus-spawn-win.c
@@ -543,8 +543,10 @@ 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;
@@ -566,6 +568,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
@@ -595,7 +606,7 @@ babysitter (void *parameter)
_dbus_verbose ("babysitter: spawning %s\n", sitter->log_name);
PING();
- handle = spawn_program (sitter->log_name, sitter->argv, sitter->envp);
+ handle = _dbus_spawn_program (sitter->log_name, sitter->argv, sitter->envp);
PING();
if (handle != INVALID_HANDLE_VALUE)
diff --git a/dbus/dbus-sysdeps-util-win.c b/dbus/dbus-sysdeps-util-win.c
index a5c3bba6..5aad2a86 100644
--- a/dbus/dbus-sysdeps-util-win.c
+++ b/dbus/dbus-sysdeps-util-win.c
@@ -1674,3 +1674,16 @@ void
_dbus_daemon_report_stopping (void)
{
}
+
+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);
+}
diff --git a/dbus/dbus-sysdeps-win.h b/dbus/dbus-sysdeps-win.h
index b8861a1f..57495cf7 100644
--- a/dbus/dbus-sysdeps-win.h
+++ b/dbus/dbus-sysdeps-win.h
@@ -46,7 +46,9 @@ const char* _dbus_win_error_from_last_error (void);
dbus_bool_t _dbus_win_startup_winsock (void);
void _dbus_win_warn_win_error (const char *message,
unsigned long code);
-
+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
@@ -90,6 +92,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 cfce4348..f3450030 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -16,6 +16,7 @@ AM_LDFLAGS = @R_DYNAMIC_LDFLAG@
bin_PROGRAMS = \
dbus-launch \
dbus-monitor \
+ dbus-run-session \
dbus-send \
dbus-test-tool \
dbus-update-activation-environment \
@@ -24,7 +25,6 @@ bin_PROGRAMS = \
if DBUS_UNIX
bin_PROGRAMS += \
dbus-cleanup-sockets \
- dbus-run-session \
dbus-uuidgen \
$(NULL)
endif
@@ -57,6 +57,8 @@ dbus_launch_SOURCES= \
tool-common.c \
tool-common.h \
$(NULL)
+endif
+
dbus_launch_CPPFLAGS = \
$(AM_CPPFLAGS) \
$(NULL)
@@ -69,9 +71,8 @@ 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
dbus_cleanup_sockets_SOURCES= \
dbus-cleanup-sockets.c
diff --git a/tools/dbus-run-session.c b/tools/dbus-run-session.c
index 6b93997e..57daa977 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 <thiago@kde.org>
* Copyright © 2011-2012 Nokia Corporation
+ * Copyright © 2018 Ralf Habacker
*
* Licensed under the Academic Free License version 2.1
*
@@ -33,9 +34,13 @@
#include <unistd.h>
#include <sys/types.h>
+#ifdef DBUS_UNIX
#include <sys/wait.h>
#include <signal.h>
-
+#else
+#include <dbus/dbus-internals.h>
+#include <dbus/dbus-sysdeps-win.h>
+#endif
#include "dbus/dbus.h"
#include "dbus/dbus-internals.h"
@@ -93,6 +98,7 @@ version (void)
"Copyright (C) 2003-2006 Red Hat, Inc.\n"
"Copyright (C) 2006 Thiago Macieira\n"
"Copyright © 2011-2012 Nokia Corporation\n"
+ "Copyright © 2018 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",
@@ -100,6 +106,7 @@ version (void)
exit (0);
}
+#ifndef DBUS_WIN
static void oom (void) _DBUS_GNUC_NORETURN;
static void
@@ -210,143 +217,16 @@ exec_app (int prog_arg, char **argv)
exit (1);
}
-int
-main (int argc, char **argv)
+static int
+run_session (const char *dbus_daemon,
+ const char *config_file,
+ char *bus_address,
+ char **argv,
+ int prog_arg)
{
- 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)
- {
- const char *arg = argv[i];
-
- if (requires_arg)
- {
- const char **arg_dest;
-
- assert (prev_arg != NULL);
-
- if (strcmp (prev_arg, "--config-file") == 0)
- {
- arg_dest = &config_file;
- }
- else if (strcmp (prev_arg, "--dbus-daemon") == 0)
- {
- arg_dest = &dbus_daemon;
- }
- else
- {
- /* shouldn't happen */
- fprintf (stderr, "%s: internal error: %s not fully implemented\n",
- me, prev_arg);
- return 127;
- }
-
- if (*arg_dest != NULL)
- {
- fprintf (stderr, "%s: %s given twice\n", me, prev_arg);
- return 127;
- }
-
- *arg_dest = arg;
- requires_arg = 0;
- prev_arg = arg;
- ++i;
- continue;
- }
-
- if (strcmp (arg, "--help") == 0 ||
- strcmp (arg, "-h") == 0 ||
- strcmp (arg, "-?") == 0)
- {
- usage (0);
- }
- else if (strcmp (arg, "--version") == 0)
- {
- version ();
- }
- else if (strstr (arg, "--config-file=") == arg)
- {
- const char *file;
-
- if (config_file != NULL)
- {
- fprintf (stderr, "%s: --config-file given twice\n", me);
- return 127;
- }
-
- file = strchr (arg, '=');
- ++file;
-
- config_file = file;
- }
- else if (strstr (arg, "--dbus-daemon=") == arg)
- {
- const char *file;
-
- if (dbus_daemon != NULL)
- {
- fprintf (stderr, "%s: --dbus-daemon given twice\n", me);
- return 127;
- }
-
- file = strchr (arg, '=');
- ++file;
-
- dbus_daemon = file;
- }
- else if (strcmp (arg, "--config-file") == 0 ||
- strcmp (arg, "--dbus-daemon") == 0)
- {
- requires_arg = 1;
- }
- else if (arg[0] == '-')
- {
- if (strcmp (arg, "--") != 0)
- {
- fprintf (stderr, "%s: option '%s' is unknown\n", me, arg);
- return 127;
- }
- else
- {
- prog_arg = i + 1;
- break;
- }
- }
- else
- {
- prog_arg = i;
- break;
- }
-
- prev_arg = arg;
- ++i;
- }
-
- /* "dbus-run-session" and "dbus-run-session ... --" are not allowed:
- * there must be something to run */
- if (prog_arg < 1 || prog_arg >= argc)
- {
- fprintf (stderr, "%s: a non-option argument is required\n", me);
- return 127;
- }
-
- if (requires_arg)
- {
- fprintf (stderr, "%s: option '%s' requires an argument\n", me, prev_arg);
- return 127;
- }
-
- if (dbus_daemon == NULL)
- dbus_daemon = "dbus-daemon";
+ int bus_address_pipe[2] = { 0, 0 };
if (pipe (bus_address_pipe) < 0)
{
@@ -482,3 +362,275 @@ main (int argc, char **argv)
return 0;
}
+#else
+static int
+run_session (const char *dbus_daemon,
+ const char *config_file,
+ char *bus_address,
+ char **argv,
+ int prog_arg)
+{
+ char *dbus_daemon_argv[3];
+ int ret = 127;
+ HANDLE server_handle = NULL;
+ HANDLE app_handle = NULL;
+ DWORD exit_code;
+ DBusString argv_strings[4];
+ DBusString address;
+ char **env = NULL;
+ DBusHashTable *env_table = NULL;
+ long sec,usec;
+ dbus_bool_t result = TRUE;
+ char *key = NULL;
+ char *value = NULL;
+
+ 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 (&address))
+ result = FALSE;
+ if (!result)
+ goto out;
+
+ /* run dbus daemon */
+ _dbus_get_real_time (&sec, &usec);
+ /* On Windows it's difficult to make use of --print-address to
+ * convert a listenable address into a connectable address, so instead
+ * we tell the temporary dbus-daemon to use the Windows autolaunch
+ * mechanism, with a unique scope that is shared by this dbus-daemon,
+ * the app process that defines its lifetime, and any other child
+ * processes they might have. */
+ _dbus_string_append_printf (&address, "autolaunch:scope=dbus-tmp-session-%ld%ld-" DBUS_PID_FORMAT, sec, usec, _dbus_getpid ());
+ _dbus_string_append_printf (&argv_strings[0], "%s", dbus_daemon);
+ if (config_file != NULL)
+ _dbus_string_append_printf (&argv_strings[1], "--config-file=%s", config_file);
+ else
+ _dbus_string_append_printf (&argv_strings[1], "--session");
+ _dbus_string_append_printf (&argv_strings[2], "--address=%s", _dbus_string_get_const_data (&address));
+ 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;
+
+ 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,
+ dbus_free,
+ dbus_free);
+ if (!_dbus_hash_table_from_array (env_table, env, '='))
+ {
+ goto out;
+ }
+
+ /* replace DBUS_SESSION_BUS_ADDRESS in environment */
+ if (!_dbus_string_steal_data (&address, &value))
+ goto out;
+
+ key = _dbus_strdup ("DBUS_SESSION_BUS_ADDRESS");
+
+ if (key == NULL)
+ goto out;
+
+ if (_dbus_hash_table_insert_string (env_table, key, value))
+ {
+ /* env_table took ownership, do not free separately */
+ key = NULL;
+ value = NULL;
+ }
+ else
+ {
+ /* we still own key and value, the cleanup code will free them */
+ goto out;
+ }
+
+ _dbus_hash_table_remove_string (env_table, "DBUS_STARTER_ADDRESS");
+ _dbus_hash_table_remove_string (env_table, "DBUS_STARTER_BUS_TYPE");
+ _dbus_hash_table_remove_string (env_table, "DBUS_SESSION_BUS_PID");
+ _dbus_hash_table_remove_string (env_table, "DBUS_SESSION_BUS_WINDOWID");
+
+ dbus_free_string_array (env);
+ 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);
+ if (server_handle != NULL)
+ CloseHandle (server_handle);
+ if (app_handle != NULL)
+ CloseHandle (app_handle);
+ _dbus_string_free (&argv_strings[0]);
+ _dbus_string_free (&argv_strings[1]);
+ _dbus_string_free (&argv_strings[2]);
+ _dbus_string_free (&address);
+ dbus_free_string_array (env);
+ if (env_table != NULL)
+ _dbus_hash_table_unref (env_table);
+ dbus_free (key);
+ dbus_free (value);
+ return ret;
+}
+#endif
+
+int
+main (int argc, char **argv)
+{
+ int prog_arg = 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;
+
+ while (i < argc)
+ {
+ const char *arg = argv[i];
+
+ if (requires_arg)
+ {
+ const char **arg_dest;
+
+ assert (prev_arg != NULL);
+
+ if (strcmp (prev_arg, "--config-file") == 0)
+ {
+ arg_dest = &config_file;
+ }
+ else if (strcmp (prev_arg, "--dbus-daemon") == 0)
+ {
+ arg_dest = &dbus_daemon;
+ }
+ else
+ {
+ /* shouldn't happen */
+ fprintf (stderr, "%s: internal error: %s not fully implemented\n",
+ me, prev_arg);
+ return 127;
+ }
+
+ if (*arg_dest != NULL)
+ {
+ fprintf (stderr, "%s: %s given twice\n", me, prev_arg);
+ return 127;
+ }
+
+ *arg_dest = arg;
+ requires_arg = 0;
+ prev_arg = arg;
+ ++i;
+ continue;
+ }
+
+ if (strcmp (arg, "--help") == 0 ||
+ strcmp (arg, "-h") == 0 ||
+ strcmp (arg, "-?") == 0)
+ {
+ usage (0);
+ }
+ else if (strcmp (arg, "--version") == 0)
+ {
+ version ();
+ }
+ else if (strstr (arg, "--config-file=") == arg)
+ {
+ const char *file;
+
+ if (config_file != NULL)
+ {
+ fprintf (stderr, "%s: --config-file given twice\n", me);
+ return 127;
+ }
+
+ file = strchr (arg, '=');
+ ++file;
+
+ config_file = file;
+ }
+ else if (strstr (arg, "--dbus-daemon=") == arg)
+ {
+ const char *file;
+
+ if (dbus_daemon != NULL)
+ {
+ fprintf (stderr, "%s: --dbus-daemon given twice\n", me);
+ return 127;
+ }
+
+ file = strchr (arg, '=');
+ ++file;
+
+ dbus_daemon = file;
+ }
+ else if (strcmp (arg, "--config-file") == 0 ||
+ strcmp (arg, "--dbus-daemon") == 0)
+ {
+ requires_arg = 1;
+ }
+ else if (arg[0] == '-')
+ {
+ if (strcmp (arg, "--") != 0)
+ {
+ fprintf (stderr, "%s: option '%s' is unknown\n", me, arg);
+ return 127;
+ }
+ else
+ {
+ prog_arg = i + 1;
+ break;
+ }
+ }
+ else
+ {
+ prog_arg = i;
+ break;
+ }
+
+ prev_arg = arg;
+ ++i;
+ }
+
+ /* "dbus-run-session" and "dbus-run-session ... --" are not allowed:
+ * there must be something to run */
+ if (prog_arg < 1 || prog_arg >= argc)
+ {
+ fprintf (stderr, "%s: a non-option argument is required\n", me);
+ return 127;
+ }
+
+ if (requires_arg)
+ {
+ fprintf (stderr, "%s: option '%s' requires an argument\n", me, prev_arg);
+ return 127;
+ }
+
+ if (dbus_daemon == NULL)
+ dbus_daemon = "dbus-daemon";
+
+ return run_session (dbus_daemon, config_file, bus_address, argv, prog_arg);
+}