index 9589875300d468c7b9e6b7268fef5705a9580773..5888963ecf8ace7b7ee703d05a332a38bc0be353 100644 (file)
#include "tools/sysdb/command.h"
#include "tools/sysdb/input.h"
#include "tools/sysdb/command.h"
#include "tools/sysdb/input.h"
+#include "tools/sysdb/json.h"
#include "frontend/proto.h"
#include "utils/error.h"
#include "utils/proto.h"
#include "utils/strbuf.h"
#include "frontend/proto.h"
#include "utils/error.h"
#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 <errno.h>
#include <assert.h>
#include <ctype.h>
+#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.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
static void
-log_printer(sdb_strbuf_t *buf)
+ok_printer(sdb_input_t __attribute__((unused)) *input, sdb_strbuf_t *buf)
{
{
- uint32_t prio = sdb_proto_get_int(buf, 0);
+ const char *msg = sdb_strbuf_string(buf);
+ if (msg && *msg)
+ printf("%s\n", msg);
+ else
+ printf("OK\n");
+} /* ok_printer */
- if (prio == UINT32_MAX) {
+static void
+log_printer(sdb_input_t __attribute__((unused)) *input, sdb_strbuf_t *buf)
+{
+ uint32_t prio = 0;
+
+ if (sdb_proto_unmarshal_int32(SDB_STRBUF_STR(buf), &prio) < 0) {
sdb_log(SDB_LOG_WARNING, "Received a LOG message with invalid "
"or missing priority");
prio = (uint32_t)SDB_LOG_ERR;
sdb_log(SDB_LOG_WARNING, "Received a LOG message with invalid "
"or missing priority");
prio = (uint32_t)SDB_LOG_ERR;
} /* log_printer */
static void
} /* log_printer */
static void
-data_printer(sdb_strbuf_t *buf)
+data_printer(sdb_input_t *input, sdb_strbuf_t *buf)
{
size_t len = sdb_strbuf_len(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 */
if ((! len) || (len == sizeof(uint32_t))) {
/* empty command or empty reply */
return;
}
return;
}
- /* At the moment, we don't care about the result type. We simply print the
- * result without further parsing it. */
+ 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));
sdb_strbuf_skip(buf, 0, sizeof(uint32_t));
- printf("%s\n", sdb_strbuf_string(buf));
+ if (sdb_json_print(out, input, (int)type, buf))
+ sdb_log(SDB_LOG_ERR, "Failed to print result");
+ fprintf(out, "\n");
+
+ if (out != stdout)
+ fclose(out); /* will close pipefd[1] */
+ if (pager > 0)
+ waitpid(pager, NULL, 0);
} /* data_printer */
static struct {
int status;
} /* data_printer */
static struct {
int status;
- void (*printer)(sdb_strbuf_t *);
+ void (*printer)(sdb_input_t *, sdb_strbuf_t *);
} response_printers[] = {
} response_printers[] = {
+ { SDB_CONNECTION_OK, ok_printer },
{ SDB_CONNECTION_LOG, log_printer },
{ SDB_CONNECTION_DATA, data_printer },
};
{ SDB_CONNECTION_LOG, log_printer },
{ SDB_CONNECTION_DATA, data_printer },
};
*/
int
*/
int
-sdb_command_print_reply(sdb_client_t *client)
+sdb_command_print_reply(sdb_input_t *input)
{
sdb_strbuf_t *recv_buf;
const char *result;
{
sdb_strbuf_t *recv_buf;
const char *result;
if (! recv_buf)
return -1;
if (! recv_buf)
return -1;
- if (sdb_client_recv(client, &rcode, recv_buf) < 0)
+ if (sdb_client_recv(input->client, &rcode, recv_buf) < 0)
rcode = UINT32_MAX;
rcode = UINT32_MAX;
- if (sdb_client_eof(client)) {
+ if (sdb_client_eof(input->client)) {
sdb_strbuf_destroy(recv_buf);
return -1;
}
sdb_strbuf_destroy(recv_buf);
return -1;
}
for (i = 0; i < SDB_STATIC_ARRAY_LEN(response_printers); ++i) {
if (status == response_printers[i].status) {
for (i = 0; i < SDB_STATIC_ARRAY_LEN(response_printers); ++i) {
if (status == response_printers[i].status) {
- response_printers[i].printer(recv_buf);
+ response_printers[i].printer(input, recv_buf);
sdb_strbuf_destroy(recv_buf);
return status;
}
sdb_strbuf_destroy(recv_buf);
return status;
}
/* The server may send back log messages but will eventually reply to the
* query, which is either DATA or ERROR. */
while (42) {
/* The server may send back log messages but will eventually reply to the
* query, which is either DATA or ERROR. */
while (42) {
- int status = sdb_command_print_reply(input->client);
+ int status = sdb_command_print_reply(input);
if (status < 0) {
sdb_log(SDB_LOG_ERR, "Failed to read reply from server");
break;
}
if (status < 0) {
sdb_log(SDB_LOG_ERR, "Failed to read reply from server");
break;
}
- if ((status == SDB_CONNECTION_DATA)
+ if ((status == SDB_CONNECTION_OK)
+ || (status == SDB_CONNECTION_DATA)
|| (status == SDB_CONNECTION_ERROR))
break;
}
|| (status == SDB_CONNECTION_ERROR))
break;
}
return data;
} /* sdb_command_exec */
return data;
} /* sdb_command_exec */
+void
+sdb_command_print_server_version(sdb_input_t *input)
+{
+ sdb_strbuf_t *buf = sdb_strbuf_create(32);
+ uint32_t code = 0, version = 0;
+ const char *extra;
+
+ if ((sdb_client_rpc(input->client, SDB_CONNECTION_SERVER_VERSION,
+ 0, NULL, &code, buf) < 0) || (code != SDB_CONNECTION_OK))
+ return;
+ if (sdb_strbuf_len(buf) < sizeof(version))
+ return;
+
+ sdb_proto_unmarshal_int32(SDB_STRBUF_STR(buf), &version);
+ extra = sdb_strbuf_string(buf) + sizeof(version);
+ sdb_log(SDB_LOG_INFO, "SysDB server %d.%d.%d%s",
+ SDB_VERSION_DECODE((int)version), extra);
+ sdb_strbuf_destroy(buf);
+} /* sdb_command_print_server_version */
+
/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
/* vim: set tw=78 sw=4 ts=4 noexpandtab : */