[RFC PATCH 6/6] Support systemd watchdog

2021-03-07 Thread Victor Westerhuis
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

2021-03-07 Thread Victor Westerhuis
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

2021-03-07 Thread Victor Westerhuis
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

2021-03-07 Thread Victor Westerhuis
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

2021-03-07 Thread Victor Westerhuis
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

2021-03-07 Thread Victor Westerhuis
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

2021-03-07 Thread Victor Westerhuis
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