mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-22 01:13:00 +02:00
confd: clean up, simplify use common log framework
- Use same log frameworks as reset of confd - Use existing primitives from libite + libsrx - Drop remaining pthreads - Coding style fixes Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
@@ -3,10 +3,9 @@
|
||||
# Single daemon handles gen-config, datastore init, config load, and plugins
|
||||
# log:prio:daemon.err
|
||||
service log:console env:/etc/default/confd \
|
||||
[S12345] <usr/ixinit> confd -f -n -v warning \
|
||||
[S12345] <usr/ixinit> confd -f -v warning \
|
||||
-F /etc/factory-config.cfg \
|
||||
-S /cfg/startup-config.cfg \
|
||||
-E /etc/failure-config.cfg \
|
||||
-p /run/confd.pid \
|
||||
-t $CONFD_TIMEOUT \
|
||||
-- Configuration daemon
|
||||
|
||||
@@ -6,8 +6,8 @@ plugin_LTLIBRARIES = confd-plugin.la
|
||||
|
||||
sbin_PROGRAMS = confd
|
||||
|
||||
confd_CFLAGS = $(sysrepo_CFLAGS) $(libyang_CFLAGS) $(jansson_CFLAGS) $(libite_CFLAGS)
|
||||
confd_LDADD = $(sysrepo_LIBS) $(libyang_LIBS) $(jansson_LIBS) $(libite_LIBS) $(EV_LIBS) -ldl
|
||||
confd_CFLAGS = $(sysrepo_CFLAGS) $(libyang_CFLAGS) $(jansson_CFLAGS) $(libite_CFLAGS) $(libsrx_CFLAGS)
|
||||
confd_LDADD = $(sysrepo_LIBS) $(libyang_LIBS) $(jansson_LIBS) $(libite_LIBS) $(libsrx_LIBS) $(EV_LIBS) -ldl
|
||||
confd_SOURCES = main.c
|
||||
|
||||
confd_plugin_la_LDFLAGS = -module -avoid-version -shared
|
||||
|
||||
+155
-304
@@ -18,10 +18,9 @@
|
||||
#include <getopt.h>
|
||||
#include <glob.h>
|
||||
#include <poll.h>
|
||||
#include <pthread.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -33,9 +32,13 @@
|
||||
#include <jansson.h>
|
||||
#include <libyang/libyang.h>
|
||||
#include <libite/lite.h>
|
||||
#include <srx/common.h>
|
||||
#include <sysrepo.h>
|
||||
#include <sysrepo/version.h>
|
||||
|
||||
/* Maximum number of sysrepo event pipe file descriptors across all plugins */
|
||||
#define MAX_EVENT_FDS 64
|
||||
|
||||
/* Callback type names from sysrepo plugin API */
|
||||
#define SRP_INIT_CB "sr_plugin_init_cb"
|
||||
#define SRP_CLEANUP_CB "sr_plugin_cleanup_cb"
|
||||
@@ -60,31 +63,17 @@ struct plugin {
|
||||
int initialized;
|
||||
};
|
||||
|
||||
/* Maximum number of sysrepo event pipe file descriptors across all plugins */
|
||||
#define MAX_EVENT_FDS 64
|
||||
static sig_atomic_t pump_running = 1;
|
||||
int debug = 0;
|
||||
|
||||
static void error_print(int sr_error, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char msg[2048];
|
||||
|
||||
if (!sr_error)
|
||||
snprintf(msg, sizeof(msg), "confd error: %s\n", format);
|
||||
else
|
||||
snprintf(msg, sizeof(msg), "confd error: %s (%s)\n", format, sr_strerror(sr_error));
|
||||
|
||||
va_start(ap, format);
|
||||
vfprintf(stderr, msg, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/* Finit style progress output on console */
|
||||
static void conout(int rc, const char *fmt, ...)
|
||||
{
|
||||
const char *sta = "%s\e[1m[\e[1;%dm%s\e[0m\e[1m]\e[0m %s";
|
||||
const char *msg[] = { " OK ", "FAIL", "WARN", " ⋯ " };
|
||||
const int col[] = { 32, 31, 33, 33 };
|
||||
const char *cr = rc == 3 ? "" : "\r";
|
||||
const int col[] = { 32, 31, 33, 33 };
|
||||
char buf[80];
|
||||
va_list ap;
|
||||
|
||||
@@ -102,46 +91,28 @@ static void version_print(void)
|
||||
|
||||
static void help_print(void)
|
||||
{
|
||||
printf(
|
||||
"Usage:\n"
|
||||
" confd [-h] [-V] [-v <level>] [-d] [-n] [-f] [-p pidfile]\n"
|
||||
" [-F factory-config] [-S startup-config] [-E failure-config]\n"
|
||||
" [-t timeout]\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -h, --help Prints usage help.\n"
|
||||
" -V, --version Prints version information.\n"
|
||||
" -v, --verbosity <level>\n"
|
||||
" Change verbosity to a level (none, error, warning, info, debug) or\n"
|
||||
" number (0, 1, 2, 3, 4).\n"
|
||||
" -d, --debug Debug mode - not daemonized and logs to stderr.\n"
|
||||
" -n, --foreground Run in foreground and log to syslog.\n"
|
||||
" -f, --fatal-plugin-fail\n"
|
||||
" Terminate if any plugin initialization fails.\n"
|
||||
" -p, --pid-file <path>\n"
|
||||
" Create a PID file at the specified path.\n"
|
||||
" -F, --factory-config <path>\n"
|
||||
" Factory default config file (default: /etc/factory-config.cfg).\n"
|
||||
" -S, --startup-config <path>\n"
|
||||
" Startup config file (default: /cfg/startup-config.cfg).\n"
|
||||
" -E, --failure-config <path>\n"
|
||||
" Failure fallback config file (default: /etc/failure-config.cfg).\n"
|
||||
" -t, --timeout <ms> Sysrepo operation timeout in seconds (default: 60).\n"
|
||||
"\n"
|
||||
"Environment variable $SRPD_PLUGINS_PATH overwrites the default plugins directory.\n"
|
||||
"\n");
|
||||
}
|
||||
|
||||
static void ignore_signals(void)
|
||||
{
|
||||
struct sigaction action;
|
||||
|
||||
memset(&action, 0, sizeof(action));
|
||||
action.sa_handler = SIG_IGN;
|
||||
sigaction(SIGPIPE, &action, NULL);
|
||||
sigaction(SIGTSTP, &action, NULL);
|
||||
sigaction(SIGTTIN, &action, NULL);
|
||||
sigaction(SIGTTOU, &action, NULL);
|
||||
printf("Usage:\n"
|
||||
" confd [-h] [-V] [-v <level>] [-f]\n"
|
||||
" [-F factory-config] [-S startup-config] [-E failure-config]\n"
|
||||
" [-t timeout]\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -h, --help Prints usage help.\n"
|
||||
" -V, --version Prints version information.\n"
|
||||
" -v, --verbosity <level>\n"
|
||||
" Change verbosity to a level (none, error, warning, info, debug).\n"
|
||||
" -f, --fatal-plugin-fail\n"
|
||||
" Terminate if any plugin initialization fails.\n"
|
||||
" -F, --factory-config <path>\n"
|
||||
" Factory default config file (default: /etc/factory-config.cfg).\n"
|
||||
" -S, --startup-config <path>\n"
|
||||
" Startup config file (default: /cfg/startup-config.cfg).\n"
|
||||
" -E, --failure-config <path>\n"
|
||||
" Failure fallback config file (default: /etc/failure-config.cfg).\n"
|
||||
" -t, --timeout <ms> Sysrepo operation timeout in seconds (default: 60).\n"
|
||||
"\n"
|
||||
"Environment variable $SRPD_PLUGINS_PATH overwrites the default plugins directory.\n"
|
||||
"\n");
|
||||
}
|
||||
|
||||
/* libev callbacks for steady-state operation */
|
||||
@@ -160,28 +131,27 @@ static void sr_event_cb(struct ev_loop *loop, struct ev_io *w, int revents)
|
||||
}
|
||||
|
||||
/*
|
||||
* Temporary event pump thread for bootstrap.
|
||||
* Temporary event pump process for bootstrap.
|
||||
*
|
||||
* With SR_SUBSCR_NO_THREAD, sysrepo writes events to a pipe and waits
|
||||
* for the application to call sr_subscription_process_events(). During
|
||||
* bootstrap, sr_replace_config() blocks waiting for callbacks — this
|
||||
* thread ensures those callbacks get dispatched.
|
||||
* child process ensures those callbacks get dispatched.
|
||||
*/
|
||||
struct event_pump {
|
||||
struct plugin *plugins;
|
||||
int plugin_count;
|
||||
int running;
|
||||
};
|
||||
static void pump_sigterm(int sig)
|
||||
{
|
||||
(void)sig;
|
||||
pump_running = 0;
|
||||
}
|
||||
|
||||
static void *event_pump_thread(void *arg)
|
||||
static void event_pump(struct plugin *plugins, int plugin_count)
|
||||
{
|
||||
struct event_pump *pump = arg;
|
||||
struct pollfd fds[MAX_EVENT_FDS];
|
||||
sr_subscription_ctx_t *subs[MAX_EVENT_FDS];
|
||||
struct pollfd fds[MAX_EVENT_FDS];
|
||||
int nfds = 0;
|
||||
|
||||
for (int i = 0; i < pump->plugin_count; i++) {
|
||||
struct plugin *p = &pump->plugins[i];
|
||||
for (int i = 0; i < plugin_count; i++) {
|
||||
struct plugin *p = &plugins[i];
|
||||
|
||||
if (p->sub && sr_get_event_pipe(p->sub, &fds[nfds].fd) == SR_ERR_OK) {
|
||||
fds[nfds].events = POLLIN;
|
||||
@@ -195,7 +165,9 @@ static void *event_pump_thread(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
while (pump->running) {
|
||||
signal(SIGTERM, pump_sigterm);
|
||||
|
||||
while (pump_running) {
|
||||
if (poll(fds, nfds, 100) > 0) {
|
||||
for (int i = 0; i < nfds; i++)
|
||||
if (fds[i].revents & POLLIN)
|
||||
@@ -203,12 +175,12 @@ static void *event_pump_thread(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
static void quiet_now(void)
|
||||
{
|
||||
int fd = -1;
|
||||
int fd;
|
||||
|
||||
fd = open("/dev/null", O_RDWR, 0);
|
||||
if (fd != -1) {
|
||||
@@ -217,89 +189,6 @@ static void quiet_now(void)
|
||||
dup2(fd, STDERR_FILENO);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
nice(0);
|
||||
}
|
||||
|
||||
static void daemon_init(int debug, sr_log_level_t log_level)
|
||||
{
|
||||
pid_t pid = 0, sid = 0;
|
||||
|
||||
nice(-20);
|
||||
|
||||
ignore_signals();
|
||||
|
||||
if (debug) {
|
||||
if (debug < 0)
|
||||
goto done;
|
||||
sr_log_stderr(log_level);
|
||||
return;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
error_print(0, "fork() failed (%s).", strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (pid > 0)
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
sid = setsid();
|
||||
if (sid < 0) {
|
||||
error_print(0, "setsid() failed (%s).", strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (chdir("/") < 0) {
|
||||
error_print(0, "chdir() failed (%s).", strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
quiet_now();
|
||||
done:
|
||||
sr_log_syslog("confd", log_level);
|
||||
}
|
||||
|
||||
static int open_pidfile(const char *pidfile)
|
||||
{
|
||||
int pidfd;
|
||||
|
||||
pidfd = open(pidfile, O_RDWR | O_CREAT, 0640);
|
||||
if (pidfd < 0) {
|
||||
error_print(0, "Unable to open the PID file \"%s\" (%s).", pidfile, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lockf(pidfd, F_TLOCK, 0) < 0) {
|
||||
if (errno == EACCES || errno == EAGAIN)
|
||||
error_print(0, "Another instance of confd is running.");
|
||||
else
|
||||
error_print(0, "Unable to lock the PID file \"%s\" (%s).", pidfile, strerror(errno));
|
||||
close(pidfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return pidfd;
|
||||
}
|
||||
|
||||
static int write_pidfile(int pidfd)
|
||||
{
|
||||
char pid[30] = {0};
|
||||
int pid_len;
|
||||
|
||||
if (ftruncate(pidfd, 0)) {
|
||||
error_print(0, "Failed to truncate pid file (%s).", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(pid, sizeof(pid) - 1, "%ld\n", (long)getpid());
|
||||
pid_len = strlen(pid);
|
||||
if (write(pidfd, pid, pid_len) < pid_len) {
|
||||
error_print(0, "Failed to write PID into pid file (%s).", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -318,14 +207,14 @@ static size_t path_len_no_ext(const char *path)
|
||||
|
||||
static int load_plugins(struct plugin **plugins, int *plugin_count)
|
||||
{
|
||||
void *mem, *handle;
|
||||
struct plugin *plugin;
|
||||
DIR *dir;
|
||||
struct dirent *ent;
|
||||
const char *plugins_dir;
|
||||
char *path;
|
||||
struct dirent *ent;
|
||||
struct plugin *plugin;
|
||||
void *mem, *handle;
|
||||
size_t name_len;
|
||||
int rc = 0;
|
||||
char *path;
|
||||
DIR *dir;
|
||||
|
||||
*plugins = NULL;
|
||||
*plugin_count = 0;
|
||||
@@ -336,7 +225,7 @@ static int load_plugins(struct plugin **plugins, int *plugin_count)
|
||||
|
||||
dir = opendir(plugins_dir);
|
||||
if (!dir) {
|
||||
error_print(0, "Opening \"%s\" directory failed (%s).", plugins_dir, strerror(errno));
|
||||
ERRNO("Opening \"%s\" directory failed", plugins_dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -345,13 +234,13 @@ static int load_plugins(struct plugin **plugins, int *plugin_count)
|
||||
continue;
|
||||
|
||||
if (asprintf(&path, "%s/%s", plugins_dir, ent->d_name) == -1) {
|
||||
error_print(0, "asprintf() failed (%s).", strerror(errno));
|
||||
ERRNO("asprintf() failed");
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
handle = dlopen(path, RTLD_LAZY);
|
||||
if (!handle) {
|
||||
error_print(0, "Opening plugin \"%s\" failed (%s).", path, dlerror());
|
||||
ERROR("Opening plugin \"%s\" failed: %s", path, dlerror());
|
||||
free(path);
|
||||
rc = -1;
|
||||
break;
|
||||
@@ -360,7 +249,7 @@ static int load_plugins(struct plugin **plugins, int *plugin_count)
|
||||
|
||||
mem = realloc(*plugins, (*plugin_count + 1) * sizeof(**plugins));
|
||||
if (!mem) {
|
||||
error_print(0, "realloc() failed (%s).", strerror(errno));
|
||||
ERRNO("realloc() failed");
|
||||
dlclose(handle);
|
||||
rc = -1;
|
||||
break;
|
||||
@@ -371,8 +260,7 @@ static int load_plugins(struct plugin **plugins, int *plugin_count)
|
||||
|
||||
*(void **)&plugin->init_cb = dlsym(handle, SRP_INIT_CB);
|
||||
if (!plugin->init_cb) {
|
||||
error_print(0, "Failed to find function \"%s\" in plugin \"%s\".",
|
||||
SRP_INIT_CB, ent->d_name);
|
||||
ERROR("Failed to find \"%s\" in plugin \"%s\".", SRP_INIT_CB, ent->d_name);
|
||||
dlclose(handle);
|
||||
rc = -1;
|
||||
break;
|
||||
@@ -380,8 +268,7 @@ static int load_plugins(struct plugin **plugins, int *plugin_count)
|
||||
|
||||
*(void **)&plugin->cleanup_cb = dlsym(handle, SRP_CLEANUP_CB);
|
||||
if (!plugin->cleanup_cb) {
|
||||
error_print(0, "Failed to find function \"%s\" in plugin \"%s\".",
|
||||
SRP_CLEANUP_CB, ent->d_name);
|
||||
ERROR("Failed to find \"%s\" in plugin \"%s\".", SRP_CLEANUP_CB, ent->d_name);
|
||||
dlclose(handle);
|
||||
rc = -1;
|
||||
break;
|
||||
@@ -394,7 +281,7 @@ static int load_plugins(struct plugin **plugins, int *plugin_count)
|
||||
|
||||
name_len = path_len_no_ext(ent->d_name);
|
||||
if (name_len == 0) {
|
||||
error_print(0, "Wrong filename \"%s\".", ent->d_name);
|
||||
ERROR("Wrong filename \"%s\".", ent->d_name);
|
||||
dlclose(handle);
|
||||
rc = -1;
|
||||
break;
|
||||
@@ -402,7 +289,7 @@ static int load_plugins(struct plugin **plugins, int *plugin_count)
|
||||
|
||||
plugin->name = strndup(ent->d_name, name_len);
|
||||
if (!plugin->name) {
|
||||
error_print(0, "strndup() failed.");
|
||||
ERRNO("strndup() failed");
|
||||
dlclose(handle);
|
||||
rc = -1;
|
||||
break;
|
||||
@@ -490,8 +377,7 @@ static int maybe_migrate(const char *path)
|
||||
}
|
||||
json_decref(root);
|
||||
|
||||
SRPLG_LOG_INF("confd", "%s config version %s vs confd %s, migrating ...",
|
||||
path, file_ver, CONFD_VERSION);
|
||||
NOTE("%s config version %s vs confd %s, migrating ...", path, file_ver, CONFD_VERSION);
|
||||
|
||||
mkpath(backup_dir, 0770);
|
||||
chown(backup_dir, 0, 10); /* root:wheel */
|
||||
@@ -499,16 +385,11 @@ static int maybe_migrate(const char *path)
|
||||
snprintf(backup, sizeof(backup), "%s/%s", backup_dir, basenm(path));
|
||||
rc = systemf("migrate -i -b \"%s\" \"%s\"", backup, path);
|
||||
if (rc)
|
||||
SRPLG_LOG_ERR("confd", "Migration of %s failed (rc=%d)", path, rc);
|
||||
ERROR("Migration of %s failed (rc=%d)", path, rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int file_exists(const char *path)
|
||||
{
|
||||
return access(path, F_OK) == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load a JSON config file into the running datastore.
|
||||
* Mirrors what sysrepocfg -I does: lyd_parse_data() + sr_replace_config().
|
||||
@@ -531,18 +412,17 @@ static int load_config(sr_conn_ctx_t *conn, sr_session_ctx_t *sess,
|
||||
|
||||
ly_in_new_memory(empty, &in);
|
||||
} else if (lyrc) {
|
||||
error_print(0, "Failed to open \"%s\" for reading", path);
|
||||
ERROR("Failed to open \"%s\" for reading", path);
|
||||
sr_release_context(conn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
lyrc = lyd_parse_data(ly_ctx, NULL, in, LYD_JSON,
|
||||
LYD_PARSE_NO_STATE | LYD_PARSE_ONLY | LYD_PARSE_STRICT,
|
||||
0, &data);
|
||||
LYD_PARSE_NO_STATE | LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &data);
|
||||
ly_in_free(in, 1);
|
||||
|
||||
if (lyrc) {
|
||||
SRPLG_LOG_ERR("confd", "Parsing %s failed", path);
|
||||
ERROR("Parsing %s failed", path);
|
||||
sr_release_context(conn);
|
||||
return -1;
|
||||
}
|
||||
@@ -551,7 +431,7 @@ static int load_config(sr_conn_ctx_t *conn, sr_session_ctx_t *sess,
|
||||
|
||||
r = sr_replace_config(sess, NULL, data, timeout_ms);
|
||||
if (r != SR_ERR_OK) {
|
||||
SRPLG_LOG_ERR("confd", "sr_replace_config failed: %s", sr_strerror(r));
|
||||
ERROR("sr_replace_config failed: %s", sr_strerror(r));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -569,14 +449,14 @@ static int export_running(sr_session_ctx_t *sess, const char *path, uint32_t tim
|
||||
|
||||
r = sr_get_data(sess, "/*", 0, timeout_ms, 0, &data);
|
||||
if (r != SR_ERR_OK) {
|
||||
SRPLG_LOG_ERR("confd", "sr_get_data failed: %s", sr_strerror(r));
|
||||
ERROR("sr_get_data failed: %s", sr_strerror(r));
|
||||
return -1;
|
||||
}
|
||||
|
||||
umask(0006);
|
||||
fp = fopen(path, "w");
|
||||
if (!fp) {
|
||||
SRPLG_LOG_ERR("confd", "Failed to open %s for writing: %s", path, strerror(errno));
|
||||
ERRNO("Failed to open %s for writing", path);
|
||||
sr_release_data(data);
|
||||
return -1;
|
||||
}
|
||||
@@ -599,21 +479,21 @@ static void handle_startup_failure(sr_session_ctx_t *sess, const char *failure_p
|
||||
{
|
||||
int r;
|
||||
|
||||
SRPLG_LOG_ERR("confd", "Failed loading startup-config, reverting to Fail Secure mode!");
|
||||
ERROR("Failed loading startup-config, reverting to Fail Secure mode!");
|
||||
|
||||
/* Reset to factory-default */
|
||||
r = sr_copy_config(sess, NULL, SR_DS_FACTORY_DEFAULT, timeout_ms);
|
||||
if (r != SR_ERR_OK) {
|
||||
SRPLG_LOG_ERR("confd", "sr_copy_config(factory-default) failed: %s", sr_strerror(r));
|
||||
ERROR("sr_copy_config(factory-default) failed: %s", sr_strerror(r));
|
||||
/* Nuclear option: wipe everything */
|
||||
systemf("rm -f /etc/sysrepo/data/*startup* /etc/sysrepo/data/*running* /dev/shm/sr_*");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Load failure-config on top */
|
||||
if (file_exists(failure_path)) {
|
||||
if (fexist(failure_path)) {
|
||||
if (load_config(conn, sess, failure_path, timeout_ms)) {
|
||||
SRPLG_LOG_ERR("confd", "Failed loading failure-config, aborting!");
|
||||
ERROR("Failed loading failure-config, aborting!");
|
||||
banner_append("CRITICAL ERROR: Logins are disabled, no credentials available");
|
||||
systemf("initctl -nbq runlevel 9");
|
||||
return;
|
||||
@@ -628,10 +508,10 @@ static void handle_startup_failure(sr_session_ctx_t *sess, const char *failure_p
|
||||
*/
|
||||
static void maybe_enable_test_mode(void)
|
||||
{
|
||||
if (file_exists("/mnt/aux/test-mode")) {
|
||||
if (fexist("/mnt/aux/test-mode")) {
|
||||
int rc;
|
||||
|
||||
conout(3, "Enbling test mode");
|
||||
conout(3, "Enabling test mode");
|
||||
rc = systemf("sysrepoctl -c infix-test -e test-mode-enable");
|
||||
conout(rc ? 1 : 0, "\n");
|
||||
}
|
||||
@@ -652,86 +532,78 @@ static int bootstrap_config(sr_conn_ctx_t *conn, sr_session_ctx_t *sess,
|
||||
int r;
|
||||
|
||||
/* Test mode support */
|
||||
if (file_exists("/mnt/aux/test-mode")) {
|
||||
if (file_exists("/mnt/aux/test-override-startup")) {
|
||||
if (fexist("/mnt/aux/test-mode")) {
|
||||
if (fexist("/mnt/aux/test-override-startup")) {
|
||||
unlink("/mnt/aux/test-override-startup");
|
||||
config_path = startup_path;
|
||||
} else {
|
||||
SRPLG_LOG_INF("confd", "Test mode detected, switching to test-config");
|
||||
NOTE("Test mode detected, switching to test-config");
|
||||
config_path = test_path;
|
||||
}
|
||||
} else {
|
||||
config_path = startup_path;
|
||||
}
|
||||
|
||||
if (file_exists(config_path)) {
|
||||
if (fexist(config_path)) {
|
||||
/* Run migration if needed */
|
||||
maybe_migrate(config_path);
|
||||
|
||||
/* Load startup (or test) config */
|
||||
SRPLG_LOG_INF("confd", "Loading %s ...", config_path);
|
||||
NOTE("Loading %s ...", config_path);
|
||||
if (load_config(conn, sess, config_path, timeout_ms)) {
|
||||
handle_startup_failure(sess, failure_path, conn, timeout_ms);
|
||||
return 0; /* continue running even in fail-secure */
|
||||
}
|
||||
|
||||
SRPLG_LOG_INF("confd", "Loaded %s successfully, syncing startup datastore.", config_path);
|
||||
NOTE("Loaded %s successfully, syncing startup datastore.", config_path);
|
||||
sr_session_switch_ds(sess, SR_DS_STARTUP);
|
||||
r = sr_copy_config(sess, NULL, SR_DS_RUNNING, timeout_ms);
|
||||
sr_session_switch_ds(sess, SR_DS_RUNNING);
|
||||
if (r != SR_ERR_OK)
|
||||
SRPLG_LOG_WRN("confd", "Failed to sync startup datastore: %s", sr_strerror(r));
|
||||
WARN("Failed to sync startup datastore: %s", sr_strerror(r));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* First boot: no startup-config, initialize from factory */
|
||||
SRPLG_LOG_INF("confd", "startup-config missing, initializing from factory-config");
|
||||
NOTE("startup-config missing, initializing from factory-config");
|
||||
|
||||
r = sr_copy_config(sess, NULL, SR_DS_FACTORY_DEFAULT, timeout_ms);
|
||||
if (r != SR_ERR_OK) {
|
||||
SRPLG_LOG_ERR("confd", "sr_copy_config(factory-default) failed: %s", sr_strerror(r));
|
||||
ERROR("sr_copy_config(factory-default) failed: %s", sr_strerror(r));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Export running → startup file */
|
||||
if (export_running(sess, startup_path, timeout_ms))
|
||||
SRPLG_LOG_WRN("confd", "Failed to export running to %s", startup_path);
|
||||
WARN("Failed to export running to %s", startup_path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *gen_config_thread(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
return (void *)(intptr_t)systemf("/usr/libexec/confd/gen-config");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *failure_path = "/etc/failure-config.cfg";
|
||||
const char *startup_path = "/cfg/startup-config.cfg";
|
||||
const char *factory_path = "/etc/factory-config.cfg";
|
||||
const char *test_path = "/etc/test-config.cfg";
|
||||
int log_opts = LOG_PID | LOG_NDELAY;
|
||||
int rc = EXIT_FAILURE, opt, i, r;
|
||||
sr_session_ctx_t *sess = NULL;
|
||||
struct plugin *plugins = NULL;
|
||||
sr_conn_ctx_t *conn = NULL;
|
||||
sr_session_ctx_t *sess = NULL;
|
||||
sr_log_level_t log_level = SR_LL_ERR;
|
||||
int plugin_count = 0, i, r, rc = EXIT_FAILURE, opt, debug = 0;
|
||||
int pidfd = -1, fatal_fail = 0;
|
||||
pthread_t tid;
|
||||
void *tret;
|
||||
const char *pidfile = NULL;
|
||||
const char *factory_path = "/etc/factory-config.cfg";
|
||||
const char *startup_path = "/cfg/startup-config.cfg";
|
||||
const char *failure_path = "/etc/failure-config.cfg";
|
||||
const char *test_path = "/etc/test-config.cfg";
|
||||
int log_level = LOG_ERR;
|
||||
pid_t gen_pid, pump_pid;
|
||||
uint32_t timeout_s = 60;
|
||||
int plugin_count = 0;
|
||||
int fatal_fail = 0;
|
||||
uint32_t timeout_ms;
|
||||
int status;
|
||||
|
||||
struct option options[] = {
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"version", no_argument, NULL, 'V'},
|
||||
{"verbosity", required_argument, NULL, 'v'},
|
||||
{"debug", no_argument, NULL, 'd'},
|
||||
{"foreground", no_argument, NULL, 'n'},
|
||||
{"pid-file", required_argument, NULL, 'p'},
|
||||
{"fatal-plugin-fail", no_argument, NULL, 'f'},
|
||||
{"factory-config", required_argument, NULL, 'F'},
|
||||
{"startup-config", required_argument, NULL, 'S'},
|
||||
@@ -741,44 +613,31 @@ int main(int argc, char **argv)
|
||||
};
|
||||
|
||||
opterr = 0;
|
||||
while ((opt = getopt_long(argc, argv, "hVv:dnp:fF:S:E:t:", options, NULL)) != -1) {
|
||||
while ((opt = getopt_long(argc, argv, "hVv:fF:S:E:t:", options, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
version_print();
|
||||
help_print();
|
||||
rc = EXIT_SUCCESS;
|
||||
goto cleanup;
|
||||
return EXIT_SUCCESS;
|
||||
case 'V':
|
||||
version_print();
|
||||
rc = EXIT_SUCCESS;
|
||||
goto cleanup;
|
||||
return EXIT_SUCCESS;
|
||||
case 'v':
|
||||
if (!strcmp(optarg, "none"))
|
||||
log_level = SR_LL_NONE;
|
||||
log_level = LOG_EMERG;
|
||||
else if (!strcmp(optarg, "error"))
|
||||
log_level = SR_LL_ERR;
|
||||
log_level = LOG_ERR;
|
||||
else if (!strcmp(optarg, "warning"))
|
||||
log_level = SR_LL_WRN;
|
||||
log_level = LOG_WARNING;
|
||||
else if (!strcmp(optarg, "info"))
|
||||
log_level = SR_LL_INF;
|
||||
log_level = LOG_NOTICE;
|
||||
else if (!strcmp(optarg, "debug"))
|
||||
log_level = SR_LL_DBG;
|
||||
else if (strlen(optarg) == 1 && optarg[0] >= '0' && optarg[0] <= '4')
|
||||
log_level = atoi(optarg);
|
||||
log_level = LOG_DEBUG;
|
||||
else {
|
||||
error_print(0, "Invalid verbosity \"%s\"", optarg);
|
||||
goto cleanup;
|
||||
fprintf(stderr, "confd error: Invalid verbosity \"%s\"\n", optarg);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
debug = 1;
|
||||
break;
|
||||
case 'n':
|
||||
debug = -1;
|
||||
break;
|
||||
case 'p':
|
||||
pidfile = optarg;
|
||||
break;
|
||||
case 'f':
|
||||
fatal_fail = 1;
|
||||
break;
|
||||
@@ -795,35 +654,44 @@ int main(int argc, char **argv)
|
||||
timeout_s = (uint32_t)atoi(optarg);
|
||||
break;
|
||||
default:
|
||||
error_print(0, "Invalid option or missing argument: -%c", optopt);
|
||||
goto cleanup;
|
||||
fprintf(stderr, "confd error: Invalid option or missing argument: -%c\n", optopt);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc) {
|
||||
error_print(0, "Redundant parameters");
|
||||
goto cleanup;
|
||||
fprintf(stderr, "confd error: Redundant parameters\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
timeout_ms = timeout_s * 1000;
|
||||
|
||||
if (pidfile && (pidfd = open_pidfile(pidfile)) < 0)
|
||||
goto cleanup;
|
||||
nice(-20);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
/* Load plugins from disk (dlopen) before daemonizing */
|
||||
if (getenv("DEBUG")) {
|
||||
log_opts |= LOG_PERROR;
|
||||
debug = 1;
|
||||
}
|
||||
openlog("confd", log_opts, LOG_DAEMON);
|
||||
setlogmask(LOG_UPTO(log_level));
|
||||
|
||||
pidfile(NULL);
|
||||
|
||||
/* Load plugins from disk (dlopen) */
|
||||
if (load_plugins(&plugins, &plugin_count))
|
||||
error_print(0, "load_plugins failed (continuing)");
|
||||
ERROR("load_plugins failed (continuing)");
|
||||
|
||||
/* Daemonize -- after this point, confd no longer logs to stderr */
|
||||
daemon_init(debug, log_level);
|
||||
|
||||
/* Start gen-config in parallel -- thread is joined before we need the result */
|
||||
/* Start gen-config in parallel — child is reaped before we need the result */
|
||||
conout(3, "Generating factory-config and failure-config");
|
||||
if (pthread_create(&tid, NULL, gen_config_thread, NULL)) {
|
||||
SRPLG_LOG_ERR("confd", "Failed to create gen-config thread: %s", strerror(errno));
|
||||
gen_pid = fork();
|
||||
if (gen_pid < 0) {
|
||||
ERRNO("Failed to fork gen-config");
|
||||
conout(1, "\n");
|
||||
goto cleanup;
|
||||
}
|
||||
if (gen_pid == 0)
|
||||
_exit(systemf("/usr/libexec/confd/gen-config"));
|
||||
|
||||
/* Phase 1: Wipe stale SHM for a clean slate */
|
||||
wipe_sysrepo_shm();
|
||||
@@ -831,25 +699,25 @@ int main(int argc, char **argv)
|
||||
/* Phase 2: Connect to sysrepo (rebuilds SHM from installed YANG modules) */
|
||||
r = sr_connect(0, &conn);
|
||||
if (r != SR_ERR_OK) {
|
||||
error_print(r, "Failed to connect");
|
||||
ERROR("Failed to connect: %s", sr_strerror(r));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Phase 3: Wait for gen-config thread to finish */
|
||||
pthread_join(tid, &tret);
|
||||
if ((intptr_t)tret != 0) {
|
||||
SRPLG_LOG_ERR("confd", "gen-config failed (rc=%d)", (int)(intptr_t)tret);
|
||||
/* Phase 3: Wait for gen-config to finish */
|
||||
waitpid(gen_pid, &status, 0);
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
||||
ERROR("gen-config failed (status=%d)", status);
|
||||
conout(1, "\n");
|
||||
goto cleanup;
|
||||
}
|
||||
conout(0, "\n");
|
||||
|
||||
/* Phase 4: Install factory defaults into all datastores */
|
||||
SRPLG_LOG_INF("confd", "Loading factory-default datastore from %s ...", factory_path);
|
||||
NOTE("Loading factory-default datastore from %s ...", factory_path);
|
||||
conout(3, "Loading factory-default datastore");
|
||||
r = sr_install_factory_config(conn, factory_path);
|
||||
if (r != SR_ERR_OK) {
|
||||
SRPLG_LOG_ERR("confd", "sr_install_factory_config failed: %s", sr_strerror(r));
|
||||
ERROR("sr_install_factory_config failed: %s", sr_strerror(r));
|
||||
conout(1, "\n");
|
||||
goto cleanup;
|
||||
}
|
||||
@@ -858,7 +726,7 @@ int main(int argc, char **argv)
|
||||
/* Phase 5: Start running-datastore session */
|
||||
r = sr_session_start(conn, SR_DS_RUNNING, &sess);
|
||||
if (r != SR_ERR_OK) {
|
||||
error_print(r, "Failed to start new session");
|
||||
ERROR("Failed to start new session: %s", sr_strerror(r));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -869,7 +737,7 @@ int main(int argc, char **argv)
|
||||
* what the plugin callbacks expect. */
|
||||
r = sr_replace_config(sess, NULL, NULL, timeout_ms);
|
||||
if (r != SR_ERR_OK) {
|
||||
SRPLG_LOG_ERR("confd", "Failed to clear running datastore: %s", sr_strerror(r));
|
||||
ERROR("Failed to clear running datastore: %s", sr_strerror(r));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -881,14 +749,13 @@ int main(int argc, char **argv)
|
||||
for (i = 0; i < plugin_count; i++) {
|
||||
r = plugins[i].init_cb(sess, &plugins[i].private_data);
|
||||
if (r) {
|
||||
SRPLG_LOG_ERR("confd", "Plugin \"%s\" initialization failed (%s).",
|
||||
plugins[i].name, sr_strerror(r));
|
||||
ERROR("Plugin \"%s\" initialization failed (%s).", plugins[i].name, sr_strerror(r));
|
||||
if (fatal_fail) {
|
||||
conout(1, "\n");
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
SRPLG_LOG_INF("confd", "Plugin \"%s\" initialized.", plugins[i].name);
|
||||
NOTE("Plugin \"%s\" initialized.", plugins[i].name);
|
||||
plugins[i].initialized = 1;
|
||||
}
|
||||
}
|
||||
@@ -897,43 +764,36 @@ int main(int argc, char **argv)
|
||||
/* Phase 8: Collect subscription contexts from plugins */
|
||||
for (i = 0; i < plugin_count; i++) {
|
||||
if (plugins[i].initialized && plugins[i].get_subs)
|
||||
plugins[i].get_subs(plugins[i].private_data,
|
||||
&plugins[i].sub, &plugins[i].fsub);
|
||||
plugins[i].get_subs(plugins[i].private_data, &plugins[i].sub, &plugins[i].fsub);
|
||||
}
|
||||
|
||||
/* Phase 9: Start event pump thread for bootstrap.
|
||||
/* Phase 9: Fork event pump process for bootstrap.
|
||||
* With SR_SUBSCR_NO_THREAD, sr_replace_config() blocks waiting
|
||||
* for callbacks. The pump thread processes those events. */
|
||||
struct event_pump pump = {
|
||||
.plugins = plugins,
|
||||
.plugin_count = plugin_count,
|
||||
.running = 1,
|
||||
};
|
||||
pthread_t pump_tid;
|
||||
|
||||
if (pthread_create(&pump_tid, NULL, event_pump_thread, &pump)) {
|
||||
SRPLG_LOG_ERR("confd", "Failed to create event pump thread: %s", strerror(errno));
|
||||
* for callbacks. The pump process processes those events. */
|
||||
pump_pid = fork();
|
||||
if (pump_pid < 0) {
|
||||
ERRNO("Failed to fork event pump");
|
||||
goto cleanup;
|
||||
}
|
||||
if (pump_pid == 0)
|
||||
event_pump(plugins, plugin_count);
|
||||
|
||||
/*
|
||||
* Phase 10: Load startup config -- plugins are now subscribed, so
|
||||
/* Phase 10: Load startup config -- plugins are now subscribed, so
|
||||
* sr_replace_config() will trigger their change callbacks.
|
||||
* The event pump thread processes those callbacks.
|
||||
*/
|
||||
* The event pump process processes those callbacks. */
|
||||
conout(3, "Loading startup-config");
|
||||
if (bootstrap_config(conn, sess, factory_path, startup_path,
|
||||
failure_path, test_path, timeout_ms)) {
|
||||
pump.running = 0;
|
||||
pthread_join(pump_tid, NULL);
|
||||
kill(pump_pid, SIGTERM);
|
||||
waitpid(pump_pid, NULL, 0);
|
||||
conout(1, "\n");
|
||||
goto cleanup;
|
||||
}
|
||||
conout(0, "\n");
|
||||
|
||||
/* Phase 11: Stop event pump — bootstrap is done */
|
||||
pump.running = 0;
|
||||
pthread_join(pump_tid, NULL);
|
||||
kill(pump_pid, SIGTERM);
|
||||
waitpid(pump_pid, NULL, 0);
|
||||
|
||||
/* No more progress to show, go to quiet daemon mode */
|
||||
quiet_now();
|
||||
@@ -941,15 +801,11 @@ int main(int argc, char **argv)
|
||||
/* Signal that bootstrap is complete (dbus, resolvconf depend on this) */
|
||||
symlink("/run/finit/cond/reconf", "/run/finit/cond/usr/bootstrap");
|
||||
|
||||
/* Write PID file after everything is ready */
|
||||
if (pidfile && write_pidfile(pidfd) < 0)
|
||||
goto cleanup;
|
||||
|
||||
/* Phase 12: Steady-state — libev event loop replaces pthread_cond_wait */
|
||||
/* Phase 12: Steady-state — libev event loop */
|
||||
{
|
||||
struct ev_loop *loop = EV_DEFAULT;
|
||||
struct ev_signal sigterm_w, sigint_w, sighup_w, sigquit_w;
|
||||
struct ev_io io_watchers[MAX_EVENT_FDS];
|
||||
struct ev_loop *loop = EV_DEFAULT;
|
||||
int nio = 0;
|
||||
|
||||
ev_signal_init(&sigterm_w, signal_cb, SIGTERM);
|
||||
@@ -995,11 +851,6 @@ cleanup:
|
||||
}
|
||||
free(plugins);
|
||||
|
||||
if (pidfd >= 0) {
|
||||
close(pidfd);
|
||||
unlink(pidfile);
|
||||
}
|
||||
|
||||
sr_disconnect(conn);
|
||||
return rc;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user