diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/Makefile.am | 18 | ||||
-rw-r--r-- | tools/dbus-launch-win.c | 11 | ||||
-rw-r--r-- | tools/dbus-launch.c | 187 | ||||
-rw-r--r-- | tools/dbus-monitor.c | 51 | ||||
-rw-r--r-- | tools/dbus-print-message.c | 10 | ||||
-rw-r--r-- | tools/dbus-run-session.c | 464 | ||||
-rw-r--r-- | tools/dbus-send.c | 73 | ||||
-rwxr-xr-x | tools/run-with-tmp-session-bus.sh | 52 | ||||
-rw-r--r-- | tools/strtoll.c | 1 | ||||
-rw-r--r-- | tools/strtoull.c | 1 |
10 files changed, 747 insertions, 121 deletions
diff --git a/tools/Makefile.am b/tools/Makefile.am index 08b90234..73d95fcf 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -2,6 +2,7 @@ configdir=$(sysconfdir)/dbus-1 AM_CPPFLAGS = \ -I$(top_srcdir) \ + $(DBUS_STATIC_BUILD_CPPFLAGS) \ $(DBUS_X_CFLAGS) \ -DDBUS_COMPILATION \ -DDBUS_MACHINE_UUID_FILE=\""$(localstatedir)/lib/dbus/machine-id"\" \ @@ -19,6 +20,7 @@ bin_PROGRAMS = \ if DBUS_UNIX bin_PROGRAMS += \ dbus-cleanup-sockets \ + dbus-run-session \ dbus-uuidgen \ $(NULL) endif @@ -42,6 +44,13 @@ dbus_launch_SOURCES= \ dbus-launch.c \ dbus-launch-x11.c \ dbus-launch.h + +dbus_run_session_SOURCES = \ + dbus-run-session.c + +dbus_run_session_LDADD = \ + $(top_builddir)/dbus/libdbus-1.la \ + $(NULL) endif dbus_cleanup_sockets_SOURCES= \ @@ -71,6 +80,9 @@ EXTRA_DIST = run-with-tmp-session-bus.sh strtoll.c strtoull.c CLEANFILES = \ run-with-tmp-session-bus.conf -#create the /var/lib/data directory for dbus-uuidgen -localstatelibdir = $(localstatedir)/lib/dbus -localstatelib_DATA = +# create the /var/lib/dbus directory for dbus-uuidgen +install-data-local: + $(MKDIR_P) $(DESTDIR)$(localstatedir)/lib/dbus + +installcheck-local: + test -d $(DESTDIR)$(localstatedir)/lib/dbus diff --git a/tools/dbus-launch-win.c b/tools/dbus-launch-win.c index ea4bf0dd..d899010a 100644 --- a/tools/dbus-launch-win.c +++ b/tools/dbus-launch-win.c @@ -130,9 +130,10 @@ main (int argc, char **argv) fprintf (stderr, "%ls %ls\n", dbusDaemonPath, command); #else command[0] = L'\0'; - /* Windows CE has a different interpretation of cmdline: Start with argv[1]. */ - wcscpy_s (command, sizeof (command), dbusDaemonPath); - wcscat_s (command, sizeof (command), L" --session"); + /* Windows cmdline starts with path, which can contain spaces. */ + wcscpy_s (command, sizeof (command), L"\""); + wcscat_s (command, sizeof (command), dbusDaemonPath); + wcscat_s (command, sizeof (command), L"\" --session"); if (verbose) fprintf (stderr, "%ls\n", command); #endif @@ -158,8 +159,8 @@ main (int argc, char **argv) if (result == 0) { if (verbose) - fprintf (stderr, "Could not start " DBUS_DAEMON_NAME ". error=%d\n", - GetLastError ()); + fprintf (stderr, "Could not start " DBUS_DAEMON_NAME ". error=%u\n", + (unsigned)GetLastError ()); return 4; } diff --git a/tools/dbus-launch.c b/tools/dbus-launch.c index bbaac2c3..7ecee63e 100644 --- a/tools/dbus-launch.c +++ b/tools/dbus-launch.c @@ -43,6 +43,47 @@ extern Display *xdisplay; #endif +/* PROCESSES + * + * If you are in a shell and run "dbus-launch myapp", here is what happens: + * + * shell [*] + * \- main() --exec--> myapp[*] + * \- "intermediate parent" + * \- bus-runner --exec--> dbus-daemon --fork + * \- babysitter[*] \- final dbus-daemon[*] + * + * Processes marked [*] survive the initial flurry of activity. + * + * If you run "dbus-launch --sh-syntax" then the diagram is the same, except + * that main() prints variables and exits 0 instead of exec'ing myapp. + * + * PIPES + * + * dbus-daemon --print-pid -> bus_pid_to_launcher_pipe -> main + * dbus-daemon --print-address -> bus_address_to_launcher_pipe -> main + * main -> bus_pid_to_babysitter_pipe -> babysitter + * + * The intermediate parent looks pretty useless at first glance. Its purpose + * is to avoid the bus-runner becoming a zombie: when the intermediate parent + * terminates, the bus-runner and babysitter are reparented to init, which + * reaps them if they have finished. We can't rely on main() to reap arbitrary + * children because it might exec myapp, after which it can't be relied on to + * reap its children. We *can* rely on main() to reap the intermediate parent, + * because that happens before it execs myapp. + * + * It's unclear why dbus-daemon needs to fork, but we explicitly tell it to + * for some reason, then wait for it. If we left it undefined, a forking + * dbus-daemon would get the parent process reparented to init and reaped + * when the intermediate parent terminated, and a non-forking dbus-daemon + * would get reparented to init and carry on there. + * + * myapp is exec'd by the process that initially ran main() so that it's + * the shell's child, so the shell knows how to do job control and stuff. + * This is desirable for the "dbus-launch an application" use-case, less so + * for the "dbus-launch a test suite in an isolated session" use-case. + */ + static char* machine_uuid = NULL; const char* @@ -64,6 +105,7 @@ save_machine_uuid (const char *uuid_arg) machine_uuid = xstrdup (uuid_arg); } +#ifdef DBUS_BUILD_X11 #define UUID_MAXLEN 40 /* Read the machine uuid from file if needed. Returns TRUE if machine_uuid is * set after this function */ @@ -90,7 +132,7 @@ read_machine_uuid_if_needed (void) goto out; /* rstrip the read uuid */ - while (len > 31 && isspace(uuid[len - 1])) + while (len > 31 && isspace((int) uuid[len - 1])) len--; if (len != 32) @@ -105,12 +147,13 @@ out: fclose(f); return ret; } - +#endif /* DBUS_BUILD_X11 */ void verbose (const char *format, ...) { +#ifdef DBUS_ENABLE_VERBOSE_MODE va_list args; static int verbose = TRUE; static int verbose_initted = FALSE; @@ -135,12 +178,16 @@ verbose (const char *format, va_start (args, format); vfprintf (stderr, format, args); va_end (args); +#endif /* DBUS_ENABLE_VERBOSE_MODE */ } static void usage (int ecode) { - fprintf (stderr, "dbus-launch [--version] [--help] [--sh-syntax] [--csh-syntax] [--auto-syntax] [--exit-with-session]\n"); + fprintf (stderr, "dbus-launch [--version] [--help] [--sh-syntax]" + " [--csh-syntax] [--auto-syntax] [--binary-syntax] [--close-stderr]" + " [--exit-with-session] [--autolaunch=MACHINEID]" + " [--config-file=FILENAME] [PROGRAM] [ARGS...]\n"); exit (ecode); } @@ -175,6 +222,26 @@ xstrdup (const char *str) return copy; } +static char * +concat2 (const char *a, + const char *b) +{ + size_t la, lb; + char *ret; + + la = strlen (a); + lb = strlen (b); + + ret = malloc (la + lb + 1); + + if (ret == NULL) + return NULL; + + memcpy (ret, a, la); + memcpy (ret + la, b, lb + 1); + return ret; +} + typedef enum { READ_STATUS_OK, /**< Read succeeded */ @@ -404,9 +471,7 @@ signal_handler (int sig) { switch (sig) { -#ifdef SIGHUP case SIGHUP: -#endif case SIGINT: case SIGTERM: got_sighup = TRUE; @@ -451,11 +516,20 @@ kill_bus_when_session_ends (void) else tty_fd = -1; - if (tty_fd >= 0) - verbose ("stdin isatty(), monitoring it\n"); + if (x_fd >= 0) + { + verbose ("session lifetime is defined by X, not monitoring stdin\n"); + tty_fd = -1; + } + else if (tty_fd >= 0) + { + verbose ("stdin isatty(), monitoring it\n"); + } else - verbose ("stdin was not a TTY, not monitoring it\n"); - + { + verbose ("stdin was not a TTY, not monitoring it\n"); + } + if (tty_fd < 0 && x_fd < 0) { fprintf (stderr, "No terminal on standard input and no X display; cannot attach message bus to session lifetime\n"); @@ -583,6 +657,7 @@ babysit (int exit_with_session, s = getenv ("DBUS_DEBUG_OUTPUT"); if (s == NULL || *s == '\0') dup2 (dev_null_fd, 2); + close (dev_null_fd); } else { @@ -704,31 +779,35 @@ pass_info (const char *runprog, const char *bus_address, pid_t bus_pid, if (envvar == NULL || args == NULL) goto oom; - args[0] = xstrdup (runprog); + 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; + 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]) + { + while (i > 1) + free (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); + 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); + execvp (runprog, args); + fprintf (stderr, "Couldn't exec %s: %s\n", runprog, strerror (errno)); + exit (1); } else { print_variables (bus_address, bus_pid, bus_wid, c_shell_syntax, - bourne_shell_syntax, binary_syntax); + bourne_shell_syntax, binary_syntax); } verbose ("dbus-launch exiting\n"); @@ -1049,24 +1128,41 @@ main (int argc, char **argv) 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 */ +#ifdef DBUS_ENABLE_EMBEDDED_TESTS + { + const char *test_daemon; + /* exec from testdir */ + if (getenv ("DBUS_USE_TEST_BINARY") != NULL && + (test_daemon = getenv ("DBUS_TEST_DAEMON")) != NULL) + { + if (config_file == NULL && getenv ("DBUS_TEST_DATA") != NULL) + { + config_file = concat2 (getenv ("DBUS_TEST_DATA"), + "/valid-config-files/session.conf"); + + if (config_file == NULL) + { + fprintf (stderr, "Out of memory\n"); + exit (1); + } + } + + execl (test_daemon, + test_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 test message bus daemon %s: %s.\n", + test_daemon, strerror (errno)); + exit (1); + } + } + #endif /* DBUS_ENABLE_EMBEDDED_TESTS */ execl (DBUS_DAEMONDIR"/dbus-daemon", DBUS_DAEMONDIR"/dbus-daemon", @@ -1111,7 +1207,6 @@ main (int argc, char **argv) char *end; long wid = 0; long val; - int ret2; verbose ("=== Parent dbus-launch continues\n"); @@ -1185,6 +1280,8 @@ main (int argc, char **argv) #ifdef DBUS_ENABLE_X11_AUTOLAUNCH if (xdisplay != NULL) { + int ret2; + verbose("Saving x11 address\n"); ret2 = x11_save_address (bus_address, bus_pid, &wid); /* Only get an existing dbus session when autolaunching */ diff --git a/tools/dbus-monitor.c b/tools/dbus-monitor.c index a4b54782..ff8390d7 100644 --- a/tools/dbus-monitor.c +++ b/tools/dbus-monitor.c @@ -106,6 +106,9 @@ monitor_filter_func (DBusConnection *connection, #ifdef __APPLE__ #define PROFILE_TIMED_FORMAT "%s\t%lu\t%d" +#elif defined(__NetBSD__) +#include <inttypes.h> +#define PROFILE_TIMED_FORMAT "%s\t%" PRId64 "\t%d" #else #define PROFILE_TIMED_FORMAT "%s\t%lu\t%lu" #endif @@ -310,7 +313,7 @@ main (int argc, char *argv[]) filters = (char **) realloc (filters, numFilters * sizeof (char *)); if (filters == NULL) oom ("adding a new filter slot"); - filters[j] = (char *) malloc (filter_len * sizeof (char *)); + filters[j] = (char *) malloc (filter_len); if (filters[j] == NULL) oom ("adding a new filter"); snprintf (filters[j], filter_len, "%s,%s", EAVESDROPPING_RULE, arg); @@ -364,41 +367,45 @@ main (int argc, char *argv[]) if (numFilters) { + size_t offset = 0; for (i = 0; i < j; i++) { - dbus_bus_add_match (connection, filters[i], &error); - if (dbus_error_is_set (&error)) + dbus_bus_add_match (connection, filters[i] + offset, &error); + if (dbus_error_is_set (&error) && i == 0 && offset == 0) + { + /* We might be talking to a pre-1.5.6 dbus-daemon + * which wouldn't understand eavesdrop=true. + * If this works, carry on with offset > 0 + * on the remaining iterations. */ + offset = strlen (EAVESDROPPING_RULE) + 1; + dbus_error_free (&error); + dbus_bus_add_match (connection, filters[i] + offset, &error); + } + + if (dbus_error_is_set (&error)) { fprintf (stderr, "Failed to setup match \"%s\": %s\n", filters[i], error.message); dbus_error_free (&error); exit (1); } - free(filters[i]); + free(filters[i]); } } else { dbus_bus_add_match (connection, - EAVESDROPPING_RULE ",type='signal'", - &error); - if (dbus_error_is_set (&error)) - goto lose; - dbus_bus_add_match (connection, - EAVESDROPPING_RULE ",type='method_call'", - &error); + EAVESDROPPING_RULE, + &error); if (dbus_error_is_set (&error)) - goto lose; - dbus_bus_add_match (connection, - EAVESDROPPING_RULE ",type='method_return'", - &error); - if (dbus_error_is_set (&error)) - goto lose; - dbus_bus_add_match (connection, - EAVESDROPPING_RULE ",type='error'", - &error); - if (dbus_error_is_set (&error)) - goto lose; + { + dbus_error_free (&error); + dbus_bus_add_match (connection, + "", + &error); + if (dbus_error_is_set (&error)) + goto lose; + } } if (!dbus_connection_add_filter (connection, filter_func, NULL, NULL)) { diff --git a/tools/dbus-print-message.c b/tools/dbus-print-message.c index 75d00aca..e0dd2da6 100644 --- a/tools/dbus-print-message.c +++ b/tools/dbus-print-message.c @@ -346,7 +346,15 @@ print_iter (DBusMessageIter *iter, dbus_bool_t literal, int depth) printf("}\n"); break; } - + + case DBUS_TYPE_UNIX_FD: + { + int fd; + dbus_message_iter_get_basic (iter, &fd); + printf ("unix fd %d\n", fd); + break; + } + default: printf (" (dbus-monitor too dumb to decipher arg type '%c')\n", type); break; diff --git a/tools/dbus-run-session.c b/tools/dbus-run-session.c new file mode 100644 index 00000000..105ab3b4 --- /dev/null +++ b/tools/dbus-run-session.c @@ -0,0 +1,464 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-run-session.c - run a child process in its own session + * + * Copyright © 2003-2006 Red Hat, Inc. + * Copyright © 2006 Thiago Macieira <thiago@kde.org> + * Copyright © 2011-2012 Nokia Corporation + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include <config.h> + +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <sys/types.h> +#include <sys/wait.h> +#include <signal.h> + +#include "dbus/dbus.h" + +#define MAX_ADDR_LEN 512 +#define PIPE_READ_END 0 +#define PIPE_WRITE_END 1 + +/* PROCESSES + * + * If you are in a shell and run "dbus-run-session myapp", here is what + * happens (compare and contrast with dbus-launch): + * + * shell + * \- dbus-run-session myapp + * \- dbus-daemon --nofork --print-address --session + * \- myapp + * + * All processes are long-running. + * + * When myapp exits, dbus-run-session kills dbus-daemon and terminates. + * + * If dbus-daemon exits, dbus-run-session warns and continues to run. + * + * PIPES + * + * dbus-daemon --print-address -> bus_address_pipe -> d-r-s + */ + +static const char me[] = "dbus-run-session"; + +static void +usage (int ecode) +{ + fprintf (stderr, + "%s [OPTIONS] [--] PROGRAM [ARGUMENTS]\n" + "%s --version\n" + "%s --help\n" + "\n" + "Options:\n" + "--dbus-daemon=BINARY run BINARY instead of dbus-daemon\n" + "--config-file=FILENAME pass to dbus-daemon instead of --session\n" + "\n", + me, me, me); + exit (ecode); +} + +static void +version (void) +{ + printf ("%s %s\n" + "Copyright (C) 2003-2006 Red Hat, Inc.\n" + "Copyright (C) 2006 Thiago Macieira\n" + "Copyright © 2011-2012 Nokia Corporation\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", + me, VERSION); + exit (0); +} + +static void +oom (void) +{ + fprintf (stderr, "%s: out of memory\n", me); + exit (1); +} + +typedef enum +{ + READ_STATUS_OK, /**< Read succeeded */ + READ_STATUS_ERROR, /**< Some kind of error */ + READ_STATUS_EOF /**< EOF returned */ +} ReadStatus; + +static ReadStatus +read_line (int fd, + char *buf, + size_t maxlen) +{ + size_t bytes = 0; + ReadStatus retval; + + memset (buf, '\0', maxlen); + maxlen -= 1; /* ensure nul term */ + + retval = READ_STATUS_OK; + + while (1) + { + ssize_t chunk; + size_t to_read; + + again: + to_read = maxlen - bytes; + + if (to_read == 0) + break; + + chunk = read (fd, + buf + bytes, + to_read); + if (chunk < 0 && errno == EINTR) + goto again; + + if (chunk < 0) + { + retval = READ_STATUS_ERROR; + break; + } + else if (chunk == 0) + { + retval = READ_STATUS_EOF; + break; /* EOF */ + } + else /* chunk > 0 */ + bytes += chunk; + } + + if (retval == READ_STATUS_EOF && + bytes > 0) + retval = READ_STATUS_OK; + + /* whack newline */ + if (retval != READ_STATUS_ERROR && + bytes > 0 && + buf[bytes-1] == '\n') + buf[bytes-1] = '\0'; + + return retval; +} + +static void +exec_dbus_daemon (const char *dbus_daemon, + int bus_address_pipe[2], + const char *config_file) +{ + /* Child process, which execs dbus-daemon or dies trying */ +#define MAX_FD_LEN 64 + char write_address_fd_as_string[MAX_FD_LEN]; + + close (bus_address_pipe[PIPE_READ_END]); + + sprintf (write_address_fd_as_string, "%d", bus_address_pipe[PIPE_WRITE_END]); + + execlp (dbus_daemon, + dbus_daemon, + "--nofork", + "--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, "%s: failed to execute message bus daemon '%s': %s\n", + me, dbus_daemon, strerror (errno)); +} + +static void +exec_app (int prog_arg, char **argv) +{ + execvp (argv[prog_arg], argv + prog_arg); + + fprintf (stderr, "%s: failed to exec '%s': %s\n", me, argv[prog_arg], + strerror (errno)); + exit (1); +} + +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) + { + 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"; + + 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; +} diff --git a/tools/dbus-send.c b/tools/dbus-send.c index e403a587..d3ff2589 100644 --- a/tools/dbus-send.c +++ b/tools/dbus-send.c @@ -51,7 +51,7 @@ static const char *appname; static void usage (int ecode) { - fprintf (stderr, "Usage: %s [--help] [--system | --session | --address=ADDRESS] [--dest=NAME] [--type=TYPE] [--print-reply[=literal]] [--reply-timeout=MSEC] <destination object path> <message name> [contents ...]\n", appname); + fprintf (stderr, "Usage: %s [--help] [--system | --session | --bus=ADDRESS | --peer=ADDRESS] [--dest=NAME] [--type=TYPE] [--print-reply[=literal]] [--reply-timeout=MSEC] <destination object path> <message name> [contents ...]\n", appname); exit (ecode); } @@ -241,6 +241,7 @@ main (int argc, char *argv[]) int message_type = DBUS_MESSAGE_TYPE_SIGNAL; const char *type_str = NULL; const char *address = NULL; + int is_bus = FALSE; int session_or_system = FALSE; appname = argv[0]; @@ -266,34 +267,66 @@ main (int argc, char *argv[]) type = DBUS_BUS_SESSION; session_or_system = TRUE; } - else if (strstr (arg, "--address") == arg) + else if ((strstr (arg, "--bus=") == arg) || (strstr (arg, "--peer=") == arg) || (strstr (arg, "--address=") == arg)) { - address = strchr (arg, '='); - - if (address == NULL) + if (arg[2] == 'b') /* bus */ { - fprintf (stderr, "\"--address=\" requires an ADDRESS\n"); - usage (1); + is_bus = TRUE; + } + else if (arg[2] == 'p') /* peer */ + { + is_bus = FALSE; } - else + else /* address; keeping backwards compatibility */ + { + is_bus = FALSE; + } + + address = strchr (arg, '=') + 1; + + if (address[0] == '\0') { - address = address + 1; + fprintf (stderr, "\"--peer=\" and \"--bus=\" require an ADDRESS\n"); + usage (1); } } else if (strncmp (arg, "--print-reply", 13) == 0) { print_reply = TRUE; message_type = DBUS_MESSAGE_TYPE_METHOD_CALL; - if (*(arg + 13) != '\0') + if (strcmp (arg + 13, "=literal") == 0) print_reply_literal = TRUE; + else if (*(arg + 13) != '\0') + { + fprintf (stderr, "invalid value (%s) of \"--print-reply\"\n", arg + 13); + usage (1); + } } else if (strstr (arg, "--reply-timeout=") == arg) { + if (*(strchr (arg, '=') + 1) == '\0') + { + fprintf (stderr, "\"--reply-timeout=\" requires an MSEC\n"); + usage (1); + } reply_timeout = strtol (strchr (arg, '=') + 1, NULL, 10); + if (reply_timeout <= 0) + { + fprintf (stderr, "invalid value (%s) of \"--reply-timeout\"\n", + strchr (arg, '=') + 1); + usage (1); + } } else if (strstr (arg, "--dest=") == arg) - dest = strchr (arg, '=') + 1; + { + if (*(strchr (arg, '=') + 1) == '\0') + { + fprintf (stderr, "\"--dest=\" requires an NAME\n"); + usage (1); + } + dest = strchr (arg, '=') + 1; + } else if (strstr (arg, "--type=") == arg) type_str = strchr (arg, '=') + 1; else if (!strcmp(arg, "--help")) @@ -312,7 +345,7 @@ main (int argc, char *argv[]) if (session_or_system && (address != NULL)) { - fprintf (stderr, "\"--address\" may not be used with \"--system\" or \"--session\"\n"); + fprintf (stderr, "\"--peer\" and \"--bus\" may not be used with \"--system\" or \"--session\"\n"); usage (1); } @@ -330,6 +363,12 @@ main (int argc, char *argv[]) dbus_error_init (&error); + if (dest && !dbus_validate_bus_name (dest, &error)) + { + fprintf (stderr, "invalid value (%s) of \"--dest\"\n", dest); + usage (1); + } + if (address != NULL) { connection = dbus_connection_open (address, &error); @@ -348,6 +387,16 @@ main (int argc, char *argv[]) dbus_error_free (&error); exit (1); } + else if ((address != NULL) && is_bus) + { + if (!dbus_bus_register (connection, &error)) + { + fprintf (stderr, "Failed to register on connection to \"%s\" message bus: %s\n", + address, error.message); + dbus_error_free (&error); + exit (1); + } + } if (message_type == DBUS_MESSAGE_TYPE_METHOD_CALL) { diff --git a/tools/run-with-tmp-session-bus.sh b/tools/run-with-tmp-session-bus.sh index c39999fb..94ae8fc8 100755 --- a/tools/run-with-tmp-session-bus.sh +++ b/tools/run-with-tmp-session-bus.sh @@ -1,16 +1,15 @@ #! /bin/sh -SCRIPTNAME=$0 -WRAPPED_SCRIPT=$1 +SCRIPTNAME="$0" +WRAPPED_SCRIPT="$1" shift -die() +CONFIG_FILE=./tmp-session-bus.$$.conf + +die () { - if ! test -z "$DBUS_SESSION_BUS_PID" ; then - echo "killing message bus "$DBUS_SESSION_BUS_PID >&2 - kill -9 $DBUS_SESSION_BUS_PID - fi - echo $SCRIPTNAME: $* >&2 + echo "$SCRIPTNAME: $*" >&2 + rm -f "$CONFIG_FILE" exit 1 } @@ -18,10 +17,6 @@ if test -z "$DBUS_TOP_BUILDDIR" ; then die "Must set DBUS_TOP_BUILDDIR" fi -## convenient to be able to ctrl+C without leaking the message bus process -trap 'die "Received SIGINT"' INT - -CONFIG_FILE=./run-with-tmp-session-bus.conf SERVICE_DIR="$DBUS_TOP_BUILDDIR/test/data/valid-service-files" ESCAPED_SERVICE_DIR=`echo $SERVICE_DIR | sed -e 's/\//\\\\\\//g'` echo "escaped service dir is: $ESCAPED_SERVICE_DIR" >&2 @@ -50,27 +45,18 @@ export LD_LIBRARY_PATH unset DBUS_SESSION_BUS_ADDRESS unset DBUS_SESSION_BUS_PID -echo "Running $DBUS_TOP_BUILDDIR/tools/dbus-launch --sh-syntax --config-file=$CONFIG_FILE" >&2 - -DBUS_USE_TEST_BINARY=1 +# this does not actually affect dbus-run-session any more, but could be +# significant for dbus-launch as used by the autolaunch test +DBUS_USE_TEST_BINARY=1 export DBUS_USE_TEST_BINARY -eval `$DBUS_TOP_BUILDDIR/tools/dbus-launch --sh-syntax --config-file=$CONFIG_FILE` - -if test -z "$DBUS_SESSION_BUS_PID" ; then - die "Failed to launch message bus for test script to run" -fi - -echo "Started bus pid $DBUS_SESSION_BUS_PID at $DBUS_SESSION_BUS_ADDRESS" >&2 - -# Execute wrapped script -echo "Running $WRAPPED_SCRIPT $@" >&2 -$WRAPPED_SCRIPT "$@" || die "script \"$WRAPPED_SCRIPT\" failed" - -kill -TERM $DBUS_SESSION_BUS_PID || die "Message bus vanished! should not have happened" && echo "Killed daemon $DBUS_SESSION_BUS_PID" >&2 - -sleep 2 -## be sure it really died -kill -9 $DBUS_SESSION_BUS_PID > /dev/null 2>&1 || true +$DBUS_TOP_BUILDDIR/tools/dbus-run-session \ + --config-file="$CONFIG_FILE" \ + --dbus-daemon="$DBUS_TOP_BUILDDIR/bus/dbus-daemon" \ + -- \ + "$WRAPPED_SCRIPT" "$@" +error=$? -exit 0 +# clean up +rm -f "$CONFIG_FILE" +exit $error diff --git a/tools/strtoll.c b/tools/strtoll.c index e4f57701..7360c630 100644 --- a/tools/strtoll.c +++ b/tools/strtoll.c @@ -27,6 +27,7 @@ * SUCH DAMAGE. */ +#include "config.h" #include <limits.h> #ifdef HAVE_ERRNO_H diff --git a/tools/strtoull.c b/tools/strtoull.c index 459c5091..35595542 100644 --- a/tools/strtoull.c +++ b/tools/strtoull.c @@ -27,6 +27,7 @@ * SUCH DAMAGE. */ +#include "config.h" #include <limits.h> #ifdef HAVE_ERRNO_H |