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