diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..378eac2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build diff --git a/README.md b/README.md new file mode 100644 index 0000000..89a91ca --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# dbus-controller-dummy +dummy controller for dbus-broker + +Provides a way lo launch [dbus-broker] without the requirement of any specific +init system running. This means that dbus activation is disabled and service +dependencies must be taken care of explicitly in other ways. + +This is also a starting point to explore the feasibility of a runit/s6 +controller. + +[dbus-broker]: https://github.com/bus1/dbus-broker diff --git a/dbus.c b/dbus.c new file mode 100644 index 0000000..a4959d5 --- /dev/null +++ b/dbus.c @@ -0,0 +1,33 @@ +#include "util.h" + +#include +#include +#include +#include +#include + +int dbus_create_socket(const char* dbus_socket_path) { + const int backlog = 50; + int sfd; + struct sockaddr_un my_addr; + + sfd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0); + if (sfd == -1) + handle_error("socket"); + + memset(&my_addr, 0, sizeof(my_addr)); + /* Clear structure */ + my_addr.sun_family = AF_UNIX; + strncpy(my_addr.sun_path, dbus_socket_path, + sizeof(my_addr.sun_path) - 1); + + mode_t old_mode = umask(0000); + if (bind(sfd, (struct sockaddr *) &my_addr, + sizeof(my_addr)) == -1) + handle_error("bind"); + umask(old_mode); + + if (listen(sfd, backlog) == -1) + handle_error("listen"); + return sfd; +} diff --git a/dbus.h b/dbus.h new file mode 100644 index 0000000..25143dc --- /dev/null +++ b/dbus.h @@ -0,0 +1,7 @@ +#ifndef dbus_h_INCLUDED +#define dbus_h_INCLUDED + +int dbus_create_socket(); + +#endif // dbus_h_INCLUDED + diff --git a/main.c b/main.c new file mode 100644 index 0000000..a37d5f6 --- /dev/null +++ b/main.c @@ -0,0 +1,133 @@ +#include "dbus.h" +#include "policy.h" +#include "syslog.h" +#include "util.h" + +#include "sd-bus.h" + +#include +#include +#include +#include +#include +#include + +#define STR_INT_MAX 16 + +static const char* default_dbus_socket_path = "/run/dbus/system_bus_socket"; +static const char* syslog_path = "/dev/log"; +static const char* dummy_machine_id = "00000000000000000000000000000001"; + +static int launcher_add_listener(sd_bus* bus_controller, int fd_listen) { + sd_bus_message *m = NULL; + int r; + + r = sd_bus_message_new_method_call(bus_controller, + &m, + NULL, + "/org/bus1/DBus/Broker", + "org.bus1.DBus.Broker", + "AddListener"); + if (r < 0) + return 1; + + r = sd_bus_message_append(m, "oh", + "/org/bus1/DBus/Listener/0", + fd_listen); + if (r < 0) + return 1; + + policy(m); + + sd_bus_error error; + r = sd_bus_call(bus_controller, m, 0, &error, NULL); + if (r < 0) { + printf("sd_bus_call falied: %s %s\n", error.name, error.message); + return 1; + } + + return 0; +} + +static int bus_method_reload_config(sd_bus_message *message, void *userdata, sd_bus_error *error) { + /* + * Do nothing... + */ + return sd_bus_reply_method_return(message, NULL); +} + +const sd_bus_vtable launcher_vtable[] = { + SD_BUS_VTABLE_START(0), + SD_BUS_METHOD("ReloadConfig", NULL, NULL, bus_method_reload_config, 0), + SD_BUS_VTABLE_END +}; + +const char *usage = "usage: dbus-controller-dummy [-h] dbus-broker\n\ +\n\ +Dummy controller for dbus-broker\n\ +\n\ +positional arguments:\n\ + dbus-broker dbus-broker to execute\n\ +\n\ +optional arguments:\n\ + -d dbus socket path (default: %s)\n\ + -l syslog socket path (default: %s)\n\ + -h show this help message and exit\n"; + +int main(int argc, char* argv[]) { + char* dbus_socket_path = NULL; + + int opt; + while ((opt = getopt(argc, argv, "hd:")) != -1) { + switch (opt) { + case 'd': dbus_socket_path = optarg; break; + default: + printf(usage, default_dbus_socket_path, syslog_path); + return EXIT_FAILURE; + } + } + + if (argc <= optind) { + printf(usage, default_dbus_socket_path, syslog_path); + return EXIT_FAILURE; + } + + const char* const broker_path = argv[optind]; + + int controller[2]; + socketpair(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, controller); + + //int logfd = syslog_connect_socket(syslog_path); + + pid_t cpid = fork(); + if (cpid == 0) { + close(controller[0]); + char str_log[STR_INT_MAX], str_controller[STR_INT_MAX]; + snprintf(str_controller, sizeof(str_controller), "%d", controller[1]); + //snprintf(str_log, sizeof(str_log), "%d", logfd); + const char * const argv[] = { + "dbus-broker", + "--controller", str_controller, + //"--log", str_log, + "--machine-id", dummy_machine_id, + NULL}; + execvp(broker_path, (char * const *)argv); + perror("Failed to execute dbus-broker"); + _exit(EXIT_FAILURE); + /* NOTREACHED */ + } else { + close(controller[1]); + //close(logfd); + sd_bus* bus_controller; + sd_bus_new(&bus_controller); + sd_bus_set_fd(bus_controller, controller[0], controller[0]); + sd_bus_add_object_vtable(bus_controller, NULL, "/org/bus1/DBus/Controller", "org.bus1.DBus.Controller", launcher_vtable, NULL); + //sd_bus_add_filter(bus_controller, NULL, launcher_on_message, NULL); + sd_bus_start(bus_controller); + if (launcher_add_listener(bus_controller, dbus_create_socket(default_dbus_socket_path))) + printf("AddListener failed\n"); + + int wstatus; + waitpid(cpid, &wstatus, 0); + } +} diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..e51e2cc --- /dev/null +++ b/meson.build @@ -0,0 +1,28 @@ +project('dbus-controller-dummy', 'c') + +if get_option('sd-bus-provider') == 'auto' +assert(get_option('auto_features').auto(), 'sd-bus-provider must not be set to auto since auto_features != auto') +sdbus = dependency('libsystemd', +required: false, +not_found_message: 'libsystemd not found, trying libelogind', +) +if not sdbus.found() +sdbus = dependency('libelogind', +required: false, +not_found_message: 'libelogind not found, trying basu', +) +endif +if not sdbus.found() +sdbus = dependency('basu', +required: false, +) +endif +if not sdbus.found() +error('Neither libsystemd, nor libelogind, nor basu was found') +endif +else +sdbus = dependency(get_option('sd-bus-provider')) +endif +add_project_arguments('-DHAVE_' + sdbus.name().to_upper() + '=1', language: 'c') + +executable('dbus-controller-dummy', ['dbus.c', 'main.c', 'policy.c', 'syslog.c'], dependencies: [sdbus]) diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..871e0bc --- /dev/null +++ b/meson_options.txt @@ -0,0 +1 @@ +option('sd-bus-provider', type: 'combo', choices: ['auto', 'libsystemd', 'libelogind', 'basu'], value: 'auto', description: 'Provider of the sd-bus library') diff --git a/policy.c b/policy.c new file mode 100644 index 0000000..e2a04eb --- /dev/null +++ b/policy.c @@ -0,0 +1,63 @@ +#include "policy.h" + +#include + +#define POLICY_T_BATCH \ + "bt" \ + "a(btbs)" \ + "a(btssssuutt)" \ + "a(btssssuutt)" + +#define POLICY_T \ + "a(u(" POLICY_T_BATCH "))" \ + "a(buu(" POLICY_T_BATCH "))" \ + "a(ss)" \ + "b" + +#define POLICY_PRIORITY_DEFAULT (UINT64_C(1)) + +void policy_export_connect(sd_bus_message *m) { + sd_bus_message_append(m, "bt", true, POLICY_PRIORITY_DEFAULT); +} + +void policy_export_own(sd_bus_message *m) { + sd_bus_message_open_container(m, 'a', "(btbs)"); + sd_bus_message_append(m, "(btbs)", true, POLICY_PRIORITY_DEFAULT, true, ""); + sd_bus_message_close_container(m); +} + +void policy_export_xmit(sd_bus_message *m) { + sd_bus_message_open_container(m, 'a', "(btssssuutt)"); + sd_bus_message_append(m, "(btssssuutt)", true, POLICY_PRIORITY_DEFAULT, "", "", "", "", 0, 0, 0, 0); + sd_bus_message_close_container(m); +} + +int policy(sd_bus_message *m) { + int r; + r = sd_bus_message_open_container(m, 'v', "(" POLICY_T ")"); + r = sd_bus_message_open_container(m, 'r', POLICY_T); + r = sd_bus_message_open_container(m, 'a', "(u(" POLICY_T_BATCH "))"); + r = sd_bus_message_open_container(m, 'r', "u(" POLICY_T_BATCH ")"); + r = sd_bus_message_append(m, "u", (uint32_t)-1); + r = sd_bus_message_open_container(m, 'r', POLICY_T_BATCH); + policy_export_connect(m); + policy_export_own(m); + policy_export_xmit(m); + policy_export_xmit(m); + + r = sd_bus_message_close_container(m); + r = sd_bus_message_close_container(m); + r = sd_bus_message_close_container(m); + + r = sd_bus_message_open_container(m, 'a', "(buu(" POLICY_T_BATCH "))"); + r = sd_bus_message_close_container(m); + + r = sd_bus_message_open_container(m, 'a', "(ss)"); + r = sd_bus_message_close_container(m); + + r = sd_bus_message_append(m, "b", false); + + r = sd_bus_message_close_container(m); + r = sd_bus_message_close_container(m); + return r; +} diff --git a/policy.h b/policy.h new file mode 100644 index 0000000..58321f7 --- /dev/null +++ b/policy.h @@ -0,0 +1,9 @@ +#ifndef policy_h_INCLUDED +#define policy_h_INCLUDED + +#include "sd-bus.h" + +int policy(sd_bus_message *m); + +#endif // policy_h_INCLUDED + diff --git a/sd-bus.h b/sd-bus.h new file mode 100644 index 0000000..b7d1d9a --- /dev/null +++ b/sd-bus.h @@ -0,0 +1,12 @@ +#ifndef sd_bus_h_INCLUDED +#define sd_bus_h_INCLUDED + +#ifdef HAVE_LIBSYSTEMD +#include +#elif HAVE_LIBELOGIND +#include +#elif HAVE_BASU +#include +#endif + +#endif // sd_bus_h_INCLUDED diff --git a/syslog.c b/syslog.c new file mode 100644 index 0000000..3911b8d --- /dev/null +++ b/syslog.c @@ -0,0 +1,24 @@ +#include "util.h" + +#include +#include +#include +#include + +int syslog_connect_socket(const char* syslog_path) { + struct sockaddr_un addr; + socklen_t addr_size; + int logfd = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0); + memset(&addr, 0, sizeof(struct sockaddr_un)); + /* Clear structure */ + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, syslog_path, + sizeof(addr.sun_path) - 1); + + addr_size = sizeof(struct sockaddr_un); + int ret = connect(logfd, (struct sockaddr *) &addr, + addr_size); + if (ret == -1) + handle_error("connect"); + return logfd; +} diff --git a/syslog.h b/syslog.h new file mode 100644 index 0000000..2627515 --- /dev/null +++ b/syslog.h @@ -0,0 +1,7 @@ +#ifndef syslog_h_INCLUDED +#define syslog_h_INCLUDED + +int syslog_connect_socket(const char* syslog_path); + +#endif // syslog_h_INCLUDED + diff --git a/util.h b/util.h new file mode 100644 index 0000000..1f5f122 --- /dev/null +++ b/util.h @@ -0,0 +1,8 @@ +#ifndef util_h_INCLUDED +#define util_h_INCLUDED + +#define handle_error(msg) \ + do { perror(msg); exit(EXIT_FAILURE); } while (0) + +#endif // util_h_INCLUDED +