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