1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2004-2011 Free Software Foundation Europe e.V.
5 Copyright (C) 2011-2012 Planets Communications B.V.
6 Copyright (C) 2013-2016 Bareos GmbH & Co. KG
7
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
11 in the file LICENSE.
12
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 Affero General Public License for more details.
17
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
21 02110-1301, USA.
22 */
23
24 #include <QDebug>
25 #include <QList>
26 #include <QPointer>
27 #include <QApplication>
28 #include <QMessageBox>
29
30 #include "mainwindow.h"
31 #include "tray-monitor.h"
32 #include "authenticate.h"
33 #include "monitoritem.h"
34 #include "monitoritemthread.h"
35 #include "lib/bsignal.h"
36
37 ConfigurationParser *my_config = nullptr;
38
39 /* QCoreApplication* app will be initialized with:
40 * - QApplication for normal execution with a GUI or
41 * - QCoreApplication for tests when no GUI must be used */
42 static QCoreApplication* app = nullptr;
43
usage()44 static void usage()
45 {
46 QString out;
47
48 out = out.sprintf(_(PROG_COPYRIGHT
49 "\nVersion: %s (%s) %s %s %s\n\n"
50 "Usage: tray-monitor [options]\n"
51 " -c <path> use <path> as configuration file or directory\n"
52 " -d <nn> set debug level to <nn>\n"
53 " -dt print timestamp in debug output\n"
54 " -t test - read configuration and exit\n"
55 " -rc test - do connection test\n"
56 " -xc print configuration and exit\n"
57 " -xs print configuration file schema in JSON format and exit\n"
58 " -? print this message.\n"
59 "\n"),
60 2004, VERSION, BDATE, HOST_OS, DISTNAME, DISTVER);
61
62 #if HAVE_WIN32
63 QMessageBox::information(0, "Help", out);
64 #else
65 fprintf(stderr, "%s", out.toUtf8().data());
66 #endif
67 }
68
ParseCommandLine(int argc,char * argv[],cl_opts & cl)69 static void ParseCommandLine(int argc, char* argv[], cl_opts& cl)
70 {
71 int ch;
72 while ((ch = getopt(argc, argv, "bc:d:th?f:r:s:x:")) != -1) {
73 switch (ch) {
74 case 'c': /* configuration file */
75 if (cl.configfile_) {
76 free(static_cast<void*>(cl.configfile_));
77 }
78 cl.configfile_ = bstrdup(optarg);
79 break;
80
81 case 'd':
82 if (*optarg == 't') {
83 dbg_timestamp = true;
84 } else {
85 debug_level = atoi(optarg);
86 if (debug_level <= 0) {
87 debug_level = 1;
88 }
89 }
90 break;
91
92 case 't':
93 cl.test_config_only_ = true;
94 break;
95
96 case 'x': /* export configuration/schema and exit */
97 if (*optarg == 's') {
98 cl.export_config_schema_ = true;
99 } else if (*optarg == 'c') {
100 cl.export_config_ = true;
101 } else {
102 usage();
103 exit(1);
104 }
105 break;
106
107 case 'r':
108 if ((*optarg) == 'c') {
109 cl.do_connection_test_only_ = true;
110 } else {
111 usage();
112 exit(1);
113 }
114 break;
115
116 case 'h':
117 case '?':
118 default:
119 usage();
120 exit(1);
121 }
122 }
123 argc -= optind;
124 //argv += optind;
125
126 if (argc) {
127 usage();
128 exit(1);
129 }
130 }
131
setupQtObjects()132 static void setupQtObjects()
133 {
134 MonitorItemThread* thr = MonitorItemThread::instance();
135 MainWindow* win = MainWindow::instance();
136
137 QObject::connect(win, SIGNAL(refreshItems()),
138 thr, SLOT(onRefreshItems()),
139 Qt::QueuedConnection);
140
141 // move the thread exec handler
142 // into its own context
143 thr->moveToThread(thr);
144 }
145
cleanup()146 static void cleanup()
147 {
148 static bool terminated = false;
149
150 if (terminated) {
151 // don't call it twice
152 return;
153 }
154
155 terminated = true;
156
157 MonitorItemThread::destruct(); //disconnects network
158 MainWindow::destruct(); //destroys the tray-icon
159
160 if(app) {
161 delete app;
162 app = nullptr;
163 }
164
165 if (my_config) {
166 delete my_config;
167 my_config = nullptr;
168 }
169
170 WSACleanup(); /* Cleanup Windows sockets */
171 }
172
intHandler(int)173 void intHandler(int)
174 {
175 exit(0);
176 }
177
InitEnvironment(int argc,char * argv[])178 static void InitEnvironment(int argc, char* argv[])
179 {
180 setlocale(LC_ALL, "");
181 bindtextdomain("bareos", LOCALEDIR);
182 textdomain("bareos");
183
184 InitStackDump();
185 MyNameIs(argc, argv, "tray-monitor");
186 InitMsg(NULL, NULL);
187 signal(SIGINT, intHandler);
188 working_directory = "/tmp";
189 OSDependentInit();
190 WSA_Init(); /* Initialize Windows sockets */
191 }
192
193 /*********************************************************************
194 *
195 * Main Bareos Tray Monitor -- User Interface Program
196 *
197 */
main(int argc,char * argv[])198 int main(int argc, char *argv[])
199 {
200 InitEnvironment(argc, argv);
201
202 cl_opts cl; // remember some command line options
203 ParseCommandLine(argc, argv, cl);
204
205 if (cl.export_config_schema_) {
206 PoolMem buffer;
207
208 my_config = InitTmonConfig(cl.configfile_, M_ERROR_TERM);
209 PrintConfigSchemaJson(buffer);
210 printf("%s\n", buffer.c_str());
211 fflush(stdout);
212 exit(0);
213 }
214
215 // read the config file
216 my_config = InitTmonConfig(cl.configfile_, M_ERROR_TERM);
217 my_config->ParseConfig();
218
219 if (cl.export_config_) {
220 my_config->DumpResources(PrintMessage, NULL);
221 exit(0);
222 }
223
224 if (InitCrypto() != 0) {
225 Emsg0(M_ERROR_TERM, 0, _("Cryptography library initialization failed.\n"));
226 }
227
228 if (cl.do_connection_test_only_) {
229 /* do not initialize a GUI */
230 app = new QCoreApplication(argc, argv);
231 } else {
232 QApplication *p = new QApplication(argc, argv);
233 p->setQuitOnLastWindowClosed(false);
234 app = p;
235 }
236
237 if (!cl.do_connection_test_only_) {
238 setupQtObjects();
239 }
240
241 QStringList tabRefs = MonitorItemThread::instance()->createRes(cl);
242
243 int ret = 0;
244 if (cl.do_connection_test_only_) {
245 ret = MonitorItemThread::instance()->doConnectionTest() ? 0 : 1;
246 } else {
247 MainWindow::instance()->addTabs(tabRefs);
248
249 if (cl.test_config_only_) {
250 exit(0);
251 }
252
253 MonitorItemThread::instance()->start();
254
255 ret = app->exec();
256 }
257
258 cleanup();
259
260 return ret;
261 }
262 /* This is a replacement for the std::exit() handler */
exit(int status)263 void exit(int status)
264 {
265 /* avoid to call the std::exit() cleanup handlers
266 * via atexit() since exit() destroys objects that
267 * are used by the QApplication class and this would
268 * lead to a sementation fault when QApplication
269 * in turn wants to destroy its child-objects. */
270
271 // first do the Qt cleanup
272 cleanup();
273
274 // do the kernel cleanup
275 _exit(status);
276 }
277