3 * Bacula Console interface to the Director
5 * Kern Sibbald, September MM
11 Copyright (C) 2000-2003 Kern Sibbald and John Walker
13 This library is free software; you can redistribute it and/or
14 modify it under the terms of the GNU Lesser General Public
15 License as published by the Free Software Foundation; either
16 version 2.1 of the License, or (at your option) any later version.
18 This library is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 Lesser General Public License for more details.
23 You should have received a copy of the GNU Lesser General Public
24 License along with this library; if not, write to the Free
25 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
31 #include "console_conf.h"
34 /* Imported functions */
35 int authenticate_director(JCR *jcr, DIRRES *director);
38 /* Exported variables */
43 extern int rl_catch_signals;
47 extern int input_line(char *line, int len);
48 extern void con_init(FILE *input);
49 extern void con_term();
50 extern void con_set_zed_keys();
51 extern void t_sendl(char *buf, int len);
52 extern void t_send(char *buf);
53 extern void t_char(char c);
57 #define con_set_zed_keys();
60 /* Forward referenced functions */
61 static void terminate_console(int sig);
62 int get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec);
63 static int do_outputcmd(FILE *input, BSOCK *UA_sock);
64 void senditf(char *fmt, ...);
65 void sendit(char *buf);
67 /* Static variables */
68 static char *configfile = NULL;
69 static BSOCK *UA_sock = NULL;
71 static FILE *output = stdout;
72 int tee = 0; /* output to output and stdout */
73 static int stop = FALSE;
76 static char *argk[MAX_CMD_ARGS];
77 static char *argv[MAX_CMD_ARGS];
79 /* Command prototypes */
80 static int versioncmd(FILE *input, BSOCK *UA_sock);
81 static int inputcmd(FILE *input, BSOCK *UA_sock);
82 static int outputcmd(FILE *input, BSOCK *UA_sock);
83 static int teecmd(FILE *input, BSOCK *UA_sock);
84 static int quitcmd(FILE *input, BSOCK *UA_sock);
85 static int timecmd(FILE *input, BSOCK *UA_sock);
86 static int sleepcmd(FILE *input, BSOCK *UA_sock);
89 #define CONFIG_FILE "./bconsole.conf" /* default configuration file */
94 "\nVersion: " VERSION " (" BDATE ") %s %s %s\n\n"
95 "Usage: bconsole [-s] [-c config_file] [-d debug_level] [config_file]\n"
96 " -c <file> set configuration file to file\n"
97 " -dnn set debug level to nn\n"
99 " -t test - read configuration and exit\n"
100 " -? print this message.\n"
101 "\n"), HOST_OS, DISTNAME, DISTVER);
107 void got_stop(int sig)
112 void got_continue(int sig)
117 void got_tout(int sig)
119 // printf("Got tout\n");
122 void got_tin(int sig)
124 // printf("Got tin\n");
127 static int zed_keyscmd(FILE *input, BSOCK *UA_sock)
134 * These are the @command
136 struct cmdstruct { char *key; int (*func)(FILE *input, BSOCK *UA_sock); char *help; };
137 static struct cmdstruct commands[] = {
138 { N_("input"), inputcmd, _("input from file")},
139 { N_("output"), outputcmd, _("output to file")},
140 { N_("quit"), quitcmd, _("quit")},
141 { N_("tee"), teecmd, _("output to file and terminal")},
142 { N_("sleep"), sleepcmd, _("sleep specified time")},
143 { N_("time"), timecmd, _("print current time")},
144 { N_("version"), versioncmd, _("print Console's version")},
145 { N_("exit"), quitcmd, _("exit = quit")},
146 { N_("zed_keyst"), zed_keyscmd, _("zed_keys = use zed keys instead of bash keys")},
148 #define comsize (sizeof(commands)/sizeof(struct cmdstruct))
150 static int do_a_command(FILE *input, BSOCK *UA_sock)
161 Dmsg1(120, "Command: %s\n", UA_sock->msg);
167 if (*cmd == '#') { /* comment */
171 for (i=0; i<comsize; i++) { /* search for command */
172 if (strncasecmp(cmd, _(commands[i].key), len) == 0) {
173 stat = (*commands[i].func)(input, UA_sock); /* go execute command */
179 pm_strcat(&UA_sock->msg, _(": is an illegal command\n"));
180 UA_sock->msglen = strlen(UA_sock->msg);
181 sendit(UA_sock->msg);
187 static void read_and_process_input(FILE *input, BSOCK *UA_sock)
190 int at_prompt = FALSE;
191 int tty_input = isatty(fileno(input));
195 if (at_prompt) { /* don't prompt multiple times */
202 stat = get_cmd(input, prompt, UA_sock, 30);
204 int len = sizeof_pool_memory(UA_sock->msg) - 1;
205 if (fgets(UA_sock->msg, len, input) == NULL) {
208 sendit(UA_sock->msg); /* echo to terminal */
209 strip_trailing_junk(UA_sock->msg);
210 UA_sock->msglen = strlen(UA_sock->msg);
216 } else if (stat == 0) { /* timeout */
217 if (strcmp(prompt, "*") == 0) {
218 bnet_fsend(UA_sock, ".messages");
224 /* @ => internal command for us */
225 if (UA_sock->msg[0] == '@') {
226 parse_args(UA_sock->msg, &args, &argc, argk, argv, MAX_CMD_ARGS);
227 if (!do_a_command(input, UA_sock)) {
232 if (!bnet_send(UA_sock)) { /* send command */
236 if (strcmp(UA_sock->msg, ".quit") == 0 || strcmp(UA_sock->msg, ".exit") == 0) {
239 while ((stat = bnet_recv(UA_sock)) >= 0) {
247 sendit(UA_sock->msg);
253 if (is_bnet_stop(UA_sock)) {
254 break; /* error or term */
255 } else if (stat == BNET_SIGNAL) {
256 if (UA_sock->msglen == BNET_PROMPT) {
259 Dmsg1(100, "Got poll %s\n", bnet_sig_to_ascii(UA_sock));
265 /*********************************************************************
267 * Main Bacula Console -- User Interface Program
270 int main(int argc, char *argv[])
272 int ch, i, ndir, item;
273 int no_signals = FALSE;
274 int test_config = FALSE;
278 my_name_is(argc, argv, "bconsole");
279 textdomain("bacula-console");
280 init_msg(NULL, NULL);
281 working_directory = "/tmp";
282 args = get_pool_memory(PM_FNAME);
284 while ((ch = getopt(argc, argv, "bc:d:r:st?")) != -1) {
286 case 'c': /* configuration file */
287 if (configfile != NULL) {
290 configfile = bstrdup(optarg);
294 debug_level = atoi(optarg);
295 if (debug_level <= 0) {
300 case 's': /* turn off signals */
318 init_signals(terminate_console);
320 signal(SIGCHLD, SIG_IGN);
321 signal(SIGTSTP, got_stop);
322 signal(SIGCONT, got_continue);
323 signal(SIGTTIN, got_tin);
324 signal(SIGTTOU, got_tout);
330 if (configfile == NULL) {
331 configfile = bstrdup(CONFIG_FILE);
334 parse_config(configfile);
338 for (dir=NULL; (dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir)); ) {
343 Emsg1(M_ERROR_TERM, 0, _("No Director resource defined in %s\n\
344 Without that I don't how to speak to the Director :-(\n"), configfile);
348 terminate_console(0);
352 memset(&jcr, 0, sizeof(jcr));
357 UA_sock = init_bsock(NULL, 0, "", "", 0);
359 sendit(_("Available Directors:\n"));
362 for (dir = NULL; (dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir)); ) {
363 senditf( _("%d %s at %s:%d\n"), 1+ndir++, dir->hdr.name, dir->address,
367 if (get_cmd(stdin, _("Select Director: "), UA_sock, 600) < 0) {
370 item = atoi(UA_sock->msg);
371 if (item < 0 || item > ndir) {
372 senditf(_("You must enter a number between 1 and %d\n"), ndir);
377 for (i=0; i<item; i++) {
378 dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir);
384 dir = (DIRRES *)GetNextRes(R_DIRECTOR, NULL);
389 senditf(_("Connecting to Director %s:%d\n"), dir->address,dir->DIRport);
390 UA_sock = bnet_connect(NULL, 5, 15, "Director daemon", dir->address,
391 NULL, dir->DIRport, 0);
392 if (UA_sock == NULL) {
393 terminate_console(0);
396 jcr.dir_bsock = UA_sock;
397 if (!authenticate_director(&jcr, dir)) {
398 fprintf(stderr, "ERR=%s", UA_sock->msg);
399 terminate_console(0);
403 Dmsg0(40, "Opened connection with Director daemon\n");
405 sendit(_("Enter a period to cancel a command.\n"));
407 char *env = getenv("HOME");
410 pm_strcpy(&UA_sock->msg, env);
411 pm_strcat(&UA_sock->msg, "/.bconsolerc");
412 fd = fopen(UA_sock->msg, "r");
414 read_and_process_input(fd, UA_sock);
420 read_and_process_input(stdin, UA_sock);
423 bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
427 terminate_console(0);
432 /* Cleanup and then exit */
433 static void terminate_console(int sig)
435 static bool already_here = false;
437 if (already_here) { /* avoid recursive temination problems */
441 free_pool_memory(args);
450 #define READLINE_LIBRARY 1
452 #include "readline.h"
457 get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec)
461 rl_catch_signals = 0; /* do it ourselves */
462 line = readline(prompt);
467 strip_trailing_junk(line);
468 sock->msglen = pm_strcpy(&sock->msg, line);
470 add_history(sock->msg);
476 #else /* no readline, do it ourselves */
479 * Returns: 1 if data available
484 wait_for_data(int fd, int sec)
494 switch(select(fd + 1, &fdset, NULL, NULL, &tv)) {
495 case 0: /* timeout */
498 if (errno == EINTR || errno == EAGAIN) {
501 return -1; /* error return */
509 * Get next input command from terminal.
511 * Returns: 1 if got input
516 get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec)
520 if (output == stdout || tee) {
525 switch (wait_for_data(fileno(input), sec)) {
527 return 0; /* timeout */
529 return -1; /* error */
531 len = sizeof_pool_memory(sock->msg) - 1;
537 if (isatty(fileno(input))) {
538 input_line(sock->msg, len);
542 if (fgets(sock->msg, len, input) == NULL) {
547 strip_trailing_junk(sock->msg);
548 sock->msglen = strlen(sock->msg);
554 static int versioncmd(FILE *input, BSOCK *UA_sock)
556 senditf("Version: " VERSION " (" BDATE ") %s %s %s\n",
557 HOST_OS, DISTNAME, DISTVER);
561 static int inputcmd(FILE *input, BSOCK *UA_sock)
566 sendit(_("Too many arguments on input command.\n"));
570 sendit(_("First argument to input command must be a filename.\n"));
573 fd = fopen(argk[1], "r");
575 senditf(_("Cannot open file %s for input. ERR=%s\n"),
576 argk[1], strerror(errno));
579 read_and_process_input(fd, UA_sock);
584 static int teecmd(FILE *input, BSOCK *UA_sock)
587 return do_outputcmd(input, UA_sock);
590 static int outputcmd(FILE *input, BSOCK *UA_sock)
593 return do_outputcmd(input, UA_sock);
597 static int do_outputcmd(FILE *input, BSOCK *UA_sock)
603 sendit(_("Too many arguments on output/tee command.\n"));
607 if (output != stdout) {
617 fd = fopen(argk[1], mode);
619 senditf(_("Cannot open file %s for output. ERR=%s\n"),
620 argk[1], strerror(errno));
627 static int quitcmd(FILE *input, BSOCK *UA_sock)
632 static int sleepcmd(FILE *input, BSOCK *UA_sock)
635 sleep(atoi(argk[1]));
641 static int timecmd(FILE *input, BSOCK *UA_sock)
644 time_t ttime = time(NULL);
646 localtime_r(&ttime, &tm);
647 strftime(sdt, sizeof(sdt), "%d-%b-%Y %H:%M:%S", &tm);
653 * Send a line to the output file and or the terminal
655 void senditf(char *fmt,...)
660 va_start(arg_ptr, fmt);
661 bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr);
666 void sendit(char *buf)
669 if (output == stdout || tee) {
672 * Here, we convert every \n into \r\n because the
673 * terminal is in raw mode when we are using
676 for (p=q=buf; (p=strchr(q, '\n')); ) {
681 q = ++p; /* point after \n */
687 if (output != stdout) {