Several daemons have similar code around general daemon startup code.
Let's move it into a file and share it among them.
Signed-off-by: Rafael Fonseca <r4f4rfs(a)gmail.com>
---
src/libvirt_private.syms | 6 +
src/util/Makefile.inc.am | 2 +
src/util/virdaemon.c | 255 +++++++++++++++++++++++++++++++++++++++
src/util/virdaemon.h | 74 ++++++++++++
4 files changed, 337 insertions(+)
create mode 100644 src/util/virdaemon.c
create mode 100644 src/util/virdaemon.h
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 3f032c7963..e276f55bb1 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1906,6 +1906,12 @@ virCryptoHashString;
virCryptoHaveCipher;
+# util/virdaemon.h
+virDaemonForkIntoBackground;
+virDaemonSetupLogging;
+virDaemonUnixSocketPaths;
+
+
# util/virdbus.h
virDBusCallMethod;
virDBusCloseSystemBus;
diff --git a/src/util/Makefile.inc.am b/src/util/Makefile.inc.am
index 718b11a5f4..5bc60cb5ea 100644
--- a/src/util/Makefile.inc.am
+++ b/src/util/Makefile.inc.am
@@ -42,6 +42,8 @@ UTIL_SOURCES = \
util/virconf.h \
util/vircrypto.c \
util/vircrypto.h \
+ util/virdaemon.c \
+ util/virdaemon.h \
util/virdbus.c \
util/virdbus.h \
util/virdbuspriv.h \
diff --git a/src/util/virdaemon.c b/src/util/virdaemon.c
new file mode 100644
index 0000000000..4b63b44d66
--- /dev/null
+++ b/src/util/virdaemon.c
@@ -0,0 +1,255 @@
+/*
+ * virdaemon.c: shared daemon setup code
+ *
+ * Copyright (C) 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; If not, see
+ * <
http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdbool.h>
+
+#include "virdaemon.h"
+#include "virutil.h"
+#include "virfile.h"
+#include "virlog.h"
+#include "viralloc.h"
+
+#include "configmake.h"
+
+int
+virDaemonForkIntoBackground(const char *argv0)
+{
+ int statuspipe[2];
+ if (virPipeQuiet(statuspipe) < 0)
+ return -1;
+
+ pid_t pid = fork();
+ switch (pid) {
+ case 0:
+ {
+ /* intermediate child */
+ int stdinfd = -1;
+ int stdoutfd = -1;
+ int nextpid;
+
+ VIR_FORCE_CLOSE(statuspipe[0]);
+
+ if ((stdinfd = open("/dev/null", O_RDONLY)) <= STDERR_FILENO)
+ goto cleanup;
+ if ((stdoutfd = open("/dev/null", O_WRONLY)) <= STDERR_FILENO)
+ goto cleanup;
+ if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO)
+ goto cleanup;
+ if (dup2(stdoutfd, STDOUT_FILENO) != STDOUT_FILENO)
+ goto cleanup;
+ if (dup2(stdoutfd, STDERR_FILENO) != STDERR_FILENO)
+ goto cleanup;
+ if (VIR_CLOSE(stdinfd) < 0)
+ goto cleanup;
+ if (VIR_CLOSE(stdoutfd) < 0)
+ goto cleanup;
+
+ if (setsid() < 0)
+ goto cleanup;
+
+ nextpid = fork();
+ switch (nextpid) {
+ case 0: /* grandchild */
+ return statuspipe[1];
+ case -1: /* error */
+ goto cleanup;
+ default: /* intermediate child succeeded */
+ _exit(EXIT_SUCCESS);
+ }
+
+ cleanup:
+ VIR_FORCE_CLOSE(stdoutfd);
+ VIR_FORCE_CLOSE(stdinfd);
+ VIR_FORCE_CLOSE(statuspipe[1]);
+ _exit(EXIT_FAILURE);
+
+ }
+
+ case -1: /* error in parent */
+ goto error;
+
+ default:
+ {
+ /* parent */
+ int got, exitstatus = 0;
+ int ret;
+ char status;
+
+ VIR_FORCE_CLOSE(statuspipe[1]);
+
+ /* We wait to make sure the first child forked successfully */
+ if ((got = waitpid(pid, &exitstatus, 0)) < 0 ||
+ got != pid ||
+ exitstatus != 0) {
+ goto error;
+ }
+
+ /* If we got here, then the grandchild was spawned, so we
+ * must exit. Block until the second child initializes
+ * successfully */
+ again:
+ ret = read(statuspipe[0], &status, 1);
+ if (ret == -1 && errno == EINTR)
+ goto again;
+
+ VIR_FORCE_CLOSE(statuspipe[0]);
+
+ if (ret != 1) {
+ fprintf(stderr,
+ _("%s: error: unable to determine if daemon is "
+ "running: %s\n"), argv0,
+ g_strerror(errno));
+ exit(EXIT_FAILURE);
+ } else if (status != 0) {
+ fprintf(stderr,
+ _("%s: error: %s. Check /var/log/messages or run without
"
+ "--daemon for more info.\n"), argv0,
+ virDaemonErrTypeToString(status));
+ exit(EXIT_FAILURE);
+ }
+ _exit(EXIT_SUCCESS);
+ }
+ }
+
+error:
+ VIR_FORCE_CLOSE(statuspipe[0]);
+ VIR_FORCE_CLOSE(statuspipe[1]);
+ return -1;
+}
+
+
+/*
+ * Set up the logging environment
+ * By default if daemonized all errors go to the logfile libvirtd.log,
+ * but if verbose or error debugging is asked for then also output
+ * informational and debug messages. Default size if 64 kB.
+ */
+void
+virDaemonSetupLogging(const char *daemon_name,
+ unsigned int log_level,
+ char *log_filters,
+ char *log_outputs,
+ bool privileged,
+ bool verbose,
+ bool godaemon)
+{
+ virLogReset();
+
+ /*
+ * Libvirtd's order of precedence is:
+ * cmdline > environment > config
+ *
+ * Given the precedence, we must process the variables in the opposite
+ * order, each one overriding the previous.
+ */
+ if (log_level != 0)
+ virLogSetDefaultPriority(log_level);
+
+ /* In case the config is empty, both filters and outputs will become empty,
+ * however we can't start with empty outputs, thus we'll need to define and
+ * setup a default one.
+ */
+ ignore_value(virLogSetFilters(log_filters));
+ ignore_value(virLogSetOutputs(log_outputs));
+
+ /* If there are some environment variables defined, use those instead */
+ virLogSetFromEnv();
+
+ /*
+ * Command line override for --verbose
+ */
+ if ((verbose) && (virLogGetDefaultPriority() > VIR_LOG_INFO))
+ virLogSetDefaultPriority(VIR_LOG_INFO);
+
+ /* Define the default output. This is only applied if there was no setting
+ * from either the config or the environment.
+ */
+ virLogSetDefaultOutput(daemon_name, godaemon, privileged);
+
+ if (virLogGetNbOutputs() == 0)
+ virLogSetOutputs(virLogGetDefaultOutput());
+}
+
+
+int
+virDaemonUnixSocketPaths(const char *sock_prefix,
+ bool privileged,
+ char *unix_sock_dir,
+ char **sockfile,
+ char **rosockfile,
+ char **admsockfile)
+{
+ int ret = -1;
+ char *rundir = NULL;
+
+ if (unix_sock_dir) {
+ if (sockfile)
+ *sockfile = g_strdup_printf("%s/%s-sock", unix_sock_dir,
sock_prefix);
+
+ if (privileged) {
+ if (rosockfile)
+ *rosockfile = g_strdup_printf("%s/%s-sock-ro",
+ unix_sock_dir, sock_prefix);
+ if (admsockfile)
+ *admsockfile = g_strdup_printf("%s/%s-admin-sock",
+ unix_sock_dir, sock_prefix);
+ }
+ } else {
+ if (privileged) {
+ if (sockfile)
+ *sockfile = g_strdup_printf("%s/libvirt/%s-sock",
+ RUNSTATEDIR, sock_prefix);
+ if (rosockfile)
+ *rosockfile = g_strdup_printf("%s/libvirt/%s-sock-ro",
+ RUNSTATEDIR, sock_prefix);
+ if (admsockfile)
+ *admsockfile = g_strdup_printf("%s/libvirt/%s-admin-sock",
+ RUNSTATEDIR, sock_prefix);
+ } else {
+ mode_t old_umask;
+
+ rundir = virGetUserRuntimeDirectory();
+
+ old_umask = umask(077);
+ if (virFileMakePath(rundir) < 0) {
+ umask(old_umask);
+ goto cleanup;
+ }
+ umask(old_umask);
+
+ if (sockfile)
+ *sockfile = g_strdup_printf("%s/%s-sock", rundir,
sock_prefix);
+ if (admsockfile)
+ *admsockfile = g_strdup_printf("%s/%s-admin-sock", rundir,
sock_prefix);
+ }
+ }
+
+ ret = 0;
+ cleanup:
+ VIR_FREE(rundir);
+ return ret;
+}
diff --git a/src/util/virdaemon.h b/src/util/virdaemon.h
new file mode 100644
index 0000000000..d032b8ddb3
--- /dev/null
+++ b/src/util/virdaemon.h
@@ -0,0 +1,74 @@
+/*
+ * virdaemon.h: shared daemon setup code
+ *
+ * Copyright (C) 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; If not, see
+ * <
http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "virenum.h"
+
+enum {
+ VIR_DAEMON_ERR_NONE = 0,
+ VIR_DAEMON_ERR_PIDFILE,
+ VIR_DAEMON_ERR_RUNDIR,
+ VIR_DAEMON_ERR_INIT,
+ VIR_DAEMON_ERR_SIGNAL,
+ VIR_DAEMON_ERR_PRIVS,
+ VIR_DAEMON_ERR_NETWORK,
+ VIR_DAEMON_ERR_CONFIG,
+ VIR_DAEMON_ERR_HOOKS,
+ VIR_DAEMON_ERR_REEXEC,
+ VIR_DAEMON_ERR_AUDIT,
+ VIR_DAEMON_ERR_DRIVER,
+
+ VIR_DAEMON_ERR_LAST
+};
+
+VIR_ENUM_DECL(virDaemonErr);
+VIR_ENUM_IMPL(virDaemonErr,
+ VIR_DAEMON_ERR_LAST,
+ "Initialization successful",
+ "Unable to obtain pidfile",
+ "Unable to create rundir",
+ "Unable to initialize libvirt",
+ "Unable to setup signal handlers",
+ "Unable to drop privileges",
+ "Unable to initialize network sockets",
+ "Unable to load configuration file",
+ "Unable to look for hook scripts",
+ "Unable to re-execute daemon",
+ "Unable to initialize audit system",
+ "Unable to initialize driver",
+);
+
+int virDaemonForkIntoBackground(const char *argv0);
+
+void virDaemonSetupLogging(const char *daemon_name,
+ unsigned int log_level,
+ char *log_filters,
+ char *log_outputs,
+ bool privileged,
+ bool verbose,
+ bool godaemon);
+
+int virDaemonUnixSocketPaths(const char *sock_prefix,
+ bool privileged,
+ char *unix_sock_dir,
+ char **sockfile,
+ char **rosockfile,
+ char **adminSockfile);
--
2.25.1