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 strip_trailing_junk(UA_sock->msg);
186 UA_sock->msglen = strlen(UA_sock->msg);
192 } else if (stat == 0) { /* timeout */
193 bnet_fsend(UA_sock, ".messages");
196 /* @ => internal command for us */
197 if (UA_sock->msg[0] == '@') {
198 parse_command_args(UA_sock->msg, args, &argc, argk, argv);
199 if (!do_a_command(input, UA_sock)) {
204 if (!bnet_send(UA_sock)) { /* send command */
208 if (strcmp(UA_sock->msg, ".quit") == 0 || strcmp(UA_sock->msg, ".exit") == 0) {
211 while ((stat = bnet_recv(UA_sock)) >= 0) {
219 sendit("%s", UA_sock->msg);
225 if (is_bnet_stop(UA_sock)) {
226 break; /* error or term */
227 } else if (stat == BNET_SIGNAL) {
228 if (UA_sock->msglen == BNET_PROMPT) {
231 Dmsg1(100, "Got poll %s\n", bnet_sig_to_ascii(UA_sock));
237 /*********************************************************************
239 * Main Bacula Console -- User Interface Program
242 int main(int argc, char *argv[])
244 int ch, i, ndir, item;
245 int no_signals = FALSE;
246 int test_config = FALSE;
250 my_name_is(argc, argv, "console");
251 textdomain("bacula-console");
252 init_msg(NULL, NULL);
253 working_directory = "/tmp";
254 args = get_pool_memory(PM_FNAME);
256 while ((ch = getopt(argc, argv, "bc:d:r:st?")) != -1) {
258 case 'c': /* configuration file */
259 if (configfile != NULL) {
262 configfile = bstrdup(optarg);
266 debug_level = atoi(optarg);
267 if (debug_level <= 0) {
272 case 's': /* turn off signals */
290 init_signals(terminate_console);
292 signal(SIGCHLD, SIG_IGN);
293 signal(SIGTSTP, got_stop);
294 signal(SIGCONT, got_continue);
295 signal(SIGTTIN, got_tin);
296 signal(SIGTTOU, got_tout);
302 if (configfile == NULL) {
303 configfile = bstrdup(CONFIG_FILE);
306 parse_config(configfile);
310 for (dir=NULL; (dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir)); ) {
315 Emsg1(M_ERROR_TERM, 0, "No Director resource defined in %s\n\
316 Without that I don't how to speak to the Director :-(\n", configfile);
320 terminate_console(0);
324 memset(&jcr, 0, sizeof(jcr));
327 UA_sock = init_bsock(NULL, 0, "", "", 0);
329 sendit("Available Directors:\n");
332 for (dir = NULL; (dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir)); ) {
333 fprintf(output, "%d %s at %s:%d\n", 1+ndir++, dir->hdr.name, dir->address,
337 if (get_cmd(stdin, "Select Director: ", UA_sock, 600) < 0) {
340 item = atoi(UA_sock->msg);
341 if (item < 0 || item > ndir) {
342 sendit("You must enter a number between 1 and %d\n", ndir);
347 for (i=0; i<item; i++) {
348 dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir);
354 dir = (DIRRES *)GetNextRes(R_DIRECTOR, NULL);
359 sendit("Connecting to Director %s:%d\n", dir->address,dir->DIRport);
360 UA_sock = bnet_connect(NULL, 5, 15, "Director daemon", dir->address,
361 NULL, dir->DIRport, 0);
362 if (UA_sock == NULL) {
363 terminate_console(0);
366 jcr.dir_bsock = UA_sock;
367 if (!authenticate_director(&jcr, dir)) {
368 fprintf(stderr, "ERR=%s", UA_sock->msg);
369 terminate_console(0);
373 Dmsg0(40, "Opened connection with Director daemon\n");
375 read_and_process_input(stdin, UA_sock);
378 bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
382 terminate_console(0);
387 /* Cleanup and then exit */
388 static void terminate_console(int sig)
390 static int already_here = FALSE;
392 if (already_here) { /* avoid recursive temination problems */
396 free_pool_memory(args);
405 #include "readline/readline.h"
406 #include "readline/history.h"
410 get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec)
414 rl_catch_signals = 0; /* do it ourselves */
415 line = readline(prompt);
420 strcpy(sock->msg, line);
421 strip_trailing_junk(sock->msg);
422 sock->msglen = strlen(sock->msg);
424 add_history(sock->msg);
430 #else /* no readline, do it ourselves */
433 * Returns: 1 if data available
438 wait_for_data(int fd, int sec)
448 switch(select(fd + 1, &fdset, NULL, NULL, &tv)) {
449 case 0: /* timeout */
452 if (errno == EINTR || errno == EAGAIN) {
455 return -1; /* error return */
463 * Get next input command from terminal.
465 * Returns: 1 if got input
470 get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec)
474 if (output == stdout || tee) {
475 fputs(prompt, stdout);
480 switch (wait_for_data(fileno(input), sec)) {
482 return 0; /* timeout */
484 return -1; /* error */
486 len = sizeof_pool_memory(sock->msg) - 1;
490 if (fgets(sock->msg, len, input) == NULL) {
495 strip_trailing_junk(sock->msg);
496 sock->msglen = strlen(sock->msg);
502 static int versioncmd(FILE *input, BSOCK *UA_sock)
504 sendit("Version: " VERSION " (" BDATE ")\n");
508 static int inputcmd(FILE *input, BSOCK *UA_sock)
513 sendit("Too many arguments.\n");
517 sendit("First argument must be a filename.\n");
520 fd = fopen(argk[1], "r");
522 sendit("Cannot open file. ERR=%s\n", strerror(errno));
525 read_and_process_input(fd, UA_sock);
530 static int teecmd(FILE *input, BSOCK *UA_sock)
533 return do_outputcmd(input, UA_sock);
536 static int outputcmd(FILE *input, BSOCK *UA_sock)
539 return do_outputcmd(input, UA_sock);
543 static int do_outputcmd(FILE *input, BSOCK *UA_sock)
549 sendit("Too many arguments.\n");
553 if (output != stdout) {
563 fd = fopen(argk[1], mode);
565 sendit("Cannot open file. ERR=%s\n", strerror(errno));
572 static int quitcmd(FILE *input, BSOCK *UA_sock)
577 static int sleepcmd(FILE *input, BSOCK *UA_sock)
580 sleep(atoi(argk[1]));
586 static int timecmd(FILE *input, BSOCK *UA_sock)
589 time_t ttime = time(NULL);
591 localtime_r(&ttime, &tm);
592 strftime(sdt, sizeof(sdt), "%d-%b-%Y %H:%M:%S", &tm);
598 static void sendit(char *fmt,...)
603 va_start(arg_ptr, fmt);
604 bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr);