3 * Bacula Console interface to the Director
5 * Kern Sibbald, September MM
11 Copyright (C) 2000, 2001 Kern Sibbald and John Walker
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.
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.
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.
29 #include "console_conf.h"
32 /* Imported functions */
33 int authenticate_director(JCR *jcr, DIRRES *director);
36 /* Exported variables */
42 extern int rl_catch_signals;
45 /* Forward referenced functions */
46 static void terminate_console(int sig);
47 int get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec);
49 /* Static variables */
50 static char *configfile = NULL;
51 static BSOCK *UA_sock = NULL;
53 static FILE *output = stdout;
54 static int stop = FALSE;
57 #define CONFIG_FILE "./console.conf" /* default configuration file */
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"
67 " -t test - read configuration and exit\n"
68 " -? print this message.\n"
75 void got_stop(int sig)
80 void got_continue(int sig)
85 void got_tout(int sig)
87 // printf("Got tout\n");
92 // printf("Got tin\n");
96 static void read_and_process_input(FILE *input, BSOCK *UA_sock)
99 int at_prompt = FALSE;
100 int tty_input = isatty(fileno(input));
104 if (at_prompt) { /* don't prompt multiple times */
111 stat = get_cmd(input, prompt, UA_sock, 30);
113 int len = sizeof_pool_memory(UA_sock->msg) - 1;
114 if (fgets(UA_sock->msg, len, input) == NULL) {
117 strip_trailing_junk(UA_sock->msg);
118 UA_sock->msglen = strlen(UA_sock->msg);
124 } else if (stat == 0) { /* timeout */
125 bnet_fsend(UA_sock, ".messages");
128 if (!bnet_send(UA_sock)) { /* send command */
132 if (strcmp(UA_sock->msg, ".quit") == 0 || strcmp(UA_sock->msg, ".exit") == 0) {
135 while ((stat = bnet_recv(UA_sock)) >= 0) {
143 fputs(UA_sock->msg, output);
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) {
155 Dmsg1(100, "Got poll %s\n", bnet_sig_to_ascii(UA_sock));
161 /*********************************************************************
163 * Main Bacula Console -- User Interface Program
166 int main(int argc, char *argv[])
168 int ch, i, ndir, item;
169 int no_signals = FALSE;
170 int test_config = FALSE;
174 my_name_is(argc, argv, "console");
175 init_msg(NULL, NULL);
176 working_directory = "/tmp";
178 while ((ch = getopt(argc, argv, "bc:d:r:st?")) != -1) {
180 case 'c': /* configuration file */
181 if (configfile != NULL) {
184 configfile = bstrdup(optarg);
188 debug_level = atoi(optarg);
189 if (debug_level <= 0) {
194 case 's': /* turn off signals */
212 init_signals(terminate_console);
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);
224 if (configfile == NULL) {
225 configfile = bstrdup(CONFIG_FILE);
228 parse_config(configfile);
232 for (dir=NULL; (dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir)); ) {
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);
242 terminate_console(0);
246 memset(&jcr, 0, sizeof(jcr));
249 UA_sock = init_bsock(NULL, 0, "", "", 0);
251 fprintf(output, "Available Directors:\n");
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,
259 if (get_cmd(stdin, "Select Director: ", UA_sock, 600) < 0) {
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);
269 for (i=0; i<item; i++) {
270 dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir);
276 dir = (DIRRES *)GetNextRes(R_DIRECTOR, NULL);
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);
288 jcr.dir_bsock = UA_sock;
289 if (!authenticate_director(&jcr, dir)) {
290 fprintf(stderr, "ERR=%s", UA_sock->msg);
291 terminate_console(0);
295 Dmsg0(40, "Opened connection with Director daemon\n");
297 read_and_process_input(stdin, UA_sock);
300 bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
304 terminate_console(0);
309 /* Cleanup and then exit */
310 static void terminate_console(int sig)
312 static int already_here = FALSE;
314 if (already_here) { /* avoid recursive temination problems */
323 #include "readline/readline.h"
324 #include "readline/history.h"
328 get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec)
332 rl_catch_signals = 0; /* do it ourselves */
333 line = readline(prompt);
338 strcpy(sock->msg, line);
339 strip_trailing_junk(sock->msg);
340 sock->msglen = strlen(sock->msg);
342 add_history(sock->msg);
348 #else /* no readline, do it ourselves */
351 * Returns: 1 if data available
356 wait_for_data(int fd, int sec)
366 switch(select(fd + 1, &fdset, NULL, NULL, &tv)) {
367 case 0: /* timeout */
370 if (errno == EINTR || errno == EAGAIN) {
373 return -1; /* error return */
381 * Get next input command from terminal.
383 * Returns: 1 if got input
388 get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec)
392 fputs(prompt, output);
396 switch (wait_for_data(fileno(input), sec)) {
398 return 0; /* timeout */
400 return -1; /* error */
402 len = sizeof_pool_memory(sock->msg) - 1;
406 if (fgets(sock->msg, len, input) == NULL) {
411 strip_trailing_junk(sock->msg);
412 sock->msglen = strlen(sock->msg);