sss_debuglevel.c revision 877b92e80bde510d5cd9f03dbf01e2bcf73ab072
/*
Authors:
Pavel Březina <pbrezina@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 <ldb.h>
#include "config.h"
#include "util/util.h"
#include "tools/tools_util.h"
#include "confdb/confdb.h"
#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 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 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 | POPT_ARGFLAG_DOC_HIDDEN, &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_CLI_INIT(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);
}
/* No more arguments expected. If something follows it is an error. */
if (poptGetArg(pc)) {
BAD_POPT_PARAMS(pc, _("Only one argument expected\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 = signal_sssd(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 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,
CONFDB_PAC_CONF_ENTRY,
CONFDB_SSH_CONF_ENTRY,
CONFDB_SUDO_CONF_ENTRY,
CONFDB_AUTOFS_CONF_ENTRY,
CONFDB_IFP_CONF_ENTRY,
};
static const int known_services_count = sizeof(known_services)
/ sizeof(*known_services);
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;
domain = get_next_domain(domain, 0)) {
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;
domain = get_next_domain(domain, 0), 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;
}
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);
}