From: Marek VavruĊĦa Date: Wed, 18 Mar 2015 12:36:34 +0000 (+0100) Subject: daemon: interactive terminal (proof-of-concept) X-Git-Tag: v1.0.0-beta1~299^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=fd54ebff791fc7a21476a28bfedb2d220dd95dce;p=thirdparty%2Fknot-resolver.git daemon: interactive terminal (proof-of-concept) --- diff --git a/daemon/cmd.c b/daemon/cmd.c new file mode 100644 index 000000000..6efaf7e5c --- /dev/null +++ b/daemon/cmd.c @@ -0,0 +1,127 @@ +/* Copyright (C) 2015 CZ.NIC, z.s.p.o. + + 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 . + */ + +#include + +#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 index 000000000..eee7f5c80 --- /dev/null +++ b/daemon/cmd.h @@ -0,0 +1,22 @@ +/* Copyright (C) 2015 CZ.NIC, z.s.p.o. + + 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 . + */ + +#pragma once + +#include +#include "daemon/worker.h" + +int cmd_exec(struct worker_ctx *worker, char *cmd); \ No newline at end of file diff --git a/daemon/kresolved.mk b/daemon/kresolved.mk index 6d532438b..7e9347d7f 100644 --- a/daemon/kresolved.mk +++ b/daemon/kresolved.mk @@ -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 diff --git a/daemon/main.c b/daemon/main.c index 08cb4af16..24481f68c 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -23,9 +23,33 @@ #include #include +#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); }