Merge branch 'daemon-ext' master
authorThomas Jarosch <thomas.jarosch@intra2net.com>
Mon, 10 Jan 2022 15:26:00 +0000 (16:26 +0100)
committerThomas Jarosch <thomas.jarosch@intra2net.com>
Mon, 10 Jan 2022 15:26:00 +0000 (16:26 +0100)
src/daemonfunc.cpp
src/daemonfunc.hpp

index 248a79b..167f45f 100644 (file)
@@ -25,6 +25,9 @@ on this file might be covered by the GNU General Public License.
 #include <stdlib.h>
 #include <pwd.h>
 #include <grp.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
 
 #include <string>
 #include <stdexcept>
@@ -227,5 +230,93 @@ bool pid_of(const std::string& name, std::vector< pid_t >& result)
    return true;
 } // eo pidOf(const std::string&,std::vector< pid_t >&)
 
+/**
+ * @brief   establish a new session for the current process.
+ *
+ * @return  the id of the new session.
+ *
+ * This wraps setsid(2); to be called from a child process after forking.
+ * Raises ``runtime_error`` if the call fails.
+ */
+pid_t create_session (void)
+{
+    pid_t sid;
+
+    errno = 0;
+    if ((sid = setsid ()) == -1)
+    {
+        throw std::runtime_error
+            ((std::string)
+             "create_session: setsid() returned an error ("
+             + I2n::to_string (errno)
+             + "): " + strerror (errno));
+    }
+
+    return sid;
+}
+
+/**
+ * @brief   reopen standard file descriptors as ``/dev/null``.
+ *
+ * Disable stdin, stdout and stderr to ensure no output can be read from or
+ * written to those descriptors. This assumes the process will interact with
+ * the outside world through other means like syslog and sockets.
+ *
+ * Raises ``runtime_error`` in case of errors.
+ */
+void null_fds () {
+    int devnull;
+
+    errno = 0;
+    if ((devnull = open ("/dev/null", O_RDWR)) == -1)
+    {
+        throw std::runtime_error
+            ((std::string)
+             "null_fds: open(/dev/null) returned an error ("
+             + I2n::to_string (errno)
+             + "): " + strerror (errno));
+    }
+
+    for (int fd = 0; fd != 3; ++fd)
+    {
+        errno = 0;
+        if (dup2 (devnull, fd) == -1)
+        {
+            throw std::runtime_error
+                ((std::string)
+                 "null_fds: dup2(/dev/null, "
+                 + I2n::to_string (fd)
+                 + ") returned an error ("
+                 + I2n::to_string (errno)
+                 + "): " + strerror (errno));
+        }
+    }
+
+    errno = 0;
+    if (close (devnull) == -1)
+    {
+        throw std::runtime_error
+            ((std::string)
+             "null_fds: close(/dev/null) returned an error ("
+             + I2n::to_string (errno)
+             + "): " + strerror (errno));
+    }
+}
+
+/**
+ * @brief   convert the current process into a background process.
+ *
+ * This convenience wrapper combines forking, creation of a new session and
+ * disabling stdio.
+ *
+ * Raises ``runtime_error`` in case of errors.
+ */
+void daemonize_full (void)
+{
+    daemonize ();
+    (void)create_session ();
+    null_fds ();
+}
+
 }
 }
index f6f77a3..bcfcc05 100644 (file)
@@ -33,11 +33,15 @@ namespace I2n
 namespace Daemon
 {
 void daemonize();
+void daemonize_full();
 
 bool drop_root_privileges(const std::string &username,
                           const std::string &group, bool get_group_from_user=false);
 
 bool pid_of(const std::string& name, std::vector< pid_t >& result);
+
+pid_t create_session (void);
+void null_fds (void);
 }
 }