summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 0a3dd5b)
raw | patch | inline | side by side (parent: 0a3dd5b)
author | Sebastian Harl <sh@tokkee.org> | |
Sun, 18 Dec 2016 15:36:38 +0000 (16:36 +0100) | ||
committer | Sebastian Harl <sh@tokkee.org> | |
Sun, 18 Dec 2016 15:36:38 +0000 (16:36 +0100) |
For now, hard code the pager to 'less -FRX'.
src/tools/sysdb/command.c | patch | blob | history | |
src/tools/sysdb/json.c | patch | blob | history | |
src/tools/sysdb/json.h | patch | blob | history | |
src/tools/sysdb/main.c | patch | blob | history |
index 61960be83505ca167e4045f6a225854b9aeb0946..5888963ecf8ace7b7ee703d05a332a38bc0be353 100644 (file)
#include "utils/proto.h"
#include "utils/strbuf.h"
+#include <sys/types.h>
+#include <sys/wait.h>
+
#include <errno.h>
#include <assert.h>
#include <ctype.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
+
+static pid_t
+exec_pager(int in)
+{
+ pid_t pid;
+ long fd;
+
+ sigset_t sigs;
+
+ pid = fork();
+ if (pid) /* parent or error */
+ return pid;
+
+ sigemptyset(&sigs);
+ sigprocmask(SIG_SETMASK, &sigs, NULL);
+
+ for (fd = 3; fd <= sysconf(_SC_OPEN_MAX); fd++)
+ if (fd != in)
+ close((int)fd);
+
+ if (dup2(in, STDIN_FILENO) >= 0) {
+ /* TODO: make configurable */
+ char *argv[] = { "less", "-FRX" };
+
+ close(in);
+ in = STDIN_FILENO;
+
+ if (execvp(argv[0], argv)) {
+ char cmdbuf[1024], errbuf[1024];
+ sdb_data_format(&(sdb_data_t){
+ SDB_TYPE_STRING | SDB_TYPE_ARRAY,
+ { .array = { SDB_STATIC_ARRAY_LEN(argv), argv } },
+ }, cmdbuf, sizeof(cmdbuf), SDB_UNQUOTED);
+ sdb_log(SDB_LOG_WARNING, "Failed to execute pager %s: %s",
+ cmdbuf, sdb_strerror(errno, errbuf, sizeof(errbuf)));
+ }
+ }
+
+ /* else: something failed, simply print all input */
+ while (42) {
+ char buf[1024 + 1];
+ ssize_t n;
+
+ n = read(in, buf, sizeof(buf) - 1);
+ if (!n) /* EOF */
+ break;
+
+ if (n > 0) {
+ buf[n] = '\0';
+ printf("%s", buf);
+ continue;
+ }
+
+ if ((errno == EAGAIN) || (errno == EWOULDBLOCK)
+ || (errno == EINTR))
+ continue;
+
+ sdb_log(SDB_LOG_ERR, "Failed to read query result: %s",
+ sdb_strerror(errno, buf, sizeof(buf)));
+ exit(1);
+ }
+ exit(0);
+} /* exec_pager */
static void
ok_printer(sdb_input_t __attribute__((unused)) *input, sdb_strbuf_t *buf)
} /* log_printer */
static void
-data_printer(sdb_input_t __attribute__((unused)) *input, sdb_strbuf_t *buf)
+data_printer(sdb_input_t *input, sdb_strbuf_t *buf)
{
size_t len = sdb_strbuf_len(buf);
uint32_t type = 0;
+ int pipefd[2] = { -1, -1 };
+ FILE *out = stdout;
+ pid_t pager = -1;
+
if ((! len) || (len == sizeof(uint32_t))) {
/* empty command or empty reply */
return;
return;
}
+ if (input->interactive) {
+ if (pipe(pipefd)) {
+ char errbuf[2014];
+ sdb_log(SDB_LOG_WARNING, "Failed to open pipe: %s",
+ sdb_strerror(errno, errbuf, sizeof(errbuf)));
+ }
+ else {
+ out = fdopen(pipefd[1], "w");
+ pager = exec_pager(pipefd[0]);
+ if (pager < 0) {
+ out = stdout;
+ close(pipefd[0]);
+ close(pipefd[1]);
+ }
+ else
+ close(pipefd[0]);
+ }
+ }
+
sdb_proto_unmarshal_int32(SDB_STRBUF_STR(buf), &type);
sdb_strbuf_skip(buf, 0, sizeof(uint32_t));
- if (sdb_json_print(input, (int)type, buf))
+ if (sdb_json_print(out, input, (int)type, buf))
sdb_log(SDB_LOG_ERR, "Failed to print result");
- printf("\n");
+ fprintf(out, "\n");
+
+ if (out != stdout)
+ fclose(out); /* will close pipefd[1] */
+ if (pager > 0)
+ waitpid(pager, NULL, 0);
} /* data_printer */
static struct {
diff --git a/src/tools/sysdb/json.c b/src/tools/sysdb/json.c
index 1bd8080970b831fe5a00c1dd586e887ee616e8e5..8e9b1e79839b709d96497e83036ea74fda16cb5d 100644 (file)
--- a/src/tools/sysdb/json.c
+++ b/src/tools/sysdb/json.c
*/
typedef struct {
+ FILE *out;
+
/* The context describes the state of the formatter along with the
* respective parent contexts. */
int context[8];
bool have_output;
} formatter_t;
#define F(obj) ((formatter_t *)(obj))
-#define F_INIT { { 0 }, { -1, -1, -1, -1, -1, -1, -1, -1 }, 0, 0, false }
+#define F_INIT(out) { (out), { 0 }, { -1, -1, -1, -1, -1, -1, -1, -1 }, 0, 0, false }
static int
push(formatter_t *f, int type)
char buf[l + 1];
strncpy(buf, s, l);
buf[l] = '\0';
- printf("%s", buf);
+ fprintf(f->out, "%s", buf);
}
else
- printf("%s", s);
+ fprintf(f->out, "%s", s);
f->have_output = true;
} /* print */
*/
int
-sdb_json_print(sdb_input_t *input, int type, sdb_strbuf_t *buf)
+sdb_json_print(FILE *out, sdb_input_t *input, int type, sdb_strbuf_t *buf)
{
#ifdef HAVE_LIBYAJL
const unsigned char *json;
yajl_handle h;
yajl_status status;
- formatter_t f = F_INIT;
+ formatter_t f = F_INIT(out);
int ret = 0;
if (!input->interactive) {
/* no formatting */
- printf("%s\n", sdb_strbuf_string(buf));
+ fprintf(out, "%s\n", sdb_strbuf_string(buf));
return 0;
}
#else /* HAVE_LIBYAJL */
(void)input;
(void)type;
- printf("%s\n", sdb_strbuf_string(buf));
+ fprintf(out, "%s\n", sdb_strbuf_string(buf));
return 0;
#endif /* HAVE_LIBYAJL */
} /* sdb_json_print */
diff --git a/src/tools/sysdb/json.h b/src/tools/sysdb/json.h
index b276eff82b62b64732a42258b7d98bfaa66eda66..ef7210dab543ba2a5dcbd1419fb51549c39d456b 100644 (file)
--- a/src/tools/sysdb/json.h
+++ b/src/tools/sysdb/json.h
#include "utils/strbuf.h"
+#include <stdio.h>
+
#ifndef SYSDB_JSON_H
#define SYSDB_JSON_H 1
* specified buffer. The output is printed to the standard output channel.
*/
int
-sdb_json_print(sdb_input_t *input, int type, sdb_strbuf_t *buf);
+sdb_json_print(FILE *out, sdb_input_t *input, int type, sdb_strbuf_t *buf);
#endif /* SYSDB_JSON_H */
diff --git a/src/tools/sysdb/main.c b/src/tools/sysdb/main.c
index b45ef878873b1b0dc943dbe38efa0555d6d042d2..1f3975a7949b52491d4b0b2fe37660260e556649 100644 (file)
--- a/src/tools/sysdb/main.c
+++ b/src/tools/sysdb/main.c
#include <sys/stat.h>
#include <fcntl.h>
-
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-
#include <unistd.h>
#include <sys/types.h>
}
}
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGCHLD, SIG_IGN);
+
sdb_input_mainloop();
sdb_client_shutdown(input.client, SHUT_WR);