chiark / gitweb /
systemd-stdio-bridge: make it socket-activatable and usable as kdbus bridge
authorDaniel Mack <zonque@gmail.com>
Fri, 15 Nov 2013 17:05:27 +0000 (18:05 +0100)
committerDaniel Mack <zonque@gmail.com>
Fri, 29 Nov 2013 13:06:50 +0000 (14:06 +0100)
Augment systemd-stdio-bridge a bit to make it a 1:1 bridge from legacy
DBus clients to kdbus. In particular,

 * allow setting the bus path of the upstream bus as command line
   argument
 * use sd_listen_fds() for systemd's socket activation
 * omit calling sd_bus_negotiate_fds() when upstream bus is kdbus
 * reply to bus send errors with proper dbus error messages
 * treat -ECONNRESET as expected end-of-connection condition

src/stdio-bridge/stdio-bridge.c

index 07218e9..9c49e0e 100644 (file)
@@ -28,6 +28,7 @@
 #include <errno.h>
 #include <sys/poll.h>
 #include <stddef.h>
+#include <getopt.h>
 
 #include "log.h"
 #include "util.h"
 #include "bus-internal.h"
 #include "bus-message.h"
 #include "bus-util.h"
+#include "build.h"
+
+#define DEFAULT_BUS_PATH "unix:path=/run/dbus/system_bus_socket"
+
+const char *arg_bus_path = DEFAULT_BUS_PATH;
+
+static int help(void) {
+
+        printf("%s [OPTIONS...]\n\n"
+               "STDIO or socket-activatable proxy to a given DBus endpoint.\n\n"
+               "  -h --help              Show this help\n"
+               "     --version           Show package version\n"
+               "     --bus-path=PATH     Path to the kernel bus (default: %s)\n",
+               program_invocation_short_name, DEFAULT_BUS_PATH);
+
+        return 0;
+}
+
+static int parse_argv(int argc, char *argv[]) {
+
+        enum {
+                ARG_VERSION = 0x100,
+        };
+
+        static const struct option options[] = {
+                { "help",            no_argument,       NULL, 'h'     },
+                { "bus-path",        required_argument, NULL, 'p'     },
+                { NULL,              0,                 NULL, 0       }
+        };
+
+        int c;
+
+        assert(argc >= 0);
+        assert(argv);
+
+        while ((c = getopt_long(argc, argv, "hsup:", options, NULL)) >= 0) {
+
+                switch (c) {
+
+                case 'h':
+                        help();
+                        return 0;
+
+                case ARG_VERSION:
+                        puts(PACKAGE_STRING);
+                        puts(SYSTEMD_FEATURES);
+                        return 0;
+
+                case '?':
+                        return -EINVAL;
+
+                case 'p':
+                        arg_bus_path = optarg;
+                        break;
+
+                default:
+                        log_error("Unknown option code %c", c);
+                        return -EINVAL;
+                }
+        }
+
+        return 1;
+}
 
 int main(int argc, char *argv[]) {
         _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
         sd_id128_t server_id;
         bool is_unix;
-        int r;
-
-        if (argc > 1) {
-                log_error("This program takes no argument.");
-                return EXIT_FAILURE;
-        }
+        int r, in_fd, out_fd;
 
         log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
         log_parse_environment();
         log_open();
 
+        r = parse_argv(argc, argv);
+        if (r <= 0)
+                goto finish;
+
+        r = sd_listen_fds(0);
+        if (r == 0) {
+                in_fd = STDIN_FILENO;
+                out_fd = STDOUT_FILENO;
+        } else if (r == 1) {
+                in_fd = SD_LISTEN_FDS_START;
+                out_fd = SD_LISTEN_FDS_START;
+        } else {
+                log_error("Illegal number of file descriptors passed\n");
+                goto finish;
+        }
+
         is_unix =
-                sd_is_socket(STDIN_FILENO, AF_UNIX, 0, 0) > 0 &&
-                sd_is_socket(STDOUT_FILENO, AF_UNIX, 0, 0) > 0;
+                sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
+                sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
 
         r = sd_bus_new(&a);
         if (r < 0) {
@@ -63,7 +138,7 @@ int main(int argc, char *argv[]) {
                 goto finish;
         }
 
-        r = sd_bus_set_address(a, "unix:path=/run/dbus/system_bus_socket");
+        r = sd_bus_set_address(a, arg_bus_path);
         if (r < 0) {
                 log_error("Failed to set address to connect to: %s", strerror(-r));
                 goto finish;
@@ -93,7 +168,7 @@ int main(int argc, char *argv[]) {
                 goto finish;
         }
 
-        r = sd_bus_set_fd(b, STDIN_FILENO, STDOUT_FILENO);
+        r = sd_bus_set_fd(b, in_fd, out_fd);
         if (r < 0) {
                 log_error("Failed to set fds: %s", strerror(-r));
                 goto finish;
@@ -131,7 +206,7 @@ int main(int argc, char *argv[]) {
 
                 r = sd_bus_process(a, &m);
                 if (r < 0) {
-                        log_error("Failed to process bus: %s", strerror(-r));
+                        log_error("Failed to process bus a: %s", strerror(-r));
                         goto finish;
                 }
 
@@ -148,7 +223,10 @@ int main(int argc, char *argv[]) {
 
                 r = sd_bus_process(b, &m);
                 if (r < 0) {
-                        log_error("Failed to process bus: %s", strerror(-r));
+                        /* treat 'connection reset by peer' as clean exit condition */
+                        if (r == -ECONNRESET)
+                                r = 0;
+
                         goto finish;
                 }