[systemd-devel] [PATCH 7/7] systemd-stdio-bridge: make it socket-activatable and usable as kdbus bridge
Zbigniew Jędrzejewski-Szmek
zbyszek at in.waw.pl
Mon Nov 18 19:00:38 PST 2013
On Fri, Nov 15, 2013 at 07:32:23PM +0100, Daniel Mack wrote:
> 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 | 116 +++++++++++++++++++++++++++++++++-------
> 1 file changed, 98 insertions(+), 18 deletions(-)
>
> diff --git a/src/stdio-bridge/stdio-bridge.c b/src/stdio-bridge/stdio-bridge.c
> index 07218e9..f16a146 100644
> --- a/src/stdio-bridge/stdio-bridge.c
> +++ b/src/stdio-bridge/stdio-bridge.c
> @@ -28,6 +28,7 @@
> #include <errno.h>
> #include <sys/poll.h>
> #include <stddef.h>
> +#include <getopt.h>
>
> #include "log.h"
> #include "util.h"
> @@ -37,25 +38,99 @@
> #include "bus-internal.h"
> #include "bus-message.h"
> #include "bus-util.h"
> +#include "build.h"
> +
> +const char *arg_bus_path = "unix:path=/run/dbus/system_bus_socket";
> +
> +static int help(void) {
> +
> + printf("%s [OPTIONS...]\n\n"
> + "Query or change system hostname.\n\n"
> + " -h --help Show this help\n"
> + " --version Show package version\n"
> + " --bus-path Path to the kernel bus (default: %s)\n",
> + program_invocation_short_name, arg_bus_path);
This will give bogus information if --bus-path xxx --help is used.
> +
> + 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);
> + switch (r) {
> + case 0:
> + in_fd = STDIN_FILENO;
> + out_fd = STDOUT_FILENO;
> + break;
> + case 1:
> + in_fd = SD_LISTEN_FDS_START;
> + out_fd = SD_LISTEN_FDS_START;
> + break;
> + default:
> + goto finish;
> + }
We usually use if() cases for those things. And indeed, a switch
here won't work, because r > 1 must be treated as an error condtion
too.
> +
> 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,16 +138,18 @@ 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;
> }
>
> - r = sd_bus_negotiate_fds(a, is_unix);
> - if (r < 0) {
> - log_error("Failed to set FD negotiation: %s", strerror(-r));
> - goto finish;
> + if (!startswith(arg_bus_path, "kernel:")) {
> + r = sd_bus_negotiate_fds(a, is_unix);
> + if (r < 0) {
> + log_error("Failed to set FD negotiation: %s", strerror(-r));
> + goto finish;
> + }
> }
>
> r = sd_bus_start(a);
> @@ -93,7 +170,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,14 +208,14 @@ 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;
> }
>
> if (m) {
> r = sd_bus_send(b, m, NULL);
> if (r < 0) {
> - log_error("Failed to send message: %s", strerror(-r));
> + sd_bus_reply_method_errno(a, m, r, NULL);
> goto finish;
> }
> }
> @@ -148,14 +225,17 @@ 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;
> }
>
> if (m) {
> r = sd_bus_send(a, m, NULL);
> if (r < 0) {
> - log_error("Failed to send message: %s", strerror(-r));
> + sd_bus_reply_method_errno(b, m, r, NULL);
> goto finish;
> }
> }
Zbyszek
More information about the systemd-devel
mailing list