diff options
Diffstat (limited to 'client/client.c')
-rw-r--r-- | client/client.c | 333 |
1 files changed, 100 insertions, 233 deletions
diff --git a/client/client.c b/client/client.c index 8711cf0a..a9d0096d 100644 --- a/client/client.c +++ b/client/client.c @@ -2,22 +2,32 @@ * BIRD Client * * (c) 1999--2004 Martin Mares <mj@ucw.cz> + * (c) 2013 Tomas Hlavacek <tmshlvck@gmail.com> * * Can be freely distributed and used under the terms of the GNU GPL. */ +/** + * DOC: BIRD client + * + * There are two variants of BIRD client: regular and light. regular + * variant depends on readline and ncurses libraries, while light + * variant uses just libc. Most of the code and the main() is common + * for both variants (in client.c file) and just a few functions are + * different (in birdc.c for regular and birdcl.c for light). Two + * binaries are generated by linking common object files like client.o + * (which is compiled from client.c just once) with either birdc.o or + * birdcl.o for each variant. + */ + #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> -#include <termios.h> #include <errno.h> #include <sys/socket.h> #include <sys/un.h> #include <sys/types.h> -#include <readline/readline.h> -#include <readline/history.h> -#include <curses.h> #include "nest/bird.h" #include "lib/resource.h" @@ -25,33 +35,31 @@ #include "client/client.h" #include "sysdep/unix/unix.h" +#define SERVER_READ_BUF_LEN 4096 + static char *opt_list = "s:vr"; -static int verbose; +static int verbose, restricted, once; static char *init_cmd; -static int once; static char *server_path = PATH_CONTROL_SOCKET; static int server_fd; -static byte server_read_buf[4096]; +static byte server_read_buf[SERVER_READ_BUF_LEN]; static byte *server_read_pos = server_read_buf; -#define STATE_PROMPT 0 -#define STATE_CMD_SERVER 1 -#define STATE_CMD_USER 2 +int init = 1; /* During intial sequence */ +int busy = 1; /* Executing BIRD command */ +int interactive; /* Whether stdin is terminal */ -static int input_initialized; -static int input_hidden_end; -static int cstate = STATE_CMD_SERVER; -static int nstate = STATE_CMD_SERVER; +static int num_lines, skip_input; +int term_lns, term_cls; -static int num_lines, skip_input, interactive; /*** Parsing of arguments ***/ static void -usage(void) +usage(char *name) { - fprintf(stderr, "Usage: birdc [-s <control-socket>] [-v] [-r]\n"); + fprintf(stderr, "Usage: %s [-s <control-socket>] [-v] [-r]\n", name); exit(1); } @@ -70,10 +78,10 @@ parse_args(int argc, char **argv) verbose++; break; case 'r': - init_cmd = "restrict"; + restricted = 1; break; default: - usage(); + usage(argv[0]); } /* If some arguments are not options, we take it as commands */ @@ -83,9 +91,6 @@ parse_args(int argc, char **argv) int i; int len = 0; - if (init_cmd) - usage(); - for (i = optind; i < argc; i++) len += strlen(argv[i]) + 1; @@ -99,17 +104,14 @@ parse_args(int argc, char **argv) tmp[-1] = 0; once = 1; + interactive = 0; } } -/*** Input ***/ -static void server_send(char *); +/*** Input ***/ -/* HACK: libreadline internals we need to access */ -extern int _rl_vis_botlin; -extern void _rl_move_vert(int); -extern Function *rl_last_func; +static void server_send(char *cmd); static int handle_internal_command(char *cmd) @@ -127,181 +129,37 @@ handle_internal_command(char *cmd) return 0; } -void +static void submit_server_command(char *cmd) { - server_send(cmd); - nstate = STATE_CMD_SERVER; + busy = 1; num_lines = 2; -} - -static void -add_history_dedup(char *cmd) -{ - /* Add history line if it differs from the last one */ - HIST_ENTRY *he = history_get(history_length); - if (!he || strcmp(he->line, cmd)) - add_history(cmd); -} - -static void -got_line(char *cmd_buffer) -{ - char *cmd; - - if (!cmd_buffer) - { - cleanup(); - exit(0); - } - if (cmd_buffer[0]) - { - cmd = cmd_expand(cmd_buffer); - if (cmd) - { - add_history_dedup(cmd); - - if (!handle_internal_command(cmd)) - submit_server_command(cmd); - - free(cmd); - } - else - add_history_dedup(cmd_buffer); - } - free(cmd_buffer); -} - -void -input_start_list(void) /* Leave the currently edited line and make space for listing */ -{ - _rl_move_vert(_rl_vis_botlin); -#ifdef HAVE_RL_CRLF - rl_crlf(); -#endif + server_send(cmd); } void -input_stop_list(void) /* Reprint the currently edited line after listing */ -{ - rl_on_new_line(); - rl_redisplay(); -} - -static int -input_complete(int arg UNUSED, int key UNUSED) +submit_command(char *cmd_raw) { - static int complete_flag; - char buf[256]; + char *cmd = cmd_expand(cmd_raw); - if (rl_last_func != input_complete) - complete_flag = 0; - switch (cmd_complete(rl_line_buffer, rl_point, buf, complete_flag)) - { - case 0: - complete_flag = 1; - break; - case 1: - rl_insert_text(buf); - break; - default: - complete_flag = 1; -#ifdef HAVE_RL_DING - rl_ding(); -#endif - } - return 0; -} - -static int -input_help(int arg, int key UNUSED) -{ - int i, in_string, in_bracket; - - if (arg != 1) - return rl_insert(arg, '?'); - - in_string = in_bracket = 0; - for (i = 0; i < rl_point; i++) - { - - if (rl_line_buffer[i] == '"') - in_string = ! in_string; - else if (! in_string) - { - if (rl_line_buffer[i] == '[') - in_bracket++; - else if (rl_line_buffer[i] == ']') - in_bracket--; - } - } + if (!cmd) + return; - /* `?' inside string or path -> insert */ - if (in_string || in_bracket) - return rl_insert(1, '?'); - - rl_begin_undo_group(); /* HACK: We want to display `?' at point position */ - rl_insert_text("?"); - rl_redisplay(); - rl_end_undo_group(); - input_start_list(); - cmd_help(rl_line_buffer, rl_point); - rl_undo_command(1, 0); - input_stop_list(); - return 0; -} + if (!handle_internal_command(cmd)) + submit_server_command(cmd); -static void -input_init(void) -{ - rl_readline_name = "birdc"; - rl_add_defun("bird-complete", input_complete, '\t'); - rl_add_defun("bird-help", input_help, '?'); - rl_callback_handler_install("bird> ", got_line); - input_initialized = 1; -// readline library does strange things when stdin is nonblocking. -// if (fcntl(0, F_SETFL, O_NONBLOCK) < 0) -// die("fcntl: %m"); -} - -static void -input_hide(void) -{ - input_hidden_end = rl_end; - rl_end = 0; - rl_expand_prompt(""); - rl_redisplay(); + free(cmd); } static void -input_reveal(void) -{ - /* need this, otherwise some lib seems to eat pending output when - the prompt is displayed */ - fflush(stdout); - tcdrain(fileno(stdout)); - - rl_end = input_hidden_end; - rl_expand_prompt("bird> "); - rl_forced_update_display(); -} - -void -cleanup(void) +init_commands(void) { - if (input_initialized) + if (restricted) { - input_initialized = 0; - input_hide(); - rl_callback_handler_remove(); + submit_server_command("restrict"); + restricted = 0; + return; } -} - -void -update_state(void) -{ - if (nstate == cstate) - return; if (init_cmd) { @@ -312,40 +170,39 @@ update_state(void) return; } - if (!init_cmd && once) + if (once) { /* Initial command is finished and we want to exit */ cleanup(); exit(0); } - if (nstate == STATE_PROMPT) - { - if (input_initialized) - input_reveal(); - else - input_init(); - } + input_init(); - if (nstate != STATE_PROMPT) - input_hide(); + term_lns = (term_lns > 0) ? term_lns : 25; + term_cls = (term_cls > 0) ? term_cls : 80; - cstate = nstate; + init = 0; } + +/*** Output ***/ + void more(void) { + more_begin(); printf("--More--\015"); fflush(stdout); redo: switch (getchar()) { - case 32: + case ' ': num_lines = 2; break; - case 13: + case '\n': + case '\r': num_lines--; break; case 'q': @@ -357,6 +214,7 @@ more(void) printf(" \015"); fflush(stdout); + more_end(); } @@ -383,6 +241,7 @@ server_connect(void) die("fcntl: %m"); } + #define PRINTF(LEN, PARGS...) do { if (!skip_input) len = printf(PARGS); } while(0) static void @@ -391,36 +250,32 @@ server_got_reply(char *x) int code; int len = 0; - if (*x == '+') /* Async reply */ + if (*x == '+') /* Async reply */ PRINTF(len, ">>> %s\n", x+1); - else if (x[0] == ' ') /* Continuation */ + else if (x[0] == ' ') /* Continuation */ PRINTF(len, "%s%s\n", verbose ? " " : "", x+1); else if (strlen(x) > 4 && - sscanf(x, "%d", &code) == 1 && code >= 0 && code < 10000 && - (x[4] == ' ' || x[4] == '-')) + sscanf(x, "%d", &code) == 1 && code >= 0 && code < 10000 && + (x[4] == ' ' || x[4] == '-')) { if (code) - PRINTF(len, "%s\n", verbose ? x : x+5); + PRINTF(len, "%s\n", verbose ? x : x+5); + if (x[4] == ' ') { - nstate = STATE_PROMPT; - skip_input = 0; - return; + busy = 0; + skip_input = 0; + return; } } else PRINTF(len, "??? <%s>\n", x); - if (skip_input) - return; - - if (interactive && input_initialized && (len > 0)) + if (interactive && busy && !skip_input && !init && (len > 0)) { - int lns = LINES ? LINES : 25; - int cls = COLS ? COLS : 80; - num_lines += (len + cls - 1) / cls; /* Divide and round up */ - if ((num_lines >= lns) && (cstate == STATE_CMD_SERVER)) - more(); + num_lines += (len + term_cls - 1) / term_cls; /* Divide and round up */ + if (num_lines >= term_lns) + more(); } } @@ -465,19 +320,23 @@ server_read(void) } } -static fd_set select_fds; - static void select_loop(void) { int rv; while (1) { + if (init && !busy) + init_commands(); + + if (!init) + input_notify(!busy); + + fd_set select_fds; FD_ZERO(&select_fds); - if (cstate != STATE_CMD_USER) - FD_SET(server_fd, &select_fds); - if (cstate != STATE_CMD_SERVER) + FD_SET(server_fd, &select_fds); + if (!busy) FD_SET(0, &select_fds); rv = select(server_fd+1, &select_fds, NULL, NULL, NULL); @@ -489,16 +348,16 @@ select_loop(void) die("select: %m"); } - if (FD_ISSET(server_fd, &select_fds)) + if (FD_ISSET(0, &select_fds)) { - server_read(); - update_state(); + input_read(); + continue; } - if (FD_ISSET(0, &select_fds)) + if (FD_ISSET(server_fd, &select_fds)) { - rl_callback_read_char(); - update_state(); + server_read(); + continue; } } } @@ -556,14 +415,22 @@ server_send(char *cmd) } } + +/* XXXX + + get_term_size(); + + if (tcgetattr(0, &tty_save) != 0) + { + perror("tcgetattr error"); + return(EXIT_FAILURE); + } + } + + */ int main(int argc, char **argv) { -#ifdef HAVE_LIBDMALLOC - if (!getenv("DMALLOC_OPTIONS")) - dmalloc_debug(0x2f03d00); -#endif - interactive = isatty(0); parse_args(argc, argv); cmd_build_tree(); |