Skip to content
Snippets Groups Projects
Commit 6888ed25 authored by Eugine Blikh's avatar Eugine Blikh
Browse files

Add pager functionality

parent dc807ae7
No related branches found
No related tags found
No related merge requests found
......@@ -9,7 +9,7 @@ endif()
set (cli "tarantool")
set (cli_sources tc.c tc_opt.c tc_admin.c tc_query.c tc_print.c tc_buf.c
tc_cli.c tc_store.c tc_print_xlog.c tc_print_snap.c)
tc_cli.c tc_store.c tc_print_xlog.c tc_print_snap.c tc_pager.c)
set (cli_libs tntrpl tntnet tntsql tnt gopt ${READLINE_LIBRARIES})
include_directories(${READLINE_INCLUDE_DIR})
......
......@@ -43,6 +43,7 @@
#include "client/tarantool/tc_opt.h"
#include "client/tarantool/tc_admin.h"
#include "client/tarantool/tc.h"
#include "client/tarantool/tc_pager.h"
#include "client/tarantool/tc_cli.h"
#include "client/tarantool/tc_print.h"
#include "client/tarantool/tc_store.h"
......@@ -57,13 +58,15 @@ struct tc tc;
static void tc_init(void) {
memset(&tc, 0, sizeof(tc));
setlocale(LC_ALL, "");
tc.pager_fd = fileno(stdout);
tc.pager_pid = 0;
}
static void tc_free(void) {
if (tc.net) {
if (tc.net)
tnt_stream_free(tc.net);
}
tc_admin_close(&tc.admin);
tc_pager_kill();
}
void tc_error(char *fmt, ...) {
......
......@@ -33,6 +33,8 @@ struct tc {
struct tc_opt opt;
struct tc_admin admin;
struct tnt_stream *net;
int pager_fd;
pid_t pager_pid;
};
void tc_error(char *fmt, ...);
......
......@@ -57,6 +57,7 @@
#include "client/tarantool/tc_opt.h"
#include "client/tarantool/tc_admin.h"
#include "client/tarantool/tc.h"
#include "client/tarantool/tc_pager.h"
#include "client/tarantool/tc_query.h"
#include "client/tarantool/tc_cli.h"
#include "client/tarantool/tc_print.h"
......@@ -95,24 +96,26 @@ enum tc_keywords {
TC_LOADFILE,
TC_HELP,
TC_SETOPT,
TC_SETOPT_DELIM
TC_SETOPT_DELIM,
TC_SETOPT_PAGER
};
static struct tnt_lex_keyword tc_lex_keywords[] =
{
{ "e", 1, TC_EXIT },
{ "ex", 2, TC_EXIT },
{ "exi", 3, TC_EXIT },
{ "exit", 4, TC_EXIT },
{ "q", 1, TC_EXIT },
{ "qu", 2, TC_EXIT },
{ "qui", 3, TC_EXIT },
{ "quit", 4, TC_EXIT },
{ "help", 4, TC_HELP },
{ "loadfile", 8, TC_LOADFILE },
{ "setopt", 6, TC_SETOPT},
{ "delimiter", 9, TC_SETOPT_DELIM},
{ NULL, 0, TNT_TK_NONE }
{ "e", 1, TC_EXIT },
{ "ex", 2, TC_EXIT },
{ "exi", 3, TC_EXIT },
{ "exit", 4, TC_EXIT },
{ "q", 1, TC_EXIT },
{ "qu", 2, TC_EXIT },
{ "qui", 3, TC_EXIT },
{ "quit", 4, TC_EXIT },
{ "help", 4, TC_HELP },
{ "loadfile", 8, TC_LOADFILE },
{ "setopt", 6, TC_SETOPT },
{ "delimiter", 9, TC_SETOPT_DELIM },
{ "pager", 5, TC_SETOPT_PAGER },
{ NULL, 0, TNT_TK_NONE }
};
enum tc_cli_cmd_ret {
......@@ -130,7 +133,8 @@ tc_cmd_usage(void)
" - help\n"
" - loadfile 'path'\n"
" - setopt key=val\n"
" - (possible pairs: delim=\'str\')\n"
" - (possible pairs: delimiter = \'string\' )\n"
" - ( pager = \'command\' )\n"
"...\n";
tc_printf("%s", usage);
}
......@@ -138,8 +142,10 @@ tc_cmd_usage(void)
static int tc_cli_admin(char *cmd, int exit) {
char *e = NULL;
tc_query_admin_t cb = (exit) ? NULL : tc_query_admin_printer;
tc_pager_start();
if (tc_query_admin(cmd, cb, &e) == -1)
return tc_cli_error(e);
tc_pager_stop();
return 0;
}
......@@ -247,7 +253,29 @@ tc_cmd_try(char *cmd, size_t size, int *reconnect)
tc.opt.delim_len = strlen(tc.opt.delim);
} else {
tc_printf("---\n");
tc_printf(" - Expected delim='string'\n");
tc_printf(" - Expected delimiter='string'\n");
tc_printf("---\n");
}
break;
case TC_SETOPT_PAGER:
if (tnt_lex(&lex, &tk) == '=' &&
tnt_lex(&lex, &tk) == TNT_TK_STRING) {
if (!TNT_TK_S(tk)->size) {
tc.opt.pager = NULL;
goto done;
}
char * temp = (char *)malloc(TNT_TK_S(tk)->size);
if (temp == NULL)
tc_error(TC_ALLOCATION_ERROR,
TNT_TK_S(tk)->size);
strncpy(temp,
(const char *)TNT_TK_S(tk)->data,
TNT_TK_S(tk)->size + 1);
temp[TNT_TK_S(tk)->size] = '\0';
tc.opt.pager = temp;
} else {
tc_printf("---\n");
tc_printf(" - Expected pager='command'\n");
tc_printf("---\n");
}
break;
......@@ -277,12 +305,14 @@ static enum tc_cli_cmd_ret tc_cli_cmd(char *cmd, size_t size)
}
char *e = NULL;
if (tnt_query_is(cmd, size)) {
tc_pager_start();
if (tc_query(cmd, &e) == 0) {
if (tc_query_foreach(tc_query_printer, NULL, &e) == -1)
reconnect = tc_cli_error(e);
} else {
reconnect = tc_cli_error(e);
}
tc_pager_stop();
/* reconnect only for network errors */
if (reconnect && tnt_error(tc.net) != TNT_ESYSTEM)
reconnect = 0;
......
......@@ -196,6 +196,7 @@ enum tc_opt_mode tc_opt_init(struct tc_opt *opt, int argc, char **argv)
} else {
opt->mode = TC_OPT_INTERACTIVE;
}
opt->pager = NULL;
done:
gopt_free(tc_options);
return opt->mode;
......
......@@ -65,6 +65,7 @@ struct tc_opt {
int cmdc;
const char *delim;
size_t delim_len;
const char *pager;
};
void tc_opt_usage(void);
......
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "client/tarantool/tc_opt.h"
#include "client/tarantool/tc_admin.h"
#include "client/tarantool/tc.h"
#include "client/tarantool/tc_pager.h"
extern struct tc tc;
void tc_pager_start() {
if (tc.pager_pid != 0)
tc_pager_kill();
if (tc.opt.pager == NULL) {
tc.pager_fd = fileno(stdout);
return;
}
char cmd[] = {"/bin/bash"};
char args[] = {"-c"};
int pipefd[2];
const char *const argv[] = {cmd, args, tc.opt.pager, NULL};
if (pipe(pipefd) < 0)
tc_error("Failed to open pipe. Errno: %d", errno);
pid_t pid = fork();
if (pid < 0)
tc_error("Failed to fork. Errno: %d", errno);
if (pid == 0) {
close(pipefd[1]);
dup2(pipefd[0], STDIN_FILENO);
execve(argv[0], (char * const*)argv, NULL);
tc_error("Can't start pager! Errno: %d", errno);
}
close(pipefd[0]);
tc.pager_fd = pipefd[1];
tc.pager_pid = pid;
return;
}
void tc_pager_stop () {
if (tc.pager_pid != 0) {
close(tc.pager_fd);
tc.pager_fd = fileno(stdout);
waitpid(tc.pager_pid, NULL, 0);
tc.pager_pid = 0;
}
return;
}
void tc_pager_kill () {
if (tc.pager_pid != 0) {
kill(tc.pager_pid, SIGTERM);
tc_pager_stop();
}
}
#ifndef TC_PAGER_H_INCLUDED
#define TC_PAGER_H_INCLUDED
/*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
void tc_pager_start();
void tc_pager_stop();
void tc_pager_kill();
#endif /* TC_PAGER_H_INCLUDED */
......@@ -57,9 +57,15 @@ void tc_print_buf(char *buf, size_t size) {
}
void tc_printf(char *fmt, ...) {
char *str;
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
ssize_t str_len = vasprintf(&str, fmt, args);
if (str_len == -1)
tc_error("Error in vasprintf - %d", errno);
ssize_t stat = write(tc.pager_fd, str, str_len);
if (stat == -1)
tc_error("Can't write into pager - %d", errno);
va_end(args);
return;
}
......
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