Skip to content
Snippets Groups Projects
Commit fd54ebff authored by Marek Vavruša's avatar Marek Vavruša
Browse files

daemon: interactive terminal (proof-of-concept)

parent 486c2a2c
No related branches found
No related tags found
No related merge requests found
/* 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
/* 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
......@@ -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
......
......@@ -23,9 +23,33 @@
#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);
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment