>From 47b0a8588dfda23662e78eb7bb09bd07b1ecc964 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Wed, 23 Sep 2009 14:19:38 +0200
Subject: [PATCH] Send debug messages to logfile

Introduces a new option --debug-to-files which makes SSSD output its
debug information to a file instead of stderr, which is still the
default.

Also introduces a new confdb option debug_to_files which does the same,
but can be specified per-service in the config file.

The logfiles are stored in /var/log/sssd by default.
---
 server/Makefile.am                  |    4 +-
 server/conf_macros.m4               |   17 ++++++++++++++++
 server/configure.ac                 |    1 +
 server/man/sssd.8.xml               |   12 +++++++++++
 server/monitor/monitor.c            |   18 ++++++++++++++--
 server/providers/data_provider.c    |    3 ++
 server/providers/data_provider_be.c |    4 +++
 server/responder/nss/nsssrv.c       |    5 +++-
 server/responder/pam/pamsrv.c       |    3 ++
 server/util/debug.c                 |   37 ++++++++++++++++++++++++++++++++++-
 server/util/server.c                |   26 +++++++++++++++++++++++-
 server/util/util.h                  |    5 ++++
 12 files changed, 127 insertions(+), 8 deletions(-)

diff --git a/server/Makefile.am b/server/Makefile.am
index 6ed405a..48628b2 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -18,7 +18,7 @@ pluginpath = @pluginpath@
 pidpath = @pidpath@
 pipepath = @pipepath@
 initdir = @initdir@
-shadow_utils_path = @shadow_utils_path@
+logpath = @logpath@
 
 AM_CFLAGS =
 if WANT_AUX_INFO
@@ -545,7 +545,7 @@ installsssddirs::
     $(DESTDIR)$(dbpath) \
     $(DESTDIR)$(pidpath) \
     $(DESTDIR)$(initdir) \
-    $(DESTDIR)$(shadow_utils_path)
+    $(DESTDIR)$(logpath)
 
 install-exec-hook: installsssddirs
 
diff --git a/server/conf_macros.m4 b/server/conf_macros.m4
index 9ab2003..410914e 100644
--- a/server/conf_macros.m4
+++ b/server/conf_macros.m4
@@ -49,6 +49,23 @@ AC_DEFUN([WITH_PID_PATH],
     AC_DEFINE_UNQUOTED(PID_PATH, "$config_pidpath", [Where to store pid files for the SSSD])
   ])
 
+AC_DEFUN([WITH_LOG_PATH],
+  [ AC_ARG_WITH([log-path],
+                [AC_HELP_STRING([--with-log-path=PATH],
+                                [Where to store log files for the SSSD [/var/log/sssd]]
+                               )
+                ]
+               )
+    config_logpath="\"VARDIR\"/log/sssd"
+    logpath="${localstatedir}/log/sssd"
+    if test x"$with_log_path" != x; then
+        config_logpath=$with_log_path
+        logpath=$with_log_path
+    fi
+    AC_SUBST(logpath)
+    AC_DEFINE_UNQUOTED(LOG_PATH, "$config_logpath", [Where to store log files for the SSSD])
+  ])
+
 AC_DEFUN([WITH_PIPE_PATH],
   [ AC_ARG_WITH([pipe-path],
                 [AC_HELP_STRING([--with-pipe-path=PATH],
diff --git a/server/configure.ac b/server/configure.ac
index 475bdca..21631b0 100644
--- a/server/configure.ac
+++ b/server/configure.ac
@@ -42,6 +42,7 @@ m4_include(conf_macros.m4)
 WITH_DB_PATH
 WITH_PLUGIN_PATH
 WITH_PID_PATH
+WITH_LOG_PATH
 WITH_PIPE_PATH
 WITH_INIT_DIR
 WITH_SHADOW_UTILS_PATH
diff --git a/server/man/sssd.8.xml b/server/man/sssd.8.xml
index f6f71c6..3f67fb7 100644
--- a/server/man/sssd.8.xml
+++ b/server/man/sssd.8.xml
@@ -56,6 +56,18 @@
             </varlistentry>
             <varlistentry>
                 <term>
+                    <option>-f</option>,<option>--debug-to-files</option>
+                </term>
+                <listitem>
+                    <para>
+                        Send the debug output to files instead of stderr. By default, the 
+                        log files are stored in /var/log and there are separate log files
+                        for every SSSD service and domain.
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
                     <option>-D</option>,<option>--daemon</option>
                 </term>
                 <listitem>
diff --git a/server/monitor/monitor.c b/server/monitor/monitor.c
index 44ce5f2..43bbcff 100644
--- a/server/monitor/monitor.c
+++ b/server/monitor/monitor.c
@@ -930,11 +930,13 @@ static int get_service_config(struct mt_ctx *ctx, const char *name,
     }
 
     if (!svc->command) {
-        svc->command = talloc_asprintf(svc, "%s/sssd_%s -d %d%s",
+        svc->command = talloc_asprintf(svc, "%s/sssd_%s -d %d%s%s",
                                        SSSD_LIBEXEC_PATH,
                                        svc->name, debug_level,
                                        (debug_timestamps?
-                                              " --debug-timestamps":""));
+                                              " --debug-timestamps":""),
+                                       (debug_to_file ?
+                                              " --debug-to-files":""));
         if (!svc->command) {
             talloc_free(svc);
             return ENOMEM;
@@ -1041,9 +1043,10 @@ static int get_provider_config(struct mt_ctx *ctx, const char *name,
     /* if there are no custom commands, build a default one */
     if (!svc->command) {
         svc->command = talloc_asprintf(svc,
-                            "%s/sssd_be -d %d%s --domain %s",
+                            "%s/sssd_be -d %d%s%s --domain %s",
                             SSSD_LIBEXEC_PATH, debug_level,
                             (debug_timestamps?" --debug-timestamps":""),
+                            (debug_to_file?" --debug-to-files":""),
                             svc->name);
         if (!svc->command) {
             talloc_free(svc);
@@ -2409,6 +2412,15 @@ int main(int argc, const char *argv[])
     /* we want a pid file check */
     flags |= FLAGS_PID_FILE;
 
+    /* Open before server_setup() does to have logging
+     * during configuration checking */
+    if (debug_to_file) {
+        ret = open_debug_file();
+        if (ret) {
+            return 7;
+        }
+    }
+
     /* Parse config file, fail if cannot be done */
     ret = load_configuration(tmp_ctx, config_file, &monitor);
     if (ret != EOK) return 4;
diff --git a/server/providers/data_provider.c b/server/providers/data_provider.c
index f8efcc8..2ba31f3 100644
--- a/server/providers/data_provider.c
+++ b/server/providers/data_provider.c
@@ -1012,6 +1012,9 @@ int main(int argc, const char *argv[])
 	poptFreeContext(pc);
 
     /* set up things like debug , signals, daemonization, etc... */
+    debug_log_file = talloc_strdup(NULL, "sssd_dp");
+    if (debug_log_file == NULL) return 2;
+
     ret = server_setup("sssd[dp]", 0, DP_CONF_ENTRY, &main_ctx);
     if (ret != EOK) return 2;
 
diff --git a/server/providers/data_provider_be.c b/server/providers/data_provider_be.c
index 85281d4..5f0271b 100644
--- a/server/providers/data_provider_be.c
+++ b/server/providers/data_provider_be.c
@@ -949,7 +949,11 @@ int main(int argc, const char *argv[])
 
     poptFreeContext(pc);
 
+
     /* set up things like debug , signals, daemonization, etc... */
+    debug_log_file = talloc_asprintf(NULL, "sssd_%s", be_domain);
+    if (!debug_log_file) return 2;
+
     srv_name = talloc_asprintf(NULL, "sssd[be[%s]]", be_domain);
     if (!srv_name) return 2;
 
diff --git a/server/responder/nss/nsssrv.c b/server/responder/nss/nsssrv.c
index 3920189..66d75a8 100644
--- a/server/responder/nss/nsssrv.c
+++ b/server/responder/nss/nsssrv.c
@@ -333,7 +333,10 @@ int main(int argc, const char *argv[])
 
     poptFreeContext(pc);
 
-    /* set up things like debug , signals, daemonization, etc... */
+   /* set up things like debug , signals, daemonization, etc... */
+    debug_log_file = talloc_strdup(NULL, "sssd_nss");
+    if (debug_log_file == NULL) return 2;
+
     ret = server_setup("sssd[nss]", 0, NSS_SRV_CONFIG, &main_ctx);
     if (ret != EOK) return 2;
 
diff --git a/server/responder/pam/pamsrv.c b/server/responder/pam/pamsrv.c
index c751528..bc4bfd8 100644
--- a/server/responder/pam/pamsrv.c
+++ b/server/responder/pam/pamsrv.c
@@ -192,6 +192,9 @@ int main(int argc, const char *argv[])
 	poptFreeContext(pc);
 
     /* set up things like debug , signals, daemonization, etc... */
+    debug_log_file = talloc_strdup(NULL, "sssd_pam");
+    if (debug_log_file == NULL) return 2;
+
     ret = server_setup("sssd[pam]", 0, PAM_SRV_CONFIG, &main_ctx);
     if (ret != EOK) return 2;
 
diff --git a/server/util/debug.c b/server/util/debug.c
index a7b3a09..c6aa27c 100644
--- a/server/util/debug.c
+++ b/server/util/debug.c
@@ -24,12 +24,19 @@
 #include <stdarg.h>
 #include <stdlib.h>
 
+#include <sys/types.h>
+#include <sys/stat.h>
+
 #include "util/util.h"
 
 const char *debug_prg_name = "sssd";
 int debug_level = 0;
 int debug_timestamps = 0;
 
+int debug_to_file = 0;
+const char *debug_log_file = "sssd";
+FILE *debug_file = NULL;
+
 void debug_fn(const char *format, ...)
 {
     va_list ap;
@@ -47,7 +54,8 @@ void debug_fn(const char *format, ...)
     va_end(ap);
 
     /*write(state.fd, s, strlen(s));*/
-    fprintf(stderr, s);
+    fprintf(debug_file ? debug_file : stderr, s);
+    fflush(debug_file ? debug_file : stderr);
     free(s);
 }
 
@@ -90,3 +98,30 @@ void ldb_debug_messages(void *context, enum ldb_debug_level level,
     }
     free(message);
 }
+
+int open_debug_file()
+{
+    FILE *f = NULL;
+    char *logpath;
+    mode_t old_umask;
+    int ret;
+
+    ret = asprintf(&logpath, "%s/%s.log", LOG_PATH, debug_log_file);
+    if (ret == -1) {
+        return ENOMEM;
+    }
+
+    if (debug_file) fclose(debug_file);
+
+    old_umask = umask(0177);
+    f = fopen(logpath, "a");
+    if (f == NULL) {
+        free(logpath);
+        return EIO;
+    }
+    umask(old_umask);
+
+    debug_file = f;
+    free(logpath);
+    return EOK;
+}
diff --git a/server/util/server.c b/server/util/server.c
index 0760e60..4249635 100644
--- a/server/util/server.c
+++ b/server/util/server.c
@@ -298,6 +298,7 @@ int server_setup(const char *name, int flags,
     char *conf_db;
     int ret = EOK;
     bool dt;
+    bool dl;
 
     debug_prg_name = strdup(name);
     if (!debug_prg_name) {
@@ -352,7 +353,6 @@ int server_setup(const char *name, int flags,
         DEBUG(0,("Out of memory, aborting!\n"));
         return ENOMEM;
     }
-    DEBUG(3, ("CONFDB: %s\n", conf_db));
 
     ret = confdb_init(ctx, &ctx->confdb_ctx, conf_db);
     if (ret != EOK) {
@@ -380,6 +380,30 @@ int server_setup(const char *name, int flags,
     }
     if (dt) debug_timestamps = 1;
 
+    /* same for debug to file */
+    dl = (debug_to_file != 0);
+    ret = confdb_get_bool(ctx->confdb_ctx, ctx, conf_entry,
+                          "debug_to_files",
+                          dl, &dl);
+    if (ret != EOK) {
+        DEBUG(0, ("Error reading from confdb (%d) [%s]\n",
+                  ret, strerror(ret)));
+        return ret;
+    }
+    if (dl) debug_to_file = 1;
+
+    /* open log file if told so */
+    if (debug_to_file) {
+        ret = open_debug_file();
+        if (ret != EOK) {
+            DEBUG(0, ("Error setting up logging (%d) [%s]\n",
+                    ret, strerror(ret)));
+            return ret;
+        }
+    }
+
+    DEBUG(3, ("CONFDB: %s\n", conf_db));
+
     if (flags & FLAGS_INTERACTIVE) {
         /* terminate when stdin goes away */
         stdin_event_flags = TEVENT_FD_READ;
diff --git a/server/util/util.h b/server/util/util.h
index ea7f44e..0212df0 100644
--- a/server/util/util.h
+++ b/server/util/util.h
@@ -43,11 +43,15 @@ typedef int errno_t;
 extern const char *debug_prg_name;
 extern int debug_level;
 extern int debug_timestamps;
+extern int debug_to_file;
+extern const char *debug_log_file;
 void debug_fn(const char *format, ...);
 
 #define SSSD_DEBUG_OPTS \
 		{"debug-level",	'd', POPT_ARG_INT, &debug_level, 0, \
 		 "Debug level", NULL}, \
+                {"debug-to-files", 'f', POPT_ARG_NONE, &debug_to_file, 0, \
+                 "Send the debug output to files instead of stderr", NULL }, \
 		{"debug-timestamps", 0, POPT_ARG_NONE, &debug_timestamps, 0, \
 		 "Add debug timestamps", NULL},
 
@@ -133,6 +137,7 @@ void debug_fn(const char *format, ...);
 /* From debug.c */
 void ldb_debug_messages(void *context, enum ldb_debug_level level,
                         const char *fmt, va_list ap);
+int open_debug_file(void);
 
 /* from server.c */
 struct main_context {
-- 
1.6.2.5

