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-2020 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 #include "lib/parse_conf.h"
37
38 ConfigurationParser* my_config = nullptr;
39
40 /* QCoreApplication* app will be initialized with:
41 * - QApplication for normal execution with a GUI or
42 * - QCoreApplication for tests when no GUI must be used */
43 static QCoreApplication* app = nullptr;
44
usage()45 static void usage()
46 {
47 std::vector<char> copyright(1024);
48 kBareosVersionStrings.FormatCopyrightWithFsfAndPlanets(
49 copyright.data(), copyright.size(), 2004);
50 QString out =
51 QString(_("%1"
52 "Usage: tray-monitor [options]\n"
53 " -c <path> use <path> as configuration file or "
54 "directory\n"
55 " -d <nn> set debug level to <nn>\n"
56 " -dt print timestamp in debug output\n"
57 " -t test - read configuration and exit\n"
58 " -rc test - do connection test\n"
59 " -xc print configuration and exit\n"
60 " -xs print configuration file schema in JSON "
61 "format "
62 "and exit\n"
63 " -? print this message.\n"
64 "\n"))
65 .arg(copyright.data());
66
67 #if HAVE_WIN32
68 QMessageBox::information(0, "Help", out);
69 #else
70 fprintf(stderr, "%s", out.toUtf8().data());
71 #endif
72 }
73
ParseCommandLine(int argc,char * argv[],cl_opts & cl)74 static void ParseCommandLine(int argc, char* argv[], cl_opts& cl)
75 {
76 int ch;
77 while ((ch = getopt(argc, argv, "bc:d:th?f:r:s:x:")) != -1) {
78 switch (ch) {
79 case 'c': /* configuration file */
80 if (cl.configfile_) { free(static_cast<void*>(cl.configfile_)); }
81 cl.configfile_ = strdup(optarg);
82 break;
83
84 case 'd':
85 if (*optarg == 't') {
86 dbg_timestamp = true;
87 } else {
88 debug_level = atoi(optarg);
89 if (debug_level <= 0) { debug_level = 1; }
90 }
91 break;
92
93 case 't':
94 cl.test_config_only_ = true;
95 break;
96
97 case 'x': /* export configuration/schema and exit */
98 if (*optarg == 's') {
99 cl.export_config_schema_ = true;
100 } else if (*optarg == 'c') {
101 cl.export_config_ = true;
102 } else {
103 usage();
104 exit(1);
105 }
106 break;
107
108 case 'r':
109 if ((*optarg) == 'c') {
110 cl.do_connection_test_only_ = true;
111 } else {
112 usage();
113 exit(1);
114 }
115 break;
116
117 case 'h':
118 case '?':
119 default:
120 usage();
121 exit(1);
122 }
123 }
124 argc -= optind;
125 // argv += optind;
126
127 if (argc) {
128 usage();
129 exit(1);
130 }
131 }
132
setupQtObjects()133 static void setupQtObjects()
134 {
135 MonitorItemThread* thr = MonitorItemThread::instance();
136 MainWindow* win = MainWindow::instance();
137
138 QObject::connect(win, SIGNAL(refreshItems()), 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) { exit(0); }
174
InitEnvironment(int argc,char * argv[])175 static void InitEnvironment(int argc, char* argv[])
176 {
177 setlocale(LC_ALL, "");
178 tzset();
179 bindtextdomain("bareos", LOCALEDIR);
180 textdomain("bareos");
181
182 InitStackDump();
183 MyNameIs(argc, argv, "tray-monitor");
184 InitMsg(NULL, NULL);
185 signal(SIGINT, intHandler);
186 working_directory = "/tmp";
187 OSDependentInit();
188 WSA_Init(); /* Initialize Windows sockets */
189 }
190
191 /*********************************************************************
192 *
193 * Main Bareos Tray Monitor -- User Interface Program
194 *
195 */
main(int argc,char * argv[])196 int main(int argc, char* argv[])
197 {
198 InitEnvironment(argc, argv);
199
200 cl_opts cl; // remember some command line options
201 ParseCommandLine(argc, argv, cl);
202
203 if (cl.export_config_schema_) {
204 PoolMem buffer;
205
206 my_config = InitTmonConfig(cl.configfile_, M_ERROR_TERM);
207 PrintConfigSchemaJson(buffer);
208 printf("%s\n", buffer.c_str());
209 fflush(stdout);
210 exit(0);
211 }
212
213 // read the config file
214 my_config = InitTmonConfig(cl.configfile_, M_ERROR_TERM);
215 my_config->ParseConfig();
216
217 if (cl.export_config_) {
218 my_config->DumpResources(PrintMessage, NULL);
219 exit(0);
220 }
221
222 if (InitCrypto() != 0) {
223 Emsg0(M_ERROR_TERM, 0, _("Cryptography library initialization failed.\n"));
224 }
225
226 if (cl.do_connection_test_only_) {
227 /* do not initialize a GUI */
228 app = new QCoreApplication(argc, argv);
229 } else {
230 QApplication* p = new QApplication(argc, argv);
231 p->setQuitOnLastWindowClosed(false);
232 app = p;
233 }
234
235 if (!cl.do_connection_test_only_) { setupQtObjects(); }
236
237 QStringList tabRefs = MonitorItemThread::instance()->createRes(cl);
238
239 int ret = 0;
240 if (cl.do_connection_test_only_) {
241 ret = MonitorItemThread::instance()->doConnectionTest() ? 0 : 1;
242 } else {
243 MainWindow::instance()->addTabs(tabRefs);
244
245 if (cl.test_config_only_) { exit(0); }
246
247 MonitorItemThread::instance()->start();
248
249 ret = app->exec();
250 }
251
252 cleanup();
253
254 return ret;
255 }
256 /* This is a replacement for the std::exit() handler */
exit(int status)257 void exit(int status)
258 {
259 /* avoid to call the std::exit() cleanup handlers
260 * via atexit() since exit() destroys objects that
261 * are used by the QApplication class and this would
262 * lead to a sementation fault when QApplication
263 * in turn wants to destroy its child-objects. */
264
265 // first do the Qt cleanup
266 cleanup();
267
268 // do the kernel cleanup
269 _exit(status);
270 }
271