confd: replace initctl shell-outs with direct finit_ C API

Add a finit_enable/disable/reload() family in core.c that directly
manipulates Finit's service state without fork+exec overhead:

  finit_enable(svc)  -- create symlink in /etc/finit.d/enabled/
  finit_disable(svc) -- remove symlink from /etc/finit.d/enabled/
  finit_delete(svc)  -- remove both symlink and service entirely
  finit_reload(svc)  -- utimensat() on .conf to schedule reload

Printf-style variants (finit_enablef/disablef/reloadf) handle
template instance names such as container@foo and hostapd@wlan0.

All systemf("initctl ... enable/disable/touch ...") call sites across
containers, dhcp-server, firewall, hardware, ntp, routing, services,
syslog, and system are converted to the new API.

As a related cleanup in services.c, drop the remaining srx_enabled()
calls in favour of reading the already-fetched config tree directly
via lydx_is_enabled(lydx_get_xpathf(config, ...)), eliminating the
last sysrepo round-trips from that module.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg
2026-03-20 16:18:14 +01:00
parent bc6313d2db
commit 0ee3159ac6
13 changed files with 192 additions and 48 deletions
+7 -4
View File
@@ -322,9 +322,12 @@ static int add(const char *name, struct lyd_node *cif)
fchmod(fileno(fp), 0700);
fclose(fp);
systemf("initctl -bnq touch container@%s.conf", name);
systemf("initctl -bnq %s container@%s.conf", lydx_is_enabled(cif, "enabled")
? "enable" : "disable", name);
if (lydx_is_enabled(cif, "enabled")) {
finit_enablef("container@%s", name);
finit_reloadf("container@%s", name);
} else {
finit_disablef("container@%s", name);
}
return 0;
}
@@ -341,7 +344,7 @@ static int del(const char *name)
FILE *pp;
erasef("%s/%s.sh", _PATH_CONT, name);
systemf("initctl -bnq disable container@%s.conf", name);
finit_disablef("container@%s", name);
/* Schedule a cleanup job for this container as soon as it has stopped */
snprintf(prune_dir, sizeof(prune_dir), "%s/%s", _PATH_CLEAN, name);
+124 -1
View File
@@ -9,6 +9,129 @@
struct confd confd;
/*
* Touch a Finit service .conf file to schedule a synchronized reload.
* Equivalent to 'initctl touch <svc>' but without the fork+exec overhead.
* The service name should be given without the .conf suffix.
*/
int finit_reload(const char *svc)
{
char path[256];
/* Prefer the enabled/ symlink -- that's what Finit watches */
snprintf(path, sizeof(path), FINIT_RCSD "/enabled/%s.conf", svc);
if (!utimensat(AT_FDCWD, path, NULL, AT_SYMLINK_NOFOLLOW))
return 0;
snprintf(path, sizeof(path), FINIT_RCSD "/available/%s.conf", svc);
if (!utimensat(AT_FDCWD, path, NULL, AT_SYMLINK_NOFOLLOW))
return 0;
ERRNO("failed marking %s for reload", svc);
return -1;
}
int finit_reloadf(const char *fmt, ...)
{
char svc[64];
va_list ap;
va_start(ap, fmt);
vsnprintf(svc, sizeof(svc), fmt, ap);
va_end(ap);
return finit_reload(svc);
}
int finit_enable(const char *svc)
{
char src[256], dst[256];
const char *at;
snprintf(src, sizeof(src), FINIT_RCSD "/available/%s.conf", svc);
if (!fexist(src)) {
/* Template instance (e.g. container@foo): point to base template */
at = strchr(svc, '@');
if (at)
snprintf(src, sizeof(src), FINIT_RCSD "/available/%.*s@.conf",
(int)(at - svc), svc);
}
snprintf(dst, sizeof(dst), FINIT_RCSD "/enabled/%s.conf", svc);
if (symlink(src, dst) && errno != EEXIST) {
ERRNO("failed enabling %s", svc);
return -1;
}
return 0;
}
int finit_disable(const char *svc)
{
char path[256];
snprintf(path, sizeof(path), FINIT_RCSD "/enabled/%s.conf", svc);
if (remove(path) && errno != ENOENT) {
ERRNO("failed disabling %s", svc);
return -1;
}
return 0;
}
int finit_delete(const char *svc)
{
char path[256];
snprintf(path, sizeof(path), FINIT_RCSD "/enabled/%s.conf", svc);
if (remove(path) && errno != ENOENT) {
ERRNO("failed removing enabled symlink for %s", svc);
return -1;
}
snprintf(path, sizeof(path), FINIT_RCSD "/available/%s.conf", svc);
if (remove(path) && errno != ENOENT) {
ERRNO("failed removing available conf for %s", svc);
return -1;
}
return 0;
}
int finit_deletef(const char *fmt, ...)
{
char svc[64];
va_list ap;
va_start(ap, fmt);
vsnprintf(svc, sizeof(svc), fmt, ap);
va_end(ap);
return finit_delete(svc);
}
int finit_enablef(const char *fmt, ...)
{
char svc[64];
va_list ap;
va_start(ap, fmt);
vsnprintf(svc, sizeof(svc), fmt, ap);
va_end(ap);
return finit_enable(svc);
}
int finit_disablef(const char *fmt, ...)
{
char svc[64];
va_list ap;
va_start(ap, fmt);
vsnprintf(svc, sizeof(svc), fmt, ap);
va_end(ap);
return finit_disable(svc);
}
static int startup_save(sr_session_ctx_t *session, uint32_t sub_id, const char *model,
const char *xpath, sr_event_t event, unsigned request_id, void *priv)
@@ -433,7 +556,7 @@ static int change_cb(sr_session_ctx_t *session, uint32_t sub_id, const char *mod
client = srx_enabled(session, "/ietf-system:system/ntp/enabled");
server = lydx_get_xpathf(config, "/ietf-ntp:ntp") != NULL;
systemf("initctl -nbq %s chronyd", client || server ? "enable" : "disable");
(client || server) ? finit_enable("chronyd") : finit_disable("chronyd");
}
if (cfg)
+15
View File
@@ -4,11 +4,14 @@
#define CONFD_CORE_H_
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <syslog.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/param.h>
#include <unistd.h>
@@ -31,6 +34,8 @@
#include "dagger.h"
#define FINIT_RCSD "/etc/finit.d"
#define SSH_HOSTKEYS "/etc/ssh/hostkeys"
#define SSH_HOSTKEYS_NEXT SSH_HOSTKEYS"+"
#define SSL_CERT_DIR "/etc/ssl/certs"
@@ -188,6 +193,16 @@ static inline int register_rpc(sr_session_ctx_t *session, const char *xpath,
}
/* core.c */
int finit_enable(const char *svc);
int finit_disable(const char *svc);
int finit_delete(const char *svc);
int finit_reload(const char *svc);
int finit_enablef(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
int finit_disablef(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
int finit_deletef(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
int finit_reloadf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
/* interfaces.c */
int interfaces_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff, sr_event_t event, struct confd *confd);
int interfaces_cand_init(struct confd *confd);
+5 -4
View File
@@ -99,7 +99,7 @@ static void add(const char *ifname, struct lyd_node *cfg)
const char *metric = lydx_get_cattr(cfg, "route-preference");
const char *client_id = lydx_get_cattr(cfg, "client-id");
char *cid = NULL, *options = NULL;
const char *action = "disable";
int ena = 0;
const char *vendor_class;
char vendor[128] = { 0 };
char do_arp[20] = { 0 };
@@ -153,9 +153,10 @@ static void add(const char *ifname, struct lyd_node *cfg)
options ? "-o " : "", options,
ifname, cid ?: "", vendor, ifname);
fclose(fp);
action = "enable";
ena = 1;
err:
systemf("initctl -bfqn %s dhcp-client-%s", action, ifname);
ena ? finit_enablef("dhcp-client-%s", ifname)
: finit_disablef("dhcp-client-%s", ifname);
if (options)
free(options);
if (cid)
@@ -164,7 +165,7 @@ err:
static void del(const char *ifname)
{
systemf("initctl -bfq delete dhcp-client-%s", ifname);
finit_deletef("dhcp-client-%s", ifname);
}
int dhcp_client_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff,
+1 -1
View File
@@ -377,7 +377,7 @@ int dhcp_server_change(sr_session_ctx_t *session, struct lyd_node *config, struc
err_done:
if (added || deleted)
system("initctl -nbq touch dnsmasq");
finit_reload("dnsmasq");
return err;
}
+5 -4
View File
@@ -80,7 +80,7 @@ static void add_v6(const char *ifname, struct lyd_node *cfg)
const char *metric = lydx_get_cattr(cfg, "route-preference");
const char *duid = lydx_get_cattr(cfg, "duid");
char *client_duid = NULL, *options = NULL;
const char *action = "disable";
int ena = 0;
const char *addr_mode = "-N try"; /* Default: stateful mode */
char prefix_del[16] = { 0 };
bool request_pd = false;
@@ -127,9 +127,10 @@ static void add_v6(const char *ifname, struct lyd_node *cfg)
options ?: "", client_duid ?: "",
ifname, ifname);
fclose(fp);
action = "enable";
ena = 1;
err:
systemf("initctl -bfqn %s dhcpv6-client-%s", action, ifname);
ena ? finit_enablef("dhcpv6-client-%s", ifname)
: finit_disablef("dhcpv6-client-%s", ifname);
if (options)
free(options);
if (client_duid)
@@ -138,7 +139,7 @@ err:
static void del_v6(const char *ifname)
{
systemf("initctl -bfq delete dhcpv6-client-%s", ifname);
finit_deletef("dhcpv6-client-%s", ifname);
}
int dhcpv6_client_change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd_node *diff,
+3 -3
View File
@@ -510,7 +510,7 @@ int firewall_change(sr_session_ctx_t *session, struct lyd_node *config, struct l
case SR_EV_DONE:
if (!fisdir(FIREWALLD_DIR_NEXT)) {
/* Firewall is disabled */
systemf("initctl -nbq disable firewalld");
finit_disable("firewalld");
return SR_ERR_OK;
}
@@ -521,8 +521,8 @@ int firewall_change(sr_session_ctx_t *session, struct lyd_node *config, struct l
return SR_ERR_SYS;
}
systemf("initctl -nbq touch firewalld");
systemf("initctl -nbq enable firewalld");
finit_reload("firewalld");
finit_enable("firewalld");
return SR_ERR_OK;
default:
+5 -5
View File
@@ -685,14 +685,14 @@ int hardware_change(sr_session_ctx_t *session, struct lyd_node *config, struct l
ap_interfaces++;
if (running)
systemf("initctl -bfq touch hostapd@%s", name);
finit_reloadf("hostapd@%s", name);
else
systemf("initctl -bfq enable hostapd@%s", name);
finit_enablef("hostapd@%s", name);
}
}
}
if (!ap_interfaces) {
systemf("initctl -bfq disable hostapd@%s", name);
finit_disablef("hostapd@%s", name);
erasef(HOSTAPD_CONF, name);
erasef(HOSTAPD_CONF_NEXT, name);
}
@@ -784,10 +784,10 @@ int hardware_change(sr_session_ctx_t *session, struct lyd_node *config, struct l
if (fexist(GPSD_CONF_NEXT)) {
unlink(GPSD_CONF);
rename(GPSD_CONF_NEXT, GPSD_CONF);
systemf("initctl -nbq enable gpsd");
finit_enable("gpsd");
} else {
unlink(GPSD_CONF);
systemf("initctl -nbq disable gpsd");
finit_disable("gpsd");
}
break;
}
+1 -1
View File
@@ -48,7 +48,7 @@ static int change(sr_session_ctx_t *session, struct lyd_node *config, struct lyd
if (systemf("chronyc reload sources >/dev/null 2>&1"))
ERRNO("Failed reloading chronyd sources");
systemf("initctl -nbq touch chronyd");
finit_reload("chronyd");
return SR_ERR_OK;
default:
+5 -5
View File
@@ -605,17 +605,17 @@ activate:
/* Enable/disable FRR daemons as standalone finit services.
* Harmless no-op when using watchfrr (services not installed). */
systemf("initctl -nbq %s ospfd", ospfd_enabled ? "enable" : "disable");
ospfd_enabled ? finit_enable("ospfd") : finit_disable("ospfd");
if (ospfd_enabled)
systemf("initctl -nbq touch ospfd");
systemf("initctl -nbq %s ripd", ripd_enabled ? "enable" : "disable");
systemf("initctl -nbq %s bfdd", bfdd_enabled ? "enable" : "disable");
finit_reload("ospfd");
ripd_enabled ? finit_enable("ripd") : finit_disable("ripd");
bfdd_enabled ? finit_enable("bfdd") : finit_disable("bfdd");
/*
* Signal netd to reload - it assembles /etc/frr/frr.conf and
* Finit propagates the restart to the frr sysv service
*/
if (systemf("initctl -bfq touch netd"))
if (finit_reload("netd"))
ERROR("Failed to signal netd for reload");
return rc;
+14 -13
View File
@@ -276,8 +276,8 @@ static int put(sr_data_t *cfg)
/*
* Enable or disable a named service: manage nginx symlinks and mDNS
* records, then start or stop via initctl. Does NOT touch (restart)
* the service -- call 'initctl touch <name>' separately when only
* config changes and the service is already running.
* the service -- call finit_reload() separately when only config
* changes and the service is already running.
*/
static void svc_enable(int ena, svc type, const char *svcname)
{
@@ -297,7 +297,7 @@ static void svc_enable(int ena, svc type, const char *svcname)
systemf("rm -f /etc/nginx/app/%s.conf", svcname);
}
systemf("initctl -nbq %s %s", ena ? "enable" : "disable", svcname);
ena ? finit_enable(svcname) : finit_disable(svcname);
if (type != none)
mdns_records(ena ? MDNS_ADD : MDNS_DELETE, type);
@@ -397,7 +397,7 @@ static int mdns_change(sr_session_ctx_t *session, struct lyd_node *config, struc
svc_enable(ena, none, "mdns-alias");
}
if (ena)
systemf("initctl -nbq touch avahi");
finit_reload("avahi");
return put(cfg);
}
@@ -456,9 +456,9 @@ static int lldp_change(sr_session_ctx_t *session, struct lyd_node *config, struc
int lldp_ena = lydx_is_enabled(lldp, "enabled");
if (lydx_get_xpathf(diff, LLDP_XPATH "/enabled"))
systemf("initctl -nbq %s lldpd", lldp_ena ? "enable" : "disable");
lldp_ena ? finit_enable("lldpd") : finit_disable("lldpd");
else if (lldp_ena)
systemf("initctl -nbq touch lldpd");
finit_reload("lldpd");
}
break;
@@ -489,7 +489,7 @@ static int ttyd_change(sr_session_ctx_t *session, struct lyd_node *config, struc
ena = lydx_is_enabled(srv, "enabled") &&
lydx_is_enabled(lydx_get_xpathf(config, WEB_XPATH), "enabled");
svc_enable(ena, ttyd, NULL);
systemf("initctl -nbq touch nginx");
finit_reload("nginx");
return put(cfg);
}
@@ -524,7 +524,8 @@ static int netbrowse_change(sr_session_ctx_t *session, struct lyd_node *config,
lydx_is_enabled(lydx_get_xpathf(config, WEB_XPATH), "enabled");
svc_enable(ena, netbrowse, NULL);
mdns_alias_conf(ena);
systemf("initctl -nbq touch nginx mdns-alias");
finit_reload("nginx");
finit_reload("mdns-alias");
return put(cfg);
}
@@ -545,7 +546,7 @@ static int restconf_change(sr_session_ctx_t *session, struct lyd_node *config, s
ena = lydx_is_enabled(srv, "enabled") &&
lydx_is_enabled(lydx_get_xpathf(config, WEB_XPATH), "enabled");
svc_enable(ena, restconf, "restconf");
systemf("initctl -nbq touch nginx");
finit_reload("nginx");
return put(cfg);
}
@@ -566,9 +567,9 @@ static int ssh_change(sr_session_ctx_t *session, struct lyd_node *config, struct
int ssh_ena = lydx_is_enabled(ssh, "enabled");
if (lydx_get_xpathf(diff, SSH_XPATH "/enabled"))
systemf("initctl -nbq %s sshd", ssh_ena ? "enable" : "disable");
ssh_ena ? finit_enable("sshd") : finit_disable("sshd");
else if (ssh_ena)
systemf("initctl -nbq touch sshd");
finit_reload("sshd");
}
return SR_ERR_OK;
case SR_EV_ENABLED:
@@ -685,7 +686,7 @@ static int web_change(sr_session_ctx_t *session, struct lyd_node *config, struct
/* Certificate changed: regenerate ssl.conf and reload nginx */
if (lydx_get_xpathf(diff, WEB_XPATH "/certificate")) {
web_ssl_conf(srv, config);
systemf("initctl -nbq touch nginx");
finit_reload("nginx");
}
/* Web master on/off: propagate to nginx and all sub-services */
@@ -699,7 +700,7 @@ static int web_change(sr_session_ctx_t *session, struct lyd_node *config, struct
restconf, "restconf");
svc_enable(ena, web, "nginx");
mdns_alias_conf(nb_ena);
systemf("initctl -nbq touch mdns-alias");
finit_reload("mdns-alias");
}
return put(cfg);
+4 -4
View File
@@ -344,7 +344,7 @@ static int file_change(sr_session_ctx_t *session, struct lyd_node *config,struct
}
srx_free_changes(tree);
systemf("initctl -nbq touch sysklogd");
finit_reload("sysklogd");
return SR_ERR_OK;
}
@@ -377,7 +377,7 @@ static int remote_change(sr_session_ctx_t *session, struct lyd_node *config, str
}
}
systemf("initctl -nbq touch sysklogd");
finit_reload("sysklogd");
return SR_ERR_OK;
}
@@ -410,7 +410,7 @@ static int rotate_change(sr_session_ctx_t *session, struct lyd_node *config, str
}
fclose(fp);
systemf("initctl -nbq touch sysklogd");
finit_reload("sysklogd");
return SR_ERR_OK;
}
@@ -458,7 +458,7 @@ static int server_change(sr_session_ctx_t *session, struct lyd_node *config, str
sr_free_values(list, count);
fclose(fp);
done:
systemf("initctl -nbq touch sysklogd");
finit_reload("sysklogd");
return SR_ERR_OK;
}
+3 -3
View File
@@ -308,7 +308,7 @@ static int change_ntp_client(sr_session_ctx_t *session, struct lyd_node *config,
(void)remove(NTP_CLIENT_CONF);
systemf("rm -f /etc/chrony/sources.d/*");
/* Note: chronyd enable/disable is managed centrally in core.c */
systemf("initctl -nbq touch chronyd");
finit_reload("chronyd");
return SR_ERR_OK;
}
@@ -318,7 +318,7 @@ static int change_ntp_client(sr_session_ctx_t *session, struct lyd_node *config,
}
/* Note: chronyd enable/disable is managed centrally in core.c */
systemf("initctl -nbq touch chronyd");
finit_reload("chronyd");
return SR_ERR_OK;
default:
@@ -466,7 +466,7 @@ static int change_dns(sr_session_ctx_t *session, struct lyd_node *config, struct
(void)rename(RESOLV_NEXT, RESOLV_CONF);
}
systemf("initctl -bq touch resolvconf");
finit_reload("resolvconf");
return SR_ERR_OK;