2 Bacula® - The Network Backup Solution
4 Copyright (C) 2004-2014 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from many
7 others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 Bacula® is a registered trademark of Kern Sibbald.
19 int doconnect(monitoritem* item);
20 int docmd(monitoritem* item, const char* command);
21 static int authenticate_daemon(monitoritem* item, JCR *jcr);
22 /* Imported functions */
23 int authenticate_director(JCR *jcr, MONITOR *monitor, DIRRES *director);
24 int authenticate_file_daemon(JCR *jcr, MONITOR *monitor, CLIENT* client);
25 int authenticate_storage_daemon(JCR *jcr, MONITOR *monitor, STORE* store);
26 extern bool parse_tmon_config(CONFIG *config, const char *configfile, int exit_code);
27 void get_list(monitoritem* item, const char *cmd, QStringList &lst);
30 int generate_daemon_event(JCR *, const char *) { return 1; }
32 /* Static variables */
33 static char *configfile = NULL;
34 static MONITOR *monitor;
36 static int nitems = 0;
37 static monitoritem items[32];
38 static CONFIG *config;
41 /* Data received from DIR/FD/SD */
42 //static char OKqstatus[] = "%c000 OK .status\n";
43 //static char DotStatusJob[] = "JobId=%d JobStatus=%c JobErrors=%d\n";
46 void updateStatusIcon(monitoritem* item);
47 void changeStatusMessage(monitoritem* item, const char *fmt,...);
49 #define CONFIG_FILE "./tray-monitor.conf" /* default configuration file */
55 "\nVersion: %s (%s) %s %s %s\n\n"
56 "Usage: tray-monitor [-c config_file] [-d debug_level]\n"
57 " -c <file> set configuration file to file\n"
58 " -d <nn> set debug level to <nn>\n"
59 " -dt print timestamp in debug output\n"
60 " -t test - read configuration and exit\n"
61 " -? print this message.\n"
62 "\n"), 2004, VERSION, BDATE, HOST_OS, DISTNAME, DISTVER);
69 for (int i = 0; i < nitems; i++) {
72 switch (items[i].type) {
75 tray->clearText(items[i].get_name());
76 docmd(&items[i], cmd);
84 void get_list(monitoritem *item, const char *cmd, QStringList &lst)
90 while((stat = bnet_recv(item->D_sock)) >= 0) {
91 strip_trailing_junk(item->D_sock->msg);
92 if (*(item->D_sock->msg)) {
93 lst << QString(item->D_sock->msg);
100 for (int i = 0; i < nitems; i++) {
102 tray->clearText(items[i].get_name());
103 switch (items[i].type) {
117 docmd(&items[i], cmd);
121 /*********************************************************************
123 * Main Bacula Tray Monitor -- User Interface Program
126 int main(int argc, char *argv[])
128 int ch, i, dir_index=-1;
129 bool test_config = false;
134 setlocale(LC_ALL, "");
135 bindtextdomain("bacula", LOCALEDIR);
136 textdomain("bacula");
139 my_name_is(argc, argv, "tray-monitor");
141 init_msg(NULL, NULL);
142 working_directory = "/tmp";
144 struct sigaction sigignore;
145 sigignore.sa_flags = 0;
146 sigignore.sa_handler = SIG_IGN;
147 sigfillset(&sigignore.sa_mask);
148 sigaction(SIGPIPE, &sigignore, NULL);
150 while ((ch = getopt(argc, argv, "bc:d:th?f:s:")) != -1) {
152 case 'c': /* configuration file */
153 if (configfile != NULL) {
156 configfile = bstrdup(optarg);
160 if (*optarg == 't') {
161 dbg_timestamp = true;
163 debug_level = atoi(optarg);
164 if (debug_level <= 0) {
189 if (configfile == NULL) {
190 configfile = bstrdup(CONFIG_FILE);
193 config = new_config_parser();
194 parse_tmon_config(config, configfile, M_ERROR_TERM);
198 foreach_res(monitor, R_MONITOR) {
203 Emsg2(M_ERROR_TERM, 0,
204 _("Error: %d Monitor resources defined in %s. You must define one and only one Monitor resource.\n"), nitems, configfile);
208 foreach_res(dird, R_DIRECTOR) {
210 items[nitems].type = R_DIRECTOR;
211 items[nitems].resource = dird;
212 items[nitems].D_sock = NULL;
213 items[nitems].state = warn;
214 items[nitems].oldstate = warn;
217 foreach_res(filed, R_CLIENT) {
218 items[nitems].type = R_CLIENT;
219 items[nitems].resource = filed;
220 items[nitems].D_sock = NULL;
221 items[nitems].state = warn;
222 items[nitems].oldstate = warn;
225 foreach_res(stored, R_STORAGE) {
226 items[nitems].type = R_STORAGE;
227 items[nitems].resource = stored;
228 items[nitems].D_sock = NULL;
229 items[nitems].state = warn;
230 items[nitems].oldstate = warn;
236 Emsg1(M_ERROR_TERM, 0, _("No Client, Storage or Director resource defined in %s\n"
237 "Without that I don't how to get status from the File, Storage or Director Daemon :-(\n"), configfile);
244 (void)WSA_Init(); /* Initialize Windows sockets */
247 monitor = (MONITOR*)GetNextRes(R_MONITOR, (RES *)NULL);
250 if ((monitor->RefreshInterval < 1) || (monitor->RefreshInterval > 600)) {
251 Emsg2(M_ERROR_TERM, 0, _("Invalid refresh interval defined in %s\n"
252 "This value must be greater or equal to 1 second and less or equal to 10 minutes (read value: %d).\n"), configfile, monitor->RefreshInterval);
256 QApplication app(argc, argv);
257 app.setQuitOnLastWindowClosed(false);
260 tray->spinRefresh->setValue(monitor->RefreshInterval);
261 if (dir_index >= 0) {
262 tray->addDirector(&items[dir_index]);
265 for (i = 0; i < nitems; i++) {
267 tray->addTab(items[i].get_name());
268 switch (items[i].type) {
270 tray->addDirector(&items[i]);
283 docmd(&items[i], cmd);
290 for (i = 0; i < nitems; i++) {
291 if (items[i].D_sock) {
292 items[i].writecmd("quit");
293 if (items[i].D_sock) {
294 bnet_sig(items[i].D_sock, BNET_TERMINATE); /* send EOF */
295 bnet_close(items[i].D_sock);
301 (void)WSACleanup(); /* Cleanup Windows sockets */
303 config->free_resources();
310 static int authenticate_daemon(monitoritem* item, JCR *jcr) {
311 switch (item->type) {
313 return authenticate_director(jcr, monitor, (DIRRES*)item->resource);
315 return authenticate_file_daemon(jcr, monitor, (CLIENT*)item->resource);
317 return authenticate_storage_daemon(jcr, monitor, (STORE*)item->resource);
319 printf(_("Error, currentitem is not a Client or a Storage..\n"));
325 void changeStatusMessage(monitoritem*, const char *fmt,...) {
329 va_start(arg_ptr, fmt);
330 bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr);
332 tray->statusbar->showMessage(QString(buf));
335 int doconnect(monitoritem* item)
338 memset(&jcr, 0, sizeof(jcr));
344 switch (item->type) {
346 dird = (DIRRES*)item->resource;
347 changeStatusMessage(item, _("Connecting to Director %s:%d"), dird->address, dird->DIRport);
348 item->D_sock = bnet_connect(NULL, monitor->DIRConnectTimeout,
349 0, 0, _("Director daemon"), dird->address, NULL, dird->DIRport, 0);
350 jcr.dir_bsock = item->D_sock;
353 filed = (CLIENT*)item->resource;
354 changeStatusMessage(item, _("Connecting to Client %s:%d"), filed->address, filed->FDport);
355 item->D_sock = bnet_connect(NULL, monitor->FDConnectTimeout,
356 0, 0, _("File daemon"), filed->address, NULL, filed->FDport, 0);
357 jcr.file_bsock = item->D_sock;
360 stored = (STORE*)item->resource;
361 changeStatusMessage(item, _("Connecting to Storage %s:%d"), stored->address, stored->SDport);
362 item->D_sock = bnet_connect(NULL, monitor->SDConnectTimeout,
363 0, 0, _("Storage daemon"), stored->address, NULL, stored->SDport, 0);
364 jcr.store_bsock = item->D_sock;
367 printf(_("Error, currentitem is not a Client, a Storage or a Director..\n"));
371 if (item->D_sock == NULL) {
372 changeStatusMessage(item, _("Cannot connect to daemon."));
374 item->oldstate = error;
378 if (!authenticate_daemon(item, &jcr)) {
380 item->oldstate = error;
381 changeStatusMessage(item, _("Authentication error : %s"), item->D_sock->msg);
386 switch (item->type) {
388 changeStatusMessage(item, _("Opened connection with Director daemon."));
391 changeStatusMessage(item, _("Opened connection with File daemon."));
394 changeStatusMessage(item, _("Opened connection with Storage daemon."));
397 printf(_("Error, currentitem is not a Client, a Storage or a Director..\n"));
402 if (item->type == R_DIRECTOR) { /* Read connection messages... */
403 docmd(item, ""); /* Usually invalid, but no matter */
409 int docmd(monitoritem* item, const char* command)
412 //qDebug() << "docmd(" << item->get_name() << "," << command << ")";
413 if (!doconnect(item)) {
418 item->writecmd(command);
421 if ((stat = bnet_recv(item->D_sock)) >= 0) {
422 strip_trailing_newline(item->D_sock->msg);
423 tray->appendText(item->get_name(), item->D_sock->msg);
425 else if (stat == BNET_SIGNAL) {
426 if (item->D_sock->msglen == BNET_EOD) {
427 // qDebug() << "<< EOD >>";
430 else if (item->D_sock->msglen == BNET_SUB_PROMPT) {
431 // qDebug() << "<< PROMPT >>";
434 else if (item->D_sock->msglen == BNET_HEARTBEAT) {
435 bnet_sig(item->D_sock, BNET_HB_RESPONSE);
438 qDebug() << bnet_sig_to_ascii(item->D_sock);
441 else { /* BNET_HARDEOF || BNET_ERROR */
444 item->oldstate = error;
445 changeStatusMessage(item, _("Error : BNET_HARDEOF or BNET_ERROR"));
446 //fprintf(stderr, _("<< ERROR >>\n"));
450 if (is_bnet_stop(item->D_sock)) {
453 item->oldstate = error;
454 changeStatusMessage(item, _("Error : Connection closed."));
455 //fprintf(stderr, "<< STOP >>\n");
456 return 0; /* error or term */