return 0;
}
+/**
+ * TTY control: process input and free() the buffer.
+ *
+ * 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 kresc;
+ */
+void io_tty_process_input(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
+{
+ char *cmd = buf ? buf->base : NULL; /* To be free()d on return. */
+
+ /* Set output streams */
+ FILE *out = stdout;
+ uv_os_fd_t stream_fd = 0;
+ struct args *args = the_args;
+ if (uv_fileno((uv_handle_t *)stream, &stream_fd)) {
+ uv_close((uv_handle_t *)stream, (uv_close_cb) free);
+ free(cmd);
+ return;
+ }
+ if (stream_fd != STDIN_FILENO) {
+ if (nread < 0) { /* Close if disconnected */
+ uv_close((uv_handle_t *)stream, (uv_close_cb) free);
+ }
+ if (nread <= 0) {
+ free(cmd);
+ return;
+ }
+ uv_os_fd_t dup_fd = dup(stream_fd);
+ if (dup_fd >= 0) {
+ out = fdopen(dup_fd, "w");
+ }
+ }
+
+ /* Execute */
+ if (stream && cmd && nread > 0) {
+ /* Ensure cmd is 0-terminated */
+ if (cmd[nread - 1] == '\n') {
+ cmd[nread - 1] = '\0';
+ } else {
+ if (nread >= buf->len) { /* only equality should be possible */
+ char *newbuf = realloc(cmd, nread + 1);
+ if (!newbuf)
+ goto finish;
+ cmd = newbuf;
+ }
+ cmd[nread] = '\0';
+ }
+
+ /* Pseudo-command for switching to "binary output"; */
+ if (strcmp(cmd, "__binary") == 0) {
+ args->tty_binary_output = true;
+ goto finish;
+ }
+
+ lua_State *L = the_worker->engine->L;
+ int ret = engine_cmd(L, cmd, false);
+ const char *message = "";
+ if (lua_gettop(L) > 0) {
+ message = lua_tostring(L, -1);
+ }
+
+ /* Simpler output in binary mode */
+ if (args->tty_binary_output) {
+ size_t len_s = strlen(message);
+ if (len_s > UINT32_MAX)
+ goto finish;
+ uint32_t len_n = htonl(len_s);
+ fwrite(&len_n, sizeof(len_n), 1, out);
+ fwrite(message, len_s, 1, out);
+ lua_settop(L, 0);
+ goto finish;
+ }
+
+ /* Log to remote socket if connected */
+ const char *delim = args->quiet ? "" : "> ";
+ if (stream_fd != STDIN_FILENO) {
+ if (VERBOSE_STATUS)
+ fprintf(stdout, "%s\n", cmd); /* Duplicate command to logs */
+ if (message)
+ fprintf(out, "%s", message); /* Duplicate output to sender */
+ if (message || !args->quiet)
+ fprintf(out, "\n");
+ fprintf(out, "%s", delim);
+ }
+ if (stream_fd == STDIN_FILENO || VERBOSE_STATUS) {
+ /* Log to standard streams */
+ FILE *fp_out = ret ? stderr : stdout;
+ if (message)
+ fprintf(fp_out, "%s", message);
+ if (message || !args->quiet)
+ fprintf(fp_out, "\n");
+ fprintf(fp_out, "%s", delim);
+ }
+ lua_settop(L, 0);
+ }
+finish:
+ free(cmd);
+ /* Close if redirected */
+ if (stream_fd != STDIN_FILENO) {
+ fclose(out);
+ }
+}
+
+void io_tty_alloc(uv_handle_t *handle, size_t suggested, uv_buf_t *buf)
+{
+ buf->len = suggested;
+ buf->base = malloc(suggested);
+}
+
+void io_tty_accept(uv_stream_t *master, int status)
+{
+ uv_tcp_t *client = malloc(sizeof(*client));
+ struct args *args = the_args;
+ if (client) {
+ uv_tcp_init(master->loop, client);
+ if (uv_accept(master, (uv_stream_t *)client) != 0) {
+ free(client);
+ return;
+ }
+ uv_read_start((uv_stream_t *)client, io_tty_alloc, io_tty_process_input);
+ /* Write command line */
+ if (!args->quiet) {
+ uv_buf_t buf = { "> ", 2 };
+ uv_try_write((uv_stream_t *)client, &buf, 1);
+ }
+ }
+}
+
int io_create(uv_loop_t *loop, uv_handle_t *handle, int type, unsigned family, bool has_tls)
{
int ret = -1;
#include <libknot/error.h>
-/* @internal Array of ip address shorthand. */
-typedef array_t(char*) addr_array_t;
-
-typedef array_t(const char*) config_array_t;
-
-typedef struct {
- int fd;
- endpoint_flags_t flags; /**< .sock_type isn't meaningful here */
-} flagged_fd_t;
-typedef array_t(flagged_fd_t) flagged_fd_array_t;
-
-struct args {
- addr_array_t addrs, addrs_tls;
- flagged_fd_array_t fds;
- int control_fd;
- int forks;
- config_array_t config;
- const char *rundir;
- bool interactive;
- bool quiet;
- bool tty_binary_output;
-};
-
-/**
- * TTY control: process input and free() the buffer.
- *
- * 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 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)
-{
- char *cmd = buf ? buf->base : NULL; /* To be free()d on return. */
-
- /* 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);
- return;
- }
- if (stream_fd != STDIN_FILENO) {
- if (nread < 0) { /* Close if disconnected */
- uv_close((uv_handle_t *)stream, (uv_close_cb) free);
- }
- if (nread <= 0) {
- free(cmd);
- return;
- }
- uv_os_fd_t dup_fd = dup(stream_fd);
- if (dup_fd >= 0) {
- out = fdopen(dup_fd, "w");
- }
- }
+struct args the_args_value; /** Static allocation for the_args singleton. */
- /* Execute */
- if (stream && cmd && nread > 0) {
- /* Ensure cmd is 0-terminated */
- if (cmd[nread - 1] == '\n') {
- cmd[nread - 1] = '\0';
- } else {
- if (nread >= buf->len) { /* only equality should be possible */
- char *newbuf = realloc(cmd, nread + 1);
- if (!newbuf)
- goto finish;
- cmd = newbuf;
- }
- cmd[nread] = '\0';
- }
-
- /* Pseudo-command for switching to "binary output"; */
- if (strcmp(cmd, "__binary") == 0) {
- args->tty_binary_output = true;
- goto finish;
- }
-
- lua_State *L = the_worker->engine->L;
- int ret = engine_cmd(L, cmd, false);
- const char *message = "";
- if (lua_gettop(L) > 0) {
- message = lua_tostring(L, -1);
- }
-
- /* Simpler output in binary mode */
- if (args->tty_binary_output) {
- size_t len_s = strlen(message);
- if (len_s > UINT32_MAX)
- goto finish;
- uint32_t len_n = htonl(len_s);
- fwrite(&len_n, sizeof(len_n), 1, out);
- fwrite(message, len_s, 1, out);
- lua_settop(L, 0);
- goto finish;
- }
-
- /* Log to remote socket if connected */
- const char *delim = args->quiet ? "" : "> ";
- if (stream_fd != STDIN_FILENO) {
- if (VERBOSE_STATUS)
- fprintf(stdout, "%s\n", cmd); /* Duplicate command to logs */
- if (message)
- fprintf(out, "%s", message); /* Duplicate output to sender */
- if (message || !args->quiet)
- fprintf(out, "\n");
- fprintf(out, "%s", delim);
- }
- if (stream_fd == STDIN_FILENO || VERBOSE_STATUS) {
- /* Log to standard streams */
- FILE *fp_out = ret ? stderr : stdout;
- if (message)
- fprintf(fp_out, "%s", message);
- if (message || !args->quiet)
- fprintf(fp_out, "\n");
- fprintf(fp_out, "%s", delim);
- }
- lua_settop(L, 0);
- }
-finish:
- free(cmd);
- /* Close if redirected */
- if (stream_fd != STDIN_FILENO) {
- fclose(out);
- }
-}
-
-static void tty_alloc(uv_handle_t *handle, size_t suggested, uv_buf_t *buf) {
- buf->len = suggested;
- buf->base = malloc(suggested);
-}
-
-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 = args;
- uv_read_start((uv_stream_t *)client, tty_alloc, tty_process_input);
- /* Write command line */
- if (!args->quiet) {
- uv_buf_t buf = { "> ", 2 };
- uv_try_write((uv_stream_t *)client, &buf, 1);
- }
- }
-}
/* @internal AF_LOCAL reads may still be interrupted, loop it. */
static bool ipc_readall(int fd, char *dst, size_t len)
if (!args->quiet)
printf("[system] interactive mode\n> ");
uv_pipe_open(&pipe, 0);
- uv_read_start((uv_stream_t*) &pipe, tty_alloc, tty_process_input);
+ uv_read_start((uv_stream_t*) &pipe, io_tty_alloc, io_tty_process_input);
} else {
int pipe_ret = -1;
if (args->control_fd != -1) {
}
}
if (!pipe_ret)
- uv_listen((uv_stream_t *) &pipe, 16, tty_accept);
+ uv_listen((uv_stream_t *) &pipe, 16, io_tty_accept);
}
/* Watch IPC pipes (or just assign them if leading the pgroup). */
if (!leader) {
int main(int argc, char **argv)
{
- struct args args;
- args_init(&args);
- int ret = parse_args(argc, argv, &args);
+ the_args = &the_args_value;
+ args_init(the_args);
+ int ret = parse_args(argc, argv, the_args);
if (ret >= 0) goto cleanup_args;
- ret = bind_sockets(&args.addrs, false, &args.fds);
+ ret = bind_sockets(&the_args->addrs, false, &the_args->fds);
if (ret) goto cleanup_args;
- ret = bind_sockets(&args.addrs_tls, true, &args.fds);
+ ret = bind_sockets(&the_args->addrs_tls, true, &the_args->fds);
if (ret) goto cleanup_args;
#if SYSTEMD_VERSION >= 227
ret = EXIT_FAILURE;
goto cleanup_args;
}
- if (sd_nsocks > 0 && args.forks != 1) {
+ if (sd_nsocks > 0 && the_args->forks != 1) {
kr_log_error("[system] when run under systemd-style supervision, "
- "use single-process only (bad: --forks=%d).\n", args.forks);
+ "use single-process only (bad: --forks=%d).\n", the_args->forks);
free_sd_socket_names(socket_names, sd_nsocks);
ret = EXIT_FAILURE;
goto cleanup_args;
}
for (int i = 0; i < sd_nsocks; ++i) {
/* when run under systemd supervision, do not use interactive mode */
- args.interactive = false;
+ the_args->interactive = false;
flagged_fd_t ffd = { .fd = SD_LISTEN_FDS_START + i };
if (!strcasecmp("control", socket_names[i])) {
- if (args.control_fd != -1) {
+ if (the_args->control_fd != -1) {
kr_log_error("[system] multiple control sockets passed from systemd\n");
ret = EXIT_FAILURE;
break;
}
- args.control_fd = ffd.fd;
+ the_args->control_fd = ffd.fd;
free(socket_names[i]);
} else {
if (!strcasecmp("dns", socket_names[i])) {
} else {
ffd.flags.kind = socket_names[i];
}
- array_push(args.fds, ffd);
+ array_push(the_args->fds, ffd);
}
/* Either freed or passed ownership. */
socket_names[i] = NULL;
#endif
/* Switch to rundir. */
- if (args.rundir != NULL) {
+ if (the_args->rundir != NULL) {
/* FIXME: access isn't a good way if we start as root and drop privileges later */
- if (access(args.rundir, W_OK) != 0
- || chdir(args.rundir) != 0) {
+ if (access(the_args->rundir, W_OK) != 0
+ || chdir(the_args->rundir) != 0) {
kr_log_error("[system] rundir '%s': %s\n",
- args.rundir, strerror(errno));
+ the_args->rundir, strerror(errno));
return EXIT_FAILURE;
}
}
/* Select which config files to load and verify they are read-able. */
bool load_defaults = true;
size_t i = 0;
- while (i < args.config.len) {
- const char *config = args.config.at[i];
+ while (i < the_args->config.len) {
+ const char *config = the_args->config.at[i];
if (strcmp(config, "-") == 0) {
load_defaults = false;
- array_del(args.config, i);
+ array_del(the_args->config, i);
continue; /* don't increment i */
} else if (access(config, R_OK) != 0) {
char cwd[PATH_MAX];
}
i++;
}
- if (args.config.len == 0 && access("config", R_OK) == 0)
- array_push(args.config, "config");
+ if (the_args->config.len == 0 && access("config", R_OK) == 0)
+ array_push(the_args->config, "config");
if (load_defaults)
- array_push(args.config, LIBDIR "/config.lua");
+ array_push(the_args->config, LIBDIR "/config.lua");
/* File-descriptor count limit: soft->hard. */
struct rlimit rlim;
fd_array_t ipc_set;
array_init(ipc_set);
/* Fork subprocesses if requested */
- int fork_id = fork_workers(&ipc_set, args.forks);
+ int fork_id = fork_workers(&ipc_set, the_args->forks);
if (fork_id < 0) {
return EXIT_FAILURE;
}
return EXIT_FAILURE;
}
/* Initialize the worker */
- ret = worker_init(&engine, fork_id, args.forks);
+ ret = worker_init(&engine, fork_id, the_args->forks);
if (ret != 0) {
kr_log_error("[system] failed to initialize worker: %s\n", kr_strerror(ret));
return EXIT_FAILURE;
}
/* Start listening, in the sense of network_listen_fd(). */
- if (start_listening(&engine.net, &args.fds) != 0) {
+ if (start_listening(&engine.net, &the_args->fds) != 0) {
ret = EXIT_FAILURE;
goto cleanup;
}
goto cleanup;
}
- for (i = 0; i < args.config.len; ++i) {
- const char *config = args.config.at[i];
+ for (i = 0; i < the_args->config.len; ++i) {
+ const char *config = the_args->config.at[i];
if (engine_loadconf(&engine, config) != 0) {
ret = EXIT_FAILURE;
goto cleanup;
}
/* Run the event loop */
- ret = run_worker(loop, &engine, &ipc_set, fork_id == 0, &args);
+ ret = run_worker(loop, &engine, &ipc_set, fork_id == 0, the_args);
cleanup:/* Cleanup. */
engine_deinit(&engine);
}
mp_delete(pool.ctx);
cleanup_args:
- args_deinit(&args);
+ args_deinit(the_args);
kr_crypto_cleanup();
return ret;
}