Skip to content

Commit

Permalink
Implement dbus-broker-session tool
Browse files Browse the repository at this point in the history
This is a functional replacement for dbus-run-session.

Exit codes and behavior is very similar,
the implementation is mostly shared with dbus-broker-launch,
adding some hooks to start and supervise the application.
  • Loading branch information
nolange committed Oct 23, 2024
1 parent be28751 commit 4d0763f
Showing 1 changed file with 199 additions and 13 deletions.
212 changes: 199 additions & 13 deletions src/launch/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@
* D-Bus Broker Launch Main Entry
*/

#include "launch/launcher.h"
#include "util/error.h"
#include <c-stdaux.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdlib.h>
#include <spawn.h>
#include <systemd/sd-daemon.h>
#include "launch/launcher.h"
#include "util/error.h"

#include <sys/auxv.h>
#include <sys/un.h>

enum {
_MAIN_SUCCESS,
Expand All @@ -21,6 +25,8 @@ static const char * main_arg_configfile = NULL;
static bool main_arg_user_scope = false;
static int main_fd_listen = -1;

#define SESSION_TOOL "dbus-broker-session"

static void help(void) {
printf("%s [GLOBALS...] ...\n\n"
"Linux D-Bus Message Broker Launcher\n\n"
Expand All @@ -32,7 +38,16 @@ static void help(void) {
, program_invocation_short_name);
}

static int parse_argv(int argc, char *argv[]) {
static void help_session(void) {
printf("%s [GLOBALS...] ...\n\n"
"Initiate a D-Bus session with a new session controller\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --config-file PATH Specify path to configuration file\n"
, program_invocation_short_name);
}

static int parse_argv(int argc, char *argv[], bool as_session) {
enum {
ARG_VERSION = 0x100,
ARG_VERBOSE,
Expand All @@ -49,16 +64,22 @@ static int parse_argv(int argc, char *argv[]) {
{ "scope", required_argument, NULL, ARG_SCOPE },
{}
};
static const struct option options_session[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "config-file", required_argument, NULL, ARG_CONFIG, },
{}
};
int c;

while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
while ((c = getopt_long(argc, argv, "h", as_session ? options_session : options, NULL)) >= 0) {
switch (c) {
case 'h':
help();
as_session ? help_session() : help();
return MAIN_EXIT;

case ARG_VERSION:
printf("dbus-broker-launch %d\n", PACKAGE_VERSION);
printf("%s %d\n", as_session ? SESSION_TOOL : "dbus-broker-launch", PACKAGE_VERSION);
return MAIN_EXIT;

/* noop for backward compatibility */
Expand Down Expand Up @@ -93,9 +114,17 @@ static int parse_argv(int argc, char *argv[]) {
}
}

if (optind != argc) {
fprintf(stderr, "%s: invalid arguments -- '%s'\n", program_invocation_name, argv[optind]);
return MAIN_FAILED;
if (as_session)
{
if (optind >= argc) {
fprintf(stderr, "%s: a non-option argument is required\n", program_invocation_name);
return MAIN_FAILED;
}
} else {
if (optind != argc) {
fprintf(stderr, "%s: invalid arguments -- '%s'\n", program_invocation_name, argv[optind]);
return MAIN_FAILED;
}
}

return 0;
Expand Down Expand Up @@ -140,23 +169,40 @@ static int inherit_fds(void) {
return 0;
}

static int run(void) {
struct app_data
{
char **argv;
pid_t pid;
int exit_code;
Launcher *launcher;
};
typedef struct app_data app_data;
static int launcher_on_controller_start(sd_event_source *source, void *userdata);

static int run(app_data *app) {
_c_cleanup_(launcher_freep) Launcher *launcher = NULL;
int r;

r = launcher_new(&launcher, main_fd_listen, main_arg_audit, main_arg_configfile, main_arg_user_scope);
if (r)
return error_fold(r);

if (app) {
app->launcher = launcher;
r = sd_event_add_defer(launcher->event, NULL, launcher_on_controller_start, app);
if (r)
return error_fold(r);
}

r = launcher_run(launcher);
return error_fold(r);
}

int main(int argc, char **argv) {
static int launch_main(int argc, char **argv) {
sigset_t mask_new, mask_old;
int r;

r = parse_argv(argc, argv);
r = parse_argv(argc, argv, false);
if (r)
goto exit;

Expand All @@ -171,7 +217,7 @@ int main(int argc, char **argv) {
sigaddset(&mask_new, SIGHUP);

sigprocmask(SIG_BLOCK, &mask_new, &mask_old);
r = run();
r = run(NULL);
sigprocmask(SIG_SETMASK, &mask_old, NULL);

exit:
Expand All @@ -180,3 +226,143 @@ int main(int argc, char **argv) {
fprintf(stderr, "Exiting due to fatal error: %d\n", r);
return (r == 0 || r == MAIN_EXIT) ? 0 : 1;
}

static int exit_event_loop(sd_event_source *source, int r, void *userdata) {
app_data *app = userdata;
app->exit_code = r;
return sd_event_exit(sd_event_source_get_event(source), 0);
}

static int launcher_on_controller_exit(sd_event_source *source, const siginfo_t *si, void *userdata) {
app_data *app = userdata;
app->pid = -1;
return exit_event_loop(source, (si->si_code == CLD_EXITED) ? si->si_status : 128 + si->si_status, userdata);
}

static int launcher_on_controller_start(sd_event_source *source, void *userdata) {
app_data *app = userdata;
Launcher *launcher = app->launcher;

pid_t pid;
sigset_t sigs;
posix_spawnattr_t spawnat;
sigemptyset ( &sigs);
posix_spawnattr_init(&spawnat);
posix_spawnattr_setflags(&spawnat, POSIX_SPAWN_SETSIGMASK);
posix_spawnattr_setsigmask(&spawnat, &sigs);
int r = posix_spawnp(&pid, app->argv[0], NULL, &spawnat, app->argv, environ);
posix_spawnattr_destroy(&spawnat);
if (r) {
error_fold(r);
exit_event_loop(source, 1, userdata);
}

app->pid = pid;
r = sd_event_add_child(launcher->event, NULL, pid, WEXITED, launcher_on_controller_exit, app);

return error_fold(r);
}

static int open_socket(int *pfd, struct sockaddr_un *p_addr) {
struct sockaddr_un addr = {AF_UNIX};
unsigned long random_bytes;
int fd, r;
void *random = (void*)getauxval(AT_RANDOM);

c_assert(random);
c_memcpy(&random_bytes, random, sizeof(random_bytes));

fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
if (fd < 0)
return error_fold(fd);
*pfd = fd;

snprintf(addr.sun_path, sizeof(addr.sun_path) - 1, "/tmp/dbus-%02lx", random_bytes);
r = bind(fd, (const struct sockaddr*)&addr, sizeof(addr));
if (r)
return error_fold(r);
*p_addr = addr;
r = listen(fd, 4096);
if (r)
return error_fold(r);
return fd;
}

static int prepare_session(struct sockaddr_un *socket_path) {
static const char *const unset_env[] = {
"DBUS_SESSION_BUS_PID",
"DBUS_SESSION_BUS_WINDOWID",
"DBUS_STARTER_ADDRESS",
"DBUS_STARTER_BUS_TYPE",
};
char buffer[sizeof(socket_path->sun_path) + 16];
int fd = -1;
int r = open_socket(&fd, socket_path);

if (r < 0) {
if (fd >= 0)
close(fd);
return r;
}
main_fd_listen = fd;
for (unsigned i = 0; i < C_ARRAY_SIZE(unset_env); ++i)
unsetenv(unset_env[i]);

snprintf(buffer, sizeof(buffer), "unix:path=%s", socket_path->sun_path);
r = setenv("DBUS_SESSION_BUS_ADDRESS", buffer, 1);
return error_fold(r);
}

static int session_main(int argc, char **argv) {
/*
* Returns 127 if bus could not be spawned
* returns 127 if app could not be forked
* returns 127 on commandline sparsing
* returns 1 if app exec fails
* returns 128 + signo if app exited by signal
* returns app exit_code else
*/
// https://gitlab.freedesktop.org/dbus/dbus/-/blob/master/tools/dbus-run-session.c
sigset_t mask_new, mask_old;
struct sockaddr_un socket_path = {0};
app_data app = {};
int r;

main_arg_user_scope = true;
r = parse_argv(argc, argv, true);
if (r)
goto exit;

app.argv = &argv[optind];
r = prepare_session(&socket_path);
if (r)
goto exit;

sigemptyset(&mask_new);
sigaddset(&mask_new, SIGCHLD);
sigaddset(&mask_new, SIGTERM);
sigaddset(&mask_new, SIGINT);
sigaddset(&mask_new, SIGHUP);

sigprocmask(SIG_BLOCK, &mask_new, &mask_old);
r = run(&app);
sigprocmask(SIG_SETMASK, &mask_old, NULL);

if (app.pid > 0)
kill(app.pid, SIGTERM);
if (socket_path.sun_path[0] != '\0')
unlink(socket_path.sun_path);
exit:
r = error_trace(r);
if (r < 0)
fprintf(stderr, "Exiting due to fatal error: %d\n", r);

return r == 0 ? app.exit_code : 127;
}

int main(int argc, char **argv) {
const char *p_last_path = strrchr(argv[0], '/');
if (strcmp(p_last_path ? p_last_path + 1 : argv[0], SESSION_TOOL) == 0)
return session_main(argc, argv);
return launch_main(argc, argv);
}

0 comments on commit 4d0763f

Please sign in to comment.