]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/console/console.c
Constrain BSR indexes, fix bscan, add some new alist code
[bacula/bacula] / bacula / src / console / console.c
1 /*
2  *
3  *   Bacula Console interface to the Director
4  *
5  *     Kern Sibbald, September MM
6  *
7  *     Version $Id$
8  */
9
10 /*
11    Copyright (C) 2000-2003 Kern Sibbald and John Walker
12
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.
17
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.
22
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,
26    MA 02111-1307, USA.
27
28  */
29
30 #include "bacula.h"
31 #include "console_conf.h"
32 #include "jcr.h"
33  
34 /* Imported functions */
35 int authenticate_director(JCR *jcr, DIRRES *director);
36
37        
38 /* Exported variables */
39
40
41 #ifdef HAVE_CYGWIN
42 int rl_catch_signals;
43 #else
44 extern int rl_catch_signals;
45 #endif
46
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, ...);
52
53 /* Static variables */
54 static char *configfile = NULL;
55 static BSOCK *UA_sock = NULL;
56 static DIRRES *dir; 
57 static FILE *output = stdout;
58 int tee = 0;                          /* output to output and stdout */
59 static int stop = FALSE;
60 static int argc;
61 static POOLMEM *args;
62 static char *argk[MAX_CMD_ARGS];
63 static char *argv[MAX_CMD_ARGS];
64
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);
73
74
75 #define CONFIG_FILE "./console.conf"   /* default configuration file */
76
77 static void usage()
78 {
79    fprintf(stderr, _(
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"
84 "       -s          no signals\n"
85 "       -t          test - read configuration and exit\n"
86 "       -?          print this message.\n"  
87 "\n"));
88
89    exit(1);
90 }
91
92
93 void got_stop(int sig)
94 {
95    stop = TRUE;
96 }
97
98 void got_continue(int sig)
99 {
100    stop = FALSE;
101 }
102
103 void got_tout(int sig) 
104 {
105 // printf("Got tout\n");
106 }
107
108 void got_tin(int sig)
109 {   
110 // printf("Got tin\n");
111 }
112
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")},
123              };
124 #define comsize (sizeof(commands)/sizeof(struct cmdstruct))
125
126 static int do_a_command(FILE *input, BSOCK *UA_sock)
127 {
128    unsigned int i;
129    int stat;
130    int found;
131    int len;
132    char *cmd;
133
134    found = 0;
135    stat = 1;
136
137    Dmsg1(120, "Command: %s\n", UA_sock->msg);
138    if (argc == 0) {
139       return 1;
140    }
141
142    cmd = argk[0]+1;
143    if (*cmd == '#') {                 /* comment */
144       return 1;
145    }
146    len = strlen(cmd);
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 */
150          found = 1;
151          break;
152       }
153    }
154    if (!found) {
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);
158       fflush(output);
159    }
160    return stat;
161 }
162
163
164 static void read_and_process_input(FILE *input, BSOCK *UA_sock) 
165 {
166    char *prompt = "*";
167    int at_prompt = FALSE;
168    int tty_input = isatty(fileno(input));
169    int stat;
170
171    for ( ;; ) { 
172       if (at_prompt) {                /* don't prompt multiple times */
173          prompt = "";
174       } else {
175          prompt = "*";
176          at_prompt = TRUE;
177       }
178       if (tty_input) {
179          stat = get_cmd(input, prompt, UA_sock, 30);
180       } else {
181          int len = sizeof_pool_memory(UA_sock->msg) - 1;
182          if (fgets(UA_sock->msg, len, input) == NULL) {
183             stat = -1;
184          } else {
185             sendit("%s", UA_sock->msg);  /* echo to terminal */
186             strip_trailing_junk(UA_sock->msg);
187             UA_sock->msglen = strlen(UA_sock->msg);
188             stat = 1;
189          }
190       }
191       if (stat < 0) {
192          break;                       /* error */
193       } else if (stat == 0) {         /* timeout */
194          bnet_fsend(UA_sock, ".messages");
195       } else {
196          at_prompt = FALSE;
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)) {
201                break;
202             }
203             continue;
204          }
205          if (!bnet_send(UA_sock)) {   /* send command */
206             break;                    /* error */
207          }
208       }
209       if (strcmp(UA_sock->msg, ".quit") == 0 || strcmp(UA_sock->msg, ".exit") == 0) {
210          break;
211       }
212       while ((stat = bnet_recv(UA_sock)) >= 0) {
213          if (at_prompt) {
214             if (!stop) {
215                sendit("\n");
216             }
217             at_prompt = FALSE;
218          }
219          if (!stop) {
220             sendit("%s", UA_sock->msg);
221          }
222       }
223       if (!stop) {
224          fflush(stdout);
225       }
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) {
230             at_prompt = TRUE;
231          }
232          Dmsg1(100, "Got poll %s\n", bnet_sig_to_ascii(UA_sock));
233       }
234    }
235 }
236
237
238 /*********************************************************************
239  *
240  *         Main Bacula Console -- User Interface Program
241  *
242  */
243 int main(int argc, char *argv[])
244 {
245    int ch, i, ndir, item;
246    int no_signals = FALSE;
247    int test_config = FALSE;
248    JCR jcr;
249
250    init_stack_dump();
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);
256
257    while ((ch = getopt(argc, argv, "bc:d:r:st?")) != -1) {
258       switch (ch) {
259          case 'c':                    /* configuration file */
260             if (configfile != NULL) {
261                free(configfile);
262             }
263             configfile = bstrdup(optarg);
264             break;
265
266          case 'd':
267             debug_level = atoi(optarg);
268             if (debug_level <= 0) {
269                debug_level = 1;
270             }
271             break;
272
273          case 's':                    /* turn off signals */
274             no_signals = TRUE;
275             break;
276
277          case 't':
278             test_config = TRUE;
279             break;
280
281          case '?':
282          default:
283             usage();
284
285       }  
286    }
287    argc -= optind;
288    argv += optind;
289
290    if (!no_signals) {
291       init_signals(terminate_console);
292    }
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);
298
299    if (argc) {
300       usage();
301    }
302
303    if (configfile == NULL) {
304       configfile = bstrdup(CONFIG_FILE);
305    }
306
307    parse_config(configfile);
308
309    LockRes();
310    ndir = 0;
311    for (dir=NULL; (dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir)); ) {
312       ndir++;
313    }
314    UnlockRes();
315    if (ndir == 0) {
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);
318    }
319
320    if (test_config) {
321       terminate_console(0);
322       exit(0);
323    }
324
325    memset(&jcr, 0, sizeof(jcr));
326
327    if (ndir > 1) {
328       UA_sock = init_bsock(NULL, 0, "", "", 0);
329 try_again:
330       sendit(_("Available Directors:\n"));
331       LockRes();
332       ndir = 0;
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,
335             dir->DIRport);
336       }
337       UnlockRes();
338       if (get_cmd(stdin, _("Select Director: "), UA_sock, 600) < 0) {
339          return 1;
340       }
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);
344          goto try_again;
345       }
346       LockRes();
347       dir = NULL;
348       for (i=0; i<item; i++) {
349          dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir);
350       }
351       UnlockRes();
352       term_bsock(UA_sock);
353    } else {
354       LockRes();
355       dir = (DIRRES *)GetNextRes(R_DIRECTOR, NULL);
356       UnlockRes();
357    }
358       
359
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);
365       return 1;
366    }
367    jcr.dir_bsock = UA_sock;
368    if (!authenticate_director(&jcr, dir)) {
369       fprintf(stderr, "ERR=%s", UA_sock->msg);
370       terminate_console(0);
371       return 1;
372    }
373
374    Dmsg0(40, "Opened connection with Director daemon\n");
375
376    read_and_process_input(stdin, UA_sock);
377
378    if (UA_sock) {
379       bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
380       bnet_close(UA_sock);
381    }
382
383    terminate_console(0);
384    return 0;
385 }
386
387
388 /* Cleanup and then exit */
389 static void terminate_console(int sig)
390 {
391    static int already_here = FALSE;
392
393    if (already_here) {                /* avoid recursive temination problems */
394       exit(1);
395    }
396    already_here = TRUE;
397    free_pool_memory(args);
398    if (sig != 0) {
399       exit(1);
400    }
401    return;
402 }
403
404 #ifdef HAVE_READLINE
405 #define READLINE_LIBRARY 1
406 #undef free
407 #include "readline.h"
408 #include "history.h"
409
410
411 int 
412 get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec)
413 {
414    char *line;
415
416    rl_catch_signals = 0;              /* do it ourselves */
417    line = readline(prompt);
418
419    if (!line) {
420       exit(1);
421    }
422    strcpy(sock->msg, line);
423    strip_trailing_junk(sock->msg);
424    sock->msglen = strlen(sock->msg);
425    if (sock->msglen) {
426       add_history(sock->msg);
427    }
428    free(line);
429    return 1;
430 }
431
432 #else /* no readline, do it ourselves */
433
434 /*
435  *   Returns: 1 if data available
436  *            0 if timeout
437  *           -1 if error
438  */
439 static int
440 wait_for_data(int fd, int sec)
441 {
442    fd_set fdset;
443    struct timeval tv;
444
445    FD_ZERO(&fdset);
446    FD_SET(fd, &fdset);
447    tv.tv_sec = sec;
448    tv.tv_usec = 0;
449    for ( ;; ) {
450       switch(select(fd + 1, &fdset, NULL, NULL, &tv)) {
451          case 0:                         /* timeout */
452             return 0;
453          case -1:
454             if (errno == EINTR || errno == EAGAIN) {
455                continue;
456             }
457             return -1;                  /* error return */
458          default:
459             return 1;
460       }
461    }
462 }
463
464 /*      
465  * Get next input command from terminal. 
466  *
467  *   Returns: 1 if got input
468  *            0 if timeout
469  *           -1 if EOF or error
470  */
471 int 
472 get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec)
473 {
474    int len;  
475    if (!stop) {
476       if (output == stdout || tee) {
477          fputs(prompt, stdout);
478          fflush(stdout);
479       }
480    }
481 again:
482    switch (wait_for_data(fileno(input), sec)) {
483       case 0:
484          return 0;                    /* timeout */
485       case -1: 
486          return -1;                   /* error */
487       default:
488          len = sizeof_pool_memory(sock->msg) - 1;
489          if (stop) {
490             goto again;
491          }
492          if (fgets(sock->msg, len, input) == NULL) {
493             return -1;
494          }
495          break;
496    }
497    strip_trailing_junk(sock->msg);
498    sock->msglen = strlen(sock->msg);
499    return 1;
500 }
501
502 #endif
503
504 static int versioncmd(FILE *input, BSOCK *UA_sock)
505 {
506    sendit("Version: " VERSION " (" BDATE ")\n");
507    return 1;
508 }
509
510 static int inputcmd(FILE *input, BSOCK *UA_sock)
511 {
512    FILE *fd;
513
514    if (argc > 2) {
515       sendit(_("Too many arguments.\n"));
516       return 0;
517    }
518    if (argc == 1) {
519       sendit(_("First argument must be a filename.\n"));
520       return 0;
521    }
522    fd = fopen(argk[1], "r");
523    if (!fd) {
524       sendit(_("Cannot open file. ERR=%s\n"), strerror(errno));
525       return 0; 
526    }
527    read_and_process_input(fd, UA_sock);
528    fclose(fd);
529    return 1;
530 }
531
532 static int teecmd(FILE *input, BSOCK *UA_sock)
533 {
534    tee = 1;
535    return do_outputcmd(input, UA_sock);
536 }
537
538 static int outputcmd(FILE *input, BSOCK *UA_sock)
539 {
540    tee = 0;
541    return do_outputcmd(input, UA_sock);
542 }
543
544
545 static int do_outputcmd(FILE *input, BSOCK *UA_sock)
546 {
547    FILE *fd;
548    char *mode = "a+";
549
550    if (argc > 3) {
551       sendit(_("Too many arguments.\n"));
552       return 1;
553    }
554    if (argc == 1) {
555       if (output != stdout) {
556          fclose(output);
557          output = stdout;
558          tee = 0;
559       }
560       return 1;
561    }
562    if (argc == 3) {
563       mode = argk[2];
564    }
565    fd = fopen(argk[1], mode);
566    if (!fd) {
567       sendit(_("Cannot open file. ERR=%s\n"), strerror(errno));
568       return 1; 
569    }
570    output = fd;
571    return 1;
572 }
573
574 static int quitcmd(FILE *input, BSOCK *UA_sock)
575 {
576    return 0;
577 }
578
579 static int sleepcmd(FILE *input, BSOCK *UA_sock)
580 {
581    if (argc > 1) {
582       sleep(atoi(argk[1]));
583    }
584    return 1;
585 }
586
587
588 static int timecmd(FILE *input, BSOCK *UA_sock)
589 {
590    char sdt[50];
591    time_t ttime = time(NULL);
592    struct tm tm;
593    localtime_r(&ttime, &tm);
594    strftime(sdt, sizeof(sdt), "%d-%b-%Y %H:%M:%S", &tm);
595    sendit(sdt);
596    sendit("\n");
597    return 1;
598 }
599
600 static void sendit(char *fmt,...)
601 {
602     char buf[3000];
603     va_list arg_ptr;
604
605     va_start(arg_ptr, fmt);
606     bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr);
607     va_end(arg_ptr);
608     fputs(buf, output);
609     if (tee) {
610        fputs(buf, stdout);
611     }
612     fflush(stdout);
613 }