Skip to content

Commit

Permalink
s6-rc: switch to bare s6 based model
Browse files Browse the repository at this point in the history
The current form of s6-rc is unsuitable for dynamic activation on
external events, such as dbus activation events. Therefore we switch to
a different model based on a dedicated s6 scandir (we don't need
dependency handling), separated from the rest of the services.
  • Loading branch information
st3r4g committed Apr 18, 2021
1 parent fc5618e commit a79753b
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 45 deletions.
27 changes: 12 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,27 @@ implementation, and are capable of running both system and session buses.
This is also a starting point to explore the feasibility of a runit/s6
controller.

## dbus-controller-s6rc
## dbus-controller-s6

Build with `meson -Ds6-rc=enabled build`.
Build with `meson -Ds6=enabled build`.

Usage: `dbus-controller-s6rc -h`.
Usage: `dbus-controller-s6 -h`.

The [s6-rc] controller looks in a s6-rc livedir for services containing the
file `data/dbus-activatable-name` with a dbus activatable name provided by the
service. It issues `s6-rc change <service>` when it receives an activation
The [s6] controller looks in a s6 scandir for services containing the file
`data/dbus-activatable-name` with a dbus activatable name provided by the
service. It issues `s6-svc -u <service>` when it receives an activation
request.

Such dbus activatable services can be autogenerated by `tools/s6rc-generator`,
which generates a s6-rc source database called `dbus` that can be included in
the list of your databases to compile with `s6-rc-compile`.

Such dbus activatable services can be autogenerated by `tools/s6-generator`.
It is typically invoked as:
```
./s6rc-generator /usr/share/dbus-1/system-services/*
./s6rc-generator /usr/share/dbus-1/services/*
./s6-generator /usr/share/dbus-1/system-services/*
./s6-generator /usr/share/dbus-1/services/*
```
for the system and session bus, respectively.

You are free to further tweak this source database as you like, for example
removing unwanted activatable services.
You are free to further tweak this scandir as you like, for example removing
unwanted activatable services.

[dbus-broker]: https://github.com/bus1/dbus-broker
[s6-rc]: https://skarnet.org/software/s6-rc
[s6]: https://skarnet.org/software/s6
33 changes: 22 additions & 11 deletions activation.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,25 +48,19 @@ struct service {
tll(struct service) service_list = tll_init();

#define NAMEFILE "data/dbus-activatable-name"
#define SERVICEDIRS "servicedirs"
#define SIZE(array) (sizeof(array)/sizeof(*array))

void add_s6rc_servicedirs(const char* s6rc_livedir) {
void add_s6_servicedirs(const char* s6_dbuscandir) {
struct dirent **namelist;
int n;

size_t s6rc_livedir_len = strlen(s6rc_livedir);
char path[s6rc_livedir_len+1+SIZE(SERVICEDIRS)];
memcpy(path, s6rc_livedir, s6rc_livedir_len);
path[s6rc_livedir_len] = '/';
memcpy(path+s6rc_livedir_len+1, SERVICEDIRS, SIZE(SERVICEDIRS));
n = scandir(path, &namelist, NULL, alphasort);
n = scandir(s6_dbuscandir, &namelist, NULL, alphasort);
if (n == -1) {
perror("scandir");
exit(EXIT_FAILURE);
}

chdir(path); // TODO: remove this, the directory could be deleted by s6-rc-update
chdir(s6_dbuscandir);
while (n--) {
if (namelist[n]->d_name[0] != '.') {
struct service service = {0};
Expand Down Expand Up @@ -110,16 +104,33 @@ static struct service *find_service_by_id(int id) {
return NULL;
}

const char* s6rc_livedir; // TODO: pass around properly
const char* s6_dbuscandir; // TODO: pass around properly

int start_service(int id) {
int r = -1;
struct service* service = find_service_by_id(id);
if (service) {
char cmd[256];
sprintf(cmd, "s6-rc -l %s change %s", s6rc_livedir, service->s6rc.s);
sprintf(cmd, "s6-svc -uwu -T 1000 %s/%s", s6_dbuscandir, service->s6rc.s);
fprintf(stderr, "%s\n", cmd);
r = system(cmd);
}
return r;
}

static int stop_service(int id) {
int r = -1;
struct service* service = find_service_by_id(id);
if (service) {
char cmd[256];
sprintf(cmd, "s6-svc -d %s/%s", s6_dbuscandir, service->s6rc.s);
fprintf(stderr, "%s\n", cmd);
r = system(cmd);
}
return r;
}

void stop_all_services() {
tll_foreach(service_list, it)
stop_service(it->item.id);
}
30 changes: 30 additions & 0 deletions controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,33 @@ void controller_run() {
if (r < 0) handle_error("Failed to wait on bus");
}
}

#ifdef HAVE_S6

#include <skalibs/iopause.h>
#include <skalibs/selfpipe.h>

void controller_run_signals() {
iopause_fd x[2] = {
{ sd_bus_get_fd(bus_controller), IOPAUSE_READ, 0 },
{ selfpipe_init(), IOPAUSE_READ, 0 },
};
int r = selfpipe_trap(SIGTERM);
for (;;) {
/* Wait for the next request to process */
r = iopause(x, 2, NULL, NULL);
if (r < 0) handle_error("Failed to wait on bus");
if (x[0].revents & IOPAUSE_READ)
/* Process requests */
while ((r = sd_bus_process(bus_controller, NULL)))
if (r < 0) handle_error("Failed to process bus");
if (x[1].revents & IOPAUSE_READ) {
int c = selfpipe_read();
break;
}
}
selfpipe_finish();
stop_all_services();
}

#endif
23 changes: 13 additions & 10 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@

static const char* default_dbus_socket_path = "/run/dbus/system_bus_socket";
#ifdef HAVE_S6
static const char* default_s6rc_livedir = "/run/s6-rc";
extern const char* s6rc_livedir; // TODO: pass around properly
static const char* default_s6_dbuscandir = "/run/dbus_activated_services";
extern const char* s6_dbuscandir; // TODO: pass around properly
#endif
static const char* dummy_machine_id = "00000000000000000000000000000001";

Expand All @@ -35,7 +35,7 @@ optional arguments:\n\
-3 notify readiness on fd 3\n"
#ifdef HAVE_S6
"\n\
-l s6-rc livedir (default: %s)\n"
-a s6 scandir of dbus-activated services (default: %s)\n"
#endif
"\n\
-h show this help message and exit\n";
Expand All @@ -45,12 +45,12 @@ int main(int argc, char* argv[]) {
bool notif = false;
bool syslog = false;
#ifdef HAVE_S6
s6rc_livedir = default_s6rc_livedir;
s6_dbuscandir = default_s6_dbuscandir;
#endif

int opt;
#ifdef HAVE_S6
while ((opt = getopt(argc, argv, "d:hl:s3")) != -1) {
while ((opt = getopt(argc, argv, "d:ha:s3")) != -1) {
#else
while ((opt = getopt(argc, argv, "d:hs3")) != -1) {
#endif
Expand All @@ -59,12 +59,12 @@ int main(int argc, char* argv[]) {
case 's': syslog = true; break;
case '3': check_3_open(); notif = true; break;
#ifdef HAVE_S6
case 'l': s6rc_livedir = optarg; break;
case 'a': s6_dbuscandir = optarg; break;
#endif
default:
printf(usage, default_dbus_socket_path
#ifdef HAVE_S6
, default_s6rc_livedir
, default_s6_dbuscandir
#endif
);
return EXIT_FAILURE;
Expand Down Expand Up @@ -115,7 +115,7 @@ int main(int argc, char* argv[]) {
if (logfd >= 0) close(logfd);

#ifdef HAVE_S6
add_s6rc_servicedirs(s6rc_livedir);
add_s6_servicedirs(s6_dbuscandir);
#endif

controller_setup(controller[0], dbus_socket_path);
Expand All @@ -125,8 +125,11 @@ int main(int argc, char* argv[]) {
close(3);
}

#ifdef HAVE_S6
controller_run_signals();
#else
controller_run();
int wstatus;
waitpid(cpid, &wstatus, 0);
#endif
// do we need to do something here to make the broker exit "cleanly"?
}
}
4 changes: 2 additions & 2 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ add_project_arguments('-DHAVE_' + sdbus.name().to_upper() + '=1', language: 'c')

executable('dbus-controller-dummy', ['controller.c', 'dbus.c', 'main.c', 'policy.c', 'syslog.c'], dependencies: [sdbus])

if get_option('s6-rc').enabled()
if get_option('s6').enabled()
tllist = dependency('tllist')

cc = meson.get_compiler('c')
skalibs = cc.find_library('skarnet')

executable('dbus-controller-s6rc', ['activation.c', 'controller.c', 'dbus.c', 'main.c', 'policy.c', 'syslog.c'], dependencies: [sdbus, skalibs, tllist], c_args : '-DHAVE_S6=1')
executable('dbus-controller-s6', ['activation.c', 'controller.c', 'dbus.c', 'main.c', 'policy.c', 'syslog.c'], dependencies: [sdbus, skalibs, tllist], c_args : '-DHAVE_S6=1')
endif
2 changes: 1 addition & 1 deletion meson_options.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
option('sd-bus-provider', type: 'combo', choices: ['auto', 'libsystemd', 'libelogind', 'basu'], value: 'auto', description: 'Provider of the sd-bus library')
option('s6-rc', type: 'feature', value: 'disabled')
option('s6', type: 'feature', value: 'disabled')
8 changes: 2 additions & 6 deletions tools/s6rc-generator → tools/s6-generator
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
#!/bin/sh -e
# Generate s6-rc service definitions for dbus services
# Generate s6 service definitions for dbus services
# usage: pass the absolute paths of dbus service definitions, i.e.
# /usr/share/dbus-1/system-services/* (for the system bus)
# or /usr/share/dbus-1/services/* (for the session bus)

# The name of the dbus service which launches controller/broker
# all dbus activated services depend on it
DBUS_S6RC_SERVICE=dbus

mkdir -p 'dbus'
cd 'dbus'

Expand All @@ -20,8 +16,8 @@ for service in "$@"; do
mkdir "$name_/data"
echo "$name_" >> "$name_/data/dbus-activatable-name"
echo 'longrun' >> "$name_/type"
echo "$DBUS_S6RC_SERVICE" >> "$name_/dependencies"
echo '#!/bin/execlineb -P' >> "$name_/run"
echo "$exec_" >> "$name_/run"
chmod +x "$name_/run"
touch "$name_/down"
done

0 comments on commit a79753b

Please sign in to comment.