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