sss_debuglevel.c revision 95d3cb8d4ff2e3e8fdc186f2ebf617fd29ddfdec
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive/*
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive Authors:
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive Pavel Březina <pbrezina@redhat.com>
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive Copyright (C) 2011 Red Hat
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive This program is free software; you can redistribute it and/or modify
51853aa2ebfdf9903a094467e1d02099f143639daaron it under the terms of the GNU General Public License as published by
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive the Free Software Foundation; either version 3 of the License, or
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive (at your option) any later version.
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive This program is distributed in the hope that it will be useful,
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive but WITHOUT ANY WARRANTY; without even the implied warranty of
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive GNU General Public License for more details.
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive You should have received a copy of the GNU General Public License
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive along with this program. If not, see <http://www.gnu.org/licenses/>.
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive*/
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive#include <stdio.h>
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive#include <stdlib.h>
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive#include <limits.h>
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive#include <talloc.h>
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive#include <popt.h>
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive#include <sys/types.h>
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive#include <dirent.h>
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive#include <ctype.h>
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive#include <signal.h>
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive#include <utime.h>
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive#include "config.h"
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive#include "ldb.h"
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive#include "util/util.h"
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive#include "tools/tools_util.h"
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive#include "confdb/confdb.h"
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive#define SSSD_PIDFILE ""PID_PATH"/sssd.pid"
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive#define MAX_PID_LENGTH 10
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive#define CHECK(expr, done, msg) do { \
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive if (expr) { \
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive ERROR(msg "\n"); \
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive goto done; \
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive } \
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive} while(0)
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive
a27e9e05958bc51ea09edb8d8d862fe8b125313bslivestruct debuglevel_tool_ctx {
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive struct confdb_ctx *confdb;
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive char **sections;
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive};
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive
a27e9e05958bc51ea09edb8d8d862fe8b125313bslivestatic errno_t set_debug_level(struct debuglevel_tool_ctx *tool_ctx,
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive int debug_to_set, const char *config_file);
51853aa2ebfdf9903a094467e1d02099f143639daaronstatic errno_t send_sighup(void);
a27e9e05958bc51ea09edb8d8d862fe8b125313bslivestatic errno_t connect_to_confdb(TALLOC_CTX *ctx, struct confdb_ctx **cdb_ctx);
a27e9e05958bc51ea09edb8d8d862fe8b125313bslivestatic errno_t get_confdb_sections(TALLOC_CTX *ctx, struct confdb_ctx *confdb,
222f0f03c2f9ee6343c18f80f0cb6e9aad21bc58slive char ***output_sections);
222f0f03c2f9ee6343c18f80f0cb6e9aad21bc58slivestatic errno_t get_sssd_pid(pid_t *out_pid);
a27e9e05958bc51ea09edb8d8d862fe8b125313bslivestatic pid_t parse_pid(const char *strpid);
a27e9e05958bc51ea09edb8d8d862fe8b125313bslivestatic int parse_debug_level(const char *strlevel);
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive
a27e9e05958bc51ea09edb8d8d862fe8b125313bsliveint main(int argc, const char **argv)
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive{
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive int ret;
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive int pc_debug = SSSDBG_DEFAULT;
a27e9e05958bc51ea09edb8d8d862fe8b125313bslive int debug_to_set = SSSDBG_INVALID;
222f0f03c2f9ee6343c18f80f0cb6e9aad21bc58slive const char *debug_as_string = NULL;
222f0f03c2f9ee6343c18f80f0cb6e9aad21bc58slive const char *config_file = NULL;
222f0f03c2f9ee6343c18f80f0cb6e9aad21bc58slive const char *pc_config_file = NULL;
222f0f03c2f9ee6343c18f80f0cb6e9aad21bc58slive struct debuglevel_tool_ctx *ctx = NULL;
222f0f03c2f9ee6343c18f80f0cb6e9aad21bc58slive struct poptOption long_options[] = {
222f0f03c2f9ee6343c18f80f0cb6e9aad21bc58slive POPT_AUTOHELP
222f0f03c2f9ee6343c18f80f0cb6e9aad21bc58slive {"debug", '\0', POPT_ARG_INT, &pc_debug,
222f0f03c2f9ee6343c18f80f0cb6e9aad21bc58slive 0, _("The debug level to run with"), NULL },
222f0f03c2f9ee6343c18f80f0cb6e9aad21bc58slive {"config", 'c', POPT_ARG_STRING, &pc_config_file,
222f0f03c2f9ee6343c18f80f0cb6e9aad21bc58slive 0, _("Specify a non-default config file"), NULL},
222f0f03c2f9ee6343c18f80f0cb6e9aad21bc58slive POPT_TABLEEND
222f0f03c2f9ee6343c18f80f0cb6e9aad21bc58slive };
222f0f03c2f9ee6343c18f80f0cb6e9aad21bc58slive poptContext pc = NULL;
222f0f03c2f9ee6343c18f80f0cb6e9aad21bc58slive
222f0f03c2f9ee6343c18f80f0cb6e9aad21bc58slive debug_prg_name = argv[0];
222f0f03c2f9ee6343c18f80f0cb6e9aad21bc58slive
222f0f03c2f9ee6343c18f80f0cb6e9aad21bc58slive /* parse parameters */
1f2a7403f1389cbf2da0a53a2b2fb425dea75506erikabele pc = poptGetContext(argv[0], argc, argv, long_options, 0);
1f2a7403f1389cbf2da0a53a2b2fb425dea75506erikabele poptSetOtherOptionHelp(pc, "DEBUG_LEVEL_TO_SET");
1f2a7403f1389cbf2da0a53a2b2fb425dea75506erikabele while((ret = poptGetNextOpt(pc)) != -1) {
1f2a7403f1389cbf2da0a53a2b2fb425dea75506erikabele switch(ret) {
1f2a7403f1389cbf2da0a53a2b2fb425dea75506erikabele default:
1f2a7403f1389cbf2da0a53a2b2fb425dea75506erikabele fprintf(stderr, "\nInvalid option %s: %s\n\n",
1f2a7403f1389cbf2da0a53a2b2fb425dea75506erikabele poptBadOption(pc, 0), poptStrerror(ret));
1f2a7403f1389cbf2da0a53a2b2fb425dea75506erikabele poptPrintUsage(pc, stderr, 0);
1f2a7403f1389cbf2da0a53a2b2fb425dea75506erikabele ret = EXIT_FAILURE;
1f2a7403f1389cbf2da0a53a2b2fb425dea75506erikabele goto fini;
1f2a7403f1389cbf2da0a53a2b2fb425dea75506erikabele }
1f2a7403f1389cbf2da0a53a2b2fb425dea75506erikabele }
1f2a7403f1389cbf2da0a53a2b2fb425dea75506erikabele debug_level = debug_convert_old_level(pc_debug);
1f2a7403f1389cbf2da0a53a2b2fb425dea75506erikabele
1f2a7403f1389cbf2da0a53a2b2fb425dea75506erikabele /* get debug level */
1f2a7403f1389cbf2da0a53a2b2fb425dea75506erikabele debug_as_string = poptGetArg(pc);
1f2a7403f1389cbf2da0a53a2b2fb425dea75506erikabele 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, 10);
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);
}