]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
daemon: interactive terminal (proof-of-concept)
authorMarek Vavruša <marek.vavrusa@nic.cz>
Wed, 18 Mar 2015 12:36:34 +0000 (13:36 +0100)
committerMarek Vavruša <marek.vavrusa@nic.cz>
Wed, 18 Mar 2015 12:36:34 +0000 (13:36 +0100)
daemon/cmd.c [new file with mode: 0644]
daemon/cmd.h [new file with mode: 0644]
daemon/kresolved.mk
daemon/main.c

diff --git a/daemon/cmd.c b/daemon/cmd.c
new file mode 100644 (file)
index 0000000..6efaf7e
--- /dev/null
@@ -0,0 +1,127 @@
+/*  Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libknot/internal/mempool.h>
+
+#include "daemon/cmd.h"
+#include "lib/defines.h"
+
+struct cmd {
+       const char *name;
+       int (*cb)(struct worker_ctx *, char *);
+};
+
+static int help(struct worker_ctx *worker, char *args)
+{
+       printf("help:\n    show this help\n");
+       printf("context:\n    show context information\n");
+       printf("load:\n    load module\n");
+       printf("unload:\n    unload module\n");
+
+       struct kr_context *ctx = &worker->resolve;
+       for (unsigned i = 0; i < ctx->mod_loaded; ++i) {
+               struct kr_module *mod = &ctx->modules[i];
+               for (struct kr_prop *p = mod->props; p && p->name; ++p) {
+                       printf("%s.%s:\n    %s\n", mod->name, p->name, p->info);
+               }
+       }
+
+       return kr_ok();
+}
+
+static int context(struct worker_ctx *worker, char *args)
+{
+       struct kr_context *ctx = &worker->resolve;
+
+       /* Modules */
+       printf("modules:\n");
+       for (unsigned i = 0; i < ctx->mod_loaded; ++i) {
+               struct kr_module *mod = &ctx->modules[i];
+               printf("    %s\n", mod->name);
+       }
+       /* Options */
+       printf("options: 0x%x\n", ctx->options);
+
+       return kr_ok();
+}
+
+static int mod_load(struct worker_ctx *worker, char *args)
+{
+       struct kr_context *ctx = &worker->resolve;
+       char *saveptr = NULL;
+       char *prop_name = strtok_r(args, " \t\n\r", &saveptr);
+       return kr_context_register(ctx, prop_name);
+}
+
+static int mod_unload(struct worker_ctx *worker, char *args)
+{
+       return kr_error(ENOTSUP);
+}
+
+static int cmd_exec_prop(struct worker_ctx *worker, char *name, char *prop, char *args)
+{
+       struct kr_context *ctx = &worker->resolve;
+
+       for (unsigned i = 0; i < ctx->mod_loaded; ++i) {
+               struct kr_module *mod = &ctx->modules[i];
+               if (strncmp(mod->name, name, strlen(mod->name)) != 0) {
+                       continue;
+               }
+               for (struct kr_prop *p = mod->props; p && p->name; ++p) {
+                       if (strncmp(p->name, prop, strlen(p->name)) == 0) {
+                               auto_free char *res = p->cb(ctx, mod, args);
+                               printf("%s\n", res);
+                               return kr_ok();
+                       }
+               }
+       }
+
+       return kr_error(ENOENT);
+}
+
+int cmd_exec(struct worker_ctx *worker, char *cmd)
+{
+       static struct cmd cmd_table[] = {
+               { "help", &help },
+               { "context", &context },
+               { "load", &mod_load },
+               { "unload", &mod_unload },
+               { NULL, NULL }
+       };
+
+       int ret = kr_error(ENOENT);
+       char *args = strchr(cmd, ' ');
+       if (args != NULL) {
+               *args = '\0';
+               args += 1;
+       }
+
+       /* Search builtin namespace. */
+       for (struct cmd *c = cmd_table; c->name; ++c) {
+               if (strncmp(cmd, c->name, strlen(c->name)) == 0) {
+                       return c->cb(worker, args);
+               }
+       }
+
+       /* Search module namespace. */
+       char *prop = strchr(cmd, '.');
+       if (prop != NULL) {
+               ret = cmd_exec_prop(worker, cmd, prop + 1, args);
+
+       }
+
+       return ret;
+}
\ No newline at end of file
diff --git a/daemon/cmd.h b/daemon/cmd.h
new file mode 100644 (file)
index 0000000..eee7f5c
--- /dev/null
@@ -0,0 +1,22 @@
+/*  Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <uv.h>
+#include "daemon/worker.h"
+
+int cmd_exec(struct worker_ctx *worker, char *cmd);
\ No newline at end of file
index 6d532438bc351561d61e9bcec231a41b2a44009f..7e9347d7f0f0ce186a7295de9f182a38b5a28824 100644 (file)
@@ -2,6 +2,7 @@ kresolved_SOURCES := \
        daemon/layer/query.c \
        daemon/udp.c         \
        daemon/tcp.c         \
+       daemon/cmd.c         \
        daemon/worker.c      \
        daemon/main.c
 
index 08cb4af16897ae17a38b33fac8058001cb1eae4a..24481f68c33ea07e8f16eb7acc356b7945bbc8b0 100644 (file)
 #include <libknot/internal/sockaddr.h>
 #include <libknot/errcode.h>
 
+#include "lib/defines.h"
 #include "lib/resolve.h"
 #include "daemon/udp.h"
 #include "daemon/tcp.h"
+#include "daemon/cmd.h"
+
+static void tty_read(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
+{
+       if (stream && buf && nread > 0) {
+               /* Trim endln */
+               char *cmd = buf->base;
+               cmd[nread - 1] = '\0';
+               /* Execute */
+               int ret = cmd_exec((struct worker_ctx *)stream->data, cmd);
+               if (ret != 0) {
+                       printf("ret: %s\n", kr_strerror(ret));
+               }
+       }
+
+       printf("> ");
+       fflush(stdout);
+}
+
+static void tty_alloc(uv_handle_t *handle, size_t suggested, uv_buf_t *buf) {
+    buf->len = suggested;
+    buf->base = malloc(suggested);
+}
 
 void signal_handler(uv_signal_t *handle, int signum)
 {
@@ -124,13 +148,24 @@ int main(int argc, char **argv)
                ret = tcp_bind((uv_handle_t *)&tcp_sock, &worker, (struct sockaddr *)&addr);
        }
 
+       /* Allocate TTY */
+       uv_pipe_t pipe;
+       uv_pipe_init(loop, &pipe, 0);
+       uv_pipe_open(&pipe, 0);
+       pipe.data = &worker;
+
        /* Check results */
        if (ret != KNOT_EOK) {
                fprintf(stderr, "[system] bind to '%s' %s\n", addr_str, knot_strerror(ret));
                ret = EXIT_FAILURE;
        } else {
+               /* Interactive stdin */
+               if (!feof(stdin)) {
+                       printf("[system] started in interactive mode, type 'help'\n");
+                       tty_read(NULL, 0, NULL);
+                       uv_read_start((uv_stream_t*) &pipe, tty_alloc, tty_read);
+               }
                /* Run the event loop. */
-               fflush(stdout);
                ret = uv_run(loop, UV_RUN_DEFAULT);
        }