Commit 96d29c0e authored by Petr Špaček's avatar Petr Špaček

Merge branch 'add_libedit_2' into 'master'

Added client (kresc) for interacting with daemon using command prompt with history and tab-completion

See merge request !177
parents b27acd9f 9027b76d
Pipeline #1568 passed with stages
in 1 minute and 40 seconds
...@@ -2,10 +2,11 @@ include config.mk ...@@ -2,10 +2,11 @@ include config.mk
include platform.mk include platform.mk
# Targets # Targets
all: info lib daemon modules all: info lib daemon client modules
install: lib-install daemon-install modules-install etc-install install: lib-install daemon-install client-install modules-install etc-install
check: all tests check: all tests
clean: contrib-clean lib-clean daemon-clean modules-clean tests-clean doc-clean bench-clean clean: contrib-clean lib-clean daemon-clean client-clean modules-clean \
tests-clean doc-clean bench-clean
doc: doc-html doc: doc-html
.PHONY: all install check clean doc info .PHONY: all install check clean doc info
...@@ -33,6 +34,7 @@ $(eval $(call find_lib,hiredis,,yes)) ...@@ -33,6 +34,7 @@ $(eval $(call find_lib,hiredis,,yes))
$(eval $(call find_lib,socket_wrapper)) $(eval $(call find_lib,socket_wrapper))
$(eval $(call find_lib,libsystemd,227)) $(eval $(call find_lib,libsystemd,227))
$(eval $(call find_lib,gnutls)) $(eval $(call find_lib,gnutls))
$(eval $(call find_lib,libedit))
# Lookup SONAME # Lookup SONAME
$(eval $(call find_soname,libknot)) $(eval $(call find_soname,libknot))
...@@ -109,6 +111,7 @@ info: ...@@ -109,6 +111,7 @@ info:
$(info [$(HAS_nettle)] nettle (modules/cookies)) $(info [$(HAS_nettle)] nettle (modules/cookies))
$(info [$(HAS_ltn12)] Lua socket ltn12 (trust anchor bootstrapping)) $(info [$(HAS_ltn12)] Lua socket ltn12 (trust anchor bootstrapping))
$(info [$(HAS_ssl.https)] Lua ssl.https (trust anchor bootstrapping)) $(info [$(HAS_ssl.https)] Lua ssl.https (trust anchor bootstrapping))
$(info [$(HAS_libedit)] libedit (client))
$(info ) $(info )
# Verify required dependencies are met, as listed above # Verify required dependencies are met, as listed above
......
...@@ -58,4 +58,16 @@ daemon/lua/kres-gen.lua: | $(libkres) ...@@ -58,4 +58,16 @@ daemon/lua/kres-gen.lua: | $(libkres)
daemon/lua/kres-gen.sh > $@ daemon/lua/kres-gen.sh > $@
.DELETE_ON_ERROR: daemon/lua/kres-gen.lua .DELETE_ON_ERROR: daemon/lua/kres-gen.lua
.PHONY: daemon daemon-install daemon-clean # Client
ifeq ($(HAS_libedit), yes)
kresc_SOURCES := daemon/kresc.c
kresc_CFLAGS += -fPIE $(libedit_CFLAGS)
kresc_LIBS += $(contrib_TARGET) $(libedit_LIBS)
kresc_DEPEND := $(libkres) $(contrib)
$(eval $(call make_sbin,kresc,daemon,yes))
client: $(kresc)
client-install: kresc-install
client-clean: kresc-clean
endif
.PHONY: daemon daemon-install daemon-clean client client-install client-clean
\ No newline at end of file
This diff is collapsed.
...@@ -114,14 +114,18 @@ setmetatable(cache, { ...@@ -114,14 +114,18 @@ setmetatable(cache, {
return t.count() return t.count()
end, end,
__index = function (t, k) __index = function (t, k)
return rawget(t, k) or (rawget(t, 'current_size') and t.get(k)) if type(k) == 'number' then
return rawget(t, k) or (rawget(t, 'current_size') and t.get(k))
end
end, end,
__newindex = function (t,k,v) __newindex = function (t,k,v)
-- Defaults -- Defaults
local storage = rawget(t, 'current_storage') if type(k) == number then
if not storage then storage = 'lmdb://' end local storage = rawget(t, 'current_storage')
local size = rawget(t, 'current_size') if not storage then storage = 'lmdb://' end
if not size then size = 10*MB end local size = rawget(t, 'current_size')
if not size then size = 10*MB end
end
-- Declarative interface for cache -- Declarative interface for cache
if k == 'size' then t.open(v, storage) if k == 'size' then t.open(v, storage)
elseif k == 'storage' then t.open(size, v) elseif k == 'storage' then t.open(size, v)
...@@ -160,7 +164,14 @@ end ...@@ -160,7 +164,14 @@ end
-- Make sandboxed environment -- Make sandboxed environment
local function make_sandbox(defined) local function make_sandbox(defined)
local __protected = { modules = true, cache = true, net = true, trust_anchors = true } local __protected = { modules = true, cache = true, net = true, trust_anchors = true }
return setmetatable({}, {
-- Compute and export the list of top-level names (hidden otherwise)
local nl = ""
for n in pairs(defined) do
nl = nl .. n .. "\n"
end
return setmetatable({ __orig_name_list = nl }, {
__index = defined, __index = defined,
__newindex = function (t, k, v) __newindex = function (t, k, v)
if __protected[k] then if __protected[k] then
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <arpa/inet.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <getopt.h> #include <getopt.h>
...@@ -58,47 +59,84 @@ static inline char *lua_strerror(int lua_err) { ...@@ -58,47 +59,84 @@ static inline char *lua_strerror(int lua_err) {
} }
} }
/* /**
* TTY control * 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 krsec;
* - stream->data represents a bool determining binary output mode (used by kresc);
* - binary output: uint32_t length in network order, followed by that many bytes.
*/ */
static void tty_read(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) 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 */ /* Set output streams */
FILE *out = stdout, *outerr = stderr; FILE *out = stdout;
uv_os_fd_t stream_fd = 0; uv_os_fd_t stream_fd = 0;
if (uv_fileno((uv_handle_t *)stream, &stream_fd)) { if (uv_fileno((uv_handle_t *)stream, &stream_fd)) {
uv_close((uv_handle_t *)stream, (uv_close_cb) free); uv_close((uv_handle_t *)stream, (uv_close_cb) free);
if (buf) { free(cmd);
free(buf->base);
}
return; return;
} }
if (stream_fd != STDIN_FILENO) { if (stream_fd != STDIN_FILENO) {
if (nread <= 0) { /* Close if disconnected */ if (nread < 0) { /* Close if disconnected */
uv_close((uv_handle_t *)stream, (uv_close_cb) free); uv_close((uv_handle_t *)stream, (uv_close_cb) free);
if (buf) { }
free(buf->base); if (nread <= 0) {
} free(cmd);
return; return;
} }
uv_os_fd_t dup_fd = dup(stream_fd); uv_os_fd_t dup_fd = dup(stream_fd);
if (dup_fd >= 0) { if (dup_fd >= 0) {
out = outerr = fdopen(dup_fd, "w"); out = fdopen(dup_fd, "w");
} }
} }
/* Execute */ /* Execute */
if (stream && buf && nread > 0) { if (stream && cmd && nread > 0) {
char *cmd = buf->base; /* Ensure cmd is 0-terminated */
if (cmd[nread - 1] == '\n') { if (cmd[nread - 1] == '\n') {
cmd[nread - 1] = '\0'; 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';
} }
struct engine *engine = stream->data;
/* Pseudo-command for switching to "binary output";
* beware: void* <-> bool */
bool is_binary = stream->data;
if (strcmp(cmd, "__binary") == 0) {
stream->data = (void *)(is_binary = true);
goto finish;
}
struct engine *engine = ((struct worker_ctx *)stream->loop->data)->engine;
lua_State *L = engine->L; lua_State *L = engine->L;
int ret = engine_cmd(L, cmd, false); int ret = engine_cmd(L, cmd, false);
const char *message = ""; const char *message = "";
if (lua_gettop(L) > 0) { if (lua_gettop(L) > 0) {
message = lua_tostring(L, -1); message = lua_tostring(L, -1);
} }
/* Simpler output in binary mode */
if (is_binary) {
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 */ /* Log to remote socket if connected */
const char *delim = g_quiet ? "" : "> "; const char *delim = g_quiet ? "" : "> ";
if (stream_fd != STDIN_FILENO) { if (stream_fd != STDIN_FILENO) {
...@@ -118,15 +156,13 @@ static void tty_read(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) ...@@ -118,15 +156,13 @@ static void tty_read(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
fprintf(fp_out, "%s", delim); fprintf(fp_out, "%s", delim);
lua_settop(L, 0); lua_settop(L, 0);
} }
finish:
fflush(out); fflush(out);
if (buf) { free(cmd);
free(buf->base);
}
/* Close if redirected */ /* Close if redirected */
if (stream_fd != STDIN_FILENO) { if (stream_fd != STDIN_FILENO) {
fclose(out); /* outerr is the same */ fclose(out);
} }
} }
static void tty_alloc(uv_handle_t *handle, size_t suggested, uv_buf_t *buf) { static void tty_alloc(uv_handle_t *handle, size_t suggested, uv_buf_t *buf) {
...@@ -143,8 +179,8 @@ static void tty_accept(uv_stream_t *master, int status) ...@@ -143,8 +179,8 @@ static void tty_accept(uv_stream_t *master, int status)
free(client); free(client);
return; return;
} }
client->data = master->data; client->data = 0;
uv_read_start((uv_stream_t *)client, tty_alloc, tty_read); uv_read_start((uv_stream_t *)client, tty_alloc, tty_process_input);
/* Write command line */ /* Write command line */
if (!g_quiet) { if (!g_quiet) {
uv_buf_t buf = { "> ", 2 }; uv_buf_t buf = { "> ", 2 };
...@@ -327,13 +363,13 @@ static int run_worker(uv_loop_t *loop, struct engine *engine, fd_array_t *ipc_se ...@@ -327,13 +363,13 @@ static int run_worker(uv_loop_t *loop, struct engine *engine, fd_array_t *ipc_se
auto_free char *sock_file = NULL; auto_free char *sock_file = NULL;
uv_pipe_t pipe; uv_pipe_t pipe;
uv_pipe_init(loop, &pipe, 0); uv_pipe_init(loop, &pipe, 0);
pipe.data = engine; pipe.data = 0;
if (g_interactive) { if (g_interactive) {
if (!g_quiet) if (!g_quiet)
printf("[system] interactive mode\n> "); printf("[system] interactive mode\n> ");
fflush(stdout); fflush(stdout);
uv_pipe_open(&pipe, 0); uv_pipe_open(&pipe, 0);
uv_read_start((uv_stream_t*) &pipe, tty_alloc, tty_read); uv_read_start((uv_stream_t*) &pipe, tty_alloc, tty_process_input);
} else { } else {
int pipe_ret = -1; int pipe_ret = -1;
if (control_fd != -1) { if (control_fd != -1) {
...@@ -372,7 +408,7 @@ static int run_worker(uv_loop_t *loop, struct engine *engine, fd_array_t *ipc_se ...@@ -372,7 +408,7 @@ static int run_worker(uv_loop_t *loop, struct engine *engine, fd_array_t *ipc_se
return kr_ok(); return kr_ok();
} }
void free_sd_socket_names(char **socket_names, int count) static void free_sd_socket_names(char **socket_names, int count)
{ {
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
free(socket_names[i]); free(socket_names[i]);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment