]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/console/console.c
Important protocol change -- see kes29Oct02
[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, 2001 Kern Sibbald and John Walker
12
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License
15    as published by the Free Software Foundation; either version 2
16    of the License, or (at your option) any later version.
17
18    This program 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
21    GNU General Public License for more details.
22
23    You should have received a copy of the GNU General Public License
24    along with this program; if not, write to the Free Software
25    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #include "bacula.h"
29 #include "console_conf.h"
30 #include "jcr.h"
31 #include <termios.h>
32  
33 /* Imported functions */
34 int authenticate_director(JCR *jcr, DIRRES *director);
35
36        
37 /* Exported variables */
38
39
40 #ifdef HAVE_CYGWIN
41 int rl_catch_signals;
42 #else
43 extern int rl_catch_signals;
44 #endif
45
46 /* Forward referenced functions */
47 static void terminate_console(int sig);
48 int get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec);
49
50 /* Static variables */
51 static char *configfile = NULL;
52 static BSOCK *UA_sock = NULL;
53 static DIRRES *dir; 
54 static FILE *output = stdout;
55 static int stop = FALSE;
56
57
58 #define CONFIG_FILE "./console.conf"   /* default configuration file */
59
60 static void usage()
61 {
62    fprintf(stderr,
63 "\nVersion: " VERSION " (" DATE ")\n\n"
64 "Usage: console [-s] [-c config_file] [-d debug_level] [config_file]\n"
65 "       -c <file>   set configuration file to file\n"
66 "       -dnn        set debug level to nn\n"
67 "       -s          no signals\n"
68 "       -t          test - read configuration and exit\n"
69 "       -?          print this message.\n"  
70 "\n");
71
72    exit(1);
73 }
74
75
76 void got_stop(int sig)
77 {
78    stop = TRUE;
79 }
80
81 void got_continue(int sig)
82 {
83    stop = FALSE;
84 }
85
86 void got_tout(int sig) 
87 {
88 // printf("Got tout\n");
89 }
90
91 void got_tin(int sig)
92 {   
93 // printf("Got tin\n");
94 }
95
96
97 static void read_and_process_input(FILE *input, BSOCK *UA_sock) 
98 {
99    char *prompt = "*";
100    int at_prompt = FALSE;
101    int tty_input = isatty(fileno(input));
102    int stat;
103
104    for ( ;; ) { 
105       if (at_prompt) {                /* don't prompt multiple times */
106          prompt = "";
107       } else {
108          prompt = "*";
109          at_prompt = TRUE;
110       }
111       if (tty_input) {
112          stat = get_cmd(input, prompt, UA_sock, 30);
113       } else {
114          int len = sizeof_pool_memory(UA_sock->msg) - 1;
115          if (fgets(UA_sock->msg, len, input) == NULL) {
116             stat = -1;
117          } else {
118             strip_trailing_junk(UA_sock->msg);
119             UA_sock->msglen = strlen(UA_sock->msg);
120             stat = 1;
121          }
122       }
123       if (stat < 0) {
124          break;                       /* error */
125       } else if (stat == 0) {         /* timeout */
126          bnet_fsend(UA_sock, ".messages");
127       } else {
128          at_prompt = FALSE;
129          if (!bnet_send(UA_sock)) {   /* send command */
130             break;                    /* error */
131          }
132       }
133       if (strcmp(UA_sock->msg, ".quit") == 0 || strcmp(UA_sock->msg, ".exit") == 0) {
134          break;
135       }
136       while ((stat = bnet_recv(UA_sock)) >= 0) {
137          if (at_prompt) {
138             if (!stop) {
139                fprintf(output, "\n");
140             }
141             at_prompt = FALSE;
142          }
143          if (!stop) {
144             fprintf(output, "%s", UA_sock->msg);
145          }
146       }
147       if (!stop) {
148          fflush(output);
149       }
150       if (is_bnet_stop(UA_sock)) {
151          break;                       /* error or term */
152       } else if (stat == BNET_SIGNAL) {
153          if (UA_sock->msglen == BNET_PROMPT) {
154             at_prompt = TRUE;
155          }
156          Dmsg1(100, "Got poll %s\n", bnet_sig_to_ascii(UA_sock));
157       }
158    }
159 }
160
161
162 /*********************************************************************
163  *
164  *         Main Bacula Console -- User Interface Program
165  *
166  */
167 int main(int argc, char *argv[])
168 {
169    int ch, i, ndir, item;
170    int no_signals = FALSE;
171    int test_config = FALSE;
172    JCR jcr;
173
174    init_stack_dump();
175    my_name_is(argc, argv, "console");
176    init_msg(NULL, NULL);
177    working_directory = "/tmp";
178
179    while ((ch = getopt(argc, argv, "bc:d:r:st?")) != -1) {
180       switch (ch) {
181          case 'c':                    /* configuration file */
182             if (configfile != NULL)
183                free(configfile);
184             configfile = bstrdup(optarg);
185             break;
186
187          case 'd':
188             debug_level = atoi(optarg);
189             if (debug_level <= 0)
190                debug_level = 1;
191             break;
192
193          case 's':                    /* turn off signals */
194             no_signals = TRUE;
195             break;
196
197          case 't':
198             test_config = TRUE;
199             break;
200
201          case '?':
202          default:
203             usage();
204
205       }  
206    }
207    argc -= optind;
208    argv += optind;
209
210    if (!no_signals) {
211       init_signals(terminate_console);
212    }
213    signal(SIGCHLD, SIG_IGN);
214    signal(SIGTSTP, got_stop);
215    signal(SIGCONT, got_continue);
216    signal(SIGTTIN, got_tin);
217    signal(SIGTTOU, got_tout);
218
219    if (argc) {
220       usage();
221    }
222
223    if (configfile == NULL) {
224       configfile = bstrdup(CONFIG_FILE);
225    }
226
227    parse_config(configfile);
228
229    LockRes();
230    ndir = 0;
231    for (dir=NULL; (dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir)); ) {
232       ndir++;
233    }
234    UnlockRes();
235    if (ndir == 0) {
236       Emsg1(M_ABORT, 0, "No Director resource defined in %s\n\
237 Without that I don't how to speak to the Director :-(\n", configfile);
238    }
239
240    if (test_config) {
241       terminate_console(0);
242       exit(0);
243    }
244
245    memset(&jcr, 0, sizeof(jcr));
246
247    if (ndir > 1) {
248       UA_sock = init_bsock(NULL, 0, "", "", 0);
249 try_again:
250       fprintf(output, "Available Directors:\n");
251       LockRes();
252       ndir = 0;
253       for (dir = NULL; (dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir)); ) {
254          fprintf(output, "%d  %s at %s:%d\n", 1+ndir++, dir->hdr.name, dir->address,
255             dir->DIRport);
256       }
257       UnlockRes();
258       if (get_cmd(stdin, "Select Director: ", UA_sock, 600) < 0) {
259          return 1;
260       }
261       item = atoi(UA_sock->msg);
262       if (item < 0 || item > ndir) {
263          fprintf(output, "You must enter a number between 1 and %d\n", ndir);
264          goto try_again;
265       }
266       LockRes();
267       dir = NULL;
268       for (i=0; i<item; i++) {
269          dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir);
270       }
271       UnlockRes();
272       term_bsock(UA_sock);
273    } else {
274       LockRes();
275       dir = (DIRRES *)GetNextRes(R_DIRECTOR, NULL);
276       UnlockRes();
277    }
278       
279
280    Dmsg2(-1, "Connecting to Director %s:%d\n", dir->address,dir->DIRport);
281    UA_sock = bnet_connect(&jcr, 5, 15, "Director daemon", dir->address, 
282                           NULL, dir->DIRport, 0);
283    if (UA_sock == NULL) {
284       terminate_console(0);
285       return 1;
286    }
287    jcr.dir_bsock = UA_sock;
288    if (!authenticate_director(&jcr, dir)) {
289       fprintf(stderr, "ERR: %s", UA_sock->msg);
290       terminate_console(0);
291       return 1;
292    }
293
294    Dmsg0(40, "Opened connection with Director daemon\n");
295
296    read_and_process_input(stdin, UA_sock);
297
298    if (UA_sock) {
299       bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
300       bnet_close(UA_sock);
301    }
302
303    terminate_console(0);
304    return 0;
305 }
306
307
308 /* Cleanup and then exit */
309 static void terminate_console(int sig)
310 {
311    static int already_here = FALSE;
312
313    if (already_here)                  /* avoid recursive temination problems */
314       exit(1);
315    already_here = TRUE;
316    exit(0);
317 }
318
319 #ifdef HAVE_READLINE
320 #undef free
321 #include "readline/readline.h"
322 #include "readline/history.h"
323
324
325 int 
326 get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec)
327 {
328    char *line;
329
330    rl_catch_signals = 1;
331    line = readline(prompt);
332
333    if (!line) {
334       exit(1);
335    }
336    strcpy(sock->msg, line);
337    strip_trailing_junk(sock->msg);
338    sock->msglen = strlen(sock->msg);
339    if (sock->msglen) {
340       add_history(sock->msg);
341    }
342    free(line);
343    return 1;
344 }
345
346 #else /* no readline, do it ourselves */
347
348 /*
349  *   Returns: 1 if data available
350  *            0 if timeout
351  *           -1 if error
352  */
353 static int
354 wait_for_data(int fd, int sec)
355 {
356    fd_set fdset;
357    struct timeval tv;
358
359    FD_ZERO(&fdset);
360    FD_SET(fd, &fdset);
361    tv.tv_sec = sec;
362    tv.tv_usec = 0;
363    for ( ;; ) {
364       switch(select(fd + 1, &fdset, NULL, NULL, &tv)) {
365          case 0:                         /* timeout */
366             return 0;
367          case -1:
368             if (errno == EINTR || errno == EAGAIN) {
369                continue;
370             }
371             return -1;                  /* error return */
372          default:
373             return 1;
374       }
375    }
376 }
377
378 /*      
379  * Get next input command from terminal. 
380  *
381  *   Returns: 1 if got input
382  *            0 if timeout
383  *           -1 if EOF or error
384  */
385 int 
386 get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec)
387 {
388    int len;  
389    if (!stop) {
390       fprintf(output, prompt);
391       fflush(output);
392    }
393 again:
394    switch (wait_for_data(fileno(input), sec)) {
395       case 0:
396          return 0;                    /* timeout */
397       case -1: 
398          return -1;                   /* error */
399       default:
400          len = sizeof_pool_memory(sock->msg) - 1;
401          if (stop) {
402             goto again;
403          }
404          if (fgets(sock->msg, len, input) == NULL) {
405             return -1;
406          }
407          break;
408    }
409    strip_trailing_junk(sock->msg);
410    sock->msglen = strlen(sock->msg);
411    return 1;
412 }
413
414 #endif