mirror of
https://github.com/troglobit/finit.git
synced 2026-10-24 11:54:36 +00:00
libink: a brokerless D-Bus implementation for Finit
Finit had no way to answer the question every service manager gets asked: what is running, and change it. D-Bus is how the rest of userspace asks, but linking libdbus, sd-bus or GIO into PID 1 buys a dependency, an allocator and a main loop we do not control. So libink: the wire format, an object tree, and a bus of Finit's own at /run/finit/bus, gated like INIT_SOCKET. It speaks the standard org.freedesktop.DBus, .Peer, .Introspectable interfaces, and Finit's own Manager1, Service1 and Cond1 on top. Methods that change something are marked privileged and answered only for a caller the kernel vouched for, via SO_PEERCRED. Server and client both, since initctl is the first thing that needs to talk to it, and its Start/Stop/Restart/Reload now go over the bus rather than the legacy socket. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
1 parent
ae9a24f44f
commit
0a269f3298
39 files changed
+5530
-49
No files matched your search
+130
-6
@@ -268,19 +268,105 @@ static int do_startstop(int cmd, char *arg)
|
||||
return do_svc(cmd, arg);
|
||||
}
|
||||
|
||||
static int do_start (char *arg) { return do_startstop(INIT_CMD_START_SVC, arg); }
|
||||
static int do_stop (char *arg) { return do_startstop(INIT_CMD_STOP_SVC, arg); }
|
||||
#ifdef HAVE_DBUS
|
||||
#include "link.h"
|
||||
|
||||
/* Try the D-Bus path for a Manager1 method. Returns:
|
||||
* 0 succeeded via D-Bus
|
||||
* 1 D-Bus replied with an error -- callers should error out
|
||||
* -1 D-Bus not reachable -- callers should fall back to the
|
||||
* legacy INIT_SOCKET transport
|
||||
*
|
||||
* On D-Bus error replies the function maps the org.* error name to
|
||||
* the same exit code initctl historically printed for that case
|
||||
* (e.g. NoSuchService -> 69 with the legacy message). */
|
||||
static int try_dbus_manager(const char *method, const char *arg_sig,
|
||||
const char *arg)
|
||||
{
|
||||
link_client_t *c;
|
||||
const char *err;
|
||||
int rc;
|
||||
|
||||
c = link_client_open(FINIT_BUS_SOCKET);
|
||||
if (!c)
|
||||
return -1;
|
||||
|
||||
/* "s" methods take the service identity (arg may be NULL ->
|
||||
* empty string); void methods pass no body. */
|
||||
if (arg_sig && !strcmp(arg_sig, "s"))
|
||||
rc = link_client_call_v(c, "/org/finit/manager",
|
||||
"org.finit.Manager1", method,
|
||||
"s", arg ? arg : "");
|
||||
else if (!arg_sig || !*arg_sig)
|
||||
rc = link_client_call_v(c, "/org/finit/manager",
|
||||
"org.finit.Manager1", method, NULL);
|
||||
else
|
||||
rc = LINK_CALL_FAIL;
|
||||
|
||||
if (rc == LINK_CALL_ERROR) {
|
||||
const link_reply_t *r = link_client_reply(c);
|
||||
|
||||
err = (r && r->error_name) ? r->error_name : "";
|
||||
/* Exact match on the fully-qualified error name; substring
|
||||
* matching would misfire on a future name that contains
|
||||
* one of these as a substring. */
|
||||
if (!strcmp(err, "org.finit.Error.NoSuchService")) {
|
||||
link_client_close(c);
|
||||
ERRX(noerr ? 0 : 69, "no such task or service(s): %s",
|
||||
arg ? arg : "");
|
||||
}
|
||||
if (!strcmp(err, "org.freedesktop.DBus.Error.AccessDenied")) {
|
||||
link_client_close(c);
|
||||
ERRX(1, "permission denied: %s requires root", method);
|
||||
}
|
||||
link_client_close(c);
|
||||
ERRX(1, "%s: %s", method, *err ? err : "D-Bus error");
|
||||
}
|
||||
link_client_close(c);
|
||||
if (rc == LINK_CALL_OK)
|
||||
return 0;
|
||||
return -1; /* LINK_CALL_FAIL or anything else: fall back */
|
||||
}
|
||||
#endif /* HAVE_DBUS */
|
||||
|
||||
static int do_start (char *arg)
|
||||
{
|
||||
#ifdef HAVE_DBUS
|
||||
int rc = try_dbus_manager("Start", "s", arg);
|
||||
if (rc >= 0) return rc;
|
||||
#endif
|
||||
return do_startstop(INIT_CMD_START_SVC, arg);
|
||||
}
|
||||
|
||||
static int do_stop (char *arg)
|
||||
{
|
||||
#ifdef HAVE_DBUS
|
||||
int rc = try_dbus_manager("Stop", "s", arg);
|
||||
if (rc >= 0) return rc;
|
||||
#endif
|
||||
return do_startstop(INIT_CMD_STOP_SVC, arg);
|
||||
}
|
||||
|
||||
static int do_reload (char *arg)
|
||||
{
|
||||
if (!arg || !arg[0])
|
||||
if (!arg || !arg[0]) {
|
||||
#ifdef HAVE_DBUS
|
||||
int rc = try_dbus_manager("Reload", "", NULL);
|
||||
if (rc >= 0) return rc;
|
||||
#endif
|
||||
return do_svc(INIT_CMD_RELOAD, NULL);
|
||||
}
|
||||
|
||||
return do_startstop(INIT_CMD_RELOAD_SVC, arg);
|
||||
}
|
||||
|
||||
static int do_restart(char *arg)
|
||||
{
|
||||
#ifdef HAVE_DBUS
|
||||
int rc = try_dbus_manager("Restart", "s", arg);
|
||||
if (rc == 0) return 0;
|
||||
if (rc == 1) ERRX(noerr ? 0 : 7, "failed restarting %s", arg);
|
||||
#endif
|
||||
if (do_startstop(INIT_CMD_RESTART_SVC, arg))
|
||||
ERRX(noerr ? 0 : 7, "failed restarting %s", arg);
|
||||
|
||||
@@ -643,9 +729,47 @@ static int do_cmd(int cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_reboot (char *arg) { return do_cmd(INIT_CMD_REBOOT); }
|
||||
int do_halt (char *arg) { return do_cmd(INIT_CMD_HALT); }
|
||||
int do_poweroff(char *arg) { return do_cmd(INIT_CMD_POWEROFF); }
|
||||
#ifdef HAVE_DBUS
|
||||
static int do_reboot_dbus(const char *method)
|
||||
{
|
||||
int rc = try_dbus_manager(method, "", NULL);
|
||||
|
||||
if (rc == 0) {
|
||||
sleep(5); /* match legacy: wait for finit to shut down */
|
||||
return 0;
|
||||
}
|
||||
return rc; /* 1 = error, -1 = fall back */
|
||||
}
|
||||
#endif
|
||||
|
||||
int do_reboot (char *arg)
|
||||
{
|
||||
#ifdef HAVE_DBUS
|
||||
int rc = do_reboot_dbus("Reboot");
|
||||
if (rc >= 0) return rc;
|
||||
#endif
|
||||
return do_cmd(INIT_CMD_REBOOT);
|
||||
}
|
||||
|
||||
int do_halt (char *arg)
|
||||
{
|
||||
#ifdef HAVE_DBUS
|
||||
int rc = do_reboot_dbus("Halt");
|
||||
if (rc >= 0) return rc;
|
||||
#endif
|
||||
return do_cmd(INIT_CMD_HALT);
|
||||
}
|
||||
|
||||
int do_poweroff(char *arg)
|
||||
{
|
||||
#ifdef HAVE_DBUS
|
||||
int rc = do_reboot_dbus("Poweroff");
|
||||
if (rc >= 0) return rc;
|
||||
#endif
|
||||
return do_cmd(INIT_CMD_POWEROFF);
|
||||
}
|
||||
|
||||
/* Suspend has no Manager1 equivalent yet; uses the legacy IPC. */
|
||||
int do_suspend (char *arg) { return do_cmd(INIT_CMD_SUSPEND); }
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user