3 * Bacula Console interface to the Director
5 * Kern Sibbald, September MM
9 Copyright (C) 2000, 2001 Kern Sibbald and John Walker
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.
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.
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.
28 #include "console_conf.h"
31 /* Imported functions */
32 int authenticate_director(JCR *jcr, DIRRES *director);
35 /* Exported variables */
41 extern int rl_catch_signals;
44 /* Forward referenced functions */
45 static void terminate_console(int sig);
46 int get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec);
48 /* Static variables */
49 static char *configfile = NULL;
50 static BSOCK *UA_sock = NULL;
52 static FILE *output = stdout;
55 #define CONFIG_FILE "./console.conf" /* default configuration file */
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"
65 " -t test - read configuration and exit\n"
66 " -? print this message.\n"
72 static void read_and_process_input(FILE *input, BSOCK *UA_sock)
75 int at_prompt = FALSE;
76 int tty_input = isatty(fileno(input));
80 if (at_prompt) { /* don't prompt multiple times */
87 stat = get_cmd(input, prompt, UA_sock, 30);
89 int len = sizeof_pool_memory(UA_sock->msg) - 1;
90 if (fgets(UA_sock->msg, len, input) == NULL) {
93 strip_trailing_junk(UA_sock->msg);
94 UA_sock->msglen = strlen(UA_sock->msg);
100 } else if (stat == 0) { /* timeout */
101 bnet_fsend(UA_sock, ".messages");
104 if (!bnet_send(UA_sock)) { /* send command */
108 if (strcmp(UA_sock->msg, "quit") == 0 || strcmp(UA_sock->msg, "exit") == 0) {
111 while ((stat = bnet_recv(UA_sock)) > 0) {
113 fprintf(output, "\n");
116 printf("%s", UA_sock->msg);
121 } else if (stat == 0) {
122 if (UA_sock->msglen == BNET_PROMPT) {
125 Dmsg1(100, "Got poll %s\n", bnet_sig_to_ascii(UA_sock));
131 /*********************************************************************
133 * Main Bacula Console -- User Interface Program
136 int main(int argc, char *argv[])
138 int ch, i, ndir, item;
139 int no_signals = FALSE;
140 int test_config = FALSE;
144 my_name_is(argc, argv, "console");
145 working_directory = "/tmp";
148 * Ensure that every message is always printed
150 for (i=1; i<=M_MAX; i++) {
151 add_msg_dest(NULL, MD_STDOUT, i, NULL, NULL);
155 while ((ch = getopt(argc, argv, "bc:d:r:st?")) != -1) {
157 case 'c': /* configuration file */
158 if (configfile != NULL)
160 configfile = bstrdup(optarg);
164 debug_level = atoi(optarg);
165 if (debug_level <= 0)
169 case 's': /* turn off signals */
187 init_signals(terminate_console);
189 signal(SIGCHLD, SIG_IGN);
195 if (configfile == NULL) {
196 configfile = bstrdup(CONFIG_FILE);
199 parse_config(configfile);
203 for (dir=NULL; (dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir)); ) {
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);
213 terminate_console(0);
217 memset(&jcr, 0, sizeof(jcr));
220 UA_sock = init_bsock(0, "", "", 0);
222 fprintf(output, "Available Directors:\n");
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,
230 if (get_cmd(stdin, "Select Director: ", UA_sock, 600) < 0) {
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);
240 for (i=0; i<item; i++) {
241 dir = (DIRRES *)GetNextRes(R_DIRECTOR, (RES *)dir);
247 dir = (DIRRES *)GetNextRes(R_DIRECTOR, NULL);
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);
259 jcr.dir_bsock = UA_sock;
260 if (!authenticate_director(&jcr, dir)) {
261 fprintf(stderr, "ERR: %s", UA_sock->msg);
262 terminate_console(0);
266 Dmsg0(40, "Opened connection with Director daemon\n");
268 read_and_process_input(stdin, UA_sock);
271 bnet_sig(UA_sock, BNET_TERMINATE); /* send EOF */
275 terminate_console(0);
280 /* Cleanup and then exit */
281 static void terminate_console(int sig)
283 static int already_here = FALSE;
285 if (already_here) /* avoid recursive temination problems */
293 #include "readline/readline.h"
294 #include "readline/history.h"
298 get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec)
302 rl_catch_signals = 1;
303 line = readline(prompt);
308 strcpy(sock->msg, line);
309 strip_trailing_junk(sock->msg);
310 sock->msglen = strlen(sock->msg);
312 add_history(sock->msg);
318 #else /* no readline, do it ourselves */
321 * Returns: 1 if data available
326 wait_for_data(int fd, int sec)
336 switch(select(fd + 1, &fdset, NULL, NULL, &tv)) {
337 case 0: /* timeout */
340 if (errno == EINTR || errno == EAGAIN) {
343 return -1; /* error return */
351 * Get next input command from terminal.
353 * Returns: 1 if got input
358 get_cmd(FILE *input, char *prompt, BSOCK *sock, int sec)
361 fprintf(output, prompt);
363 switch (wait_for_data(fileno(input), sec)) {
365 return 0; /* timeout */
367 return -1; /* error */
369 len = sizeof_pool_memory(sock->msg) - 1;
370 if (fgets(sock->msg, len, input) == NULL) {
375 strip_trailing_junk(sock->msg);
376 sock->msglen = strlen(sock->msg);