]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/console/console.c
ebl Add readline history support to bconsole.
[bacula/bacula] / bacula / src / console / console.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *
30  *   Bacula Console interface to the Director
31  *
32  *     Kern Sibbald, September MM
33  *
34  *     Version $Id$
35  */
36
37 #include "bacula.h"
38 #include "console_conf.h"
39 #include "jcr.h"
40
41
42 #ifdef HAVE_CONIO
43 #include "conio.h"
44 //#define CONIO_FIX 1
45 #else
46 #define con_init(x)
47 #define con_term()
48 #define con_set_zed_keys();
49 #define trapctlc()
50 #define clrbrk()
51 #define usrbrk() 0
52 #endif
53
54 #if defined(HAVE_WIN32)
55 #define isatty(fd) (fd==0)
56 #endif
57
58 /* Exported variables */
59
60 //extern int rl_catch_signals;
61
62 /* Imported functions */
63 int authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons);
64
65 /* Forward referenced functions */
66 static void terminate_console(int sig);
67 static int check_resources();
68 int get_cmd(FILE *input, const char *prompt, BSOCK *sock, int sec);
69 static int do_outputcmd(FILE *input, BSOCK *UA_sock);
70 void senditf(const char *fmt, ...);
71 void sendit(const char *buf);
72
73 extern "C" void got_sigstop(int sig);
74 extern "C" void got_sigcontinue(int sig);
75 extern "C" void got_sigtout(int sig);
76 extern "C" void got_sigtin(int sig);
77
78
79 /* Static variables */
80 static char *configfile = NULL;
81 static BSOCK *UA_sock = NULL;
82 static DIRRES *dir = NULL;
83 static CONRES *cons = NULL;
84 static FILE *output = stdout;
85 static bool teeout = false;               /* output to output and stdout */
86 static bool stop = false;
87 static bool no_conio = false;
88 static int argc;
89 static int numdir;
90 static int numcon;
91 static POOLMEM *args;
92 static char *argk[MAX_CMD_ARGS];
93 static char *argv[MAX_CMD_ARGS];
94
95
96 /* Command prototypes */
97 static int versioncmd(FILE *input, BSOCK *UA_sock);
98 static int inputcmd(FILE *input, BSOCK *UA_sock);
99 static int outputcmd(FILE *input, BSOCK *UA_sock);
100 static int teecmd(FILE *input, BSOCK *UA_sock);
101 static int quitcmd(FILE *input, BSOCK *UA_sock);
102 static int echocmd(FILE *input, BSOCK *UA_sock);
103 static int timecmd(FILE *input, BSOCK *UA_sock);
104 static int sleepcmd(FILE *input, BSOCK *UA_sock);
105 static int execcmd(FILE *input, BSOCK *UA_sock);
106
107
108 #define CONFIG_FILE "bconsole.conf"   /* default configuration file */
109
110 static void usage()
111 {
112    fprintf(stderr, _(
113 PROG_COPYRIGHT
114 "\nVersion: " VERSION " (" BDATE ") %s %s %s\n\n"
115 "Usage: bconsole [-s] [-c config_file] [-d debug_level]\n"
116 "       -c <file>   set configuration file to file\n"
117 "       -dnn        set debug level to nn\n"
118 "       -n          no conio\n"
119 "       -s          no signals\n"
120 "       -t          test - read configuration and exit\n"
121 "       -?          print this message.\n"
122 "\n"), 2000, HOST_OS, DISTNAME, DISTVER);
123 }
124
125
126 extern "C"
127 void got_sigstop(int sig)
128 {
129    stop = true;
130 }
131
132 extern "C"
133 void got_sigcontinue(int sig)
134 {
135    stop = false;
136 }
137
138 extern "C"
139 void got_sigtout(int sig)
140 {
141 // printf("Got tout\n");
142 }
143
144 extern "C"
145 void got_sigtin(int sig)
146 {
147 // printf("Got tin\n");
148 }
149
150
151 static int zed_keyscmd(FILE *input, BSOCK *UA_sock)
152 {
153    con_set_zed_keys();
154    return 1;
155 }
156
157 /*
158  * These are the @command
159  */
160 struct cmdstruct { const char *key; int (*func)(FILE *input, BSOCK *UA_sock); const char *help; };
161 static struct cmdstruct commands[] = {
162  { N_("input"),      inputcmd,     _("input from file")},
163  { N_("output"),     outputcmd,    _("output to file")},
164  { N_("quit"),       quitcmd,      _("quit")},
165  { N_("tee"),        teecmd,       _("output to file and terminal")},
166  { N_("sleep"),      sleepcmd,     _("sleep specified time")},
167  { N_("time"),       timecmd,      _("print current time")},
168  { N_("version"),    versioncmd,   _("print Console's version")},
169  { N_("echo"),       echocmd,      _("echo command string")},
170  { N_("exec"),       execcmd,      _("execute an external command")},
171  { N_("exit"),       quitcmd,      _("exit = quit")},
172  { N_("zed_keys"),   zed_keyscmd,  _("zed_keys = use zed keys instead of bash keys")},
173              };
174 #define comsize (sizeof(commands)/sizeof(struct cmdstruct))
175
176 static int do_a_command(FILE *input, BSOCK *UA_sock)
177 {
178    unsigned int i;
179    int stat;
180    int found;
181    int len;
182    char *cmd;
183
184    found = 0;
185    stat = 1;
186
187    Dmsg1(120, "Command: %s\n", UA_sock->msg);
188    if (argc == 0) {
189       return 1;
190    }
191
192    cmd = argk[0]+1;
193    if (*cmd == '#') {                 /* comment */
194       return 1;
195    }
196    len = strlen(cmd);
197    for (i=0; i<comsize; i++) {     /* search for command */
198       if (strncasecmp(cmd,  _(commands[i].key), len) == 0) {
199          stat = (*commands[i].func)(input, UA_sock);   /* go execute command */
200          found = 1;
201          break;
202       }
203    }
204    if (!found) {
205       pm_strcat(&UA_sock->msg, _(": is an invalid command\n"));
206       UA_sock->msglen = strlen(UA_sock->msg);
207       sendit(UA_sock->msg);
208    }
209    return stat;
210 }
211
212
213 static void read_and_process_input(FILE *input, BSOCK *UA_sock)
214 {
215    const char *prompt = "*";
216    bool at_prompt = false;
217    int tty_input = isatty(fileno(input));
218    int stat;
219
220    for ( ;; ) {
221       if (at_prompt) {                /* don't prompt multiple times */
222          prompt = "";
223       } else {
224          prompt = "*";
225          at_prompt = true;
226       }
227       if (tty_input) {
228          stat = get_cmd(input, prompt, UA_sock, 30);
229          if (usrbrk() == 1) {
230             clrbrk();
231          }
232          if (usrbrk()) {
233             break;
234          }
235       } else {
236          /* Reading input from a file */
237          int len = sizeof_pool_memory(UA_sock->msg) - 1;
238          if (usrbrk()) {
239             break;
240          }
241          if (fgets(UA_sock->msg, len, input) == NULL) {
242             stat = -1;
243          } else {
244             sendit(UA_sock->msg);  /* echo to terminal */
245             strip_trailing_junk(UA_sock->msg);
246             UA_sock->msglen = strlen(UA_sock->msg);
247             stat = 1;
248          }
249       }
250       if (stat < 0) {
251          break;                       /* error or interrupt */
252       } else if (stat == 0) {         /* timeout */
253          if (strcmp(prompt, "*") == 0) {
254             bnet_fsend(UA_sock, ".messages");
255          } else {
256             continue;
257          }
258       } else {
259          at_prompt = FALSE;
260          /* @ => internal command for us */
261          if (UA_sock->msg[0] == '@') {
262             parse_args(UA_sock->msg, &args, &argc, argk, argv, MAX_CMD_ARGS);
263             if (!do_a_command(input, UA_sock)) {
264                break;
265             }
266             continue;
267          }
268          if (!bnet_send(UA_sock)) {   /* send command */
269             break;                    /* error */
270          }
271       }
272       if (strcmp(UA_sock->msg, ".quit") == 0 || strcmp(UA_sock->msg, ".exit") == 0) {
273          break;
274       }
275       while ((stat = bnet_recv(UA_sock)) >= 0) {
276          if (at_prompt) {
277             if (!stop) {
278                sendit("\n");
279             }
280             at_prompt = false;
281          }
282          /* Suppress output if running in background or user hit ctl-c */
283          if (!stop && !usrbrk()) {
284             sendit(UA_sock->msg);
285          }
286       }
287       if (usrbrk() > 1) {
288          break;
289       } else {
290          clrbrk();
291       }
292       if (!stop) {
293          fflush(stdout);
294       }
295       if (is_bnet_stop(UA_sock)) {
296          break;                       /* error or term */
297       } else if (stat == BNET_SIGNAL) {
298          if (UA_sock->msglen == BNET_PROMPT) {
299             at_prompt = true;
300          }
301          Dmsg1(100, "Got poll %s\n", bnet_sig_to_ascii(UA_sock));
302       }
303    }
304 }
305
306 /*
307  * Call-back for reading a passphrase for an encrypted PEM file
308  * This function uses getpass(), 
309  *  which uses a static buffer and is NOT thread-safe.
310  */
311 static int tls_pem_callback(char *buf, int size, const void *userdata)
312 {
313 #ifdef HAVE_TLS
314    const char *prompt = (const char *)userdata;
315 # if defined(HAVE_WIN32)
316    sendit(prompt);
317    if (win32_cgets(buf, size) == NULL) {
318       buf[0] = 0;
319       return 0;
320    } else {
321       return strlen(buf);
322    }
323 # else
324    char *passwd;
325
326    passwd = getpass(prompt);
327    bstrncpy(buf, passwd, size);
328    return strlen(buf);
329 # endif
330 #else
331    buf[0] = 0;
332    return 0;
333 #endif
334 }
335
336 #ifdef HAVE_READLINE
337 #define READLINE_LIBRARY 1
338 #undef free
339 #include "readline.h"
340 #include "history.h"
341
342 int
343 get_cmd(FILE *input, const char *prompt, BSOCK *sock, int sec)
344 {
345    char *line;
346
347    rl_catch_signals = 0;              /* do it ourselves */
348    line = readline((char *)prompt);   /* cast needed for old readlines */
349
350    if (!line) {
351       exit(1);
352    }
353    strip_trailing_junk(line);
354    sock->msglen = pm_strcpy(&sock->msg, line);
355    if (sock->msglen) {
356       add_history(sock->msg);
357    }
358    free(line);
359    return 1;
360 }
361
362 #else /* no readline, do it ourselves */
363
364 #if !defined(HAVE_WIN32)
365 static bool bisatty(int fd)
366 {
367    if (no_conio) {
368       return false;
369    }
370    return isatty(fd);
371 }
372 #endif
373
374 /*
375  *   Returns: 1 if data available
376  *            0 if timeout
377  *           -1 if error
378  */
379 static int
380 wait_for_data(int fd, int sec)
381 {
382 #if defined(HAVE_WIN32)
383    return 1;
384 #else
385    fd_set fdset;
386    struct timeval tv;
387
388    tv.tv_sec = sec;
389    tv.tv_usec = 0;
390    for ( ;; ) {
391       FD_ZERO(&fdset);
392       FD_SET((unsigned)fd, &fdset);
393       switch(select(fd + 1, &fdset, NULL, NULL, &tv)) {
394       case 0:                         /* timeout */
395          return 0;
396       case -1:
397          if (errno == EINTR || errno == EAGAIN) {
398             continue;
399          }
400          return -1;                  /* error return */
401       default:
402          return 1;
403       }
404    }
405 #endif
406 }
407
408 /*
409  * Get next input command from terminal.
410  *
411  *   Returns: 1 if got input
412  *            0 if timeout
413  *           -1 if EOF or error
414  */
415 int
416 get_cmd(FILE *input, const char *prompt, BSOCK *sock, int sec)
417 {
418    int len;
419    if (!stop) {
420       if (output == stdout || teeout) {
421          sendit(prompt);
422       }
423    }
424 again:
425    switch (wait_for_data(fileno(input), sec)) {
426    case 0:
427       return 0;                    /* timeout */
428    case -1:
429       return -1;                   /* error */
430    default:
431       len = sizeof_pool_memory(sock->msg) - 1;
432       if (stop) {
433          sleep(1);
434          goto again;
435       }
436 #ifdef HAVE_CONIO
437       if (bisatty(fileno(input))) {
438          input_line(sock->msg, len);
439          break;
440       }
441 #endif
442 #ifdef HAVE_WIN32 /* use special console for input on win32 */
443       if (input == stdin) {
444          if (win32_cgets(sock->msg, len) == NULL) {
445             return -1;
446          }
447       }
448       else
449 #endif
450       if (fgets(sock->msg, len, input) == NULL) {
451          return -1;
452
453       }
454       break;
455    }
456    if (usrbrk()) {
457       clrbrk();
458    }
459    strip_trailing_junk(sock->msg);
460    sock->msglen = strlen(sock->msg);
461    return 1;
462 }
463
464 #endif /* ! HAVE_READLINE */
465
466
467 static int console_update_history(const char *histfile)
468 {
469    int ret=0;
470
471 #ifdef HAVE_READLINE
472 /* first, try to truncate the history file, and if it
473  * fail, the file is probably not present, and we
474  * can use write_history to create it
475  */
476
477    if (history_truncate_file(histfile, 100) == 0) {
478       ret = append_history(history_length, histfile);
479    } else {
480       ret = write_history(histfile);
481    }
482
483 #endif
484
485    return ret;
486 }
487
488 static int console_init_history(const char *histfile)
489 {
490    int ret=0;
491
492 #ifdef HAVE_READLINE
493
494    using_history();
495    ret = read_history(histfile);
496
497 #endif
498
499    return ret;
500 }
501
502 /*********************************************************************
503  *
504  *         Main Bacula Console -- User Interface Program
505  *
506  */
507 int main(int argc, char *argv[])
508 {
509    int ch, i, item;
510    bool no_signals = false;
511    bool test_config = false;
512    JCR jcr;
513    utime_t heart_beat;
514
515    setlocale(LC_ALL, "");
516    bindtextdomain("bacula", LOCALEDIR);
517    textdomain("bacula");
518
519    init_stack_dump();
520    my_name_is(argc, argv, "bconsole");
521    init_msg(NULL, NULL);
522    working_directory = "/tmp";
523    args = get_pool_memory(PM_FNAME);
524
525    while ((ch = getopt(argc, argv, "bc:d:nst?")) != -1) {
526       switch (ch) {
527       case 'c':                    /* configuration file */
528          if (configfile != NULL) {
529             free(configfile);
530          }
531          configfile = bstrdup(optarg);
532          break;
533
534       case 'd':
535          debug_level = atoi(optarg);
536          if (debug_level <= 0) {
537             debug_level = 1;
538          }
539          break;
540
541       case 'n':                    /* no conio */
542          no_conio = true;
543          break;
544
545       case 's':                    /* turn off signals */
546          no_signals = true;
547          break;
548
549       case 't':
550          test_config = true;
551          break;
552
553       case '?':
554       default:
555          usage();
556          exit(1);
557       }
558    }
559    argc -= optind;
560    argv += optind;
561
562    if (!no_signals) {
563       init_signals(terminate_console);
564    }
565
566
567 #if !defined(HAVE_WIN32)
568    /* Override Bacula default signals */
569    signal(SIGQUIT, SIG_IGN);
570    signal(SIGTSTP, got_sigstop);
571    signal(SIGCONT, got_sigcontinue);
572    signal(SIGTTIN, got_sigtin);
573    signal(SIGTTOU, got_sigtout);
574    trapctlc();
575 #endif
576
577    OSDependentInit();
578
579    if (argc) {
580       usage();
581       exit(1);
582    }
583
584    if (configfile == NULL) {
585       configfile = bstrdup(CONFIG_FILE);
586    }
587
588    parse_config(configfile);
589
590    if (init_crypto() != 0) {
591       Emsg0(M_ERROR_TERM, 0, _("Cryptography library initialization failed.\n"));
592    }
593
594    if (!check_resources()) {
595       Emsg1(M_ERROR_TERM, 0, _("Please correct configuration file: %s\n"), configfile);
596    }
597
598    if (!no_conio) {
599       con_init(stdin);
600    }
601
602    if (test_config) {
603       terminate_console(0);
604       exit(0);
605    }
606
607    memset(&jcr, 0, sizeof(jcr));
608
609    (void)WSA_Init();                        /* Initialize Windows sockets */
610
611    LockRes();
612    numdir = 0;
613    foreach_res(dir, R_DIRECTOR) {
614       numdir++;
615    }
616    numcon = 0;
617    foreach_res(cons, R_CONSOLE) {
618       numcon++;
619    }
620    UnlockRes();
621
622    if (numdir > 1) {
623       struct sockaddr client_addr;
624       memset(&client_addr, 0, sizeof(client_addr));
625       UA_sock = init_bsock(NULL, 0, "", "", 0, &client_addr);
626 try_again:
627       sendit(_("Available Directors:\n"));
628       LockRes();
629       numdir = 0;
630       foreach_res(dir, R_DIRECTOR) {
631          senditf( _("%2d:  %s at %s:%d\n"), 1+numdir++, dir->hdr.name, dir->address,
632             dir->DIRport);
633       }
634       UnlockRes();
635       if (get_cmd(stdin, _("Select Director by entering a number: "), UA_sock, 600) < 0) {
636          (void)WSACleanup();               /* Cleanup Windows sockets */
637          return 1;
638       }
639       if (!is_a_number(UA_sock->msg)) {
640          senditf(_("%s is not a number. You must enter a number between 1 and %d\n"), 
641                  UA_sock->msg, numdir);
642          goto try_again;
643       }
644       item = atoi(UA_sock->msg);
645       if (item < 0 || item > numdir) {
646          senditf(_("You must enter a number between 1 and %d\n"), numdir);
647          goto try_again;
648       }
649       term_bsock(UA_sock);
650       LockRes();
651       for (i=0; i<item; i++) {
652          dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir);
653       }
654       /* Look for a console linked to this director */
655       for (i=0; i<numcon; i++) {
656          cons = (CONRES *)GetNextRes(R_CONSOLE, (RES *)cons);
657          if (cons->director && strcmp(cons->director, dir->hdr.name) == 0) {
658             break;
659          }
660          cons = NULL;
661       }
662       /* Look for the first non-linked console */
663       if (cons == NULL) {
664          for (i=0; i<numcon; i++) {
665             cons = (CONRES *)GetNextRes(R_CONSOLE, (RES *)cons);
666             if (cons->director == NULL)
667                break;
668             cons = NULL;
669         }
670       }
671       UnlockRes();
672    }
673    /* If no director, take first one */
674    if (!dir) {
675       LockRes();
676       dir = (DIRRES *)GetNextRes(R_DIRECTOR, NULL);
677       UnlockRes();
678    }
679    /* If no console, take first one */
680    if (!cons) {
681       LockRes();
682       cons = (CONRES *)GetNextRes(R_CONSOLE, (RES *)NULL);
683       UnlockRes();
684    }
685
686    senditf(_("Connecting to Director %s:%d\n"), dir->address,dir->DIRport);
687
688    char buf[1024];
689    /* Initialize Console TLS context */
690    if (cons && (cons->tls_enable || cons->tls_require)) {
691       /* Generate passphrase prompt */
692       bsnprintf(buf, sizeof(buf), "Passphrase for Console \"%s\" TLS private key: ", cons->hdr.name);
693
694       /* Initialize TLS context:
695        * Args: CA certfile, CA certdir, Certfile, Keyfile,
696        * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer   
697        */
698       cons->tls_ctx = new_tls_context(cons->tls_ca_certfile,
699          cons->tls_ca_certdir, cons->tls_certfile,
700          cons->tls_keyfile, tls_pem_callback, &buf, NULL, true);
701
702       if (!cons->tls_ctx) {
703          senditf(_("Failed to initialize TLS context for Console \"%s\".\n"),
704             dir->hdr.name);
705          terminate_console(0);
706          return 1;
707       }
708    }
709
710    /* Initialize Director TLS context */
711    if (dir->tls_enable || dir->tls_require) {
712       /* Generate passphrase prompt */
713       bsnprintf(buf, sizeof(buf), "Passphrase for Director \"%s\" TLS private key: ", dir->hdr.name);
714
715       /* Initialize TLS context:
716        * Args: CA certfile, CA certdir, Certfile, Keyfile,
717        * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */
718       dir->tls_ctx = new_tls_context(dir->tls_ca_certfile,
719          dir->tls_ca_certdir, dir->tls_certfile,
720          dir->tls_keyfile, tls_pem_callback, &buf, NULL, true);
721
722       if (!dir->tls_ctx) {
723          senditf(_("Failed to initialize TLS context for Director \"%s\".\n"),
724             dir->hdr.name);
725          terminate_console(0);
726          return 1;
727       }
728    }
729
730    if (dir->heartbeat_interval) {
731       heart_beat = dir->heartbeat_interval;
732    } else if (cons) {
733       heart_beat = cons->heartbeat_interval;
734    } else {
735       heart_beat = 0;
736    }
737    UA_sock = bnet_connect(NULL, 5, 15, heart_beat, "Director daemon", dir->address,
738                           NULL, dir->DIRport, 0);
739    if (UA_sock == NULL) {
740       terminate_console(0);
741       return 1;
742    }
743    jcr.dir_bsock = UA_sock;
744
745    /* If cons==NULL, default console will be used */
746    if (!authenticate_director(&jcr, dir, cons)) {
747       terminate_console(0);
748       return 1;
749    }
750
751    Dmsg0(40, "Opened connection with Director daemon\n");
752
753    sendit(_("Enter a period to cancel a command.\n"));
754
755    /* Read/Update history file if HOME exists */
756    POOL_MEM history_file;
757
758    /* Run commands in ~/.bconsolerc if any */
759    char *env = getenv("HOME");
760    if (env) {
761       FILE *fd;
762       pm_strcpy(&UA_sock->msg, env);
763       pm_strcat(&UA_sock->msg, "/.bconsolerc");
764       fd = fopen(UA_sock->msg, "rb");
765       if (fd) {
766          read_and_process_input(fd, UA_sock);
767          fclose(fd);
768       }
769
770       pm_strcpy(history_file, env);
771       pm_strcat(history_file, "/.bconsole_history");
772       console_init_history(history_file.c_str());
773    }
774
775    read_and_process_input(stdin, UA_sock);
776
777    if (UA_sock) {
778       UA_sock->signal(BNET_TERMINATE); /* send EOF */
779       UA_sock->close();
780    }
781
782    if (env) {
783       console_update_history(history_file.c_str());
784    }
785
786    terminate_console(0);
787    return 0;
788 }
789
790 /* Cleanup and then exit */
791 static void terminate_console(int sig)
792 {
793
794    static bool already_here = false;
795
796    if (already_here) {                /* avoid recursive temination problems */
797       exit(1);
798    }
799    already_here = true;
800    cleanup_crypto();
801    free_pool_memory(args);
802    if (!no_conio) {
803       con_term();
804    }
805    (void)WSACleanup();               /* Cleanup Windows sockets */
806    if (sig != 0) {
807       exit(1);
808    }
809    return;
810 }
811
812 /*
813  * Make a quick check to see that we have all the
814  * resources needed.
815  */
816 static int check_resources()
817 {
818    bool OK = true;
819    DIRRES *director;
820
821    LockRes();
822
823    numdir = 0;
824    foreach_res(director, R_DIRECTOR) {
825
826       numdir++;
827       /* tls_require implies tls_enable */
828       if (director->tls_require) {
829          if (have_tls) {
830             director->tls_enable = true;
831          } else {
832             Jmsg(NULL, M_FATAL, 0, _("TLS required but not configured in Bacula.\n"));
833             OK = false;
834             continue;
835          }
836       }
837
838       if ((!director->tls_ca_certfile && !director->tls_ca_certdir) && director->tls_enable) {
839          Emsg2(M_FATAL, 0, _("Neither \"TLS CA Certificate\""
840                              " or \"TLS CA Certificate Dir\" are defined for Director \"%s\" in %s."
841                              " At least one CA certificate store is required.\n"),
842                              director->hdr.name, configfile);
843          OK = false;
844       }
845    }
846    
847    if (numdir == 0) {
848       Emsg1(M_FATAL, 0, _("No Director resource defined in %s\n"
849                           "Without that I don't how to speak to the Director :-(\n"), configfile);
850       OK = false;
851    }
852
853    CONRES *cons;
854    /* Loop over Consoles */
855    foreach_res(cons, R_CONSOLE) {
856       /* tls_require implies tls_enable */
857       if (cons->tls_require) {
858          if (have_tls) {
859             cons->tls_enable = true;
860          } else {
861             Jmsg(NULL, M_FATAL, 0, _("TLS required but not configured in Bacula.\n"));
862             OK = false;
863             continue;
864          }
865       }
866
867       if ((!cons->tls_ca_certfile && !cons->tls_ca_certdir) && cons->tls_enable) {
868          Emsg2(M_FATAL, 0, _("Neither \"TLS CA Certificate\""
869                              " or \"TLS CA Certificate Dir\" are defined for Console \"%s\" in %s.\n"),
870                              cons->hdr.name, configfile);
871          OK = false;
872       }
873    }
874
875    UnlockRes();
876
877    return OK;
878 }
879
880 static int versioncmd(FILE *input, BSOCK *UA_sock)
881 {
882    senditf("Version: " VERSION " (" BDATE ") %s %s %s\n",
883       HOST_OS, DISTNAME, DISTVER);
884    return 1;
885 }
886
887 static int inputcmd(FILE *input, BSOCK *UA_sock)
888 {
889    FILE *fd;
890
891    if (argc > 2) {
892       sendit(_("Too many arguments on input command.\n"));
893       return 1;
894    }
895    if (argc == 1) {
896       sendit(_("First argument to input command must be a filename.\n"));
897       return 1;
898    }
899    fd = fopen(argk[1], "rb");
900    if (!fd) {
901       senditf(_("Cannot open file %s for input. ERR=%s\n"),
902          argk[1], strerror(errno));
903       return 1;
904    }
905    read_and_process_input(fd, UA_sock);
906    fclose(fd);
907    return 1;
908 }
909
910 /* Send output to both termina and specified file */
911 static int teecmd(FILE *input, BSOCK *UA_sock)
912 {
913    teeout = true;
914    return do_outputcmd(input, UA_sock);
915 }
916
917 /* Send output to specified "file" */
918 static int outputcmd(FILE *input, BSOCK *UA_sock)
919 {
920    teeout = false;
921    return do_outputcmd(input, UA_sock);
922 }
923
924
925 static int do_outputcmd(FILE *input, BSOCK *UA_sock)
926 {
927    FILE *fd;
928    const char *mode = "a+b";
929
930    if (argc > 3) {
931       sendit(_("Too many arguments on output/tee command.\n"));
932       return 1;
933    }
934    if (argc == 1) {
935       if (output != stdout) {
936          fclose(output);
937          output = stdout;
938          teeout = false;
939       }
940       return 1;
941    }
942    if (argc == 3) {
943       mode = argk[2];
944    }
945    fd = fopen(argk[1], mode);
946    if (!fd) {
947       berrno be;
948       senditf(_("Cannot open file %s for output. ERR=%s\n"),
949          argk[1], be.bstrerror(errno));
950       return 1;
951    }
952    output = fd;
953    return 1;
954 }
955
956 /*
957  * exec "some-command" [wait-seconds]
958 */
959 static int execcmd(FILE *input, BSOCK *UA_sock)
960 {
961    BPIPE *bpipe;
962    char line[5000];
963    int stat;
964    int wait = 0;
965
966    if (argc > 3) {
967       sendit(_("Too many arguments. Enclose command in double quotes.\n"));
968       return 1;
969    }
970    if (argc == 3) {
971       wait = atoi(argk[2]);
972    }
973    bpipe = open_bpipe(argk[1], wait, "r");
974    if (!bpipe) {
975       berrno be;
976       senditf(_("Cannot popen(\"%s\", \"r\"): ERR=%s\n"),
977          argk[1], be.bstrerror(errno));
978       return 1;
979    }
980   
981    while (fgets(line, sizeof(line), bpipe->rfd)) {
982       senditf("%s", line);
983    }
984    stat = close_bpipe(bpipe);
985    if (stat != 0) {
986       berrno be;
987       be.set_errno(stat);
988      senditf(_("Autochanger error: ERR=%s\n"), be.bstrerror());
989    }
990    return 1;
991 }
992
993
994 static int echocmd(FILE *input, BSOCK *UA_sock)
995 {
996    for (int i=1; i < argc; i++) {
997       senditf("%s", argk[i]);
998       sendit(" ");
999    }
1000    sendit("\n");
1001    return 1;
1002 }
1003
1004 static int quitcmd(FILE *input, BSOCK *UA_sock)
1005 {
1006    return 0;
1007 }
1008
1009 static int sleepcmd(FILE *input, BSOCK *UA_sock)
1010 {
1011    if (argc > 1) {
1012       sleep(atoi(argk[1]));
1013    }
1014    return 1;
1015 }
1016
1017
1018 static int timecmd(FILE *input, BSOCK *UA_sock)
1019 {
1020    char sdt[50];
1021    time_t ttime = time(NULL);
1022    struct tm tm;
1023    (void)localtime_r(&ttime, &tm);
1024    strftime(sdt, sizeof(sdt), "%d-%b-%Y %H:%M:%S", &tm);
1025    sendit("\n");
1026    return 1;
1027 }
1028
1029 /*
1030  * Send a line to the output file and or the terminal
1031  */
1032 void senditf(const char *fmt,...)
1033 {
1034    char buf[3000];
1035    va_list arg_ptr;
1036
1037    va_start(arg_ptr, fmt);
1038    bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr);
1039    va_end(arg_ptr);
1040    sendit(buf);
1041 }
1042
1043 void sendit(const char *buf)
1044 {
1045 #ifdef CONIO_FIX
1046    char obuf[3000];
1047    if (output == stdout || teeout) {
1048       const char *p, *q;
1049       /*
1050        * Here, we convert every \n into \r\n because the
1051        *  terminal is in raw mode when we are using
1052        *  conio.
1053        */
1054       for (p=q=buf; (p=strchr(q, '\n')); ) {
1055          int len = p - q;
1056          if (len > 0) {
1057             memcpy(obuf, q, len);
1058          }
1059          memcpy(obuf+len, "\r\n", 3);
1060          q = ++p;                    /* point after \n */
1061          fputs(obuf, output);
1062       }
1063       if (*q) {
1064          fputs(q, output);
1065       }
1066       fflush(output);
1067    }
1068    if (output != stdout) {
1069       fputs(buf, output);
1070    }
1071 #else
1072
1073    fputs(buf, output);
1074    fflush(output);
1075    if (teeout) {
1076       fputs(buf, stdout);
1077       fflush(stdout);
1078    }
1079 #endif
1080 }