2 Bacula® - The Network Backup Solution
4 Copyright (C) 2004-2011 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
31 int doconnect(monitoritem* item);
32 int docmd(monitoritem* item, const char* command);
33 static int authenticate_daemon(monitoritem* item, JCR *jcr);
34 /* Imported functions */
35 int authenticate_director(JCR *jcr, MONITOR *monitor, DIRRES *director);
36 int authenticate_file_daemon(JCR *jcr, MONITOR *monitor, CLIENT* client);
37 int authenticate_storage_daemon(JCR *jcr, MONITOR *monitor, STORE* store);
38 extern bool parse_tmon_config(CONFIG *config, const char *configfile, int exit_code);
39 void get_list(monitoritem* item, const char *cmd, QStringList &lst);
42 int generate_daemon_event(JCR *, const char *) { return 1; }
44 /* Static variables */
45 static char *configfile = NULL;
46 static MONITOR *monitor;
48 static int nitems = 0;
49 static monitoritem items[32];
50 static CONFIG *config;
53 /* Data received from DIR/FD/SD */
54 //static char OKqstatus[] = "%c000 OK .status\n";
55 //static char DotStatusJob[] = "JobId=%d JobStatus=%c JobErrors=%d\n";
58 void updateStatusIcon(monitoritem* item);
59 void changeStatusMessage(monitoritem* item, const char *fmt,...);
61 #define CONFIG_FILE "./tray-monitor.conf" /* default configuration file */
67 "\nVersion: %s (%s) %s %s %s\n\n"
68 "Usage: tray-monitor [-c config_file] [-d debug_level]\n"
69 " -c <file> set configuration file to file\n"
70 " -d <nn> set debug level to <nn>\n"
71 " -dt print timestamp in debug output\n"
72 " -t test - read configuration and exit\n"
73 " -? print this message.\n"
74 "\n"), 2004, VERSION, BDATE, HOST_OS, DISTNAME, DISTVER);
81 for (int i = 0; i < nitems; i++) {
84 switch (items[i].type) {
87 tray->clearText(items[i].get_name());
88 docmd(&items[i], cmd);
96 void get_list(monitoritem *item, const char *cmd, QStringList &lst)
102 while((stat = bnet_recv(item->D_sock)) >= 0) {
103 strip_trailing_junk(item->D_sock->msg);
104 if (*(item->D_sock->msg)) {
105 lst << QString(item->D_sock->msg);
112 for (int i = 0; i < nitems; i++) {
114 tray->clearText(items[i].get_name());
115 switch (items[i].type) {
129 docmd(&items[i], cmd);
133 /*********************************************************************
135 * Main Bacula Tray Monitor -- User Interface Program
138 int main(int argc, char *argv[])
140 int ch, i, dir_index=-1;
141 bool test_config = false;
146 setlocale(LC_ALL, "");
147 bindtextdomain("bacula", LOCALEDIR);
148 textdomain("bacula");
151 my_name_is(argc, argv, "tray-monitor");
153 init_msg(NULL, NULL);
154 working_directory = "/tmp";
156 struct sigaction sigignore;
157 sigignore.sa_flags = 0;
158 sigignore.sa_handler = SIG_IGN;
159 sigfillset(&sigignore.sa_mask);
160 sigaction(SIGPIPE, &sigignore, NULL);
162 while ((ch = getopt(argc, argv, "bc:d:th?f:s:")) != -1) {
164 case 'c': /* configuration file */
165 if (configfile != NULL) {
168 configfile = bstrdup(optarg);
172 if (*optarg == 't') {
173 dbg_timestamp = true;
175 debug_level = atoi(optarg);
176 if (debug_level <= 0) {
201 if (configfile == NULL) {
202 configfile = bstrdup(CONFIG_FILE);
205 config = new_config_parser();
206 parse_tmon_config(config, configfile, M_ERROR_TERM);
210 foreach_res(monitor, R_MONITOR) {
215 Emsg2(M_ERROR_TERM, 0,
216 _("Error: %d Monitor resources defined in %s. You must define one and only one Monitor resource.\n"), nitems, configfile);
220 foreach_res(dird, R_DIRECTOR) {
222 items[nitems].type = R_DIRECTOR;
223 items[nitems].resource = dird;
224 items[nitems].D_sock = NULL;
225 items[nitems].state = warn;
226 items[nitems].oldstate = warn;
229 foreach_res(filed, R_CLIENT) {
230 items[nitems].type = R_CLIENT;
231 items[nitems].resource = filed;
232 items[nitems].D_sock = NULL;
233 items[nitems].state = warn;
234 items[nitems].oldstate = warn;
237 foreach_res(stored, R_STORAGE) {
238 items[nitems].type = R_STORAGE;
239 items[nitems].resource = stored;
240 items[nitems].D_sock = NULL;
241 items[nitems].state = warn;
242 items[nitems].oldstate = warn;
248 Emsg1(M_ERROR_TERM, 0, _("No Client, Storage or Director resource defined in %s\n"
249 "Without that I don't how to get status from the File, Storage or Director Daemon :-(\n"), configfile);
256 (void)WSA_Init(); /* Initialize Windows sockets */
259 monitor = (MONITOR*)GetNextRes(R_MONITOR, (RES *)NULL);
262 if ((monitor->RefreshInterval < 1) || (monitor->RefreshInterval > 600)) {
263 Emsg2(M_ERROR_TERM, 0, _("Invalid refresh interval defined in %s\n"
264 "This value must be greater or equal to 1 second and less or equal to 10 minutes (read value: %d).\n"), configfile, monitor->RefreshInterval);
268 QApplication app(argc, argv);
269 app.setQuitOnLastWindowClosed(false);
272 tray->spinRefresh->setValue(monitor->RefreshInterval);
273 if (dir_index >= 0) {
274 tray->addDirector(&items[dir_index]);
277 for (i = 0; i < nitems; i++) {
279 tray->addTab(items[i].get_name());
280 switch (items[i].type) {
282 tray->addDirector(&items[i]);
295 docmd(&items[i], cmd);
302 for (i = 0; i < nitems; i++) {
303 if (items[i].D_sock) {
304 items[i].writecmd("quit");
305 if (items[i].D_sock) {
306 bnet_sig(items[i].D_sock, BNET_TERMINATE); /* send EOF */
307 bnet_close(items[i].D_sock);
313 (void)WSACleanup(); /* Cleanup Windows sockets */
315 config->free_resources();
322 static int authenticate_daemon(monitoritem* item, JCR *jcr) {
323 switch (item->type) {
325 return authenticate_director(jcr, monitor, (DIRRES*)item->resource);
327 return authenticate_file_daemon(jcr, monitor, (CLIENT*)item->resource);
329 return authenticate_storage_daemon(jcr, monitor, (STORE*)item->resource);
331 printf(_("Error, currentitem is not a Client or a Storage..\n"));
337 void changeStatusMessage(monitoritem*, const char *fmt,...) {
341 va_start(arg_ptr, fmt);
342 bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr);
344 tray->statusbar->showMessage(QString(buf));
347 int doconnect(monitoritem* item)
350 memset(&jcr, 0, sizeof(jcr));
356 switch (item->type) {
358 dird = (DIRRES*)item->resource;
359 changeStatusMessage(item, _("Connecting to Director %s:%d"), dird->address, dird->DIRport);
360 item->D_sock = bnet_connect(NULL, monitor->DIRConnectTimeout,
361 0, 0, _("Director daemon"), dird->address, NULL, dird->DIRport, 0);
362 jcr.dir_bsock = item->D_sock;
365 filed = (CLIENT*)item->resource;
366 changeStatusMessage(item, _("Connecting to Client %s:%d"), filed->address, filed->FDport);
367 item->D_sock = bnet_connect(NULL, monitor->FDConnectTimeout,
368 0, 0, _("File daemon"), filed->address, NULL, filed->FDport, 0);
369 jcr.file_bsock = item->D_sock;
372 stored = (STORE*)item->resource;
373 changeStatusMessage(item, _("Connecting to Storage %s:%d"), stored->address, stored->SDport);
374 item->D_sock = bnet_connect(NULL, monitor->SDConnectTimeout,
375 0, 0, _("Storage daemon"), stored->address, NULL, stored->SDport, 0);
376 jcr.store_bsock = item->D_sock;
379 printf(_("Error, currentitem is not a Client, a Storage or a Director..\n"));
383 if (item->D_sock == NULL) {
384 changeStatusMessage(item, _("Cannot connect to daemon."));
386 item->oldstate = error;
390 if (!authenticate_daemon(item, &jcr)) {
392 item->oldstate = error;
393 changeStatusMessage(item, _("Authentication error : %s"), item->D_sock->msg);
398 switch (item->type) {
400 changeStatusMessage(item, _("Opened connection with Director daemon."));
403 changeStatusMessage(item, _("Opened connection with File daemon."));
406 changeStatusMessage(item, _("Opened connection with Storage daemon."));
409 printf(_("Error, currentitem is not a Client, a Storage or a Director..\n"));
414 if (item->type == R_DIRECTOR) { /* Read connection messages... */
415 docmd(item, ""); /* Usually invalid, but no matter */
421 int docmd(monitoritem* item, const char* command)
424 //qDebug() << "docmd(" << item->get_name() << "," << command << ")";
425 if (!doconnect(item)) {
430 item->writecmd(command);
433 if ((stat = bnet_recv(item->D_sock)) >= 0) {
434 strip_trailing_newline(item->D_sock->msg);
435 tray->appendText(item->get_name(), item->D_sock->msg);
437 else if (stat == BNET_SIGNAL) {
438 if (item->D_sock->msglen == BNET_EOD) {
439 // qDebug() << "<< EOD >>";
442 else if (item->D_sock->msglen == BNET_SUB_PROMPT) {
443 // qDebug() << "<< PROMPT >>";
446 else if (item->D_sock->msglen == BNET_HEARTBEAT) {
447 bnet_sig(item->D_sock, BNET_HB_RESPONSE);
450 qDebug() << bnet_sig_to_ascii(item->D_sock);
453 else { /* BNET_HARDEOF || BNET_ERROR */
456 item->oldstate = error;
457 changeStatusMessage(item, _("Error : BNET_HARDEOF or BNET_ERROR"));
458 //fprintf(stderr, _("<< ERROR >>\n"));
462 if (is_bnet_stop(item->D_sock)) {
465 item->oldstate = error;
466 changeStatusMessage(item, _("Error : Connection closed."));
467 //fprintf(stderr, "<< STOP >>\n");
468 return 0; /* error or term */