]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/console/console.c
82af3448a553e1df283b3e3f7a60d068ed657682
[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 " (" BDATE ")\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                putc('\n', output);
140             }
141             at_prompt = FALSE;
142          }
143          if (!stop) {
144             fputs(UA_sock->msg, output);
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             }
185             configfile = bstrdup(optarg);
186             break;
187
188          case 'd':
189             debug_level = atoi(optarg);
190             if (debug_level <= 0) {
191                debug_level = 1;
192             }
193             break;
194
195          case 's':                    /* turn off signals */
196             no_signals = TRUE;
197             break;
198
199          case 't':
200             test_config = TRUE;
201             break;
202
203          case '?':
204          default:
205             usage();
206
207       }  
208    }
209    argc -= optind;
210    argv += optind;
211
212    if (!no_signals) {
213       init_signals(terminate_console);
214    }
215    signal(SIGCHLD, SIG_IGN);
216    signal(SIGTSTP, got_stop);
217    signal(SIGCONT, got_continue);
218    signal(SIGTTIN, got_tin);
219    signal(SIGTTOU, got_tout);
220
221    if (argc) {
222       usage();
223    }
224
225    if (configfile == NULL) {
226       configfile = bstrdup(CONFIG_FILE);
227    }
228
229    parse_config(configfile);
230
231    LockRes();
232    ndir = 0;
233    for (dir=NULL; (dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir)); ) {
234       ndir++;
235    }
236    UnlockRes();
237    if (ndir == 0) {
238       Emsg1(M_ERROR_TERM, 0, "No Director resource defined in %s\n\
239 Without that I don't how to speak to the Director :-(\n", configfile);
240    }
241
242    if (test_config) {
243       terminate_console(0);
244       exit(0);
245    }
246
247    memset(&jcr, 0, sizeof(jcr));
248
249    if (ndir > 1) {
250       UA_sock = init_bsock(NULL, 0, "", "", 0);
251 try_again:
252       fprintf(output, "Available Directors:\n");
253       LockRes();
254       ndir = 0;
255       for (dir = NULL; (dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir)); ) {
256          fprintf(output, "%d  %s at %s:%d\n", 1+ndir++, dir->hdr.name, dir->address,
257             dir->DIRport);
258       }
259       UnlockRes();
260       if (get_cmd(stdin, "Select Director: ", UA_sock, 600) < 0) {
261          return 1;
262       }
263       item = atoi(UA_sock->msg);
264       if (item < 0 || item > ndir) {
265          fprintf(output, "You must enter a number between 1 and %d\n", ndir);
266          goto try_again;
267       }
268       LockRes();
269       dir = NULL;
270       for (i=0; i<item; i++) {
271          dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir);
272       }
273       UnlockRes();
274       term_bsock(UA_sock);
275    } else {
276       LockRes();
277       dir = (DIRRES *)GetNextRes(R_DIRECTOR, NULL);
278       UnlockRes();
279    }
280       
281
282    Dmsg2(-1, "Connecting to Director %s:%d\n", dir->address,dir->DIRport);
283    UA_sock = bnet_connect(NULL, 5, 15, "Director daemon", dir->address, 
284                           NULL, dir->DIRport, 0);
285    if (UA_sock == NULL) {
286       terminate_console(0);
287       return 1;
288    }
289    jcr.dir_bsock = UA_sock;
290    if (!authenticate_director(&jcr, dir)) {
291       fprintf(stderr, "ERR=%s", UA_sock->msg);
292       terminate_console(0);
293       return 1;
294    }
295
296    Dmsg0(40, "Opened connection with Director daemon\n");
297
298    read_and_process_input(stdin, UA_sock);
299
300    if (UA_sock) {
301       bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
302       bnet_close(UA_sock);
303    }
304
305    terminate_console(0);
306    return 0;
307 }
308
309
310 /* Cleanup and then exit */
311 static void terminate_console(int sig)
312 {
313    static int already_here = FALSE;
314
315    if (already_here) {                /* avoid recursive temination problems */
316       exit(1);
317    }
318    already_here = TRUE;
319    exit(0);
320 }
321
322 #ifdef HAVE_READLINE
323 #undef free
324 #include "readline/readline.h"
325 #include "readline/history.h"
326
327
328 int 
329 get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec)
330 {
331    char *line;
332
333    rl_catch_signals = 0;              /* do it ourselves */
334    line = readline(prompt);
335
336    if (!line) {
337       exit(1);
338    }
339    strcpy(sock->msg, line);
340    strip_trailing_junk(sock->msg);
341    sock->msglen = strlen(sock->msg);
342    if (sock->msglen) {
343       add_history(sock->msg);
344    }
345    free(line);
346    return 1;
347 }
348
349 #else /* no readline, do it ourselves */
350
351 /*
352  *   Returns: 1 if data available
353  *            0 if timeout
354  *           -1 if error
355  */
356 static int
357 wait_for_data(int fd, int sec)
358 {
359    fd_set fdset;
360    struct timeval tv;
361
362    FD_ZERO(&fdset);
363    FD_SET(fd, &fdset);
364    tv.tv_sec = sec;
365    tv.tv_usec = 0;
366    for ( ;; ) {
367       switch(select(fd + 1, &fdset, NULL, NULL, &tv)) {
368          case 0:                         /* timeout */
369             return 0;
370          case -1:
371             if (errno == EINTR || errno == EAGAIN) {
372                continue;
373             }
374             return -1;                  /* error return */
375          default:
376             return 1;
377       }
378    }
379 }
380
381 /*      
382  * Get next input command from terminal. 
383  *
384  *   Returns: 1 if got input
385  *            0 if timeout
386  *           -1 if EOF or error
387  */
388 int 
389 get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec)
390 {
391    int len;  
392    if (!stop) {
393       fputs(prompt, output);
394       fflush(output);
395    }
396 again:
397    switch (wait_for_data(fileno(input), sec)) {
398       case 0:
399          return 0;                    /* timeout */
400       case -1: 
401          return -1;                   /* error */
402       default:
403          len = sizeof_pool_memory(sock->msg) - 1;
404          if (stop) {
405             goto again;
406          }
407          if (fgets(sock->msg, len, input) == NULL) {
408             return -1;
409          }
410          break;
411    }
412    strip_trailing_junk(sock->msg);
413    sock->msglen = strlen(sock->msg);
414    return 1;
415 }
416
417 #endif