1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2013-2013 Bareos GmbH & Co. KG
5
6 This program is Free Software; you can redistribute it and/or
7 modify it under the terms of version three of the GNU Affero General Public
8 License as published by the Free Software Foundation and included
9 in the file LICENSE.
10
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Affero General Public License for more details.
15
16 You should have received a copy of the GNU Affero General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301, USA.
20 */
21 #include <QDebug>
22 #include <QThread>
23
24 #include "monitoritem.h"
25 #include "authenticate.h"
26 #include "monitoritemthread.h"
27 #include "lib/bnet.h"
28
MonitorItem(QObject * parent)29 MonitorItem::MonitorItem(QObject* parent)
30 : QObject(parent)
31 , d(new MonitorItemPrivate)
32 {
33 /* Run this class only in the context of
34 MonitorItemThread because of the networking */
35 Q_ASSERT(QThread::currentThreadId() == MonitorItemThread::instance()->getThreadId());
36 }
37
~MonitorItem()38 MonitorItem::~MonitorItem()
39 {
40 delete d;
41 }
42
get_name() const43 char* MonitorItem::get_name() const
44 {
45 return static_cast<UnionOfResources*>(d->resource)->hdr.name;
46 }
47
writecmd(const char * command)48 void MonitorItem::writecmd(const char* command)
49 {
50 if (d->DSock) {
51 d->DSock->message_length = PmStrcpy(d->DSock->msg, command);
52 BnetSend(d->DSock);
53 }
54 }
55
GetJobDefaults(struct JobDefaults & job_defs)56 bool MonitorItem::GetJobDefaults(struct JobDefaults &job_defs)
57 {
58 int stat;
59 char *def;
60 BareosSocket *dircomm;
61 QString scmd = QString(".defaults job=\"%1\"").arg(job_defs.job_name);
62
63 if (job_defs.job_name == "" || !doconnect()) {
64 return false;
65 }
66
67 dircomm = d->DSock;
68 dircomm->fsend("%s", scmd.toUtf8().data());
69
70 while ((stat = dircomm->recv()) > 0) {
71
72 def = strchr(dircomm->msg, '=');
73
74 if (def) {
75
76 /* Pointer to default value */
77 *def++ = 0;
78 StripTrailingNewline(def);
79
80 if (strcmp(dircomm->msg, "job") == 0) {
81
82 if (strcmp(def, job_defs.job_name.toUtf8().data()) != 0)
83 return false;
84 } else if (strcmp(dircomm->msg, "pool") == 0) {
85 job_defs.pool_name = def;
86 } else if (strcmp(dircomm->msg, "messages") == 0) {
87 job_defs.messages_name = def;
88 } else if (strcmp(dircomm->msg, "client") == 0) {
89 job_defs.client_name = def;
90 } else if (strcmp(dircomm->msg, "storage") == 0) {
91 job_defs.StoreName = def;
92 } else if (strcmp(dircomm->msg, "where") == 0) {
93 job_defs.where = def;
94 } else if (strcmp(dircomm->msg, "level") == 0) {
95 job_defs.level = def;
96 } else if (strcmp(dircomm->msg, "type") == 0) {
97 job_defs.type = def;
98 } else if (strcmp(dircomm->msg, "fileset") == 0) {
99 job_defs.fileset_name = def;
100 } else if (strcmp(dircomm->msg, "catalog") == 0) {
101 job_defs.catalog_name = def;
102 job_defs.enabled = *def == '1' ? true : false;
103 }
104 }
105 }
106 return true;
107 }
108
doconnect()109 bool MonitorItem::doconnect()
110 {
111 if (d->DSock) {
112 //already connected
113 return true;
114 }
115
116 JobControlRecord jcr;
117 memset(&jcr, 0, sizeof(jcr));
118
119 DirectorResource *dird;
120 ClientResource *filed;
121 StorageResource *stored;
122 QString message;
123
124 switch (d->type) {
125
126 case R_DIRECTOR:
127 dird = static_cast<DirectorResource*>(d->resource);
128 message = QString("Connecting to Director %1:%2").arg(dird->address).arg(dird->DIRport);
129 emit showStatusbarMessage(message);
130 d->DSock = New(BareosSocketTCP);
131 if (!d->DSock->connect(NULL, d->connectTimeout, 0, 0, "Director daemon",
132 dird->address, NULL, dird->DIRport, false)) {
133 delete d->DSock;
134 d->DSock = NULL;
135 } else {
136 jcr.dir_bsock = d->DSock;
137 }
138 break;
139
140 case R_CLIENT:
141 filed = static_cast<ClientResource*>(d->resource);
142 message = QString("Connecting to Client %1:%2").arg(filed->address).arg(filed->FDport);
143 emit showStatusbarMessage(message);
144 d->DSock = New(BareosSocketTCP);
145 if (!d->DSock->connect(NULL, d->connectTimeout, 0, 0, "File daemon",
146 filed->address, NULL, filed->FDport, false)) {
147 delete d->DSock;
148 d->DSock = NULL;
149 } else {
150 jcr.file_bsock = d->DSock;
151 }
152 break;
153
154 case R_STORAGE:
155 stored = static_cast<StorageResource*>(d->resource);
156 message = QString("Connecting to Storage %1:%2").arg(stored->address).arg(stored->SDport);
157 emit showStatusbarMessage(message);
158 d->DSock = New(BareosSocketTCP);
159 if (!d->DSock->connect(NULL, d->connectTimeout, 0, 0, "Storage daemon",
160 stored->address, NULL, stored->SDport, false)) {
161 delete d->DSock;
162 d->DSock = NULL;
163 } else {
164 jcr.store_bsock = d->DSock;
165 }
166 break;
167
168 default:
169 printf("Error, currentitem is not a Client, a Storage or a Director..\n");
170 return false;
171 }
172
173 char *name = get_name();
174
175 if (d->DSock == NULL) {
176
177 emit showStatusbarMessage("Cannot connect to daemon.");
178 emit clearText(name);
179 emit appendText(name, QString("Cannot connect to daemon."));
180 d->state = MonitorItem::Error;
181 emit statusChanged(name, d->state);
182 return false;
183 }
184
185 AuthenticationResult auth_result = AuthenticateWithDaemon(this, &jcr);
186
187 bool authentication_ok = ((auth_result == AuthenticationResult::kAlreadyAuthenticated)
188 || (auth_result == AuthenticationResult::kNoError));
189
190 if (!authentication_ok) {
191
192 d->state = MonitorItem::Error;
193 emit statusChanged(name, d->state);
194 std::string err_buffer;
195 if (GetAuthenticationResultString(auth_result, err_buffer)) {
196 message = QString("Authentication error : %1").arg(err_buffer.c_str());
197 } else {
198 message = QString("Authentication error : %1").arg("Unknown");
199 }
200 emit showStatusbarMessage(message);
201 emit clearText(name);
202 emit appendText(name, message);
203 d->DSock->signal(BNET_TERMINATE); /* send EOF */
204 d->DSock->close();
205 delete d->DSock;
206 d->DSock = NULL;
207 return false;
208 }
209
210 switch (d->type) {
211
212 case R_DIRECTOR:
213 emit showStatusbarMessage("Opened connection with Director daemon.");
214 break;
215
216 case R_CLIENT:
217 emit showStatusbarMessage("Opened connection with File daemon.");
218 break;
219
220 case R_STORAGE:
221 emit showStatusbarMessage("Opened connection with Storage daemon.");
222 break;
223
224 default:
225 emit showStatusbarMessage("Error, currentitem is not a Client, a Storage or a Director..\n");
226 d->state = Error;
227 emit statusChanged(name, d->state);
228 return false;
229 }
230
231 d->state = Running;
232 emit statusChanged(name, d->state);
233
234 return true;
235 }
236
disconnect()237 void MonitorItem::disconnect()
238 {
239 if (d->DSock) {
240 writecmd("quit");
241 d->DSock->signal(BNET_TERMINATE); /* send EOF */
242 d->DSock->close();
243 delete d->DSock;
244 d->DSock = NULL;
245 }
246 }
247
docmd(const char * command)248 bool MonitorItem::docmd(const char* command)
249 {
250 if (!doconnect()) {
251 return false;
252 }
253
254 if (command[0] != 0) {
255 writecmd(command);
256 }
257
258 emit clearText(get_name());
259 bool jobRunning = false;
260
261 while (1) {
262 int stat;
263 if ((stat = BnetRecv(d->DSock)) >= 0) {
264 StripTrailingNewline(d->DSock->msg);
265 QString msg = QString::fromUtf8(d->DSock->msg);
266 emit appendText(QString::fromUtf8(get_name()), msg);
267 if (d->type == R_CLIENT) {
268 if (msg.contains("Job started:"))
269 jobRunning = true;
270 }
271 } else if (stat == BNET_SIGNAL) {
272 if (d->DSock->message_length == BNET_EOD) {
273 // qDebug() << "<< EOD >>";
274 if (d->type == R_CLIENT)
275 emit jobIsRunning (jobRunning);
276 return true;
277 } else if (d->DSock->message_length == BNET_SUB_PROMPT) {
278 // qDebug() << "<< PROMPT >>";
279 return false;
280 } else if (d->DSock->message_length == BNET_HEARTBEAT) {
281 BnetSig(d->DSock, BNET_HB_RESPONSE);
282 } else {
283 qDebug() << BnetSigToAscii(d->DSock);
284 }
285 } else { /* BNET_HARDEOF || BNET_ERROR */
286 d->DSock = NULL;
287 d->state = MonitorItem::Error;
288 emit statusChanged(get_name(), d->state);
289 emit showStatusbarMessage("Error : BNET_HARDEOF or BNET_ERROR");
290 //fprintf(stderr, "<< ERROR >>\n"));
291 return false;
292 } /* if ((stat = BnetRecv(d->DSock)) >= 0) */
293
294 if (IsBnetStop(d->DSock)) {
295 d->DSock = NULL;
296 d->state = MonitorItem::Error;
297 emit statusChanged(get_name(), d->state);
298 emit showStatusbarMessage("Error : Connection closed.");
299 //fprintf(stderr, "<< STOP >>\n");
300 return false; /* error or term */
301 } /* if (IsBnetStop(d->DSock) */
302
303 } /* while (1) */
304 }
305
get_list(const char * cmd,QStringList & lst)306 void MonitorItem::get_list(const char *cmd, QStringList &lst)
307 {
308 doconnect();
309 writecmd(cmd);
310 while (BnetRecv(d->DSock) >= 0) {
311 StripTrailingNewline(d->DSock->msg);
312 if (*(d->DSock->msg)) {
313 lst << QString(d->DSock->msg);
314 }
315 }
316 }
317
GetStatus()318 void MonitorItem::GetStatus()
319 {
320 switch (d->type) {
321 case R_DIRECTOR:
322 docmd("status dir");
323 break;
324 case R_CLIENT:
325 if (!docmd("status"))
326 emit jobIsRunning(false);
327 break;
328 case R_STORAGE:
329 docmd("status");
330 break;
331 default:
332 break;
333 }
334 }
335
connectToMainWindow(QObject * mainWindow)336 void MonitorItem::connectToMainWindow(QObject* mainWindow)
337 {
338 connect(this, SIGNAL(showStatusbarMessage(QString)),
339 mainWindow, SLOT(onShowStatusbarMessage(QString)));
340 connect(this, SIGNAL(appendText(QString,QString)),
341 mainWindow, SLOT(onAppendText(QString,QString)));
342 connect(this, SIGNAL(clearText(QString)),
343 mainWindow, SLOT(onClearText(QString)));
344 connect(this, SIGNAL(statusChanged(QString,int)),
345 mainWindow, SLOT(onStatusChanged(QString,int)));
346 if (d->type == R_CLIENT) {
347 connect(this, SIGNAL(jobIsRunning(bool)),
348 mainWindow, SLOT(onFdJobIsRunning(bool)));
349 }
350 }
351
type() const352 Rescode MonitorItem::type() const { return d->type; }
resource() const353 void* MonitorItem::resource() const { return d->resource; }
DSock() const354 BareosSocket* MonitorItem::DSock() const { return d->DSock; }
state() const355 MonitorItem::StateEnum MonitorItem::state() const { return d->state; }
connectTimeout() const356 int MonitorItem::connectTimeout() const { return d->connectTimeout; }
357
setType(Rescode type)358 void MonitorItem::setType(Rescode type) { d->type = type; }
setResource(void * resource)359 void MonitorItem::setResource(void* resource) { d->resource = resource; }
setDSock(BareosSocket * DSock)360 void MonitorItem::setDSock(BareosSocket* DSock) { d->DSock = DSock; }
setState(MonitorItem::StateEnum state)361 void MonitorItem::setState(MonitorItem::StateEnum state) { d->state = state; }
setConnectTimeout(int timeout)362 void MonitorItem::setConnectTimeout(int timeout) { d->connectTimeout = timeout; }
363