index e08ad5b40da52d63ce9b16ebda9e0916193b6db0..08f639f1ac104c9a8c0527321bc92ba89070e4db 100644 (file)
--- a/src/tools/sysdb/input.c
+++ b/src/tools/sysdb/input.c
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+/*
+ * This module implements the core of the command line tool. It handles all
+ * input from the user and the remote server, interacting with the scanner and
+ * command handling as needed.
+ *
+ * The main loop is managed by the flex scanner which parses the user input.
+ * It will call into this module (using sdb_input_readline()) whenever it
+ * needs further input to continue parsing. Whenever it finds a full query
+ * (terminated by a semicolon), it will hand the query back to this module
+ * (using sdb_input_exec_query()) which will then execute it.
+ *
+ * Most of the process life-time will be spend waiting for input. User input
+ * and (asynchronous) server replies are handled at the same time.
+ */
+
#if HAVE_CONFIG_H
# include "config.h"
#endif /* HAVE_CONFIG_H */
#if HAVE_CONFIG_H
# include "config.h"
#endif /* HAVE_CONFIG_H */
#include "tools/sysdb/input.h"
#include "tools/sysdb/command.h"
#include "tools/sysdb/input.h"
#include "tools/sysdb/command.h"
+#include "utils/error.h"
#include "utils/strbuf.h"
#include "utils/strbuf.h"
+#include <errno.h>
+
+#include <sys/select.h>
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
#if HAVE_EDITLINE_READLINE_H
# include <editline/readline.h>
# if HAVE_EDITLINE_HISTORY_H
#if HAVE_EDITLINE_READLINE_H
# include <editline/readline.h>
# if HAVE_EDITLINE_HISTORY_H
# endif
#endif /* READLINEs */
# endif
#endif /* READLINEs */
+extern int yylex(void);
+
/*
* public variables
*/
sdb_input_t *sysdb_input = NULL;
/*
* public variables
*/
sdb_input_t *sysdb_input = NULL;
+/*
+ * private variables
+ */
+
+static struct termios orig_term_attrs;
+static bool have_orig_term_attrs;
+
/*
* private helper functions
*/
/*
* private helper functions
*/
-static size_t
+static void
+reset_term_attrs(void)
+{
+ tcsetattr(STDIN_FILENO, TCSANOW, &orig_term_attrs);
+} /* reset_term_attrs */
+
+static void
+term_rawmode(void)
+{
+ struct termios attrs;
+
+ if (! have_orig_term_attrs) {
+ memset(&orig_term_attrs, 0, sizeof(orig_term_attrs));
+ tcgetattr(STDIN_FILENO, &orig_term_attrs);
+ atexit(reset_term_attrs);
+ have_orig_term_attrs = 1;
+ }
+
+ /* setup terminal to operate in non-canonical mode
+ * and single character input */
+ memset(&attrs, 0, sizeof(attrs));
+ tcgetattr(STDIN_FILENO, &attrs);
+ attrs.c_lflag &= (tcflag_t)(~ICANON);
+ attrs.c_cc[VMIN] = 1;
+ tcsetattr(STDIN_FILENO, TCSANOW, &attrs);
+} /* term_rawmode */
+
+static void
+handle_input(char *line)
+{
+ if (! line) {
+ sysdb_input->eof = 1;
+ return;
+ }
+
+ if (sdb_client_eof(sysdb_input->client))
+ sdb_input_reconnect();
+
+ sdb_strbuf_append(sysdb_input->input, "%s\n", line);
+ free(line);
+
+ if (sysdb_input->interactive)
+ rl_callback_handler_remove();
+} /* handle_input */
+
+/* wait for a new line of data to be available */
+static ssize_t
input_readline(void)
{
input_readline(void)
{
+ size_t len;
+
+ fd_set fds;
+ int client_fd;
+
const char *prompt = "sysdb=> ";
const char *prompt = "sysdb=> ";
- char *line;
- size_t len;
+ len = sdb_strbuf_len(sysdb_input->input);
+
+ if (! sysdb_input->interactive) {
+ char *line = readline("");
+ handle_input(line);
+ return (ssize_t)(sdb_strbuf_len(sysdb_input->input) - len);
+ }
if (sysdb_input->query_len)
prompt = "sysdb-> ";
if (sysdb_input->query_len)
prompt = "sysdb-> ";
+ if (sdb_client_eof(sysdb_input->client))
+ prompt = "!-> ";
- line = readline(prompt);
+ rl_callback_handler_install(prompt, handle_input);
+ client_fd = sdb_client_sockfd(sysdb_input->client);
+ while ((sdb_strbuf_len(sysdb_input->input) == len)
+ && (! sysdb_input->eof)) {
+ bool connected = !sdb_client_eof(sysdb_input->client);
+ int max_fd, n;
- if (! line)
- return 0;
+ /* XXX: some versions of libedit don't properly reset the terminal in
+ * rl_callback_read_char(); detect those versions */
+ term_rawmode();
- len = strlen(line) + 1;
+ FD_ZERO(&fds);
+ FD_SET(STDIN_FILENO, &fds);
+ max_fd = STDIN_FILENO;
- sdb_strbuf_append(sysdb_input->input, line);
- sdb_strbuf_append(sysdb_input->input, "\n");
- free(line);
- return len;
+ if (connected) {
+ FD_SET(client_fd, &fds);
+ if (client_fd > max_fd)
+ max_fd = client_fd;
+ }
+
+ n = select(max_fd + 1, &fds, NULL, NULL, /* timeout = */ NULL);
+ if (n < 0)
+ return (ssize_t)n;
+ else if (! n)
+ continue;
+
+ /* handle user input with highest priority */
+ if (FD_ISSET(STDIN_FILENO, &fds)) {
+ rl_callback_read_char();
+ continue;
+ }
+
+ if ((! connected) || (! FD_ISSET(client_fd, &fds)))
+ continue;
+
+ /* some response / error message from the server pending */
+ /* XXX: clear current line */
+ printf("\n");
+ sdb_command_print_reply(sysdb_input->client);
+
+ if (sdb_client_eof(sysdb_input->client)) {
+ rl_callback_handler_remove();
+ /* XXX */
+ printf("Remote side closed the connection.\n");
+ /* return EOF -> restart scanner */
+ return 0;
+ }
+ else
+ rl_forced_update_display();
+ }
+
+ /* new data available */
+ return (ssize_t)(sdb_strbuf_len(sysdb_input->input) - len);
} /* input_readline */
/*
} /* input_readline */
/*
{
/* register input handler */
sysdb_input = input;
{
/* register input handler */
sysdb_input = input;
+
+ input->interactive = isatty(STDIN_FILENO) != 0;
+ errno = 0;
+ if (input->interactive)
+ term_rawmode();
return 0;
} /* sdb_input_init */
return 0;
} /* sdb_input_init */
+int
+sdb_input_mainloop(void)
+{
+ while (! sysdb_input->eof)
+ yylex();
+ return 0;
+} /* sdb_input_mainloop */
+
ssize_t
ssize_t
-sdb_input_readline(char *buf, int *n_chars, size_t max_chars)
+sdb_input_readline(char *buf, size_t *n_chars, size_t max_chars)
{
const char *data;
size_t len;
{
const char *data;
size_t len;
len = sdb_strbuf_len(sysdb_input->input) - sysdb_input->tokenizer_pos;
if (! len) {
len = sdb_strbuf_len(sysdb_input->input) - sysdb_input->tokenizer_pos;
if (! len) {
- size_t n = input_readline();
- if (! n) {
+ ssize_t n = input_readline();
+ if (n <= 0) {
*n_chars = 0; /* YY_NULL */
*n_chars = 0; /* YY_NULL */
- return 0;
+ return n;
}
}
- len += n;
+ len += (size_t)n;
}
len = (len < max_chars) ? len : max_chars;
}
len = (len < max_chars) ? len : max_chars;
} /* sdb_input_readline */
int
} /* sdb_input_readline */
int
-sdb_input_exec_query()
+sdb_input_exec_query(void)
{
char *query = sdb_command_exec(sysdb_input);
{
char *query = sdb_command_exec(sysdb_input);
return 0;
} /* sdb_input_exec_query */
return 0;
} /* sdb_input_exec_query */
+int
+sdb_input_reconnect(void)
+{
+ sdb_client_close(sysdb_input->client);
+ if (sdb_client_connect(sysdb_input->client, sysdb_input->user)) {
+ printf("Failed to reconnect to SysDBd.\n");
+ return -1;
+ }
+ printf("Successfully reconnected to SysDBd.\n");
+ return 0;
+} /* sdb_input_reconnect */
+
/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
/* vim: set tw=78 sw=4 ts=4 noexpandtab : */