From e5e4b22c7f25c4f747b0bf742e52d3b3e4e0a8c2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?V=C3=ADt=C4=9Bzslav=20K=C5=99=C3=AD=C5=BE?= Date: Tue, 24 Oct 2017 14:25:10 +0200 Subject: [PATCH] daemon: remove globals, split main into functions --- daemon/main.c | 299 ++++++++++++++++++++++++++------------------------ 1 file changed, 156 insertions(+), 143 deletions(-) diff --git a/daemon/main.c b/daemon/main.c index 0fc44afbb..0d2126962 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -46,11 +45,25 @@ #define CAN_FORK_EARLY 1 #endif -/* - * Globals - */ -static bool g_quiet = false; -static bool g_interactive = true; +/* @internal Array of ip address shorthand. */ +typedef array_t(char*) addr_array_t; + +struct args { + int forks; + addr_array_t addr_set; + addr_array_t tls_set; + fd_array_t fd_set; + fd_array_t tls_fd_set; + char *keyfile; + int keyfile_unmanaged; + const char *moduledir; + const char *config; + int control_fd; + const char *rundir; + bool interactive; + bool quiet; + bool tty_binary_output; +}; /* lua_pcall helper function */ static inline char *lua_strerror(int lua_err) { @@ -67,9 +80,8 @@ static inline char *lua_strerror(int lua_err) { * * For parameters see http://docs.libuv.org/en/v1.x/stream.html#c.uv_read_cb * - * - This is just basic read-eval-print; libedit is supported through krsec; - * - stream->data represents a bool determining binary output mode (used by kresc); - * - binary output: uint32_t length in network order, followed by that many bytes. + * - This is just basic read-eval-print; libedit is supported through kresc; + * - stream->data contains program arguments (struct args); */ static void tty_process_input(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { @@ -78,6 +90,7 @@ static void tty_process_input(uv_stream_t *stream, ssize_t nread, const uv_buf_t /* Set output streams */ FILE *out = stdout; uv_os_fd_t stream_fd = 0; + struct args *args = stream->data; if (uv_fileno((uv_handle_t *)stream, &stream_fd)) { uv_close((uv_handle_t *)stream, (uv_close_cb) free); free(cmd); @@ -112,11 +125,9 @@ static void tty_process_input(uv_stream_t *stream, ssize_t nread, const uv_buf_t cmd[nread] = '\0'; } - /* Pseudo-command for switching to "binary output"; - * beware: void* <-> bool */ - bool is_binary = stream->data; + /* Pseudo-command for switching to "binary output"; */ if (strcmp(cmd, "__binary") == 0) { - stream->data = (void *)(is_binary = true); + args->tty_binary_output = true; goto finish; } @@ -129,7 +140,7 @@ static void tty_process_input(uv_stream_t *stream, ssize_t nread, const uv_buf_t } /* Simpler output in binary mode */ - if (is_binary) { + if (args->tty_binary_output) { size_t len_s = strlen(message); if (len_s > UINT32_MAX) goto finish; @@ -141,12 +152,12 @@ static void tty_process_input(uv_stream_t *stream, ssize_t nread, const uv_buf_t } /* Log to remote socket if connected */ - const char *delim = g_quiet ? "" : "> "; + const char *delim = args->quiet ? "" : "> "; if (stream_fd != STDIN_FILENO) { fprintf(stdout, "%s\n", cmd); /* Duplicate command to logs */ if (message) fprintf(out, "%s", message); /* Duplicate output to sender */ - if (message || !g_quiet) + if (message || !args->quiet) fprintf(out, "\n"); fprintf(out, "%s", delim); } @@ -154,7 +165,7 @@ static void tty_process_input(uv_stream_t *stream, ssize_t nread, const uv_buf_t FILE *fp_out = ret ? stderr : stdout; if (message) fprintf(fp_out, "%s", message); - if (message || !g_quiet) + if (message || !args->quiet) fprintf(fp_out, "\n"); fprintf(fp_out, "%s", delim); lua_settop(L, 0); @@ -176,16 +187,17 @@ static void tty_alloc(uv_handle_t *handle, size_t suggested, uv_buf_t *buf) { static void tty_accept(uv_stream_t *master, int status) { uv_tcp_t *client = malloc(sizeof(*client)); + struct args *args = master->data; if (client) { uv_tcp_init(master->loop, client); if (uv_accept(master, (uv_stream_t *)client) != 0) { free(client); return; } - client->data = 0; + client->data = args; uv_read_start((uv_stream_t *)client, tty_alloc, tty_process_input); /* Write command line */ - if (!g_quiet) { + if (!args->quiet) { uv_buf_t buf = { "> ", 2 }; uv_try_write((uv_stream_t *)client, &buf, 1); } @@ -364,23 +376,23 @@ static void help(int argc, char *argv[]) " [rundir] Path to the working directory (default: .)\n"); } -static int run_worker(uv_loop_t *loop, struct engine *engine, fd_array_t *ipc_set, bool leader, int control_fd) +static int run_worker(uv_loop_t *loop, struct engine *engine, fd_array_t *ipc_set, bool leader, struct args *args) { /* Control sockets or TTY */ auto_free char *sock_file = NULL; uv_pipe_t pipe; uv_pipe_init(loop, &pipe, 0); - pipe.data = 0; - if (g_interactive) { - if (!g_quiet) + pipe.data = args; + if (args->interactive) { + if (!args->quiet) printf("[system] interactive mode\n> "); fflush(stdout); uv_pipe_open(&pipe, 0); uv_read_start((uv_stream_t*) &pipe, tty_alloc, tty_process_input); } else { int pipe_ret = -1; - if (control_fd != -1) { - pipe_ret = uv_pipe_open(&pipe, control_fd); + if (args->control_fd != -1) { + pipe_ret = uv_pipe_open(&pipe, args->control_fd); } else { (void) mkdir("tty", S_IRWXU|S_IRWXG); sock_file = afmt("tty/%ld", getpid()); @@ -424,10 +436,11 @@ static void free_sd_socket_names(char **socket_names, int count) } #endif -static int init_keyfile(struct engine *engine, const char *keyfile, bool keyfile_unmanaged) +static int set_keyfile(struct engine *engine, char *keyfile, bool unmanaged) { + assert(keyfile != NULL); auto_free char *cmd = afmt("trust_anchors.config('%s',%s)", - keyfile, keyfile_unmanaged ? "true" : "nil"); + keyfile, unmanaged ? "true" : "nil"); if (!cmd) { kr_log_error("[system] not enough memory\n"); return kr_error(ENOMEM); @@ -440,32 +453,32 @@ static int init_keyfile(struct engine *engine, const char *keyfile, bool keyfile kr_log_error("[ ta ] keyfile '%s': failed to load (%s)\n", keyfile, lua_strerror(lua_ret)); } - return kr_error(EIO); + return lua_ret; } lua_settop(engine->L, 0); - return 0; + return kr_ok(); } -int main(int argc, char **argv) + +static void args_init(struct args *args) { - int forks = 1; - array_t(char*) addr_set; - array_t(char*) tls_set; - array_init(addr_set); - array_init(tls_set); - array_t(int) fd_set; - array_init(fd_set); - array_t(int) tls_fd_set; - array_init(tls_fd_set); - char *keyfile = NULL; - int keyfile_unmanaged = 0; - char *moduledir = MODULEDIR; - const char *config = NULL; - int control_fd = -1; + memset(args, 0, sizeof(struct args)); + args->forks = -1; + array_init(args->addr_set); + array_init(args->tls_set); + array_init(args->fd_set); + array_init(args->tls_fd_set); + args->moduledir = MODULEDIR; + args->control_fd = -1; + args->interactive = true; + args->quiet = false; +} +int parse_args(int argc, char **argv, struct args *args) +{ /* Long options. */ - int c = 0, li = 0, ret = 0; + int c = 0, li = 0; struct option opts[] = { {"addr", required_argument, 0, 'a'}, {"tls", required_argument, 0, 't'}, @@ -486,40 +499,40 @@ int main(int argc, char **argv) switch (c) { case 'a': - array_push(addr_set, optarg); + array_push(args->addr_set, optarg); break; case 't': - array_push(tls_set, optarg); + array_push(args->tls_set, optarg); break; case 'S': - array_push(fd_set, strtol(optarg, NULL, 10)); + array_push(args->fd_set, strtol(optarg, NULL, 10)); break; case 'T': - array_push(tls_fd_set, strtol(optarg, NULL, 10)); + array_push(args->tls_fd_set, strtol(optarg, NULL, 10)); break; case 'c': - config = optarg; + args->config = optarg; break; case 'f': - g_interactive = false; - forks = strtol(optarg, NULL, 10); - if (forks <= 0) { + args->interactive = false; + args->forks = strtol(optarg, NULL, 10); + if (args->forks <= 0) { kr_log_error("[system] error '-f' requires a positive" " number, not '%s'\n", optarg); return EXIT_FAILURE; } break; case 'K': - keyfile_unmanaged = 1; + args->keyfile_unmanaged = 1; case 'k': - if (keyfile != NULL) { + if (args->keyfile != NULL) { kr_log_error("[system] error only one of '--keyfile' and '--keyfile-ro' allowed\n"); return EXIT_FAILURE; } - keyfile = optarg; + args->keyfile = optarg; break; case 'm': - moduledir = optarg; + args->moduledir = optarg; break; case 'v': kr_verbose_set(true); @@ -528,7 +541,7 @@ int main(int argc, char **argv) #endif break; case 'q': - g_quiet = true; + args->quiet = true; break; case 'V': kr_log_info("%s, version %s\n", "Knot DNS Resolver", PACKAGE_VERSION); @@ -541,6 +554,49 @@ int main(int argc, char **argv) help(argc, argv); return EXIT_FAILURE; } + } + if (optind < argc) { + args->rundir = argv[optind]; + } + return EXIT_SUCCESS; +} + +static int bind_fds(struct network *net, fd_array_t *fd_set, bool tls) { + int ret = 0; + for (size_t i = 0; i < fd_set->len; ++i) { + ret = network_listen_fd(net, fd_set->at[i], tls); + if (ret != 0) { + kr_log_error("[system] %slisten on fd=%d %s\n", + tls ? "TLS " : "", fd_set->at[i], kr_strerror(ret)); + break; + } + } + return ret; +} + +static int bind_sockets(struct network *net, addr_array_t *addr_set, bool tls) { + uint32_t flags = tls ? NET_TCP|NET_TLS : NET_UDP|NET_TCP; + int ret = 0; + for (size_t i = 0; i < addr_set->len; ++i) { + int port = tls ? KR_DNS_TLS_PORT : KR_DNS_PORT; + const char *addr = set_addr(addr_set->at[i], &port); + ret = network_listen(net, addr, (uint16_t)port, flags); + if (ret != 0) { + kr_log_error("[system] bind to '%s@%d' %s%s\n", + addr, port, tls ? "(TLS) " : "", kr_strerror(ret)); + break; + } + } + return ret; +} + +int main(int argc, char **argv) +{ + int ret = 0; + struct args args; + args_init(&args); + if ((ret = parse_args(argc, argv, &args)) != EXIT_SUCCESS) { + return ret; } #ifdef HAS_SYSTEMD @@ -550,45 +606,44 @@ int main(int argc, char **argv) for (int i = 0; i < sd_nsocks; ++i) { int fd = SD_LISTEN_FDS_START + i; /* when run under systemd supervision, do not use interactive mode */ - g_interactive = false; - if (forks != 1) { + args.interactive = false; + if (args.forks != 1) { kr_log_error("[system] when run under systemd-style supervision, " - "use single-process only (bad: --fork=%d).\n", forks); + "use single-process only (bad: --fork=%d).\n", args.forks); free_sd_socket_names(socket_names, sd_nsocks); return EXIT_FAILURE; } if (!strcasecmp("control",socket_names[i])) { - control_fd = fd; + args.control_fd = fd; } else if (!strcasecmp("tls",socket_names[i])) { - array_push(tls_fd_set, fd); + array_push(args.tls_fd_set, fd); } else { - array_push(fd_set, fd); + array_push(args.fd_set, fd); } } free_sd_socket_names(socket_names, sd_nsocks); #endif /* Switch to rundir. */ - if (optind < argc) { - const char *rundir = argv[optind]; + if (args.rundir != NULL) { /* FIXME: access isn't a good way if we start as root and drop privileges later */ - if (access(rundir, W_OK) != 0) { - kr_log_error("[system] rundir '%s': %s\n", rundir, strerror(errno)); + if (access(args.rundir, W_OK) != 0) { + kr_log_error("[system] rundir '%s': %s\n", args.rundir, strerror(errno)); return EXIT_FAILURE; } - ret = chdir(rundir); + ret = chdir(args.rundir); if (ret != 0) { - kr_log_error("[system] rundir '%s': %s\n", rundir, strerror(errno)); + kr_log_error("[system] rundir '%s': %s\n", args.rundir, strerror(errno)); return EXIT_FAILURE; } } - if (config && strcmp(config, "-") != 0 && access(config, R_OK) != 0) { - kr_log_error("[system] config '%s': %s\n", config, strerror(errno)); + if (args.config && strcmp(args.config, "-") != 0 && access(args.config, R_OK) != 0) { + kr_log_error("[system] config '%s': %s\n", args.config, strerror(errno)); return EXIT_FAILURE; } - if (!config && access("config", R_OK) == 0) { - config = "config"; + if (!args.config && access("config", R_OK) == 0) { + args.config = "config"; } #ifndef CAN_FORK_EARLY @@ -606,7 +661,7 @@ int main(int argc, char **argv) fd_array_t ipc_set; array_init(ipc_set); /* Fork subprocesses if requested */ - int fork_id = fork_workers(&ipc_set, forks); + int fork_id = fork_workers(&ipc_set, args.forks); if (fork_id < 0) { return EXIT_FAILURE; } @@ -625,54 +680,20 @@ int main(int argc, char **argv) return EXIT_FAILURE; } /* Create worker */ - struct worker_ctx *worker = worker_create(&engine, &pool, fork_id, forks); + struct worker_ctx *worker = worker_create(&engine, &pool, fork_id, args.forks); if (!worker) { kr_log_error("[system] not enough memory\n"); return EXIT_FAILURE; } - /* Bind to passed fds and run */ - for (size_t i = 0; i < fd_set.len; ++i) { - ret = network_listen_fd(&engine.net, fd_set.at[i], false); - if (ret != 0) { - kr_log_error("[system] listen on fd=%d %s\n", fd_set.at[i], kr_strerror(ret)); - ret = EXIT_FAILURE; - break; - } - } - /* Do the same for TLS */ - for (size_t i = 0; i < tls_fd_set.len; ++i) { - ret = network_listen_fd(&engine.net, tls_fd_set.at[i], true); - if (ret != 0) { - kr_log_error("[system] TLS listen on fd=%d %s\n", tls_fd_set.at[i], kr_strerror(ret)); - ret = EXIT_FAILURE; - break; - } - } - /* Bind to sockets and run */ - if (ret == 0) { - for (size_t i = 0; i < addr_set.len; ++i) { - int port = 53; - const char *addr = set_addr(addr_set.at[i], &port); - ret = network_listen(&engine.net, addr, (uint16_t)port, NET_UDP|NET_TCP); - if (ret != 0) { - kr_log_error("[system] bind to '%s@%d' %s\n", addr, port, kr_strerror(ret)); - ret = EXIT_FAILURE; - break; - } - } - } - /* Bind to TLS sockets */ - if (ret == 0) { - for (size_t i = 0; i < tls_set.len; ++i) { - int port = KR_DNS_TLS_PORT; - const char *addr = set_addr(tls_set.at[i], &port); - ret = network_listen(&engine.net, addr, (uint16_t)port, NET_TCP|NET_TLS); - if (ret != 0) { - kr_log_error("[system] bind to '%s@%d' (TLS) %s\n", addr, port, kr_strerror(ret)); - ret = EXIT_FAILURE; - break; - } - } + + /* Bind to passed fds and sockets*/ + if (bind_fds(&engine.net, &args.fd_set, false) != 0 || + bind_fds(&engine.net, &args.tls_fd_set, true) != 0 || + bind_sockets(&engine.net, &args.addr_set, false) != 0 || + bind_sockets(&engine.net, &args.tls_set, true) != 0 + ) { + ret = EXIT_FAILURE; + goto cleanup; } /* Workaround for https://github.com/libuv/libuv/issues/45 @@ -687,7 +708,7 @@ int main(int argc, char **argv) goto cleanup; } - engine_set_moduledir(&engine, moduledir); + engine_set_moduledir(&engine, args.moduledir); /* Block signals. */ uv_loop_t *loop = uv_default_loop(); @@ -700,42 +721,34 @@ int main(int argc, char **argv) worker->loop = loop; loop->data = worker; - ret = engine_load_sandbox(&engine); - if (ret == 0 && config != NULL && strcmp(config, "-") !=0) { - ret = engine_loadconf(&engine, config); - } - - if (ret != 0) { + if (engine_load_sandbox(&engine) != 0) { ret = EXIT_FAILURE; goto cleanup; } - - if (keyfile) { - ret = init_keyfile(&engine, keyfile, keyfile_unmanaged); - if (ret != 0) { - kr_log_error("[system] failed to initialized keyfile: %s\n", kr_strerror(ret)); + if (args.config != NULL && strcmp(args.config, "-") != 0) { + if(engine_loadconf(&engine, args.config) != 0) { ret = EXIT_FAILURE; goto cleanup; } + lua_settop(engine.L, 0); } - - if (config == NULL || strcmp(config, "-") !=0) { - ret = engine_load_defaults(&engine); - } - - if (ret != 0) { + if (args.keyfile != NULL && set_keyfile(&engine, args.keyfile, args.keyfile_unmanaged) != 0) { ret = EXIT_FAILURE; goto cleanup; } - - ret = engine_start(&engine); - if (ret != 0) { + if (args.config == NULL || strcmp(args.config, "-") !=0) { + if(engine_load_defaults(&engine) != 0) { + ret = EXIT_FAILURE; + goto cleanup; + } + } + if (engine_start(&engine) != 0) { ret = EXIT_FAILURE; goto cleanup; } /* Run the event loop */ - ret = run_worker(loop, &engine, &ipc_set, fork_id == 0, control_fd); + ret = run_worker(loop, &engine, &ipc_set, fork_id == 0, &args); if (ret != 0) { perror("[system] worker failed"); ret = EXIT_FAILURE; @@ -746,8 +759,8 @@ cleanup:/* Cleanup. */ engine_deinit(&engine); worker_reclaim(worker); mp_delete(pool.ctx); - array_clear(addr_set); - array_clear(tls_set); + array_clear(args.addr_set); + array_clear(args.tls_set); kr_crypto_cleanup(); return ret; } -- 2.47.2