]> git.puffer.fish Git - mirror/frr.git/commitdiff
lib, watchfrr: remove `HAVE_SYSTEMD`, use own code
authorDavid Lamparter <equinox@diac24.net>
Mon, 19 Apr 2021 08:33:18 +0000 (10:33 +0200)
committerDavid Lamparter <equinox@opensourcerouting.org>
Tue, 29 Jun 2021 15:57:04 +0000 (17:57 +0200)
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>
lib/libfrr.c
lib/systemd.c
lib/systemd.h
watchfrr/watchfrr.c

index 0817182f7a462a15db8ff5196f9a3382eb15bbd0..97dab74d9b937e4fc0b95cb838ec913ab488e037 100644 (file)
@@ -44,6 +44,7 @@
 #include "frr_pthread.h"
 #include "defaults.h"
 #include "frrscript.h"
+#include "systemd.h"
 
 DEFINE_HOOK(frr_late_init, (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;
        }
+
+       /* 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)
index c5cc3aa447f5c9790a47af279163c3a18bda90ad..7944c2493b0bfb54b54f846d54ae59c2591ab353 100644 (file)
  */
 
 #include <zebra.h>
+#include <sys/un.h>
 
 #include "thread.h"
 #include "systemd.h"
+#include "lib_errors.h"
 
-#if defined HAVE_SYSTEMD
-#include <systemd/sd-daemon.h>
-#endif
+/* these are cleared from env so they don't "leak" into things we fork(),
+ * particularly for watchfrr starting individual daemons
+ *
+ * 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 */
+bool sd_stdout_is_journal;
+bool sd_stderr_is_journal;
+
+static char *notify_socket;
 
-/*
- * Wrapper this silliness if we
- * don't have systemd
+/* 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)
 {
-#if defined HAVE_SYSTEMD
-       sd_notify(0, info);
-#else
-       return;
-#endif
-}
+       int sock;
+       struct sockaddr_un sun;
 
-/*
- * A return of 0 means that we are not watchdoged
- */
-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);
-
-       /*
-        * If return is 0 -> we don't want watchdog
-        * if return is < 0, some sort of failure occurred
-        */
-       if (ret < 0)
-               return 0;
-
-       /*
-        * systemd can return that this process
-        * is not the expected sender of the watchdog timer
-        * 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) {
-               watchdog = getenv("WATCHDOG_USEC");
-               if (!watchdog)
-                       return 0;
-
-               usec = atol(watchdog);
-       }
+       if (!notify_socket)
+               return;
+
+       sock = socket(AF_UNIX, SOCK_DGRAM, 0);
+       if (sock < 0)
+               return;
+
+       sun.sun_family = AF_UNIX;
+       strlcpy(sun.sun_path, notify_socket, sizeof(sun.sun_path));
 
-       return (usec / 1000000) / 3;
-#else
-       return 0;
-#endif
+       /* linux abstract unix socket namespace */
+       if (sun.sun_path[0] == '@')
+               sun.sun_path[0] = '\0';
+
+       /* nothing we can do if this errors out... */
+       sendto(sock, info, strlen(info), 0, (struct sockaddr *)&sun,
+              sizeof(sun));
+
+       close(sock);
 }
 
 void systemd_send_stopping(void)
@@ -90,34 +78,27 @@ void systemd_send_stopping(void)
        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 int systemd_send_watchdog(struct thread *t)
 {
        systemd_send_information("WATCHDOG=1");
 
-       thread_add_timer(systemd_master, systemd_send_watchdog, NULL, wsecs,
-                        NULL);
-
+       assert(watchdog_msec > 0);
+       thread_add_timer_msec(systemd_master, systemd_send_watchdog, NULL,
+                             watchdog_msec, NULL);
        return 1;
 }
 
-void systemd_send_started(struct thread_master *m, int the_process)
+void systemd_send_started(struct thread_master *m)
 {
        assert(m != NULL);
 
-       wsecs = systemd_get_watchdog_time(the_process);
        systemd_master = m;
 
        systemd_send_information("READY=1");
-       if (wsecs != 0) {
-               systemd_send_information("WATCHDOG=1");
-               thread_add_timer(m, systemd_send_watchdog, m, wsecs, NULL);
-       }
+       if (watchdog_msec > 0)
+               systemd_send_watchdog(NULL);
 }
 
 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);
        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");
+}
index d9885c5d9c3ef2267613cee9ad9566d8300e4a30..1933f4f6887dea14b8b074890869adb7493bf2a2 100644 (file)
@@ -28,9 +28,6 @@ extern "C" {
  *
  * Design point is that if systemd is not being used on this system
  * then these functions becomes a no-op.
- *
- * To turn on systemd compilation, use --enable-systemd on
- * configure run.
  */
 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
  *                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
  */
 void systemd_send_status(const char *status);
 
+/*
+ * grab startup state from env vars
+ */
+void systemd_init_env(void);
+
 #ifdef __cplusplus
 }
 #endif
index faf1777d7fd8922a5280da7c0b5783349853515b..d0b4be81d4825ca76c18473ff71436140a7f63e9 100644 (file)
@@ -469,12 +469,10 @@ static int run_job(struct restart_info *restart, const char *cmdtype,
                return -1;
        }
 
-#if defined HAVE_SYSTEMD
        char buffer[512];
 
        snprintf(buffer, sizeof(buffer), "restarting %s", restart->name);
        systemd_send_status(buffer);
-#endif
 
        /* Note: time_elapsed test must come before the force test, since we
           need
@@ -506,9 +504,8 @@ static int run_job(struct restart_info *restart, const char *cmdtype,
                        restart->pid = 0;
        }
 
-#if defined HAVE_SYSTEMD
        systemd_send_status("FRR Operational");
-#endif
+
        /* Calculate the new restart interval. */
        if (update_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");
        if (fp)
                fclose(fp);
-#if defined HAVE_SYSTEMD
-       systemd_send_started(master, 0);
+
+       systemd_send_started(master);
        systemd_send_status("FRR Operational");
-#endif
        sent = 1;
 }