]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/console/console.c
Final variable expansion fixes + misc
[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 ") %s %s %s\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"), HOST_OS, DISTNAME, DISTVER);
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          if (strcmp(prompt, "*") == 0) {
195             bnet_fsend(UA_sock, ".messages");
196          } else {
197             continue;
198          }
199       } else {
200          at_prompt = FALSE;
201          /* @ => internal command for us */
202          if (UA_sock->msg[0] == '@') {
203             parse_args(UA_sock->msg, &args, &argc, argk, argv, MAX_CMD_ARGS);
204             if (!do_a_command(input, UA_sock)) {
205                break;
206             }
207             continue;
208          }
209          if (!bnet_send(UA_sock)) {   /* send command */
210             break;                    /* error */
211          }
212       }
213       if (strcmp(UA_sock->msg, ".quit") == 0 || strcmp(UA_sock->msg, ".exit") == 0) {
214          break;
215       }
216       while ((stat = bnet_recv(UA_sock)) >= 0) {
217          if (at_prompt) {
218             if (!stop) {
219                sendit("\n");
220             }
221             at_prompt = FALSE;
222          }
223          if (!stop) {
224             sendit("%s", UA_sock->msg);
225          }
226       }
227       if (!stop) {
228          fflush(stdout);
229       }
230       if (is_bnet_stop(UA_sock)) {
231          break;                       /* error or term */
232       } else if (stat == BNET_SIGNAL) {
233          if (UA_sock->msglen == BNET_PROMPT) {
234             at_prompt = TRUE;
235          }
236          Dmsg1(100, "Got poll %s\n", bnet_sig_to_ascii(UA_sock));
237       }
238    }
239 }
240
241
242 /*********************************************************************
243  *
244  *         Main Bacula Console -- User Interface Program
245  *
246  */
247 int main(int argc, char *argv[])
248 {
249    int ch, i, ndir, item;
250    int no_signals = FALSE;
251    int test_config = FALSE;
252    JCR jcr;
253
254    init_stack_dump();
255    my_name_is(argc, argv, "console");
256    textdomain("bacula-console");
257    init_msg(NULL, NULL);
258    working_directory = "/tmp";
259    args = get_pool_memory(PM_FNAME);
260
261    while ((ch = getopt(argc, argv, "bc:d:r:st?")) != -1) {
262       switch (ch) {
263          case 'c':                    /* configuration file */
264             if (configfile != NULL) {
265                free(configfile);
266             }
267             configfile = bstrdup(optarg);
268             break;
269
270          case 'd':
271             debug_level = atoi(optarg);
272             if (debug_level <= 0) {
273                debug_level = 1;
274             }
275             break;
276
277          case 's':                    /* turn off signals */
278             no_signals = TRUE;
279             break;
280
281          case 't':
282             test_config = TRUE;
283             break;
284
285          case '?':
286          default:
287             usage();
288
289       }  
290    }
291    argc -= optind;
292    argv += optind;
293
294    if (!no_signals) {
295       init_signals(terminate_console);
296    }
297    signal(SIGCHLD, SIG_IGN);
298    signal(SIGTSTP, got_stop);
299    signal(SIGCONT, got_continue);
300    signal(SIGTTIN, got_tin);
301    signal(SIGTTOU, got_tout);
302
303    if (argc) {
304       usage();
305    }
306
307    if (configfile == NULL) {
308       configfile = bstrdup(CONFIG_FILE);
309    }
310
311    parse_config(configfile);
312
313    LockRes();
314    ndir = 0;
315    for (dir=NULL; (dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir)); ) {
316       ndir++;
317    }
318    UnlockRes();
319    if (ndir == 0) {
320       Emsg1(M_ERROR_TERM, 0, _("No Director resource defined in %s\n\
321 Without that I don't how to speak to the Director :-(\n"), configfile);
322    }
323
324    if (test_config) {
325       terminate_console(0);
326       exit(0);
327    }
328
329    memset(&jcr, 0, sizeof(jcr));
330
331    if (ndir > 1) {
332       UA_sock = init_bsock(NULL, 0, "", "", 0);
333 try_again:
334       sendit(_("Available Directors:\n"));
335       LockRes();
336       ndir = 0;
337       for (dir = NULL; (dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir)); ) {
338          fprintf(output, _("%d  %s at %s:%d\n"), 1+ndir++, dir->hdr.name, dir->address,
339             dir->DIRport);
340       }
341       UnlockRes();
342       if (get_cmd(stdin, _("Select Director: "), UA_sock, 600) < 0) {
343          return 1;
344       }
345       item = atoi(UA_sock->msg);
346       if (item < 0 || item > ndir) {
347          sendit(_("You must enter a number between 1 and %d\n"), ndir);
348          goto try_again;
349       }
350       LockRes();
351       dir = NULL;
352       for (i=0; i<item; i++) {
353          dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir);
354       }
355       UnlockRes();
356       term_bsock(UA_sock);
357    } else {
358       LockRes();
359       dir = (DIRRES *)GetNextRes(R_DIRECTOR, NULL);
360       UnlockRes();
361    }
362       
363
364    sendit(_("Connecting to Director %s:%d\n"), dir->address,dir->DIRport);
365    UA_sock = bnet_connect(NULL, 5, 15, "Director daemon", dir->address, 
366                           NULL, dir->DIRport, 0);
367    if (UA_sock == NULL) {
368       terminate_console(0);
369       return 1;
370    }
371    jcr.dir_bsock = UA_sock;
372    if (!authenticate_director(&jcr, dir)) {
373       fprintf(stderr, "ERR=%s", UA_sock->msg);
374       terminate_console(0);
375       return 1;
376    }
377
378    Dmsg0(40, "Opened connection with Director daemon\n");
379
380    read_and_process_input(stdin, UA_sock);
381
382    if (UA_sock) {
383       bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
384       bnet_close(UA_sock);
385    }
386
387    terminate_console(0);
388    return 0;
389 }
390
391
392 /* Cleanup and then exit */
393 static void terminate_console(int sig)
394 {
395    static int already_here = FALSE;
396
397    if (already_here) {                /* avoid recursive temination problems */
398       exit(1);
399    }
400    already_here = TRUE;
401    free_pool_memory(args);
402    if (sig != 0) {
403       exit(1);
404    }
405    return;
406 }
407
408 #ifdef HAVE_READLINE
409 #define READLINE_LIBRARY 1
410 #undef free
411 #include "readline.h"
412 #include "history.h"
413
414
415 int 
416 get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec)
417 {
418    char *line;
419
420    rl_catch_signals = 0;              /* do it ourselves */
421    line = readline(prompt);
422
423    if (!line) {
424       exit(1);
425    }
426    strcpy(sock->msg, line);
427    strip_trailing_junk(sock->msg);
428    sock->msglen = strlen(sock->msg);
429    if (sock->msglen) {
430       add_history(sock->msg);
431    }
432    free(line);
433    return 1;
434 }
435
436 #else /* no readline, do it ourselves */
437
438 /*
439  *   Returns: 1 if data available
440  *            0 if timeout
441  *           -1 if error
442  */
443 static int
444 wait_for_data(int fd, int sec)
445 {
446    fd_set fdset;
447    struct timeval tv;
448
449    tv.tv_sec = sec;
450    tv.tv_usec = 0;
451    for ( ;; ) {
452       FD_ZERO(&fdset);
453       FD_SET(fd, &fdset);
454       switch(select(fd + 1, &fdset, NULL, NULL, &tv)) {
455       case 0:                         /* timeout */
456          return 0;
457       case -1:
458          if (errno == EINTR || errno == EAGAIN) {
459             continue;
460          }
461          return -1;                  /* error return */
462       default:
463          return 1;
464       }
465    }
466 }
467
468 /*      
469  * Get next input command from terminal. 
470  *
471  *   Returns: 1 if got input
472  *            0 if timeout
473  *           -1 if EOF or error
474  */
475 int 
476 get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec)
477 {
478    int len;  
479    if (!stop) {
480       if (output == stdout || tee) {
481          fputs(prompt, stdout);
482          fflush(stdout);
483       }
484    }
485 again:
486    switch (wait_for_data(fileno(input), sec)) {
487    case 0:
488       return 0;                    /* timeout */
489    case -1: 
490       return -1;                   /* error */
491    default:
492       len = sizeof_pool_memory(sock->msg) - 1;
493       if (stop) {
494          sleep(1);
495          goto again;
496       }
497       if (fgets(sock->msg, len, input) == NULL) {
498          return -1;
499       }
500       break;
501    }
502    strip_trailing_junk(sock->msg);
503    sock->msglen = strlen(sock->msg);
504    return 1;
505 }
506
507 #endif
508
509 static int versioncmd(FILE *input, BSOCK *UA_sock)
510 {
511    sendit("Version: " VERSION " (" BDATE ") %s %s %s\n",
512       HOST_OS, DISTNAME, DISTVER);
513    return 1;
514 }
515
516 static int inputcmd(FILE *input, BSOCK *UA_sock)
517 {
518    FILE *fd;
519
520    if (argc > 2) {
521       sendit(_("Too many arguments on input command.\n"));
522       return 1;
523    }
524    if (argc == 1) {
525       sendit(_("First argument to input command must be a filename.\n"));
526       return 1;
527    }
528    fd = fopen(argk[1], "r");
529    if (!fd) {
530       sendit(_("Cannot open file %s for input. ERR=%s\n"), 
531          argk[1], strerror(errno));
532       return 1; 
533    }
534    read_and_process_input(fd, UA_sock);
535    fclose(fd);
536    return 1;
537 }
538
539 static int teecmd(FILE *input, BSOCK *UA_sock)
540 {
541    tee = 1;
542    return do_outputcmd(input, UA_sock);
543 }
544
545 static int outputcmd(FILE *input, BSOCK *UA_sock)
546 {
547    tee = 0;
548    return do_outputcmd(input, UA_sock);
549 }
550
551
552 static int do_outputcmd(FILE *input, BSOCK *UA_sock)
553 {
554    FILE *fd;
555    char *mode = "a+";
556
557    if (argc > 3) {
558       sendit(_("Too many arguments on output/tee command.\n"));
559       return 1;
560    }
561    if (argc == 1) {
562       if (output != stdout) {
563          fclose(output);
564          output = stdout;
565          tee = 0;
566       }
567       return 1;
568    }
569    if (argc == 3) {
570       mode = argk[2];
571    }
572    fd = fopen(argk[1], mode);
573    if (!fd) {
574       sendit(_("Cannot open file %s for output. ERR=%s\n"), 
575          argk[1], strerror(errno));
576       return 1; 
577    }
578    output = fd;
579    return 1;
580 }
581
582 static int quitcmd(FILE *input, BSOCK *UA_sock)
583 {
584    return 0;
585 }
586
587 static int sleepcmd(FILE *input, BSOCK *UA_sock)
588 {
589    if (argc > 1) {
590       sleep(atoi(argk[1]));
591    }
592    return 1;
593 }
594
595
596 static int timecmd(FILE *input, BSOCK *UA_sock)
597 {
598    char sdt[50];
599    time_t ttime = time(NULL);
600    struct tm tm;
601    localtime_r(&ttime, &tm);
602    strftime(sdt, sizeof(sdt), "%d-%b-%Y %H:%M:%S", &tm);
603    sendit(sdt);
604    sendit("\n");
605    return 1;
606 }
607
608 static void sendit(char *fmt,...)
609 {
610     char buf[3000];
611     va_list arg_ptr;
612
613     va_start(arg_ptr, fmt);
614     bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr);
615     va_end(arg_ptr);
616     fputs(buf, output);
617     if (tee) {
618        fputs(buf, stdout);
619     }
620     fflush(stdout);
621 }