audioc.c: Always free IO buffer.
[paraslash.git] / daemon.c
index b7a0a3267b68df5b020159f90c56337073463244..c47aa954fd8a1bfc94cd3a3c379500ddc8a22a93 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1997-2011 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 1997-2012 Andre Noll <maan@systemlinux.org>
  *
  * Licensed under the GPL v2. For licencing details see COPYING.
  */
@@ -11,7 +11,7 @@
 #include <sys/types.h> /* getgrnam() */
 #include <grp.h>
 #include <sys/time.h>
-#include <stdbool.h>
+#include <signal.h>
 
 #include "para.h"
 #include "daemon.h"
@@ -26,7 +26,6 @@ struct daemon {
        char *logfile_name;
        /** Current loglevel, see \ref daemon_set_loglevel(). */
        int loglevel;
-
        /** Used by \ref server_uptime() and \ref uptime_str(). */
        time_t startuptime;
        /** The file pointer if the logfile is open. */
@@ -143,14 +142,25 @@ static bool daemon_test_flag(unsigned flag)
        return me->flags & flag;
 }
 
+static void dummy_sighandler(__a_unused int s)
+{
+}
+
 /**
  * Do the usual stuff to become a daemon.
  *
- * Fork, become session leader, dup fd 0, 1, 2 to /dev/null.
+ * \param parent_waits Whether the parent process should pause before exit.
+ *
+ * Fork, become session leader, cd to /, and dup fd 0, 1, 2 to /dev/null. If \a
+ * parent_waits is false, the parent process terminates immediately.
+ * Otherwise, it calls pause() to sleep until it receives \p SIGTERM or \p
+ * SIGCHLD and exits successfully thereafter. This behaviour is useful if the
+ * daemon process should not detach from the console until the child process
+ * has completed its setup.
  *
- * \sa fork(2), setsid(2), dup(2).
+ * \sa fork(2), setsid(2), dup(2), pause(2).
  */
-void daemonize(void)
+void daemonize(bool parent_waits)
 {
        pid_t pid;
        int null;
@@ -159,8 +169,14 @@ void daemonize(void)
        pid = fork();
        if (pid < 0)
                goto err;
-       if (pid)
+       if (pid) {
+               if (parent_waits) {
+                       signal(SIGTERM, dummy_sighandler);
+                       signal(SIGCHLD, dummy_sighandler);
+                       pause();
+               }
                exit(EXIT_SUCCESS); /* parent exits */
+       }
        /* become session leader */
        if (setsid() < 0)
                goto err;
@@ -277,43 +293,59 @@ void drop_privileges_or_die(const char *username, const char *groupname)
 }
 
 /**
- * Set/get the server uptime.
+ * Set the server startup time.
  *
- * \param set_or_get Chose one of the two modes.
+ * \param startuptime The value to store as the server start time.
  *
- * This should be called at startup time with \a set_or_get equal to \p
- * UPTIME_SET which sets the uptime to zero.  Subsequent calls with \a
- * set_or_get equal to \p UPTIME_GET return the uptime.
+ * This should be called once on startup with \a startuptime either NULL or a
+ * pointer to a struct timeval which contains the current time. If \a
+ * startuptime is NULL, the server start time is set to the current time.
+ *
+ * \sa time(2), difftime(3) \ref get_server_uptime(), \ref
+ * get_server_uptime_str().
+ */
+void set_server_start_time(const struct timeval *startuptime)
+{
+       if (startuptime)
+               me->startuptime = startuptime->tv_sec;
+       else
+               time(&me->startuptime);
+}
 
- * \return Zero if called with \a set_or_get equal to \p UPTIME_SET, the number
- * of seconds elapsed since the last reset otherwise.
+/**
+ * Get the server uptime.
+ *
+ * \param current_time The current time.
  *
- * \sa time(2), difftime(3).
+ * The \a current_time pointer may be \p NULL. In this case the function
+ * obtains the current time from the system.
+ *
+ * \return This returns the server uptime in seconds, i.e. the difference
+ * between the current time and the value stored previously via \ref
+ * set_server_start_time().
  */
-time_t server_uptime(enum uptime set_or_get)
+time_t get_server_uptime(const struct timeval *current_time)
 {
-       time_t now;
-       double diff;
+       time_t t;
 
-       if (set_or_get == UPTIME_SET) {
-               time(&me->startuptime);
-               return 0;
-       }
-       time(&now);
-       diff = difftime(now, me->startuptime);
-       return (time_t) diff;
+       if (current_time)
+               return current_time->tv_sec - me->startuptime;
+       time(&t);
+       return difftime(t, me->startuptime);
 }
 
 /**
- * Construct string containing uptime.
+ * Construct a string containing the current uptime.
+ *
+ * \param current_time See a \ref get_server_uptime().
  *
  * \return A dynamically allocated string of the form "days:hours:minutes".
  *
  * \sa server_uptime.
  */
-__malloc char *uptime_str(void)
+__malloc char *get_server_uptime_str(const struct timeval *current_time)
 {
-       long t = server_uptime(UPTIME_GET);
+       long t = get_server_uptime(current_time);
        return make_message("%li:%02li:%02li", t / 86400,
                (t / 3600) % 24, (t / 60) % 60);
 }
@@ -324,7 +356,7 @@ __malloc char *uptime_str(void)
  * \param ll The log level.
  * \param fmt The format string describing the log message.
  */
-__printf_2_3 void para_log(int ll, const char* fmt,...)
+__printf_2_3 void daemon_log(int ll, const char* fmt,...)
 {
        va_list argp;
        FILE *fp;