mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-15 18:56:40 +00:00
lib, watchfrr: remove HAVE_SYSTEMD
, use own code
This replaces the external libsystemd dependency with... pretty much the same amount of built-in code. But with one fewer dependency and build switch needed. Also check `JOURNAL_STREAM` for future logging integration. Signed-off-by: David Lamparter <equinox@diac24.net>
This commit is contained in:
parent
32694c41bb
commit
247898d5d2
@ -44,6 +44,7 @@
|
|||||||
#include "frr_pthread.h"
|
#include "frr_pthread.h"
|
||||||
#include "defaults.h"
|
#include "defaults.h"
|
||||||
#include "frrscript.h"
|
#include "frrscript.h"
|
||||||
|
#include "systemd.h"
|
||||||
|
|
||||||
DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm));
|
DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm));
|
||||||
DEFINE_HOOK(frr_config_pre, (struct thread_master * tm), (tm));
|
DEFINE_HOOK(frr_config_pre, (struct thread_master * tm), (tm));
|
||||||
@ -363,6 +364,11 @@ void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv)
|
|||||||
|
|
||||||
startup_fds |= UINT64_C(0x1) << (uint64_t)i;
|
startup_fds |= UINT64_C(0x1) << (uint64_t)i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* note this doesn't do anything, it just grabs state, so doing it
|
||||||
|
* early in _preinit is perfect.
|
||||||
|
*/
|
||||||
|
systemd_init_env();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool frr_is_startup_fd(int fd)
|
bool frr_is_startup_fd(int fd)
|
||||||
|
165
lib/systemd.c
165
lib/systemd.c
@ -20,68 +20,56 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <zebra.h>
|
#include <zebra.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "systemd.h"
|
#include "systemd.h"
|
||||||
|
#include "lib_errors.h"
|
||||||
|
|
||||||
#if defined HAVE_SYSTEMD
|
/* these are cleared from env so they don't "leak" into things we fork(),
|
||||||
#include <systemd/sd-daemon.h>
|
* particularly for watchfrr starting individual daemons
|
||||||
#endif
|
*
|
||||||
|
* watchdog_pid is currently not used since watchfrr starts forking.
|
||||||
|
* (TODO: handle that better, somehow?)
|
||||||
|
*/
|
||||||
|
static pid_t watchdog_pid = -1;
|
||||||
|
static intmax_t watchdog_msec;
|
||||||
|
|
||||||
/*
|
/* not used yet, but can trigger auto-switch to journald logging */
|
||||||
* Wrapper this silliness if we
|
bool sd_stdout_is_journal;
|
||||||
* don't have systemd
|
bool sd_stderr_is_journal;
|
||||||
|
|
||||||
|
static char *notify_socket;
|
||||||
|
|
||||||
|
/* talk to whatever entity claims to be systemd ;)
|
||||||
|
*
|
||||||
|
* refer to sd_notify docs for messages systemd accepts over this socket.
|
||||||
|
* This function should be functionally equivalent to sd_notify().
|
||||||
*/
|
*/
|
||||||
static void systemd_send_information(const char *info)
|
static void systemd_send_information(const char *info)
|
||||||
{
|
{
|
||||||
#if defined HAVE_SYSTEMD
|
int sock;
|
||||||
sd_notify(0, info);
|
struct sockaddr_un sun;
|
||||||
#else
|
|
||||||
|
if (!notify_socket)
|
||||||
return;
|
return;
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
sock = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||||
* A return of 0 means that we are not watchdoged
|
if (sock < 0)
|
||||||
*/
|
return;
|
||||||
static int systemd_get_watchdog_time(int the_process)
|
|
||||||
{
|
|
||||||
#if defined HAVE_SYSTEMD
|
|
||||||
uint64_t usec;
|
|
||||||
char *watchdog = NULL;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = sd_watchdog_enabled(0, &usec);
|
sun.sun_family = AF_UNIX;
|
||||||
|
strlcpy(sun.sun_path, notify_socket, sizeof(sun.sun_path));
|
||||||
|
|
||||||
/*
|
/* linux abstract unix socket namespace */
|
||||||
* If return is 0 -> we don't want watchdog
|
if (sun.sun_path[0] == '@')
|
||||||
* if return is < 0, some sort of failure occurred
|
sun.sun_path[0] = '\0';
|
||||||
*/
|
|
||||||
if (ret < 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/*
|
/* nothing we can do if this errors out... */
|
||||||
* systemd can return that this process
|
sendto(sock, info, strlen(info), 0, (struct sockaddr *)&sun,
|
||||||
* is not the expected sender of the watchdog timer
|
sizeof(sun));
|
||||||
* If we set the_process = 0 then we expect to
|
|
||||||
* be able to send the watchdog to systemd
|
|
||||||
* irrelevant of the pid of this process.
|
|
||||||
*/
|
|
||||||
if (ret == 0 && the_process)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (ret == 0 && !the_process) {
|
close(sock);
|
||||||
watchdog = getenv("WATCHDOG_USEC");
|
|
||||||
if (!watchdog)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
usec = atol(watchdog);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (usec / 1000000) / 3;
|
|
||||||
#else
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void systemd_send_stopping(void)
|
void systemd_send_stopping(void)
|
||||||
@ -90,34 +78,27 @@ void systemd_send_stopping(void)
|
|||||||
systemd_send_information("STOPPING=1");
|
systemd_send_information("STOPPING=1");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* How many seconds should we wait between watchdog sends
|
|
||||||
*/
|
|
||||||
static int wsecs = 0;
|
|
||||||
static struct thread_master *systemd_master = NULL;
|
static struct thread_master *systemd_master = NULL;
|
||||||
|
|
||||||
static int systemd_send_watchdog(struct thread *t)
|
static int systemd_send_watchdog(struct thread *t)
|
||||||
{
|
{
|
||||||
systemd_send_information("WATCHDOG=1");
|
systemd_send_information("WATCHDOG=1");
|
||||||
|
|
||||||
thread_add_timer(systemd_master, systemd_send_watchdog, NULL, wsecs,
|
assert(watchdog_msec > 0);
|
||||||
NULL);
|
thread_add_timer_msec(systemd_master, systemd_send_watchdog, NULL,
|
||||||
|
watchdog_msec, NULL);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void systemd_send_started(struct thread_master *m, int the_process)
|
void systemd_send_started(struct thread_master *m)
|
||||||
{
|
{
|
||||||
assert(m != NULL);
|
assert(m != NULL);
|
||||||
|
|
||||||
wsecs = systemd_get_watchdog_time(the_process);
|
|
||||||
systemd_master = m;
|
systemd_master = m;
|
||||||
|
|
||||||
systemd_send_information("READY=1");
|
systemd_send_information("READY=1");
|
||||||
if (wsecs != 0) {
|
if (watchdog_msec > 0)
|
||||||
systemd_send_information("WATCHDOG=1");
|
systemd_send_watchdog(NULL);
|
||||||
thread_add_timer(m, systemd_send_watchdog, m, wsecs, NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void systemd_send_status(const char *status)
|
void systemd_send_status(const char *status)
|
||||||
@ -127,3 +108,65 @@ void systemd_send_status(const char *status)
|
|||||||
snprintf(buffer, sizeof(buffer), "STATUS=%s", status);
|
snprintf(buffer, sizeof(buffer), "STATUS=%s", status);
|
||||||
systemd_send_information(buffer);
|
systemd_send_information(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static intmax_t getenv_int(const char *varname, intmax_t dflt)
|
||||||
|
{
|
||||||
|
char *val, *err;
|
||||||
|
intmax_t intval;
|
||||||
|
|
||||||
|
val = getenv(varname);
|
||||||
|
if (!val)
|
||||||
|
return dflt;
|
||||||
|
|
||||||
|
intval = strtoimax(val, &err, 0);
|
||||||
|
if (*err || !*val)
|
||||||
|
return dflt;
|
||||||
|
return intval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void systemd_init_env(void)
|
||||||
|
{
|
||||||
|
char *tmp;
|
||||||
|
uintmax_t dev, ino;
|
||||||
|
int len;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
notify_socket = getenv("NOTIFY_SOCKET");
|
||||||
|
|
||||||
|
/* no point in setting up watchdog w/o notify socket */
|
||||||
|
if (notify_socket) {
|
||||||
|
intmax_t watchdog_usec;
|
||||||
|
|
||||||
|
watchdog_pid = getenv_int("WATCHDOG_PID", -1);
|
||||||
|
if (watchdog_pid <= 0)
|
||||||
|
watchdog_pid = -1;
|
||||||
|
|
||||||
|
/* note this is the deadline, hence the divide by 3 */
|
||||||
|
watchdog_usec = getenv_int("WATCHDOG_USEC", 0);
|
||||||
|
if (watchdog_usec >= 3000)
|
||||||
|
watchdog_msec = watchdog_usec / 3000;
|
||||||
|
else {
|
||||||
|
if (watchdog_usec != 0)
|
||||||
|
flog_err(
|
||||||
|
EC_LIB_UNAVAILABLE,
|
||||||
|
"systemd expects a %jd microsecond watchdog timer, but FRR only supports millisecond resolution!",
|
||||||
|
watchdog_usec);
|
||||||
|
watchdog_msec = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = getenv("JOURNAL_STREAM");
|
||||||
|
if (tmp && sscanf(tmp, "%ju:%ju%n", &dev, &ino, &len) == 2
|
||||||
|
&& (size_t)len == strlen(tmp)) {
|
||||||
|
if (fstat(1, &st) == 0 && st.st_dev == (dev_t)dev
|
||||||
|
&& st.st_ino == (ino_t)ino)
|
||||||
|
sd_stdout_is_journal = true;
|
||||||
|
if (fstat(2, &st) == 0 && st.st_dev == (dev_t)dev
|
||||||
|
&& st.st_ino == (ino_t)ino)
|
||||||
|
sd_stderr_is_journal = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* these should *not* be passed to any other process we start */
|
||||||
|
unsetenv("WATCHDOG_PID");
|
||||||
|
unsetenv("WATCHDOG_USEC");
|
||||||
|
}
|
||||||
|
@ -28,9 +28,6 @@ extern "C" {
|
|||||||
*
|
*
|
||||||
* Design point is that if systemd is not being used on this system
|
* Design point is that if systemd is not being used on this system
|
||||||
* then these functions becomes a no-op.
|
* then these functions becomes a no-op.
|
||||||
*
|
|
||||||
* To turn on systemd compilation, use --enable-systemd on
|
|
||||||
* configure run.
|
|
||||||
*/
|
*/
|
||||||
void systemd_send_stopping(void);
|
void systemd_send_stopping(void);
|
||||||
|
|
||||||
@ -39,13 +36,18 @@ void systemd_send_stopping(void);
|
|||||||
* the_process - Should we send watchdog if we are not the requested
|
* the_process - Should we send watchdog if we are not the requested
|
||||||
* process?
|
* process?
|
||||||
*/
|
*/
|
||||||
void systemd_send_started(struct thread_master *master, int the_process);
|
void systemd_send_started(struct thread_master *master);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* status - A status string to send to systemd
|
* status - A status string to send to systemd
|
||||||
*/
|
*/
|
||||||
void systemd_send_status(const char *status);
|
void systemd_send_status(const char *status);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* grab startup state from env vars
|
||||||
|
*/
|
||||||
|
void systemd_init_env(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -469,12 +469,10 @@ static int run_job(struct restart_info *restart, const char *cmdtype,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined HAVE_SYSTEMD
|
|
||||||
char buffer[512];
|
char buffer[512];
|
||||||
|
|
||||||
snprintf(buffer, sizeof(buffer), "restarting %s", restart->name);
|
snprintf(buffer, sizeof(buffer), "restarting %s", restart->name);
|
||||||
systemd_send_status(buffer);
|
systemd_send_status(buffer);
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Note: time_elapsed test must come before the force test, since we
|
/* Note: time_elapsed test must come before the force test, since we
|
||||||
need
|
need
|
||||||
@ -506,9 +504,8 @@ static int run_job(struct restart_info *restart, const char *cmdtype,
|
|||||||
restart->pid = 0;
|
restart->pid = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined HAVE_SYSTEMD
|
|
||||||
systemd_send_status("FRR Operational");
|
systemd_send_status("FRR Operational");
|
||||||
#endif
|
|
||||||
/* Calculate the new restart interval. */
|
/* Calculate the new restart interval. */
|
||||||
if (update_interval) {
|
if (update_interval) {
|
||||||
if (delay.tv_sec > 2 * gs.max_restart_interval)
|
if (delay.tv_sec > 2 * gs.max_restart_interval)
|
||||||
@ -718,10 +715,9 @@ static void daemon_send_ready(int exitcode)
|
|||||||
fp = fopen(started, "w");
|
fp = fopen(started, "w");
|
||||||
if (fp)
|
if (fp)
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
#if defined HAVE_SYSTEMD
|
|
||||||
systemd_send_started(master, 0);
|
systemd_send_started(master);
|
||||||
systemd_send_status("FRR Operational");
|
systemd_send_status("FRR Operational");
|
||||||
#endif
|
|
||||||
sent = 1;
|
sent = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user