[SSSD] [PATCH] new tool - sss_debuglevel

Pavel Březina pbrezina at redhat.com
Mon Aug 29 07:46:40 UTC 2011


Dne 26.8.2011 19:20, Simo Sorce napsal(a):
> On Mon, 2011-08-22 at 13:46 +0200, Jakub Hrozek wrote:
>> On Tue, Aug 16, 2011 at 02:35:42PM +0200, Pavel Březina wrote:
>>> sss_debuglevel - change the debug level on the fly
>>>
>>> https://fedorahosted.org/sssd/ticket/950
>>>
>>> Requires "New DEBUG facility" patches.
>>
>>> +errno_t set_debug_level(
>>> +    struct debuglevel_tool_ctx *tool_ctx, int debug_to_set,
>>> +    const char *config_file
>>> +)
>>> +{
>>> +    int ret;
>>> +    int err;
>>> +    const char *values[2];
>>> +    char **section = NULL;
>>> +    TALLOC_CTX *ctx = talloc_new(NULL);
>>> +
>>
>> Please name temporary context tmp_ctx so it is immediatelly clear that it
>> is a just a temporary one.

Done.

> I don't like it either and I think we have in the guidelines something
> about how we use parenthesis. Please follow the style used in the rest
> of the sssd code when it comes to declarations.

Sorry about that! I'm used to very different coding style and it's not 
like you can switch to this one immediately. But I'll try harder to keep 
it on minimum next time. I hope it's good now.

Also, I noticed that I forgot to ask: There are two comments on lines 
121 and 122 /* free pc_config_file? */ and /* free debug_as_string? */.
I made some tests and it looks like resources allocated in popt should 
be freed manually but I'm not sure as I don't see it anywhere in the code.
There are actually statements like this (monitor.c 2380, 2397):
get string from popt
poptFreeContext()
use string from popt
but no free()

Man page is not clear enough what poptFreeContext() does.
-------------- next part --------------
From 1d70207e8491a26483c9efdc293cbf2467655bc2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina at redhat.com>
Date: Wed, 10 Aug 2011 10:56:10 +0200
Subject: [PATCH] sss_debuglevel - change the debug levels on the fly

https://fedorahosted.org/sssd/ticket/950
---
 .gitignore                   |    1 +
 Makefile.am                  |   10 +-
 contrib/sssd.spec.in         |    2 +
 contrib/suse/sssd.spec.in    |    2 +
 src/man/Makefile.am          |    2 +-
 src/man/sss_debuglevel.8.xml |   66 +++++++
 src/tools/sss_debuglevel.c   |  393 ++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 474 insertions(+), 2 deletions(-)
 create mode 100644 src/man/sss_debuglevel.8.xml
 create mode 100644 src/tools/sss_debuglevel.c

diff --git a/.gitignore b/.gitignore
index 478cd7f..fa5495a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -52,6 +52,7 @@ sss_useradd
 sss_userdel
 sss_usermod
 sss_groupshow
+sss_debuglevel
 sssd
 sssd_be
 sssd_dp
diff --git a/Makefile.am b/Makefile.am
index 4e2e26b..1863564 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -58,7 +58,8 @@ sbin_PROGRAMS = \
     sss_usermod \
     sss_groupmod \
     sss_groupshow \
-    sss_cache
+    sss_cache \
+    sss_debuglevel
 
 sssdlibexec_PROGRAMS = \
     sssd_nss \
@@ -511,6 +512,13 @@ sss_cache_LDADD = \
     libsss_util.la \
     $(TOOLS_LIBS)
 
+sss_debuglevel_SOURCES = \
+    src/tools/sss_debuglevel.c \
+    $(SSSD_TOOLS_OBJ)
+sss_debuglevel_LDADD = \
+    libsss_util.la \
+    $(TOOLS_LIBS)
+
 #################
 # Feature Tests #
 #################
diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
index 2639f3a..3c7e3c9 100644
--- a/contrib/sssd.spec.in
+++ b/contrib/sssd.spec.in
@@ -296,6 +296,7 @@ rm -rf $RPM_BUILD_ROOT
 %{_sbindir}/sss_groupshow
 %{_sbindir}/sss_obfuscate
 %{_sbindir}/sss_cache
+%{_sbindir}/sss_debuglevel
 %{_mandir}/man8/sss_groupadd.8*
 %{_mandir}/man8/sss_groupdel.8*
 %{_mandir}/man8/sss_groupmod.8*
@@ -305,6 +306,7 @@ rm -rf $RPM_BUILD_ROOT
 %{_mandir}/man8/sss_usermod.8*
 %{_mandir}/man8/sss_obfuscate.8*
 %{_mandir}/man8/sss_cache.8*
+%{_mandir}/man8/sss_debuglevel.8*
 
 %files -n libipa_hbac
 %defattr(-,root,root,-)
diff --git a/contrib/suse/sssd.spec.in b/contrib/suse/sssd.spec.in
index 5c3178f..e943427 100644
--- a/contrib/suse/sssd.spec.in
+++ b/contrib/suse/sssd.spec.in
@@ -176,6 +176,7 @@ rm -rf $RPM_BUILD_ROOT
 %{_sbindir}/sss_groupdel
 %{_sbindir}/sss_groupmod
 %{_sbindir}/sss_groupshow
+%{_sbindir}/sss_debuglevel
 %{_libexecdir}/%{servicename}/
 %{_libdir}/%{name}/
 %{_libdir}/ldb/memberof.so
@@ -202,6 +203,7 @@ rm -rf $RPM_BUILD_ROOT
 %{_mandir}/man8/sss_useradd.8*
 %{_mandir}/man8/sss_userdel.8*
 %{_mandir}/man8/sss_usermod.8*
+%{_mandir}/man8/sss_debuglevel.8*
 %{_mandir}/man8/sssd_krb5_locator_plugin.8*
 %{python_sitearch}/pysss.so
 %{python_sitelib}/*.py*
diff --git a/src/man/Makefile.am b/src/man/Makefile.am
index 24acb06..09af898 100644
--- a/src/man/Makefile.am
+++ b/src/man/Makefile.am
@@ -17,7 +17,7 @@ man_MANS = \
     sssd.8 sssd.conf.5 sssd-ldap.5 \
     sssd-krb5.5 sssd-ipa.5 sssd-simple.5 \
     sssd_krb5_locator_plugin.8 sss_groupshow.8 \
-    pam_sss.8 sss_obfuscate.8 sss_cache.8
+    pam_sss.8 sss_obfuscate.8 sss_cache.8 sss_debuglevel.8
 EXTRA_DIST = $(man_MANS:%=%.xml) $(wildcard $(srcdir)/include/*.xml)
 
 SUFFIXES = .1.xml .1 .3.xml .3 .5.xml .5 .8.xml .8
diff --git a/src/man/sss_debuglevel.8.xml b/src/man/sss_debuglevel.8.xml
new file mode 100644
index 0000000..1c596bb
--- /dev/null
+++ b/src/man/sss_debuglevel.8.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE reference PUBLIC "-//OASIS//DTD DocBook V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
+<reference>
+<title>SSSD Manual pages</title>
+<refentry>
+    <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/upstream.xml" />
+
+    <refmeta>
+        <refentrytitle>sss_debuglevel</refentrytitle>
+        <manvolnum>8</manvolnum>
+    </refmeta>
+
+    <refnamediv id='name'>
+        <refname>sss_debuglevel</refname>
+        <refpurpose>change debug level while SSSD is running</refpurpose>
+    </refnamediv>
+
+    <refsynopsisdiv id='synopsis'>
+        <cmdsynopsis>
+            <command>sss_debuglevel</command>
+            <arg choice='opt'>
+                <replaceable>options</replaceable>
+            </arg>
+            <arg choice='plain'><replaceable>NEW_DEBUG_LEVEL</replaceable></arg>
+        </cmdsynopsis>
+    </refsynopsisdiv>
+
+    <refsect1 id='description'>
+        <title>DESCRIPTION</title>
+        <para>
+            <command>sss_debuglevel</command> changes debug level of SSSD monitor
+            and providers to <replaceable>NEW_DEBUG_LEVEL</replaceable> while SSSD is running.
+        </para>
+    </refsect1>
+
+    <refsect1 id='options'>
+        <title>OPTIONS</title>
+        <variablelist remap='IP'>
+            <varlistentry>
+                <term>
+                    <option>-c</option>,<option>--config</option>
+                </term>
+                <listitem>
+                    <para>
+                        Specify a non-default config file. The default is
+                        <filename>/etc/sssd/sssd.conf</filename>. For reference
+                        on the config file syntax and options, consult the
+                        <citerefentry>
+                            <refentrytitle>sssd.conf</refentrytitle>
+                            <manvolnum>5</manvolnum>
+                        </citerefentry>
+                        manual page.
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>
+                    <replaceable>NEW_DEBUG_LEVEL</replaceable>
+                </term>
+                <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/debug_levels.xml" />
+            </varlistentry>
+        </variablelist>
+    </refsect1>
+</refentry>
+</reference>
diff --git a/src/tools/sss_debuglevel.c b/src/tools/sss_debuglevel.c
new file mode 100644
index 0000000..255e42c
--- /dev/null
+++ b/src/tools/sss_debuglevel.c
@@ -0,0 +1,393 @@
+/*
+    Authors:
+        Pavel Březina <pbrezina at redhat.com>
+
+    Copyright (C) 2011 Red Hat
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    This program 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <talloc.h>
+#include <popt.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <signal.h>
+#include <utime.h>
+
+#include "config.h"
+#include "ldb.h"
+#include "util/util.h"
+#include "tools/tools_util.h"
+#include "confdb/confdb.h"
+
+#define SSSD_PIDFILE            ""PID_PATH"/sssd.pid"
+#define MAX_PID_LENGTH          10
+
+#define CHECK(expr, done, msg) do { \
+    if (expr) { \
+        ERROR(msg "\n"); \
+        goto done; \
+    } \
+} while(0);
+
+struct debuglevel_tool_ctx {
+    struct confdb_ctx *confdb;
+    char **sections;
+};
+
+static errno_t set_debug_level(struct debuglevel_tool_ctx *tool_ctx,
+                               int debug_to_set, const char *config_file);
+static errno_t send_sighup(void);
+static errno_t connect_to_confdb(TALLOC_CTX *ctx, struct confdb_ctx **cdb_ctx);
+static errno_t get_confdb_sections(TALLOC_CTX *ctx, struct confdb_ctx *confdb,
+                                   char ***output_sections);
+static errno_t get_sssd_pid(pid_t *out_pid);
+static pid_t parse_pid(const char *strpid);
+static int parse_debug_level(const char *strlevel);
+
+int main(int argc, const char **argv)
+{
+    int ret;
+    int pc_debug = SSSDBG_DEFAULT;
+    int debug_to_set = SSSDBG_INVALID;
+    const char *debug_as_string = NULL;
+    const char *config_file = NULL;
+    const char *pc_config_file = NULL;
+    struct debuglevel_tool_ctx *ctx = NULL;
+    struct poptOption long_options[] = {
+        POPT_AUTOHELP
+        {"debug", '\0', POPT_ARG_INT, &pc_debug,
+            0, _("The debug level to run with"), NULL },
+        {"config", 'c', POPT_ARG_STRING, &pc_config_file,
+            0, _("Specify a non-default config file"), NULL},
+        POPT_TABLEEND
+    };
+    poptContext pc = NULL;
+
+    debug_prg_name = argv[0];
+
+    /* parse parameters */
+    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+    poptSetOtherOptionHelp(pc, "DEBUG_LEVEL_TO_SET");
+    while((ret = poptGetNextOpt(pc)) != -1) {
+        switch(ret) {
+        default:
+            fprintf(stderr, "\nInvalid option %s: %s\n\n",
+                    poptBadOption(pc, 0), poptStrerror(ret));
+            poptPrintUsage(pc, stderr, 0);
+            ret = EXIT_FAILURE;
+            goto fini;
+        }
+    }
+    debug_level = debug_convert_old_level(pc_debug);
+
+    /* get debug level */
+    debug_as_string = poptGetArg(pc);
+    if (debug_as_string == NULL) {
+        BAD_POPT_PARAMS(pc, _("Specify debug level you want to set\n"),
+                        ret, fini);
+    }
+
+    /* get config file */
+    if (pc_config_file) {
+        config_file = talloc_strdup(ctx, pc_config_file);
+    } else {
+        config_file = talloc_strdup(ctx, CONFDB_DEFAULT_CONFIG_FILE);
+    }
+
+    if (config_file == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_strdup() failed\n"));
+        ret = ENOMEM;
+        goto fini;
+    }
+
+    CHECK_ROOT(ret, debug_prg_name);
+
+    /* free pc_config_file? */
+    /* free debug_as_string? */
+
+    debug_to_set = parse_debug_level(debug_as_string);
+    CHECK(debug_to_set == SSSDBG_INVALID, fini, "Invalid debug level.");
+
+    /* allocate context */
+    ctx = talloc_zero(NULL, struct debuglevel_tool_ctx);
+    if (ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              ("Could not allocate memory for tools context\n"));
+        ret = ENOMEM;
+        goto fini;
+    }
+
+    ret = connect_to_confdb(ctx, &ctx->confdb);
+    CHECK(ret != EOK, fini, "Could not connect to configuration database.");
+
+    ret = get_confdb_sections(ctx, ctx->confdb, &ctx->sections);
+    CHECK(ret != EOK, fini, "Could not get all configuration sections.");
+
+    ret = set_debug_level(ctx, debug_to_set, config_file);
+    CHECK(ret != EOK, fini, "Could not set debug level.");
+
+    ret = send_sighup();
+    CHECK(ret != EOK, fini,
+          "Could not force sssd processes to reload configuration. "
+          "Is sssd running?");
+
+fini:
+    poptFreeContext(pc);
+    talloc_free(ctx);
+    return ret;
+}
+
+errno_t set_debug_level(struct debuglevel_tool_ctx *tool_ctx,
+                        int debug_to_set, const char *config_file)
+{
+    int ret;
+    int err;
+    const char *values[2];
+    char **section = NULL;
+    TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+
+    if (tmp_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n"));
+        return ENOMEM;
+    }
+
+    /* convert debug_to_set to string */
+    values[0] = talloc_asprintf(tmp_ctx, "0x%.4x", debug_to_set);
+    if (values[0] == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Could not allocate memory for "
+              "debug_to_set to string conversion\n"));
+        ret = ENOMEM;
+        goto done;
+    }
+    values[1] = NULL;
+
+    /* write to confdb */
+    for (section = tool_ctx->sections; *section != NULL; section++) {
+        ret = confdb_add_param(tool_ctx->confdb, 1, *section,
+                               CONFDB_SERVICE_DEBUG_LEVEL, values);
+        if (ret != EOK) {
+            goto done;
+        }
+    }
+
+    /*
+     * Change atime and mtime of sssd.conf,
+     * so the configuration can be restored on next start.
+     */
+    errno = 0;
+    if (utime(config_file, NULL) == -1 ) {
+        err = errno;
+        DEBUG(SSSDBG_MINOR_FAILURE, ("Unable to change mtime of \"%s\": %s\n",
+              config_file, strerror(err)));
+    }
+
+    ret = EOK;
+
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+errno_t send_sighup()
+{
+    int ret;
+    pid_t pid;
+
+    ret = get_sssd_pid(&pid);
+    if (ret != EOK) {
+        return ret;
+    }
+
+    if (kill(pid, SIGHUP) != 0) {
+        ret = errno;
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Could not send SIGHUP to process %d: %s\n",
+              pid, strerror(errno)));
+        return errno;
+    }
+
+    return EOK;
+}
+
+errno_t connect_to_confdb(TALLOC_CTX *ctx, struct confdb_ctx **cdb_ctx)
+{
+    int ret;
+    char* confdb_path = NULL;
+
+    confdb_path = talloc_asprintf(ctx, "%s/%s", DB_PATH, CONFDB_FILE);
+    if (confdb_path == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              ("Could not allocate memory for confdb path\n"));
+        return ENOMEM;
+    }
+
+    ret = confdb_init(ctx, cdb_ctx, confdb_path);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              ("Could not initialize connection to the confdb\n"));
+    }
+
+    talloc_free(confdb_path);
+    return ret;
+}
+
+errno_t get_confdb_sections(TALLOC_CTX *ctx, struct confdb_ctx *confdb,
+                            char ***output_sections)
+{
+    int ret;
+    int domain_count = 0;
+    int i = 0;
+    struct sss_domain_info *domain = NULL;
+    struct sss_domain_info *domain_list = NULL;
+    char **sections;
+    const char *known_services[] = {
+        CONFDB_MONITOR_CONF_ENTRY,
+        CONFDB_NSS_CONF_ENTRY,
+        CONFDB_PAM_CONF_ENTRY
+    };
+    static const int known_services_count = 3;
+    TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+
+    if (tmp_ctx == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_new() failed\n"));
+        return ENOMEM;
+    }
+
+    /* get domains */
+    ret = confdb_get_domains(confdb, &domain_list);
+    if (ret != EOK)
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to get domain list\n"));
+
+    for (domain = domain_list; domain != NULL; domain = domain->next)
+        domain_count++;
+
+    /* allocate output space */
+    sections = talloc_array(ctx, char*,
+                            domain_count + known_services_count + 1);
+    if (sections == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              ("Could not allocate memory for sections\n"));
+        ret = ENOMEM;
+        goto fail;
+    }
+
+    for (i = 0; i < known_services_count; i++) {
+        sections[i] = talloc_strdup(tmp_ctx, known_services[i]);
+        if (sections[i] == NULL) {
+            DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_strdup() failed\n"));
+            ret = ENOMEM;
+            goto fail;
+        }
+    }
+
+    for (domain = domain_list; domain != NULL; domain = domain->next, i++) {
+        sections[i] = talloc_asprintf(tmp_ctx, CONFDB_DOMAIN_PATH_TMPL,
+                                      domain->name);
+        if (sections[i] == NULL) {
+            DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_asprintf() failed\n"));
+            ret = ENOMEM;
+            goto fail;
+        }
+    }
+
+    /* add NULL to the end */
+    sections[i] = NULL;
+
+    *output_sections = talloc_steal(ctx, sections);
+
+    return EOK;
+fail:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+errno_t get_sssd_pid(pid_t *out_pid)
+{
+    int ret;
+    FILE *pid_file = NULL;
+    char pid_str[MAX_PID_LENGTH] = {'\0'};
+
+    *out_pid = 0;
+
+    errno = 0;
+    pid_file = fopen(SSSD_PIDFILE, "r");
+    if (pid_file == NULL) {
+        ret = errno;
+        DEBUG(SSSDBG_MINOR_FAILURE, ("Unable to open pid file \"%s\": %s\n",
+              SSSD_PIDFILE, strerror(ret)));
+        goto done;
+    }
+
+    ret = fread(pid_str, sizeof(char), MAX_PID_LENGTH * sizeof(char), pid_file);
+    if (!feof(pid_file)) {
+        /* eof not reached */
+        ret = ferror(pid_file);
+        if (ret != 0) {
+            DEBUG(SSSDBG_CRIT_FAILURE, ("Unable to read from file \"%s\": %s\n",
+                  SSSD_PIDFILE, strerror(ret)));
+        } else {
+            DEBUG(SSSDBG_CRIT_FAILURE, ("File \"%s\" contains invalid pid.\n",
+                  SSSD_PIDFILE));
+        }
+        goto done;
+    }
+
+    *out_pid = parse_pid(pid_str);
+    if (*out_pid == 0) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              ("File \"%s\" contains invalid pid.\n", SSSD_PIDFILE));
+        return EINVAL;
+    }
+
+    ret = EOK;
+
+done:
+    if (pid_file != NULL) {
+        fclose(pid_file);
+    }
+    return ret;
+}
+
+pid_t parse_pid(const char *strpid)
+{
+    long value;
+    char *endptr;
+
+    errno = 0;
+    value = strtol(strpid, &endptr, 0);
+    if ((errno != 0) || (endptr == strpid)
+        || ((*endptr != '\0') && (*endptr != '\n'))) {
+        return 0;
+    }
+
+    return value;
+}
+
+int parse_debug_level(const char *strlevel)
+{
+    long value;
+    char *endptr;
+
+    errno = 0;
+    value = strtol(strlevel, &endptr, 0);
+    if ((errno != 0) || (endptr == strlevel) || (*endptr != '\0')) {
+        return SSSDBG_INVALID;
+    }
+
+    return debug_convert_old_level(value);
+}
-- 
1.7.6



More information about the sssd-devel mailing list