2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2016 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many 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 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
22 int doconnect(monitoritem* item);
23 int docmd(monitoritem* item, const char* command);
24 static int authenticate_daemon(monitoritem* item, JCR *jcr);
25 /* Imported functions */
26 int authenticate_director(JCR *jcr, MONITOR *monitor, DIRRES *director);
27 int authenticate_file_daemon(JCR *jcr, MONITOR *monitor, CLIENT* client);
28 int authenticate_storage_daemon(JCR *jcr, MONITOR *monitor, STORE* store);
29 extern bool parse_tmon_config(CONFIG *config, const char *configfile, int exit_code);
30 void get_list(monitoritem* item, const char *cmd, QStringList &lst);
33 int generate_daemon_event(JCR *, const char *) { return 1; }
35 /* Static variables */
36 static char *configfile = NULL;
37 static MONITOR *monitor;
39 static int nitems = 0;
40 static monitoritem items[32];
41 static CONFIG *config;
44 /* Data received from DIR/FD/SD */
45 //static char OKqstatus[] = "%c000 OK .status\n";
46 //static char DotStatusJob[] = "JobId=%d JobStatus=%c JobErrors=%d\n";
49 void updateStatusIcon(monitoritem* item);
50 void changeStatusMessage(monitoritem* item, const char *fmt,...);
52 #define CONFIG_FILE "./tray-monitor.conf" /* default configuration file */
58 "\nVersion: %s (%s) %s %s %s\n\n"
59 "Usage: tray-monitor [-c config_file] [-d debug_level]\n"
60 " -c <file> set configuration file to file\n"
61 " -d <nn> set debug level to <nn>\n"
62 " -dt print timestamp in debug output\n"
63 " -t test - read configuration and exit\n"
64 " -? print this message.\n"
65 "\n"), 2004, VERSION, BDATE, HOST_OS, DISTNAME, DISTVER);
72 for (int i = 0; i < nitems; i++) {
75 switch (items[i].type) {
78 tray->clearText(items[i].get_name());
79 docmd(&items[i], cmd);
87 void get_list(monitoritem *item, const char *cmd, QStringList &lst)
93 while((stat = item->D_sock->recv()) >= 0) {
94 strip_trailing_junk(item->D_sock->msg);
95 if (*(item->D_sock->msg)) {
96 lst << QString(item->D_sock->msg);
103 for (int i = 0; i < nitems; i++) {
105 tray->clearText(items[i].get_name());
106 switch (items[i].type) {
120 docmd(&items[i], cmd);
124 /*********************************************************************
126 * Main Bacula Tray Monitor -- User Interface Program
129 int main(int argc, char *argv[])
131 int ch, i, dir_index=-1;
132 bool test_config = false;
137 setlocale(LC_ALL, "");
138 bindtextdomain("bacula", LOCALEDIR);
139 textdomain("bacula");
142 my_name_is(argc, argv, "tray-monitor");
144 init_msg(NULL, NULL, NULL);
145 working_directory = "/tmp";
148 struct sigaction sigignore;
149 sigignore.sa_flags = 0;
150 sigignore.sa_handler = SIG_IGN;
151 sigfillset(&sigignore.sa_mask);
152 sigaction(SIGPIPE, &sigignore, NULL);
155 while ((ch = getopt(argc, argv, "bc:d:th?f:s:")) != -1) {
157 case 'c': /* configuration file */
158 if (configfile != NULL) {
161 configfile = bstrdup(optarg);
165 if (*optarg == 't') {
166 dbg_timestamp = true;
168 debug_level = atoi(optarg);
169 if (debug_level <= 0) {
194 if (configfile == NULL) {
195 configfile = bstrdup(CONFIG_FILE);
198 config = new_config_parser();
199 parse_tmon_config(config, configfile, M_ERROR_TERM);
203 foreach_res(monitor, R_MONITOR) {
208 Emsg2(M_ERROR_TERM, 0,
209 _("Error: %d Monitor resources defined in %s. You must define one and only one Monitor resource.\n"), nitems, configfile);
213 foreach_res(dird, R_DIRECTOR) {
215 items[nitems].type = R_DIRECTOR;
216 items[nitems].resource = dird;
217 items[nitems].D_sock = NULL;
218 items[nitems].state = warn;
219 items[nitems].oldstate = warn;
222 foreach_res(filed, R_CLIENT) {
223 items[nitems].type = R_CLIENT;
224 items[nitems].resource = filed;
225 items[nitems].D_sock = NULL;
226 items[nitems].state = warn;
227 items[nitems].oldstate = warn;
230 foreach_res(stored, R_STORAGE) {
231 items[nitems].type = R_STORAGE;
232 items[nitems].resource = stored;
233 items[nitems].D_sock = NULL;
234 items[nitems].state = warn;
235 items[nitems].oldstate = warn;
241 Emsg1(M_ERROR_TERM, 0, _("No Client, Storage or Director resource defined in %s\n"
242 "Without that I don't how to get status from the File, Storage or Director Daemon :-(\n"), configfile);
249 (void)WSA_Init(); /* Initialize Windows sockets */
252 monitor = (MONITOR*)GetNextRes(R_MONITOR, (RES *)NULL);
255 if ((monitor->RefreshInterval < 1) || (monitor->RefreshInterval > 600)) {
256 Emsg2(M_ERROR_TERM, 0, _("Invalid refresh interval defined in %s\n"
257 "This value must be greater or equal to 1 second and less or equal to 10 minutes (read value: %d).\n"), configfile, monitor->RefreshInterval);
261 QApplication app(argc, argv);
262 app.setQuitOnLastWindowClosed(false);
265 tray->spinRefresh->setValue(monitor->RefreshInterval);
266 if (dir_index >= 0) {
267 tray->addDirector(&items[dir_index]);
270 for (i = 0; i < nitems; i++) {
272 tray->addTab(items[i].get_name());
273 switch (items[i].type) {
275 tray->addDirector(&items[i]);
288 docmd(&items[i], cmd);
295 for (i = 0; i < nitems; i++) {
296 if (items[i].D_sock) {
297 items[i].writecmd("quit");
298 if (items[i].D_sock) {
299 items[i].D_sock->signal(BNET_TERMINATE); /* send EOF */
300 free_bsock(items[i].D_sock);
306 (void)WSACleanup(); /* Cleanup Windows sockets */
308 config->free_resources();
315 static int authenticate_daemon(monitoritem* item, JCR *jcr) {
316 switch (item->type) {
318 return authenticate_director(jcr, monitor, (DIRRES*)item->resource);
320 return authenticate_file_daemon(jcr, monitor, (CLIENT*)item->resource);
322 return authenticate_storage_daemon(jcr, monitor, (STORE*)item->resource);
324 printf(_("Error, currentitem is not a Client or a Storage..\n"));
330 void changeStatusMessage(monitoritem*, const char *fmt,...) {
334 va_start(arg_ptr, fmt);
335 bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr);
337 tray->statusbar->showMessage(QString(buf));
340 int doconnect(monitoritem* item)
342 if (!is_bsock_open(item->D_sock)) {
343 memset(&jcr, 0, sizeof(jcr));
349 switch (item->type) {
351 dird = (DIRRES*)item->resource;
352 changeStatusMessage(item, _("Connecting to Director %s:%d"), dird->address, dird->DIRport);
354 item->D_sock = new_bsock();
356 item->D_sock->connect(NULL, monitor->DIRConnectTimeout,
357 0, 0, _("Director daemon"), dird->address, NULL, dird->DIRport, 0);
358 jcr.dir_bsock = item->D_sock;
361 filed = (CLIENT*)item->resource;
362 changeStatusMessage(item, _("Connecting to Client %s:%d"), filed->address, filed->FDport);
364 item->D_sock = new_bsock();
366 item->D_sock->connect(NULL, monitor->FDConnectTimeout,
367 0, 0, _("File daemon"), filed->address, NULL, filed->FDport, 0);
368 jcr.file_bsock = item->D_sock;
371 stored = (STORE*)item->resource;
372 changeStatusMessage(item, _("Connecting to Storage %s:%d"), stored->address, stored->SDport);
374 item->D_sock = new_bsock();
376 item->D_sock->connect(NULL, monitor->SDConnectTimeout,
377 0, 0, _("Storage daemon"), stored->address, NULL, stored->SDport, 0);
378 jcr.store_bsock = item->D_sock;
381 printf(_("Error, currentitem is not a Client, a Storage or a Director..\n"));
385 if (item->D_sock == NULL) {
386 changeStatusMessage(item, _("Cannot connect to daemon."));
388 item->oldstate = error;
392 if (!authenticate_daemon(item, &jcr)) {
394 item->oldstate = error;
395 changeStatusMessage(item, _("Authentication error : %s"), item->D_sock->msg);
400 switch (item->type) {
402 changeStatusMessage(item, _("Opened connection with Director daemon."));
405 changeStatusMessage(item, _("Opened connection with File daemon."));
408 changeStatusMessage(item, _("Opened connection with Storage daemon."));
411 printf(_("Error, currentitem is not a Client, a Storage or a Director..\n"));
416 if (item->type == R_DIRECTOR) { /* Read connection messages... */
417 docmd(item, ""); /* Usually invalid, but no matter */
423 int docmd(monitoritem* item, const char* command)
426 //qDebug() << "docmd(" << item->get_name() << "," << command << ")";
427 if (!doconnect(item)) {
432 item->writecmd(command);
435 if ((stat = item->D_sock->recv()) >= 0) {
436 strip_trailing_newline(item->D_sock->msg);
437 tray->appendText(item->get_name(), item->D_sock->msg);
439 else if (stat == BNET_SIGNAL) {
440 if (item->D_sock->msglen == BNET_EOD) {
441 // qDebug() << "<< EOD >>";
444 else if (item->D_sock->msglen == BNET_SUB_PROMPT) {
445 // qDebug() << "<< PROMPT >>";
448 else if (item->D_sock->msglen == BNET_HEARTBEAT) {
449 item->D_sock->signal(BNET_HB_RESPONSE);
452 qDebug() << bnet_sig_to_ascii(item->D_sock->msglen);
455 else { /* BNET_HARDEOF || BNET_ERROR */
458 item->oldstate = error;
459 changeStatusMessage(item, _("Error : BNET_HARDEOF or BNET_ERROR"));
460 //fprintf(stderr, _("<< ERROR >>\n"));
464 if (item->D_sock->is_stop()) {
467 item->oldstate = error;
468 changeStatusMessage(item, _("Error : Connection closed."));
469 //fprintf(stderr, "<< STOP >>\n");
470 return 0; /* error or term */