[RFC PATCH 6/6] Support systemd watchdog
Signed-off-by: Victor Westerhuis --- debuginfod/debuginfod.cxx | 35 +-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/debuginfod/debuginfod.cxx b/debuginfod/debuginfod.cxx index 35b5fc18..b31c77d3 100644 --- a/debuginfod/debuginfod.cxx +++ b/debuginfod/debuginfod.cxx @@ -94,6 +94,7 @@ using namespace std; #include #ifdef ENABLE_SYSTEMD +#include #include #endif @@ -3600,13 +3601,43 @@ main (int argc, char *argv[]) } } +#ifdef ENABLE_SYSTEMD + uint64_t timeout_usec; + int watchdog_enabled = sd_watchdog_enabled (true, &timeout_usec); + if (watchdog_enabled < 0) +report_error (0, -watchdog_enabled, + "warning: cannot determine if watchdog is enabled"); +#endif + /* Trivial main loop! */ #ifdef ENABLE_SYSTEMD (void) sd_notify (false, "READY=1"); #endif set_metric("ready", 1); - while (! interrupted) -pause (); +#ifdef ENABLE_SYSTEMD + if (watchdog_enabled > 0) +{ + timeout_usec /= 2; + struct timespec timeout; + timeout.tv_sec = timeout_usec / 100; + timeout.tv_nsec = timeout_usec % 100 * 1000; + + rc = 0; + struct timespec remaining_timeout; + while (! interrupted) +{ + if (rc == 0) +{ + (void) sd_notify (false, "WATCHDOG=1"); + remaining_timeout = timeout; +} + rc = nanosleep (&remaining_timeout, &remaining_timeout); +} +} + else +#endif +while (! interrupted) + pause (); scanq.nuke(); // wake up any remaining scanq-related threads, let them die set_metric("ready", 0); #ifdef ENABLE_SYSTEMD -- 2.30.1
[RFC PATCH 5/6] Report error exit reason to systemd
Signed-off-by: Victor Westerhuis --- debuginfod/debuginfod.cxx | 74 --- 1 file changed, 46 insertions(+), 28 deletions(-) diff --git a/debuginfod/debuginfod.cxx b/debuginfod/debuginfod.cxx index 9542c5e2..35b5fc18 100644 --- a/debuginfod/debuginfod.cxx +++ b/debuginfod/debuginfod.cxx @@ -120,6 +120,24 @@ using namespace std; #endif +#ifdef ENABLE_SYSTEMD +#define report_error(status, errnum, format, ...) \ + do \ +{ \ + int s = (status), e = (errnum); \ + if (s != 0 && e != 0) \ +{ \ + (void) sd_notifyf (false, "ERRNO=%d", e); \ + (void) sd_notifyf (false, "STATUS=" format, ##__VA_ARGS__); \ +} \ + error (s, e, format, ##__VA_ARGS__); \ +} \ + while (false) +#else +#define report_error(...) error(__VA_ARGS__) +#endif + + inline bool string_endswith(const string& haystack, const string& needle) { @@ -3316,10 +3334,10 @@ main (int argc, char *argv[]) #endif int rc = regcomp (& file_include_regex, ".*", REG_EXTENDED|REG_NOSUB); // match everything if (rc != 0) -error (EXIT_FAILURE, 0, "regcomp failure: %d", rc); +report_error (EXIT_FAILURE, 0, "regcomp failure: %d", rc); rc = regcomp (& file_exclude_regex, "^$", REG_EXTENDED|REG_NOSUB); // match nothing if (rc != 0) -error (EXIT_FAILURE, 0, "regcomp failure: %d", rc); +report_error (EXIT_FAILURE, 0, "regcomp failure: %d", rc); // default parameters for fdcache are computed from system stats struct statfs sfs; @@ -3337,8 +3355,8 @@ main (int argc, char *argv[]) argp_program_version_hook = print_version; // this works (void) argp_parse (&argp, argc, argv, ARGP_IN_ORDER, &remaining, NULL); if (remaining != argc) - error (EXIT_FAILURE, 0, - "unexpected argument: %s", argv[remaining]); + report_error (EXIT_FAILURE, 0, +"unexpected argument: %s", argv[remaining]); if (scan_archives.size()==0 && !scan_files && source_paths.size()>0) obatched(clog) << "warning: without -F -R -U -Z, ignoring PATHs" << endl; @@ -3362,13 +3380,13 @@ main (int argc, char *argv[]) if (rc == SQLITE_CORRUPT) { (void) unlink (db_path.c_str()); - error (EXIT_FAILURE, 0, - "cannot open %s, deleted database: %s", db_path.c_str(), sqlite3_errmsg(db)); + report_error (EXIT_FAILURE, 0, +"cannot open %s, deleted database: %s", db_path.c_str(), sqlite3_errmsg(db)); } else if (rc) { - error (EXIT_FAILURE, 0, - "cannot open %s, consider deleting database: %s", db_path.c_str(), sqlite3_errmsg(db)); + report_error (EXIT_FAILURE, 0, +"cannot open %s, consider deleting database: %s", db_path.c_str(), sqlite3_errmsg(db)); } // open the readonly query variant @@ -3381,8 +3399,8 @@ main (int argc, char *argv[]) NULL); if (rc) { - error (EXIT_FAILURE, 0, - "cannot open %s, consider deleting database: %s", db_path.c_str(), sqlite3_errmsg(dbq)); + report_error (EXIT_FAILURE, 0, +"cannot open %s, consider deleting database: %s", db_path.c_str(), sqlite3_errmsg(dbq)); } @@ -3393,16 +3411,16 @@ main (int argc, char *argv[]) rc = sqlite3_create_function(dbq, "sharedprefix", 2, SQLITE_UTF8, NULL, & sqlite3_sharedprefix_fn, NULL, NULL); if (rc != SQLITE_OK) -error (EXIT_FAILURE, 0, - "cannot create sharedprefix function: %s", sqlite3_errmsg(dbq)); +report_error (EXIT_FAILURE, 0, + "cannot create sharedprefix function: %s", sqlite3_errmsg(dbq)); if (verbose > 3) obatched(clog) << "ddl: " << DEBUGINFOD_SQLITE_DDL << endl; rc = sqlite3_exec (db, DEBUGINFOD_SQLITE_DDL, NULL, NULL, NULL); if (rc != SQLITE_OK) { - error (EXIT_FAILURE, 0, - "cannot run database schema ddl: %s", sqlite3_errmsg(db)); + report_error (EXIT_FAILURE, 0, +"cannot run database schema ddl: %s", sqlite3_errmsg(db)); } vector daemons; @@ -3413,7 +3431,7 @@ main (int argc, char *argv[]) if (fds <= 0) { close_databases (); - error (EXIT_FAILURE, -fds, "cannot get fds from systemd"); + report_error (EXIT_FAILURE, -fds, "cannot get fds from systemd"); } for (int i = 0; i < fds; ++i) @@ -3424,13 +3442,13 @@ main (int argc, char *argv[]) if (rc < 0) { close_databases (); - error (EXIT_FAILURE, -rc, "unable to determine fd type"); +
[RFC PATCH 3/6] Notify systemd when ready and stopping
Signed-off-by: Victor Westerhuis --- config/debuginfod.service | 1 + debuginfod/debuginfod.cxx | 6 ++ 2 files changed, 7 insertions(+) diff --git a/config/debuginfod.service b/config/debuginfod.service index b64d8cb9..6c434705 100644 --- a/config/debuginfod.service +++ b/config/debuginfod.service @@ -4,6 +4,7 @@ Documentation=http://elfutils.org/ After=network.target [Service] +Type=Notify EnvironmentFile=/etc/sysconfig/debuginfod User=debuginfod Group=debuginfod diff --git a/debuginfod/debuginfod.cxx b/debuginfod/debuginfod.cxx index caced48c..4dece371 100644 --- a/debuginfod/debuginfod.cxx +++ b/debuginfod/debuginfod.cxx @@ -3576,11 +3576,17 @@ main (int argc, char *argv[]) } /* Trivial main loop! */ +#ifdef ENABLE_SYSTEMD + (void) sd_notify (false, "READY=1"); +#endif set_metric("ready", 1); while (! interrupted) pause (); scanq.nuke(); // wake up any remaining scanq-related threads, let them die set_metric("ready", 0); +#ifdef ENABLE_SYSTEMD + (void) sd_notify (false, "STOPPING=1"); +#endif if (verbose) obatched(clog) << "stopping" << endl; -- 2.30.1
[RFC PATCH 2/6] Allow socket activation by systemd
Signed-off-by: Victor Westerhuis --- debuginfod/debuginfod.cxx | 161 -- 1 file changed, 121 insertions(+), 40 deletions(-) diff --git a/debuginfod/debuginfod.cxx b/debuginfod/debuginfod.cxx index 2aecc049..caced48c 100644 --- a/debuginfod/debuginfod.cxx +++ b/debuginfod/debuginfod.cxx @@ -93,6 +93,10 @@ using namespace std; #include +#ifdef ENABLE_SYSTEMD +#include +#endif + #if MHD_VERSION >= 0x00097002 // libmicrohttpd 0.9.71 broke API #define MHD_RESULT enum MHD_Result @@ -367,6 +371,10 @@ static const struct argp_option options[] = { "fdcache-prefetch", ARGP_KEY_FDCACHE_PREFETCH, "NUM", 0, "Number of archive files to prefetch into fdcache.", 0 }, #define ARGP_KEY_FDCACHE_MINTMP 0x1004 { "fdcache-mintmp", ARGP_KEY_FDCACHE_MINTMP, "NUM", 0, "Minimum free space% on tmpdir.", 0 }, +#ifdef ENABLE_SYSTEMD +#define ARGP_KEY_SYSTEMD 0x1005 + { "systemd", ARGP_KEY_SYSTEMD, NULL, 0, "Use systemd socket activation and cache directory.", 0 }, +#endif { NULL, 0, NULL, 0, NULL, 0 } }; @@ -412,6 +420,9 @@ static long fdcache_mbs; static long fdcache_prefetch; static long fdcache_mintmp; static string tmpdir; +#ifdef ENABLE_SYSTEMD +static bool systemd; +#endif static void set_metric(const string& key, double value); // static void inc_metric(const string& key); @@ -541,6 +552,11 @@ parse_opt (int key, char *arg, case ARGP_KEY_ARG: source_paths.insert(string(arg)); break; +#ifdef ENABLE_SYSTEMD +case ARGP_KEY_SYSTEMD: + systemd = true; + break; +#endif // case 'h': argp_state_help (state, stderr, ARGP_HELP_LONG|ARGP_HELP_EXIT_OK); default: return ARGP_ERR_UNKNOWN; } @@ -3267,6 +3283,16 @@ static void sqlite3_sharedprefix_fn (sqlite3_context* c, int argc, sqlite3_value } +static void close_databases () +{ + sqlite3 *database = db; + sqlite3 *databaseq = dbq; + db = dbq = 0; // for signal_handler not to freak + (void) sqlite3_close (databaseq); + (void) sqlite3_close (database); +} + + int main (int argc, char *argv[]) { @@ -3372,46 +3398,105 @@ main (int argc, char *argv[]) "cannot run database schema ddl: %s", sqlite3_errmsg(db)); } - // Start httpd server threads. Separate pool for IPv4 and IPv6, in - // case the host only has one protocol stack. - MHD_Daemon *d4 = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION + vector daemons; +#ifdef ENABLE_SYSTEMD + if (systemd) +{ + int fds = sd_listen_fds (true); + if (fds <= 0) +{ + close_databases (); + error (EXIT_FAILURE, -fds, "cannot get fds from systemd"); +} + + for (int i = 0; i < fds; ++i) +{ + int fd = SD_LISTEN_FDS_START + i; + + rc = sd_is_socket_inet (fd, AF_UNSPEC, SOCK_STREAM, true, 0); + if (rc < 0) +{ + close_databases (); + error (EXIT_FAILURE, -rc, "unable to determine fd type"); +} + else if (rc == 0) +{ + close_databases (); + error (EXIT_FAILURE, 0, + "fd %d is not of the correct socket type", fd); +} + + MHD_Daemon *d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION #if MHD_VERSION >= 0x00095300 - | MHD_USE_INTERNAL_POLLING_THREAD +| MHD_USE_INTERNAL_POLLING_THREAD #else - | MHD_USE_SELECT_INTERNALLY +| MHD_USE_SELECT_INTERNALLY #endif - | MHD_USE_DEBUG, /* report errors to stderr */ - http_port, - NULL, NULL, /* default accept policy */ - handler_cb, NULL, /* handler callback */ - MHD_OPTION_END); - MHD_Daemon *d6 = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION +| MHD_USE_DEBUG /* report errors to stderr */ +| MHD_USE_ITC, /* don't close socket on shutdown */ +0, +NULL, NULL, /* default accept policy */ +handler_cb, NULL, /* handler callback */ +MHD_OPTION_LISTEN_SOCKET, +fd, +MHD_OPTION_END); + if (d == NULL) +{ + close_databases (); + error (EXIT_FAILURE, 0, +"cannot start http server on fd %d", fd); +} + + obatche
[RFC PATCH 0/6] Allow systemd activation for debuginfod
As a developer I have a few self-built Debian packages in a small repo on my own laptop. I like having debuginfod running when debugging them, but it does not have to be running all the time. This patch series is a first try at integrating systemd socket activation in debuginfod. I've tried to split the series into different ways of integration. I'm not sure if watchdog support is really useful, since the main loop doesn't do any work. If it isn't, I can drop it. Victor Westerhuis (6): Find and link libsystemd Allow socket activation by systemd Notify systemd when ready and stopping Use cache directory from systemd Report error exit reason to systemd Support systemd watchdog config/debuginfod.service | 3 +- configure.ac | 12 ++ debuginfod/Makefile.am| 7 + debuginfod/debuginfod.cxx | 267 +- 4 files changed, 226 insertions(+), 63 deletions(-) -- 2.30.1
[RFC PATCH 1/6] Find and link libsystemd
Signed-off-by: Victor Westerhuis --- configure.ac | 12 debuginfod/Makefile.am | 7 +++ 2 files changed, 19 insertions(+) diff --git a/configure.ac b/configure.ac index aa8439e8..8d52b666 100644 --- a/configure.ac +++ b/configure.ac @@ -773,6 +773,17 @@ AS_IF([test "x$enable_debuginfod" != "xno"], [ if test "x$enable_debuginfod" = "xno"; then AC_MSG_ERROR([dependencies not found, use --disable-debuginfod to disable.]) fi + +AC_ARG_ENABLE([systemd],AC_HELP_STRING([--enable-systemd], [Enable systemd support in debuginfod])) +AS_IF([test "x$enable_systemd" != "xno"], [ +PKG_CHECK_MODULES([libsystemd],[libsystemd],[enable_systemd=yes],[ +AS_IF([test "x$enable_systemd" = "xyes"], [ +AC_MSG_ERROR([need libsystemd, use --disable-systemd to disable.]) +], [enable_systemd=no]) +]) +]) +AS_IF([test "x$enable_systemd" = "xyes"],AC_DEFINE([ENABLE_SYSTEMD],[1],[Enable systemd support])) +AM_CONDITIONAL([SYSTEMD],[test "x$enable_systemd" = "xyes"]) ]) AS_IF([test "x$enable_debuginfod" != "xno"],AC_DEFINE([ENABLE_DEBUGINFOD],[1],[Build debuginfod])) @@ -823,6 +834,7 @@ AC_MSG_NOTICE([ Extra Valgrind annotations : ${use_vg_annotations} libdebuginfod client support : ${enable_libdebuginfod} Debuginfod server support : ${enable_debuginfod} +Debuginfod systemd support : ${enable_systemd} Default DEBUGINFOD_URLS: ${default_debuginfod_urls} EXTRA TEST FEATURES (used with make check) diff --git a/debuginfod/Makefile.am b/debuginfod/Makefile.am index 3adb2755..e7528c3a 100644 --- a/debuginfod/Makefile.am +++ b/debuginfod/Makefile.am @@ -35,6 +35,10 @@ AM_CPPFLAGS += -I$(srcdir) -I$(srcdir)/../libelf -I$(srcdir)/../libebl \ $(libmicrohttpd_CFLAGS) $(libcurl_CFLAGS) $(sqlite3_CFLAGS) \ $(libarchive_CFLAGS) +if SYSTEMD +AM_CPPFLAGS += $(libsystemd_CFLAGS) +endif + # Disable eu- prefixing for artifacts (binaries & man pages) in this # directory, since they do not conflict with binutils tools. program_prefix= @@ -71,6 +75,9 @@ endif debuginfod_SOURCES = debuginfod.cxx debuginfod_LDADD = $(libdw) $(libelf) $(libeu) $(libdebuginfod) $(argp_LDADD) $(fts_LIBS) $(libmicrohttpd_LIBS) $(sqlite3_LIBS) $(libarchive_LIBS) -lpthread -ldl +if SYSTEMD +debuginfod_LDADD += $(libsystemd_LIBS) +endif debuginfod_find_SOURCES = debuginfod-find.c debuginfod_find_LDADD = $(libdw) $(libelf) $(libeu) $(libdebuginfod) $(argp_LDADD) $(fts_LIBS) -- 2.30.1
[RFC PATCH 4/6] Use cache directory from systemd
Signed-off-by: Victor Westerhuis --- config/debuginfod.service | 2 +- debuginfod/debuginfod.cxx | 7 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/config/debuginfod.service b/config/debuginfod.service index 6c434705..c99b5406 100644 --- a/config/debuginfod.service +++ b/config/debuginfod.service @@ -8,7 +8,7 @@ Type=Notify EnvironmentFile=/etc/sysconfig/debuginfod User=debuginfod Group=debuginfod -#CacheDirectory=debuginfod +CacheDirectory=debuginfod ExecStart=/usr/bin/debuginfod -d /var/cache/debuginfod/debuginfod.sqlite -p $DEBUGINFOD_PORT $DEBUGINFOD_VERBOSE $DEBUGINFOD_PRAGMAS $DEBUGINFOD_PATHS # Stopping can take a long time if scanning of large archives is in progress TimeoutStopSec=60 diff --git a/debuginfod/debuginfod.cxx b/debuginfod/debuginfod.cxx index 4dece371..9542c5e2 100644 --- a/debuginfod/debuginfod.cxx +++ b/debuginfod/debuginfod.cxx @@ -3307,6 +3307,13 @@ main (int argc, char *argv[]) /* Set computed default values. */ db_path = string(getenv("HOME") ?: "/") + string("/.debuginfod.sqlite"); /* XDG? */ +#ifdef ENABLE_SYSTEMD + if (getenv("CACHE_DIRECTORY")) +{ + db_path = string(getenv("CACHE_DIRECTORY")) + string("/debuginfod.sqlite"); + setenv (DEBUGINFOD_CACHE_PATH_ENV_VAR, getenv("CACHE_DIRECTORY"), false); +} +#endif int rc = regcomp (& file_include_regex, ".*", REG_EXTENDED|REG_NOSUB); // match everything if (rc != 0) error (EXIT_FAILURE, 0, "regcomp failure: %d", rc); -- 2.30.1