Mercurial > dovecot > core-2.2
view src/config/doveconf.c @ 10119:1e63221f5c83 HEAD
Moved most of getopt() handling to lib-master.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 20 Oct 2009 20:07:45 -0400 |
parents | dcda7c495eb6 |
children | b584904d3bc7 |
line wrap: on
line source
/* Copyright (C) 2005-2009 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "array.h" #include "env-util.h" #include "ostream.h" #include "settings-parser.h" #include "master-service.h" #include "all-settings.h" #include "sysinfo-get.h" #include "config-connection.h" #include "config-parser.h" #include "config-request.h" #include <stdio.h> #include <unistd.h> struct config_request_get_string_ctx { pool_t pool; ARRAY_TYPE(const_string) strings; }; static void config_request_get_strings(const char *key, const char *value, bool list, void *context) { struct config_request_get_string_ctx *ctx = context; value = p_strdup_printf(ctx->pool, list ? "-%s=%s" : "%s=%s", key, value); array_append(&ctx->strings, &value, 1); } static int config_string_cmp(const char *const *p1, const char *const *p2) { const char *s1 = *p1, *s2 = *p2; unsigned int i = 0; while (s1[i] == s2[i]) { if (s1[i] == '\0' || s1[i] == '=') return 0; i++; } if (s1[i] == '=') return -1; if (s2[i] == '=') return 1; return s1[i] - s2[i]; } static unsigned int prefix_stack_pop(ARRAY_TYPE(uint) *stack) { const unsigned int *indexes; unsigned int idx, count; indexes = array_get(stack, &count); idx = count <= 1 ? -1U : indexes[count-2]; array_delete(stack, count-1, 1); return idx; } static void config_connection_request_human(struct ostream *output, const struct config_filter *filter, const char *module, enum config_dump_scope scope) { static const char *ident_str = " "; ARRAY_TYPE(const_string) prefixes_arr; ARRAY_TYPE(uint) prefix_idx_stack; struct config_request_get_string_ctx ctx; const char *const *strings, *const *args, *p, *str, *const *prefixes; const char *key, *value; unsigned int i, j, count, len, prefix_count, skip_len; unsigned int indent = 0, prefix_idx = -1U; ctx.pool = pool_alloconly_create("config human strings", 10240); i_array_init(&ctx.strings, 256); if (config_request_handle(filter, module, scope, TRUE, config_request_get_strings, &ctx) < 0) return; array_sort(&ctx.strings, config_string_cmp); strings = array_get(&ctx.strings, &count); p_array_init(&prefixes_arr, ctx.pool, 32); for (i = 0; i < count && strings[i][0] == '-'; i++) T_BEGIN { p = strchr(strings[i], '='); i_assert(p != NULL); for (args = t_strsplit(p + 1, " "); *args != NULL; args++) { str = p_strdup_printf(ctx.pool, "%s/%s/", t_strcut(strings[i]+1, '='), *args); array_append(&prefixes_arr, &str, 1); } } T_END; prefixes = array_get(&prefixes_arr, &prefix_count); p_array_init(&prefix_idx_stack, ctx.pool, 8); for (; i < count; i++) T_BEGIN { value = strchr(strings[i], '='); i_assert(value != NULL); key = t_strdup_until(strings[i], value); value++; j = 0; while (prefix_idx != -1U) { len = strlen(prefixes[prefix_idx]); if (strncmp(prefixes[prefix_idx], key, len) != 0) { prefix_idx = prefix_stack_pop(&prefix_idx_stack); indent--; o_stream_send(output, ident_str, indent*2); o_stream_send_str(output, "}\n"); } else if (strchr(key + len, '/') == NULL) { /* keep the prefix */ j = prefix_count; break; } else { /* subprefix */ break; } } for (; j < prefix_count; j++) { len = strlen(prefixes[j]); if (strncmp(prefixes[j], key, len) == 0 && strchr(key + len, '/') == NULL) { key += prefix_idx == -1U ? 0 : strlen(prefixes[prefix_idx]); o_stream_send(output, ident_str, indent*2); o_stream_send_str(output, t_strcut(key, '/')); o_stream_send_str(output, " {\n"); indent++; prefix_idx = j; array_append(&prefix_idx_stack, &prefix_idx, 1); break; } } skip_len = prefix_idx == -1U ? 0 : strlen(prefixes[prefix_idx]); i_assert(skip_len == 0 || strncmp(prefixes[prefix_idx], strings[i], skip_len) == 0); o_stream_send(output, ident_str, indent*2); key = strings[i] + skip_len; value = strchr(key, '='); o_stream_send(output, key, value-key); o_stream_send_str(output, " = "); o_stream_send_str(output, value+1); o_stream_send(output, "\n", 1); } T_END; while (prefix_idx != -1U) { prefix_idx = prefix_stack_pop(&prefix_idx_stack); indent--; o_stream_send(output, ident_str, indent*2); o_stream_send_str(output, "}\n"); } array_free(&ctx.strings); pool_unref(&ctx.pool); } static void config_dump_human(const struct config_filter *filter, const char *module, enum config_dump_scope scope) { struct ostream *output; output = o_stream_create_fd(STDOUT_FILENO, 0, FALSE); o_stream_cork(output); config_connection_request_human(output, filter, module, scope); o_stream_uncork(output); o_stream_unref(&output); } static void config_request_putenv(const char *key, const char *value, bool list ATTR_UNUSED, void *context ATTR_UNUSED) { T_BEGIN { env_put(t_strconcat(t_str_ucase(key), "=", value, NULL)); } T_END; } static const char *get_mail_location(void) { struct config_module_parser *l; const struct setting_define *def; const char *const *value; const void *set; for (l = config_module_parsers; l->root != NULL; l++) { if (strcmp(l->root->module_name, "mail") != 0) continue; set = settings_parser_get(l->parser); for (def = l->root->defines; def->key != NULL; def++) { if (strcmp(def->key, "mail_location") == 0) { value = CONST_PTR_OFFSET(set, def->offset); return *value; } } } return ""; } static void filter_parse_arg(struct config_filter *filter, const char *arg) { if (strncmp(arg, "service=", 8) == 0) filter->service = arg + 8; else if (strncmp(arg, "protocol=", 9) == 0) filter->service = arg + 9; else if (strncmp(arg, "lip=", 4) == 0) { if (net_parse_range(arg + 4, &filter->local_net, &filter->local_bits) < 0) i_fatal("lip: Invalid network mask"); } else if (strncmp(arg, "rip=", 4) == 0) { if (net_parse_range(arg + 4, &filter->remote_net, &filter->remote_bits) < 0) i_fatal("rip: Invalid network mask"); } else { i_fatal("Unknown filter argument: %s", arg); } } int main(int argc, char *argv[]) { enum config_dump_scope scope = CONFIG_DUMP_SCOPE_ALL; const char *config_path, *module = ""; struct config_filter filter; const char *error; char **exec_args = NULL; int c, ret; memset(&filter, 0, sizeof(filter)); master_service = master_service_init("config", MASTER_SERVICE_FLAG_STANDALONE, argc, argv, "af:m:nNe"); i_set_failure_prefix("doveconf: "); while ((c = master_getopt(master_service)) > 0) { if (c == 'e') break; switch (c) { case 'a': break; case 'f': filter_parse_arg(&filter, optarg); break; case 'm': module = optarg; break; case 'n': scope = CONFIG_DUMP_SCOPE_CHANGED; break; case 'N': scope = CONFIG_DUMP_SCOPE_SET; break; default: return FATAL_DEFAULT; } } config_path = master_service_get_config_path(master_service); if (argv[optind] != NULL) { if (c != 'e') i_fatal("Unknown argument: %s", argv[optind]); exec_args = &argv[optind]; } else { /* print the config file path before parsing it, so in case of errors it's still shown */ printf("# "VERSION": %s\n", config_path); fflush(stdout); } master_service_init_finish(master_service); if ((ret = config_parse_file(config_path, FALSE, &error)) == 0 && access(EXAMPLE_CONFIG_DIR, X_OK) == 0) { i_fatal("%s (copy example configs from "EXAMPLE_CONFIG_DIR"/)", error); } if (ret <= 0) i_fatal("%s", error); if (exec_args == NULL) { const char *info; info = sysinfo_get(get_mail_location()); if (*info != '\0') printf("# %s\n", info); fflush(stdout); config_dump_human(&filter, module, scope); } else { env_put("DOVECONF_ENV=1"); if (config_request_handle(&filter, module, CONFIG_DUMP_SCOPE_SET, TRUE, config_request_putenv, NULL) < 0) i_fatal("Invalid configuration"); execvp(exec_args[0], exec_args); i_fatal("execvp(%s) failed: %m", exec_args[0]); } config_filter_deinit(&config_filter); master_service_deinit(&master_service); return 0; }