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