]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
daemon/main: cleanup, forking and remote tty
authorMarek Vavruša <marek.vavrusa@nic.cz>
Mon, 29 Jun 2015 22:27:00 +0000 (00:27 +0200)
committerMarek Vavruša <marek.vavrusa@nic.cz>
Mon, 29 Jun 2015 22:27:00 +0000 (00:27 +0200)
when the daemon starts in non-interactive mode, it creates a pipe in the ‘tty/<pid>’ which can be used to interact with it remotely - much wow

e.g. $ socat - UNIX-CONNECT:tty/38284

daemon/engine.c
daemon/engine.h
daemon/lua/sandbox.lua
daemon/main.c

index dd36156a7ac559f972a7c994d90f47a175203f35..d9b078c70bee50451250350f259eddcf83c3953c 100644 (file)
@@ -335,13 +335,7 @@ int engine_cmd(struct engine *engine, const char *str)
        lua_pushstring(engine->L, str);
 
        /* Check result. */
-       if (engine_pcall(engine->L, 1) != 0) {
-               fprintf(stderr, "%s\n", lua_tostring(engine->L, -1));
-               lua_pop(engine->L, 1);
-               return kr_error(EINVAL);
-       }
-
-       return kr_ok();
+       return engine_pcall(engine->L, 1);
 }
 
 /* Execute byte code */
@@ -363,10 +357,10 @@ static int engine_loadconf(struct engine *engine)
                return kr_error(ENOEXEC);
        }
        /* Use module path for including Lua scripts */
-       engine_cmd(engine, "package.path = package.path..';" PREFIX MODULEDIR "/?.lua'");
+       int ret = engine_cmd(engine, "package.path = package.path..';" PREFIX MODULEDIR "/?.lua'");
+       lua_pop(engine->L, 1);
 
        /* Load config file */
-       int ret = 0;
        if(access("config", F_OK ) != -1 ) {
                ret = l_dosandboxfile(engine->L, "config");
        } else {
index 4c64d61af21db3a29ef9d90cc50bc11216678f56..e82474cd9054552c1afcf84cb2353a2912ad7e37 100644 (file)
@@ -56,6 +56,7 @@ struct engine {
 
 int engine_init(struct engine *engine, mm_ctx_t *pool);
 void engine_deinit(struct engine *engine);
+/** @warning This function leaves 1 string result on stack. */
 int engine_cmd(struct engine *engine, const char *str);
 int engine_start(struct engine *engine);
 void engine_stop(struct engine *engine);
index a94b050cbf0783d4814550bffc4664c1235d252d..a7ca501c08ad6f1453ef432ffbd8f3542193786a 100644 (file)
@@ -119,15 +119,14 @@ function eval_cmd(line)
            end
        end
        local status, err, chunk
-       chunk, err = load_code('table_print('..line..')')
+       chunk, err = load_code('return table_print('..line..')')
        if err then
                chunk, err = load_code(line)
        end
        if not err then
-               chunk()
-       end
-       if err then
-               print(err)
+               return chunk()
+       else
+               error(err)
        end
 end
 
@@ -135,21 +134,23 @@ end
 function table_print (tt, indent, done)
        done = done or {}
        indent = indent or 0
+       result = ""
        if type(tt) == "table" then
                for key, value in pairs (tt) do
-                       io.write(string.rep (" ", indent))
+                       result = result .. string.rep (" ", indent)
                        if type (value) == "table" and not done [value] then
                                done [value] = true
-                               io.write(string.format("[%s] => {\n", tostring (key)));
+                               result = result .. string.format("[%s] => {\n", tostring (key))
                                table_print (value, indent + 4, done)
-                               io.write(string.rep (" ", indent))
-                               io.write("}\n");
+                               result = result .. string.rep (" ", indent)
+                               result = result .. "}\n"
                        else
-                               io.write(string.format("[%s] => %s\n",
-                                        tostring (key), tostring(value)))
+                               result = result .. string.format("[%s] => %s\n",
+                                        tostring (key), tostring(value))
                        end
                end
        else
-               io.write(tostring(tt) .. "\n")
+               result = result .. tostring(tt) .. "\n"
        end
+       return result
 end
index 9ad4dba7da6afacc1dff2fb68393fb71950d6cbf..791ec26883e0b1409d8ba6b434b6df7289a7b5ba 100644 (file)
@@ -19,8 +19,9 @@
 #include <getopt.h>
 #include <uv.h>
 #include <libknot/internal/sockaddr.h>
-#include <ucw/mempool.h>
 
+#include "contrib/ucw/mempool.h"
+#include "contrib/ccan/asprintf/asprintf.h"
 #include "lib/defines.h"
 #include "lib/resolve.h"
 #include "daemon/network.h"
 #include "daemon/bindings.h"
 #include "daemon/bindings/kres.h"
 
+/*
+ * Globals
+ */
+static int g_interactive = 1;
+
+/*
+ * TTY control
+ */
 static void tty_read(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
 {
+       /* Set output streams */
+       FILE *out = stdout, *outerr = stderr;
+       uv_os_fd_t stream_fd = 0;
+       uv_fileno((uv_handle_t *)stream, &stream_fd);
+       if (stream_fd != STDIN_FILENO) {
+               if (nread <= 0) { /* Close if disconnected */
+                       uv_close((uv_handle_t *)stream, (uv_close_cb) free);
+                       return;
+               }
+               out = outerr = fdopen(dup(stream_fd), "w");
+       }
+       /* Execute */
        if (stream && buf && nread > 0) {
-               /* Trim endln */
                char *cmd = buf->base;
-               cmd[nread - 1] = '\0';
-               /* Execute */
-               engine_cmd((struct engine *)stream->data, cmd);
+               if (cmd[nread - 1] == '\n') {
+                       cmd[nread - 1] = '\0';
+               }
+               struct engine *engine = stream->data;
+               lua_State *L = engine->L;
+               int ret = engine_cmd(engine, cmd);
+               fprintf(ret ? outerr : out, "%s\n> ", lua_tostring(L, -1));
+               lua_pop(L, 1);
                free(buf->base);
        }
+       fflush(out);
+       /* Close if redirected */
+       if (stream_fd != STDIN_FILENO) {
+               fclose(out); /* outerr is the same */
+       }
 
-       printf("> ");
-       fflush(stdout);
 }
 
 static void tty_alloc(uv_handle_t *handle, size_t suggested, uv_buf_t *buf) {
@@ -49,12 +77,44 @@ static void tty_alloc(uv_handle_t *handle, size_t suggested, uv_buf_t *buf) {
        buf->base = malloc(suggested);
 }
 
-void signal_handler(uv_signal_t *handle, int signum)
+static void tty_accept(uv_stream_t *master, int status)
+{
+       uv_tcp_t *client = malloc(sizeof(*client));
+       if (client) {
+                uv_tcp_init(master->loop, client);
+                if (uv_accept(master, (uv_stream_t *)client) != 0) {
+                       free(client);
+                       return;
+                }
+                client->data = master->data;
+                uv_read_start((uv_stream_t *)client, tty_alloc, tty_read);
+                /* Write command line */
+                uv_buf_t buf = { "> ", 2 };
+                uv_try_write((uv_stream_t *)client, &buf, 1);
+       }
+}
+
+static void signal_handler(uv_signal_t *handle, int signum)
 {
        uv_stop(uv_default_loop());
        uv_signal_stop(handle);
 }
 
+static const char *set_addr(char *addr, int *port)
+{
+       char *p = strchr(addr, '#');
+       if (p) {
+               *port = atoi(p + 1);
+               *p = '\0';
+       }
+
+       return addr;
+}
+
+/*
+ * Server operation.
+ */
+
 static void help(int argc, char *argv[])
 {
        printf("Usage: %s [parameters] [rundir]\n", argv[0]);
@@ -67,15 +127,70 @@ static void help(int argc, char *argv[])
               " [rundir]            Path to the working directory (default: .)\n");
 }
 
-static const char *set_addr(char *addr, int *port)
+static struct worker_ctx *init_worker(uv_loop_t *loop, struct engine *engine, mm_ctx_t *pool)
 {
-       char *p = strchr(addr, '#');
-       if (p) {
-               *port = atoi(p + 1);
-               *p = '\0';
+       /* Load bindings */
+       engine_lualib(engine, "modules", lib_modules);
+       engine_lualib(engine, "net",     lib_net);
+       engine_lualib(engine, "cache",   lib_cache);
+       engine_lualib(engine, "event",   lib_event);
+       engine_lualib(engine, "kres",    lib_kres);
+
+       /* Create main worker. */
+       struct worker_ctx *worker = mm_alloc(pool, sizeof(*worker));
+       if(!worker) {
+               return NULL;
        }
+       memset(worker, 0, sizeof(*worker));
+       worker->engine = engine,
+       worker->loop = loop;
+       loop->data = worker;
+       worker_reserve(worker, MP_FREELIST_SIZE);
+       return worker;
+}
 
-       return addr;
+static int run_worker(uv_loop_t *loop, struct engine *engine, int forks)
+{
+       /* Fork subprocesses if requested */
+       while (--forks > 0) {
+               int pid = fork();
+               if (pid < 0) {
+                       perror("[system] fork");
+                       return EXIT_FAILURE;
+               }
+               /* Forked process */
+               if (pid == 0) {
+                       break;
+               }
+       }
+
+       /* Control sockets or TTY */
+       auto_free char *sock_file = NULL;
+       uv_pipe_t pipe;
+       uv_pipe_init(loop, &pipe, 0);
+       pipe.data = engine;
+       if (g_interactive) {
+               printf("[system] interactive mode\n> ");
+               fflush(stdout);
+               uv_pipe_open(&pipe, 0);
+               uv_read_start((uv_stream_t*) &pipe, tty_alloc, tty_read);
+       } else {
+               (void) mkdir("tty", S_IRWXU|S_IRWXG);
+               sock_file = afmt("tty/%ld", getpid());
+               if (sock_file) {
+                       uv_pipe_bind(&pipe, sock_file);
+                       uv_listen((uv_stream_t *) &pipe, 16, tty_accept);
+               }
+       }
+       /* Run event loop */
+       int ret = engine_start(engine);
+       if (ret == 0) {
+               ret = uv_run(loop, UV_RUN_DEFAULT);
+       }
+       if (sock_file) {
+               unlink(sock_file);
+       }
+       return ret;
 }
 
 int main(int argc, char **argv)
@@ -83,7 +198,6 @@ int main(int argc, char **argv)
        const char *addr = NULL;
        int port = 53;
        int forks = 1;
-       int headless = 0;
 
        /* Long options. */
        int c = 0, li = 0, ret = 0;
@@ -101,7 +215,7 @@ int main(int argc, char **argv)
                        addr = set_addr(optarg, &port);
                        break;
                case 'f':
-                       headless = 1;
+                       g_interactive = 0;
                        forks = atoi(optarg);
                        if (forks == 0) {
                                fprintf(stderr, "[system] error '-f' requires number, not '%s'\n", optarg);
@@ -140,7 +254,6 @@ int main(int argc, char **argv)
        uv_signal_t sigint;
        uv_signal_init(loop, &sigint);
        uv_signal_start(&sigint, signal_handler, SIGINT);
-
        /* Create a server engine. */
        mm_ctx_t pool = {
                .ctx = mp_new (4096),
@@ -152,27 +265,13 @@ int main(int argc, char **argv)
                fprintf(stderr, "[system] failed to initialize engine: %s\n", kr_strerror(ret));
                return EXIT_FAILURE;
        }
-
-       /* Load bindings */
-       engine_lualib(&engine, "modules", lib_modules);
-       engine_lualib(&engine, "net",     lib_net);
-       engine_lualib(&engine, "cache",   lib_cache);
-       engine_lualib(&engine, "event",   lib_event);
-       engine_lualib(&engine, "kres",    lib_kres);
-
-       /* Create main worker. */
-       struct worker_ctx *worker = mm_alloc(&pool, sizeof(*worker));
-       if(!worker) {
+       /* Create worker */
+       struct worker_ctx *worker = init_worker(loop, &engine, &pool);
+       if (!worker) {
                fprintf(stderr, "[system] not enough memory\n");
                return EXIT_FAILURE;
        }
-       memset(worker, 0, sizeof(*worker));
-       worker->engine = &engine,
-       worker->loop = loop;
-       loop->data = worker;
-       worker_reserve(worker, MP_FREELIST_SIZE);
-
-       /* Bind to sockets. */
+       /* Bind to sockets and run */
        if (addr != NULL) {
                ret = network_listen(&engine.net, addr, (uint16_t)port, NET_UDP|NET_TCP);
                if (ret != 0) {
@@ -180,46 +279,14 @@ int main(int argc, char **argv)
                        ret = EXIT_FAILURE;
                }
        }
-
-       /* Fork subprocesses if requested */
-       while (--forks > 0) {
-               int pid = fork();
-               if (pid < 0) {
-                       perror("[system] fork");
-                       exit(1);
-               }
-               /* Forked process */
-               if (pid == 0) {
-                       break;
-               }
-               printf("[system] forked PID %d\n", pid);
-       }
-
        if (ret == 0) {
-               /* Interactive stdin */
-               uv_pipe_t pipe;
-               if (!headless) {
-                       printf("[system] started in interactive mode, type 'help()'\n");
-                       uv_pipe_init(loop, &pipe, 0);
-                       uv_pipe_open(&pipe, 0);
-                       pipe.data = &engine;
-                       tty_read(NULL, 0, NULL);
-                       uv_read_start((uv_stream_t*) &pipe, tty_alloc, tty_read);
-               }
-
-               /* Run the event loop. */
-               ret = engine_start(&engine);
-               if (ret == 0) {
-                       ret = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
-               }
+               ret = run_worker(loop, &engine, forks);
        }
-
        /* Cleanup. */
        fprintf(stderr, "\n[system] quitting\n");
        engine_deinit(&engine);
        worker_reclaim(worker);
        mp_delete(pool.ctx);
-
        if (ret != 0) {
                ret = EXIT_FAILURE;
        }