Avoid warning about sys/sysctl.h on glibc-2.30.
[paraslash.git] / daemon.c
index 20cdc6a..a4e2f31 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -1,8 +1,4 @@
-/*
- * Copyright (C) 1997 Andre Noll <maan@tuebingen.mpg.de>
- *
- * Licensed under the GPL v2. For licencing details see COPYING.
- */
+/* Copyright (C) 1997 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
 
 /** \file daemon.c Some helpers for programs that detach from the console. */
 
@@ -34,6 +30,13 @@ struct daemon {
        char *hostname;
        /** Used for colored log messages. */
        char log_colors[NUM_LOGLEVELS][COLOR_MAXLEN];
+       char *old_cwd;
+       /*
+        * If these pointers are non-NULL, the functions are called from
+        * daemon_log() before and after writing each log message.
+        */
+       void (*pre_log_hook)(void);
+       void (*post_log_hook)(void);
 };
 
 static struct daemon the_daemon, *me = &the_daemon;
@@ -121,7 +124,12 @@ void daemon_set_logfile(const char *logfile_name)
 {
        free(me->logfile_name);
        me->logfile_name = NULL;
-       if (logfile_name)
+       if (!logfile_name)
+               return;
+       if (me->old_cwd && logfile_name[0] != '/')
+               me->logfile_name = make_message("%s/%s", me->old_cwd,
+                       logfile_name);
+       else
                me->logfile_name = para_strdup(logfile_name);
 }
 
@@ -138,6 +146,28 @@ void daemon_set_loglevel(const char *loglevel)
        me->loglevel = ret;
 }
 
+/**
+ * Register functions to be called before and after a message is logged.
+ *
+ * \param pre_log_hook Called before the message is logged.
+ * \param post_log_hook Called after the message is logged.
+ *
+ * The purpose of this function is to provide a primitive for multi-threaded
+ * applications to serialize the access to the log facility, preventing
+ * interleaving log messages. This can be achieved by having the pre-log hook
+ * acquire a lock which blocks the other threads on the attempt to log a
+ * message at the same time.  The post-log hook is responsible for releasing
+ * the lock.
+ *
+ * If these hooks are unnecessary, for example because the application is
+ * single-threaded, this function does not need to be called.
+ */
+void daemon_set_hooks(void (*pre_log_hook)(void), void (*post_log_hook)(void))
+{
+       me->pre_log_hook = pre_log_hook;
+       me->post_log_hook = post_log_hook;
+}
+
 /**
  * Set one of the daemon config flags.
  *
@@ -201,6 +231,7 @@ int daemonize(bool parent_waits)
        /* become session leader */
        if (setsid() < 0)
                goto err;
+       me->old_cwd = getcwd(NULL, 0);
        if (chdir("/") < 0)
                goto err;
        null = open("/dev/null", O_RDWR);
@@ -238,15 +269,18 @@ void daemon_close_log(void)
  */
 void daemon_open_log_or_die(void)
 {
-       daemon_close_log();
+       FILE *new_log;
+
        if (!me->logfile_name)
                return;
-       me->logfile = fopen(me->logfile_name, "a");
-       if (!me->logfile) {
+       new_log = fopen(me->logfile_name, "a");
+       if (!new_log) {
                PARA_EMERG_LOG("can not open %s: %s\n", me->logfile_name,
                        strerror(errno));
                exit(EXIT_FAILURE);
        }
+       daemon_close_log();
+       me->logfile = new_log;
        /* equivalent to setlinebuf(), but portable */
        setvbuf(me->logfile, NULL, _IOLBF, 0);
 }
@@ -374,8 +408,6 @@ time_t daemon_get_uptime(const struct timeval *current_time)
  * \param current_time See a \ref daemon_get_uptime().
  *
  * \return A dynamically allocated string of the form "days:hours:minutes".
- *
- * \sa server_uptime.
  */
 __malloc char *daemon_get_uptime_str(const struct timeval *current_time)
 {
@@ -405,6 +437,8 @@ __printf_2_3 void daemon_log(int ll, const char* fmt,...)
                return;
 
        fp = me->logfile? me->logfile : stderr;
+       if (me->pre_log_hook)
+               me->pre_log_hook();
        color = daemon_test_flag(DF_COLOR_LOG)? me->log_colors[ll] : NULL;
        if (color)
                fprintf(fp, "%s", color);
@@ -437,4 +471,6 @@ __printf_2_3 void daemon_log(int ll, const char* fmt,...)
        va_end(argp);
        if (color)
                fprintf(fp, "%s", COLOR_RESET);
+       if (me->post_log_hook)
+               me->post_log_hook();
 }