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 */
44 extern int rl_catch_signals;
47 /* Forward referenced functions */
48 static void terminate_console(int sig);
49 int get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec);
50 static int do_outputcmd(FILE *input, BSOCK *UA_sock);
51 static void sendit(char *fmt, ...);
53 /* Static variables */
54 static char *configfile = NULL;
55 static BSOCK *UA_sock = NULL;
57 static FILE *output = stdout;
58 int tee = 0; /* output to output and stdout */
59 static int stop = FALSE;
62 static char *argk[MAX_CMD_ARGS];
63 static char *argv[MAX_CMD_ARGS];
65 /* Command prototypes */
66 static int versioncmd(FILE *input, BSOCK *UA_sock);
67 static int inputcmd(FILE *input, BSOCK *UA_sock);
68 static int outputcmd(FILE *input, BSOCK *UA_sock);
69 static int teecmd(FILE *input, BSOCK *UA_sock);
70 static int quitcmd(FILE *input, BSOCK *UA_sock);
71 static int timecmd(FILE *input, BSOCK *UA_sock);
72 static int sleepcmd(FILE *input, BSOCK *UA_sock);
75 #define CONFIG_FILE "./console.conf" /* default configuration file */
80 "\nVersion: " VERSION " (" BDATE ")\n\n"
81 "Usage: console [-s] [-c config_file] [-d debug_level] [config_file]\n"
82 " -c <file> set configuration file to file\n"
83 " -dnn set debug level to nn\n"
85 " -t test - read configuration and exit\n"
86 " -? print this message.\n"
93 void got_stop(int sig)
98 void got_continue(int sig)
103 void got_tout(int sig)
105 // printf("Got tout\n");
108 void got_tin(int sig)
110 // printf("Got tin\n");
113 struct cmdstruct { char *key; int (*func)(FILE *input, BSOCK *UA_sock); char *help; };
114 static struct cmdstruct commands[] = {
115 { N_("input"), inputcmd, _("input from file")},
116 { N_("output"), outputcmd, _("output to file")},
117 { N_("quit"), quitcmd, _("quit")},
118 { N_("tee"), teecmd, _("output to file and terminal")},
119 { N_("sleep"), sleepcmd, _("sleep specified time")},
120 { N_("time"), timecmd, _("print current time")},
121 { N_("version"), versioncmd, _("print Console's version")},
122 { N_("exit"), quitcmd, _("exit = quit")},
124 #define comsize (sizeof(commands)/sizeof(struct cmdstruct))
126 static int do_a_command(FILE *input, BSOCK *UA_sock)
137 Dmsg1(120, "Command: %s\n", UA_sock->msg);
143 if (*cmd == '#') { /* comment */
147 for (i=0; i<comsize; i++) { /* search for command */
148 if (strncasecmp(cmd, _(commands[i].key), len) == 0) {
149 stat = (*commands[i].func)(input, UA_sock); /* go execute command */
155 pm_strcat(&UA_sock->msg, _(": is an illegal command\n"));
156 UA_sock->msglen = strlen(UA_sock->msg);
157 fputs(UA_sock->msg, output);
164 static void read_and_process_input(FILE *input, BSOCK *UA_sock)
167 int at_prompt = FALSE;
168 int tty_input = isatty(fileno(input));
172 if (at_prompt) { /* don't prompt multiple times */
179 stat = get_cmd(input, prompt, UA_sock, 30);
181 int len = sizeof_pool_memory(UA_sock->msg) - 1;
182 if (fgets(UA_sock->msg, len, input) == NULL) {
185 sendit("%s", UA_sock->msg); /* echo to terminal */
186 strip_trailing_junk(UA_sock->msg);
187 UA_sock->msglen = strlen(UA_sock->msg);
193 } else if (stat == 0) { /* timeout */
194 bnet_fsend(UA_sock, ".messages");
197 /* @ => internal command for us */
198 if (UA_sock->msg[0] == '@') {
199 parse_args(UA_sock->msg, &args, &argc, argk, argv, MAX_CMD_ARGS);
200 if (!do_a_command(input, UA_sock)) {
205 if (!bnet_send(UA_sock)) { /* send command */
209 if (strcmp(UA_sock->msg, ".quit") == 0 || strcmp(UA_sock->msg, ".exit") == 0) {
212 while ((stat = bnet_recv(UA_sock)) >= 0) {
220 sendit("%s", UA_sock->msg);
226 if (is_bnet_stop(UA_sock)) {
227 break; /* error or term */
228 } else if (stat == BNET_SIGNAL) {
229 if (UA_sock->msglen == BNET_PROMPT) {
232 Dmsg1(100, "Got poll %s\n", bnet_sig_to_ascii(UA_sock));
238 /*********************************************************************
240 * Main Bacula Console -- User Interface Program
243 int main(int argc, char *argv[])
245 int ch, i, ndir, item;
246 int no_signals = FALSE;
247 int test_config = FALSE;
251 my_name_is(argc, argv, "console");
252 textdomain("bacula-console");
253 init_msg(NULL, NULL);
254 working_directory = "/tmp";
255 args = get_pool_memory(PM_FNAME);
257 while ((ch = getopt(argc, argv, "bc:d:r:st?")) != -1) {
259 case 'c': /* configuration file */
260 if (configfile != NULL) {
263 configfile = bstrdup(optarg);
267 debug_level = atoi(optarg);
268 if (debug_level <= 0) {
273 case 's': /* turn off signals */
291 init_signals(terminate_console);
293 signal(SIGCHLD, SIG_IGN);
294 signal(SIGTSTP, got_stop);
295 signal(SIGCONT, got_continue);
296 signal(SIGTTIN, got_tin);
297 signal(SIGTTOU, got_tout);
303 if (configfile == NULL) {
304 configfile = bstrdup(CONFIG_FILE);
307 parse_config(configfile);
311 for (dir=NULL; (dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir)); ) {
316 Emsg1(M_ERROR_TERM, 0, _("No Director resource defined in %s\n\
317 Without that I don't how to speak to the Director :-(\n"), configfile);
321 terminate_console(0);
325 memset(&jcr, 0, sizeof(jcr));
328 UA_sock = init_bsock(NULL, 0, "", "", 0);
330 sendit(_("Available Directors:\n"));
333 for (dir = NULL; (dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir)); ) {
334 fprintf(output, _("%d %s at %s:%d\n"), 1+ndir++, dir->hdr.name, dir->address,
338 if (get_cmd(stdin, _("Select Director: "), UA_sock, 600) < 0) {
341 item = atoi(UA_sock->msg);
342 if (item < 0 || item > ndir) {
343 sendit(_("You must enter a number between 1 and %d\n"), ndir);
348 for (i=0; i<item; i++) {
349 dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir);
355 dir = (DIRRES *)GetNextRes(R_DIRECTOR, NULL);
360 sendit(_("Connecting to Director %s:%d\n"), dir->address,dir->DIRport);
361 UA_sock = bnet_connect(NULL, 5, 15, "Director daemon", dir->address,
362 NULL, dir->DIRport, 0);
363 if (UA_sock == NULL) {
364 terminate_console(0);
367 jcr.dir_bsock = UA_sock;
368 if (!authenticate_director(&jcr, dir)) {
369 fprintf(stderr, "ERR=%s", UA_sock->msg);
370 terminate_console(0);
374 Dmsg0(40, "Opened connection with Director daemon\n");
376 read_and_process_input(stdin, UA_sock);
379 bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
383 terminate_console(0);
388 /* Cleanup and then exit */
389 static void terminate_console(int sig)
391 static int already_here = FALSE;
393 if (already_here) { /* avoid recursive temination problems */
397 free_pool_memory(args);
405 #define READLINE_LIBRARY 1
407 #include "readline.h"
412 get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec)
416 rl_catch_signals = 0; /* do it ourselves */
417 line = readline(prompt);
422 strcpy(sock->msg, line);
423 strip_trailing_junk(sock->msg);
424 sock->msglen = strlen(sock->msg);
426 add_history(sock->msg);
432 #else /* no readline, do it ourselves */
435 * Returns: 1 if data available
440 wait_for_data(int fd, int sec)
450 switch(select(fd + 1, &fdset, NULL, NULL, &tv)) {
451 case 0: /* timeout */
454 if (errno == EINTR || errno == EAGAIN) {
457 return -1; /* error return */
465 * Get next input command from terminal.
467 * Returns: 1 if got input
472 get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec)
476 if (output == stdout || tee) {
477 fputs(prompt, stdout);
482 switch (wait_for_data(fileno(input), sec)) {
484 return 0; /* timeout */
486 return -1; /* error */
488 len = sizeof_pool_memory(sock->msg) - 1;
492 if (fgets(sock->msg, len, input) == NULL) {
497 strip_trailing_junk(sock->msg);
498 sock->msglen = strlen(sock->msg);
504 static int versioncmd(FILE *input, BSOCK *UA_sock)
506 sendit("Version: " VERSION " (" BDATE ")\n");
510 static int inputcmd(FILE *input, BSOCK *UA_sock)
515 sendit(_("Too many arguments.\n"));
519 sendit(_("First argument must be a filename.\n"));
522 fd = fopen(argk[1], "r");
524 sendit(_("Cannot open file. ERR=%s\n"), strerror(errno));
527 read_and_process_input(fd, UA_sock);
532 static int teecmd(FILE *input, BSOCK *UA_sock)
535 return do_outputcmd(input, UA_sock);
538 static int outputcmd(FILE *input, BSOCK *UA_sock)
541 return do_outputcmd(input, UA_sock);
545 static int do_outputcmd(FILE *input, BSOCK *UA_sock)
551 sendit(_("Too many arguments.\n"));
555 if (output != stdout) {
565 fd = fopen(argk[1], mode);
567 sendit(_("Cannot open file. ERR=%s\n"), strerror(errno));
574 static int quitcmd(FILE *input, BSOCK *UA_sock)
579 static int sleepcmd(FILE *input, BSOCK *UA_sock)
582 sleep(atoi(argk[1]));
588 static int timecmd(FILE *input, BSOCK *UA_sock)
591 time_t ttime = time(NULL);
593 localtime_r(&ttime, &tm);
594 strftime(sdt, sizeof(sdt), "%d-%b-%Y %H:%M:%S", &tm);
600 static void sendit(char *fmt,...)
605 va_start(arg_ptr, fmt);
606 bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr);