From 3e454b5de596f2e4d1b4d9df4cc33aeec7a5af5f Mon Sep 17 00:00:00 2001 From: Ondrej Kos Date: Nov 19 2012 12:39:52 +0000 Subject: Display more information on DB version crash https://fedorahosted.org/sssd/ticket/1589 Added check for determining, whether database version is higher or lower than expected. To distinguish it from other errors it uses following retun values (further used for appropriate error message): EMEDIUMTYPE for lower version than expected EUCLEAN for higher version than expected When SSSD or one of it's tools fails on DB version mismatch, new error message is showed suggesting how to proceed. --- diff --git a/src/db/sysdb.c b/src/db/sysdb.c index 9685163..dda288f 100644 --- a/src/db/sysdb.c +++ b/src/db/sysdb.c @@ -947,6 +947,38 @@ errno_t sysdb_add_to_domain(struct sss_domain_info *domain, return EOK; } +/* Compare versions of sysdb, returns ERRNO accordingly */ +static errno_t +sysdb_version_check(const char *expected, + const char *received) +{ + int ret; + unsigned int exp_major, exp_minor, recv_major, recv_minor; + + ret = sscanf(expected, "%u.%u", &exp_major, &exp_minor); + if (ret != 2) { + return EINVAL; + } + ret = sscanf(received, "%u.%u", &recv_major, &recv_minor); + if (ret != 2) { + return EINVAL; + } + + if (recv_major > exp_major) { + return EUCLEAN; + } else if (recv_major < exp_major) { + return EMEDIUMTYPE; + } + + if (recv_minor > exp_minor) { + return EUCLEAN; + } else if (recv_minor < exp_minor) { + return EMEDIUMTYPE; + } + + return EOK; +} + int sysdb_domain_init_internal(TALLOC_CTX *mem_ctx, struct sss_domain_info *domain, const char *db_path, @@ -1037,7 +1069,7 @@ int sysdb_domain_init_internal(TALLOC_CTX *mem_ctx, if (!allow_upgrade) { DEBUG(0, ("Wrong DB version (got %s expected %s)\n", version, SYSDB_VERSION)); - ret = EINVAL; + ret = sysdb_version_check(SYSDB_VERSION, version); goto done; } @@ -1136,7 +1168,7 @@ int sysdb_domain_init_internal(TALLOC_CTX *mem_ctx, DEBUG(0,("Unknown DB version [%s], expected [%s] for domain %s!\n", version?version:"not found", SYSDB_VERSION, domain->name)); - ret = EINVAL; + ret = sysdb_version_check(SYSDB_VERSION, version); goto done; } diff --git a/src/db/sysdb.h b/src/db/sysdb.h index 39e0f9f..c60f7e9 100644 --- a/src/db/sysdb.h +++ b/src/db/sysdb.h @@ -214,6 +214,36 @@ #define SYSDB_MOD_DEL LDB_FLAG_MOD_DELETE #define SYSDB_MOD_REP LDB_FLAG_MOD_REPLACE +/* sysdb version check macros */ +#define SYSDB_VERSION_ERROR_HINT \ + ERROR("Removing cache files in "DB_PATH" should fix the issue, " \ + "but note that removing cache files will also remove all of your " \ + "cached credentials.\n") + +#define SYSDB_VERSION_LOWER_ERROR(ret) do { \ + if (ret == EUCLEAN) { \ + ERROR("Lower version of database is expected!\n"); \ + SYSDB_VERSION_ERROR_HINT; \ + } \ +} while(0) + +#define SYSDB_VERSION_HIGHER_ERROR(ret) do { \ + if (ret == EMEDIUMTYPE) { \ + ERROR("Higher version of database is expected!\n"); \ + ERROR("In order to upgrade the database, you must run SSSD.\n"); \ + SYSDB_VERSION_ERROR_HINT; \ + } \ +} while(0) + +/* use this in daemons */ +#define SYSDB_VERSION_ERROR_DAEMON(ret) \ + SYSDB_VERSION_LOWER_ERROR(ret) + +/* use this in tools */ +#define SYSDB_VERSION_ERROR(ret) \ + SYSDB_VERSION_LOWER_ERROR(ret); \ + SYSDB_VERSION_HIGHER_ERROR(ret) + struct confdb_ctx; struct sysdb_ctx; diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c index 1fbbcb9..7f7bbd0 100644 --- a/src/monitor/monitor.c +++ b/src/monitor/monitor.c @@ -2185,6 +2185,7 @@ int monitor_process_init(struct mt_ctx *ctx, } ret = sysdb_init(tmp_ctx, ctx->cdb, NULL, true, &db_list); if (ret != EOK) { + SYSDB_VERSION_ERROR_DAEMON(ret); return ret; } talloc_zfree(tmp_ctx); diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c index d9f73fe..50705a3 100644 --- a/src/responder/common/responder_common.c +++ b/src/responder/common/responder_common.c @@ -839,6 +839,7 @@ int sss_process_init(TALLOC_CTX *mem_ctx, ret = sysdb_init(rctx, cdb, NULL, false, &rctx->db_list); if (ret != EOK) { + SYSDB_VERSION_ERROR_DAEMON(ret); DEBUG(0, ("fatal error initializing resp_ctx\n")); return ret; } diff --git a/src/tools/sss_cache.c b/src/tools/sss_cache.c index 267b8ac..dfc58a7 100644 --- a/src/tools/sss_cache.c +++ b/src/tools/sss_cache.c @@ -339,6 +339,7 @@ errno_t init_domains(struct cache_tool_ctx *ctx, const char *domain) ret = sysdb_init_domain_and_sysdb(ctx, ctx->confdb, domain, DB_PATH, &ctx->domains, &db_ctx); if (ret != EOK) { + SYSDB_VERSION_ERROR(ret); DEBUG(1, ("Could not initialize connection to the sysdb\n")); goto fail; } @@ -350,6 +351,7 @@ errno_t init_domains(struct cache_tool_ctx *ctx, const char *domain) } } else { ret = sysdb_init(ctx, ctx->confdb, NULL, false, &ctx->sysdb_list); + SYSDB_VERSION_ERROR(ret); if (ret != EOK) { DEBUG(1, ("Could not initialize connection to the sysdb\n")); goto fail; diff --git a/src/tools/sss_seed.c b/src/tools/sss_seed.c index 18d0b9d..8eaf959 100644 --- a/src/tools/sss_seed.c +++ b/src/tools/sss_seed.c @@ -631,6 +631,7 @@ static int seed_init_db(TALLOC_CTX *mem_ctx, ret = sysdb_init_domain_and_sysdb(tmp_ctx, confdb, domain_name, DB_PATH, &domain, &sysdb); if (ret != EOK) { + SYSDB_VERSION_ERROR(ret); DEBUG(SSSDBG_CRIT_FAILURE, ("Could not initialize connection to domain '%s' in sysdb.%s\n", domain_name, ret == ENOENT ? " Domain not found." : "")); diff --git a/src/tools/tools_util.c b/src/tools/tools_util.c index 99b79f1..73e9413 100644 --- a/src/tools/tools_util.c +++ b/src/tools/tools_util.c @@ -57,6 +57,7 @@ static int setup_db(struct tools_ctx *ctx) ret = sysdb_init_domain_and_sysdb(ctx, ctx->confdb, "local", DB_PATH, &ctx->local, &ctx->sysdb); if (ret != EOK) { + SYSDB_VERSION_ERROR(ret); DEBUG(1, ("Could not initialize connection to the sysdb\n")); return ret; }