libink: a message bus is not a peer

libink was written against the only bus it had, its own, where the
peer on the other end is the client.  A broker is not: it routes for
senders it names itself, expects a DESTINATION on anything addressed
through it, and answers on its own schedule rather than next.

Runlevels go on the wire as S and N rather than the digits Finit
keeps internally, since that is what a caller outside Finit means by
one.

The library stays a convenience library, linked into finit and
initctl and installed nowhere: the ABI promise waits until libink is
its own project.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg committed 2026-08-13 09:28:26 +02:00
1 parent 6310d9e760
commit b55dada80b
16 files changed
+340 -250

No files matched your search

+28 -9
View File
@@ -457,15 +457,31 @@ static int manager_suspend(link_call_t *call, void *u)
* org.freedesktop.DBus.Properties interface. Getters write a
* variant containing a single string. */
/* Two distinct getters because the property table is static const --
* we can't bind &runlevel/&prevlevel through userdata. */
/*
* Two distinct getters because the property table is static const --
* we can't bind &runlevel/&prevlevel through userdata. The values
* use the same encoding as the runlevel(8) command and `initctl
* runlevel`: "S" for single-user, "N" for no previous runlevel --
* the internal digit is not a wire format.
*/
static const char *runlevel_encode(int level, char *buf, size_t len)
{
if (level == INIT_LEVEL)
strlcpy(buf, "S", len);
else if (level >= 0 && level <= 9)
snprintf(buf, len, "%d", level);
else
strlcpy(buf, "N", len);
return buf;
}
static int prop_runlevel(link_writer_t *w, void *u)
{
char buf[8];
(void)u;
snprintf(buf, sizeof(buf), "%d", runlevel);
link_w_string(w, buf);
link_w_string(w, runlevel_encode(runlevel, buf, sizeof(buf)));
return 0;
}
@@ -474,7 +490,10 @@ static int prop_prevrunlevel(link_writer_t *w, void *u)
char buf[8];
(void)u;
snprintf(buf, sizeof(buf), "%d", prevlevel);
if (prevlevel <= 0 || prevlevel > 9)
strlcpy(buf, "N", sizeof(buf));
else
snprintf(buf, sizeof(buf), "%d", prevlevel);
link_w_string(w, buf);
return 0;
}
@@ -893,8 +912,8 @@ void dbus_notify_service_state(svc_t *svc, int old_state, int new_state)
/* ---------- signal emission: RunlevelChanged ----------
*
* Fired by sm.c right after the runlevel global flips. Body is
* (old, new) as one-digit strings, matching the format that
* Manager1.Runlevel (the property) returns. */
* (old, new) in the same runlevel(8) encoding as the Manager1
* Runlevel property: digits, "S", or "N". */
void dbus_notify_runlevel_change(int old_level, int new_level)
{
uint8_t body[64];
@@ -902,8 +921,8 @@ void dbus_notify_runlevel_change(int old_level, int new_level)
char old_s[8], new_s[8];
ssize_t blen;
snprintf(old_s, sizeof(old_s), "%d", old_level);
snprintf(new_s, sizeof(new_s), "%d", new_level);
runlevel_encode(old_level, old_s, sizeof(old_s));
runlevel_encode(new_level, new_s, sizeof(new_s));
link_writer_init(&w, body, sizeof(body));
link_w_string(&w, old_s);
+13 -8
View File
@@ -308,12 +308,8 @@ static int do_runlevel(char *arg)
if (dbus_get_manager_props(wanted, out, sizeof(curr_buf)) == 0 &&
curr_buf[0] && prev_buf[0]) {
int cl = atoi(curr_buf);
int pl = atoi(prev_buf);
curr = (cl == INIT_LEVEL) ? 'S' : (char)(cl + '0');
prev = (pl > 0 && pl <= 9) ? (char)(pl + '0') : 'N';
printf("%c %c\n", prev, curr);
/* already in runlevel(8) encoding: digits, S, N */
printf("%s %s\n", prev_buf, curr_buf);
return 0;
}
#endif
@@ -2181,6 +2177,15 @@ fail:
return -1;
}
/* wire encoding is runlevel(8) style: digits, S, N */
static int runlevel_from_str(const char *s)
{
if (!strcmp(s, "S"))
return INIT_LEVEL;
return atoi(s);
}
/*
* All show_status() views over D-Bus, self-contained (the current
* runlevel comes from Manager1, not the legacy socket). Returns 0
@@ -2216,7 +2221,7 @@ static int dbus_show_status(char *arg, int *retval)
/* runlevel feeds the detail view's Runlevels line */
if (dbus_get_manager_props(wanted, outv, sizeof(curr)) < 0)
goto fail;
runlevel = atoi(curr);
runlevel = runlevel_from_str(curr);
if (json) {
*retval = json_status_one(stdout, &rows[0], "", 0);
puts("");
@@ -2230,7 +2235,7 @@ static int dbus_show_status(char *arg, int *retval)
if (dbus_get_manager_props(wanted, outv, sizeof(curr)) < 0)
goto fail;
runlevel = atoi(curr);
runlevel = runlevel_from_str(curr);
filter = (arg && arg[0]) ? arg : NULL;
if (json) {