diff --git a/0001-Add-new-tray-monitor-files-that-were-omitted-in-the-.patch b/0001-Add-new-tray-monitor-files-that-were-omitted-in-the-.patch new file mode 100644 index 0000000..7e31d8f --- /dev/null +++ b/0001-Add-new-tray-monitor-files-that-were-omitted-in-the-.patch @@ -0,0 +1,3617 @@ +From a34f61be3e65120b8b22d306c0718d7a5aec7bc1 Mon Sep 17 00:00:00 2001 +From: Kern Sibbald +Date: Mon, 10 Jul 2017 17:50:29 +0200 +Subject: [PATCH 1/4] Add new tray-monitor files that were omitted in the + backport from Enterprise + +--- + .../tray-monitor/bacula-tray-monitor.conf.in | 32 + + bacula/src/qt-console/tray-monitor/conf.h | 85 ++ + .../qt-console/tray-monitor/install_conf_file.in | 3 + + bacula/src/qt-console/tray-monitor/main-conf.ui | 350 ++++++++ + bacula/src/qt-console/tray-monitor/res-conf.ui | 565 ++++++++++++ + bacula/src/qt-console/tray-monitor/run.ui | 379 ++++++++ + bacula/src/qt-console/tray-monitor/runjob.cpp | 515 +++++++++++ + bacula/src/qt-console/tray-monitor/runjob.h | 118 +++ + bacula/src/qt-console/tray-monitor/sd-monitor.ui | 162 ++++ + bacula/src/qt-console/tray-monitor/sdstatus.cpp | 125 +++ + bacula/src/qt-console/tray-monitor/sdstatus.h | 42 + + bacula/src/qt-console/tray-monitor/status.cpp | 42 + + bacula/src/qt-console/tray-monitor/status.h | 44 + + bacula/src/qt-console/tray-monitor/task.cpp | 951 +++++++++++++++++++++ + .../qt-console/tray-monitor/tray-monitor.conf.in | 3 + + .../qt-console/tray-monitor/tray-monitor.pro.in | 3 + + .../tray-monitor/tray-monitor.pro.mingw32.in | 9 +- + .../tray-monitor/tray-monitor.pro.mingw64.in | 9 +- + 18 files changed, 3433 insertions(+), 4 deletions(-) + create mode 100644 bacula/src/qt-console/tray-monitor/bacula-tray-monitor.conf.in + create mode 100644 bacula/src/qt-console/tray-monitor/conf.h + create mode 100644 bacula/src/qt-console/tray-monitor/main-conf.ui + create mode 100644 bacula/src/qt-console/tray-monitor/res-conf.ui + create mode 100644 bacula/src/qt-console/tray-monitor/run.ui + create mode 100644 bacula/src/qt-console/tray-monitor/runjob.cpp + create mode 100644 bacula/src/qt-console/tray-monitor/runjob.h + create mode 100644 bacula/src/qt-console/tray-monitor/sd-monitor.ui + create mode 100644 bacula/src/qt-console/tray-monitor/sdstatus.cpp + create mode 100644 bacula/src/qt-console/tray-monitor/sdstatus.h + create mode 100644 bacula/src/qt-console/tray-monitor/status.cpp + create mode 100644 bacula/src/qt-console/tray-monitor/status.h + create mode 100644 bacula/src/qt-console/tray-monitor/task.cpp + +diff --git a/bacula/src/qt-console/tray-monitor/bacula-tray-monitor.conf.in b/bacula/src/qt-console/tray-monitor/bacula-tray-monitor.conf.in +new file mode 100644 +index 000000000..4a9eff7b1 +--- /dev/null ++++ b/bacula/src/qt-console/tray-monitor/bacula-tray-monitor.conf.in +@@ -0,0 +1,32 @@ ++# ++# Bacula Tray Monitor Configuration File ++# ++# Copyright (C) 2000-2017 Kern Sibbald ++# License: BSD 2-Clause; see file LICENSE-FOSS ++# ++ ++Monitor { ++ Name = @basename@-mon ++ RefreshInterval = 120 seconds ++} ++ ++Client { ++ Name = @basename@-fd ++ Password = "@mon_fd_password@" # password for FileDaemon ++ Address = @hostname@ ++ Port = @fd_port@ ++} ++ ++#Storage { ++# Name = @basename@-sd ++# Address = @hostname@ ++# Port = @sd_port@ ++# Password = "@mon_sd_password@" # password for StorageDaemon ++#} ++# ++#Director { ++# Name = @basename@-dir ++# Address = @hostname@ ++# Port = @dir_port@ ++# Password = "@mon_dir_password@" # password for the Directors ++#} +diff --git a/bacula/src/qt-console/tray-monitor/conf.h b/bacula/src/qt-console/tray-monitor/conf.h +new file mode 100644 +index 000000000..e2cb52802 +--- /dev/null ++++ b/bacula/src/qt-console/tray-monitor/conf.h +@@ -0,0 +1,85 @@ ++/* ++ Bacula(R) - The Network Backup Solution ++ ++ Copyright (C) 2000-2017 Kern Sibbald ++ ++ The original author of Bacula is Kern Sibbald, with contributions ++ from many others, a complete list can be found in the file AUTHORS. ++ ++ You may use this file and others of this release according to the ++ license defined in the LICENSE file, which includes the Affero General ++ Public License, v3.0 ("AGPLv3") and some additional permissions and ++ terms pursuant to its AGPLv3 Section 7. ++ ++ This notice must be preserved when any source code is ++ conveyed and/or propagated. ++ ++ Bacula(R) is a registered trademark of Kern Sibbald. ++*/ ++ ++#ifndef CONF_H ++#define CONF_H ++ ++#include "common.h" ++#include "ui_main-conf.h" ++#include "ui_res-conf.h" ++#include "tray_conf.h" ++ ++class Conf: public QDialog ++{ ++ Q_OBJECT ++ ++private: ++ CONFIG *config; ++ RES_HEAD **rhead; ++public: ++ int items; ++ QLineEdit::EchoMode passtype; ++ Ui::Conf UIConf; ++ Conf(); ++ ~Conf(); ++ bool parse_config(); ++ void addResource(RESMON *res, const char *title); ++ void addRes(int type, const char *title); /* create the resource */ ++public slots: ++ void accept(); ++ void selectCommandDir(); ++ void addDir(); ++ void addStore(); ++ void addClient(); ++ void togglePassword(); ++}; ++ ++class ConfTab: public QWidget ++{ ++ Q_OBJECT ++ ++public: ++ Ui::ResConf ui; ++ RESMON *res; ++ int type; ++ bool new_resource; ++ ConfTab(RESMON *r): QWidget() { ++ res = r; ++ type = r->type; ++ new_resource = r->new_resource; ++ ui.setupUi(this); ++ connect(ui.bpDelete, SIGNAL(clicked()), this, SLOT(disable())); ++ }; ++ ~ConfTab() { ++ if (new_resource && res) { ++ free_resource((RES*) res, res->type); ++ res = NULL; ++ } ++ }; ++public slots: ++ void disable() { ++ setEnabled(false); ++ }; ++ void selectCaCertificateFile(); ++ void selectCaCertificateDir(); ++ void selectCertificate(); ++ void selectKey(); ++}; ++ ++#endif +diff --git a/bacula/src/qt-console/tray-monitor/install_conf_file.in b/bacula/src/qt-console/tray-monitor/install_conf_file.in +index 6b9d27823..3698afb44 100755 +--- a/bacula/src/qt-console/tray-monitor/install_conf_file.in ++++ b/bacula/src/qt-console/tray-monitor/install_conf_file.in +@@ -1,4 +1,7 @@ + #!/bin/sh ++# Copyright (C) 2000-2017 Kern Sibbald ++# License: BSD 2-Clause; see file LICENSE-FOSS ++# + + sbindir=@sbindir@ + sysconfdir=@sysconfdir@ +diff --git a/bacula/src/qt-console/tray-monitor/main-conf.ui b/bacula/src/qt-console/tray-monitor/main-conf.ui +new file mode 100644 +index 000000000..4e023ab6b +--- /dev/null ++++ b/bacula/src/qt-console/tray-monitor/main-conf.ui +@@ -0,0 +1,350 @@ ++ ++ ++ Conf ++ ++ ++ ++ 0 ++ 0 ++ 556 ++ 337 ++ ++ ++ ++ Configuration ++ ++ ++ ++ ++ ++ 0 ++ ++ ++ ++ Monitor Configuration ++ ++ ++ ++ ++ ++ QFormLayout::AllNonFixedFieldsGrow ++ ++ ++ ++ ++ The Monitor name will be used during the authentication phase. ++ ++ ++ Name: ++ ++ ++ ++ ++ ++ ++ The Monitor name will be used during the authentication phase. ++ ++ ++ 127 ++ ++ ++ ++ ++ ++ ++ Refresh Interval: ++ ++ ++ ++ ++ ++ ++ 5 ++ ++ ++ 9999 ++ ++ ++ 120 ++ ++ ++ ++ ++ ++ ++ Specify the "Command Directory" where the tray-monitor program will check regularly for jobs to run ++ ++ ++ Command Directory: ++ ++ ++ ++ ++ ++ ++ ++ ++ Specify the "Command Directory" where the tray-monitor program will check regularly for jobs to run ++ ++ ++ ++ ++ ++ ++ ... ++ ++ ++ ++ ++ ++ ++ ++ ++ Display or Hide advanced options in the "Run Job" window ++ ++ ++ Display Advanced Options: ++ ++ ++ ++ ++ ++ ++ Display or Hide advanced options in the "Run Job" window ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Save and Apply the changes ++ ++ ++ Save ++ ++ ++ ++ :/images/label.png:/images/label.png ++ ++ ++ ++ ++ ++ ++ Cancel ++ ++ ++ ++ :/images/A.png:/images/A.png ++ ++ ++ ++ ++ ++ ++ Qt::Vertical ++ ++ ++ ++ 20 ++ 40 ++ ++ ++ ++ ++ ++ ++ ++ Show/Hide Passwords ++ ++ ++ Password ++ ++ ++ ++ :/images/zoom.png:/images/zoom.png ++ ++ ++ ++ ++ ++ ++ Add Client resource to monitor ++ ++ ++ Client ++ ++ ++ ++ :/images/mark.png:/images/mark.png ++ ++ ++ ++ ++ ++ ++ Add Storage resource to monitor ++ ++ ++ Storage ++ ++ ++ ++ :/images/mark.png:/images/mark.png ++ ++ ++ ++ ++ ++ ++ Add Director resource to monitor ++ ++ ++ Director ++ ++ ++ ++ :/images/mark.png:/images/mark.png ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ bpSave ++ clicked() ++ Conf ++ accept() ++ ++ ++ 511 ++ 30 ++ ++ ++ 521 ++ 46 ++ ++ ++ ++ ++ bpCancel ++ clicked() ++ Conf ++ close() ++ ++ ++ 511 ++ 76 ++ ++ ++ 521 ++ 159 ++ ++ ++ ++ ++ bpStrip ++ clicked() ++ Conf ++ togglePassword() ++ ++ ++ 511 ++ 178 ++ ++ ++ 496 ++ 142 ++ ++ ++ ++ ++ bpAddClient ++ clicked() ++ Conf ++ addClient() ++ ++ ++ 511 ++ 239 ++ ++ ++ 521 ++ 245 ++ ++ ++ ++ ++ bpAddStorage ++ clicked() ++ Conf ++ addStore() ++ ++ ++ 511 ++ 272 ++ ++ ++ 521 ++ 289 ++ ++ ++ ++ ++ bpAddDir ++ clicked() ++ Conf ++ addDir() ++ ++ ++ 511 ++ 313 ++ ++ ++ 521 ++ 331 ++ ++ ++ ++ ++ bpCommandDir ++ clicked() ++ Conf ++ selectCommandDir() ++ ++ ++ 405 ++ 135 ++ ++ ++ 466 ++ 112 ++ ++ ++ ++ ++ ++ togglePassword() ++ addClient() ++ addStore() ++ addDir() ++ selectCommandDir() ++ ++ +diff --git a/bacula/src/qt-console/tray-monitor/res-conf.ui b/bacula/src/qt-console/tray-monitor/res-conf.ui +new file mode 100644 +index 000000000..7cf21a783 +--- /dev/null ++++ b/bacula/src/qt-console/tray-monitor/res-conf.ui +@@ -0,0 +1,565 @@ ++ ++ ++ ResConf ++ ++ ++ ++ 0 ++ 0 ++ 417 ++ 541 ++ ++ ++ ++ Form ++ ++ ++ ++ ++ ++ General ++ ++ ++ ++ QFormLayout::AllNonFixedFieldsGrow ++ ++ ++ ++ ++ The Name will be used only in the Tray Monitor interface ++ ++ ++ Name: ++ ++ ++ ++ ++ ++ ++ The Name will be used only in the Tray Monitor interface ++ ++ ++ 127 ++ ++ ++ ++ ++ ++ ++ Description: ++ ++ ++ ++ ++ ++ ++ 512 ++ ++ ++ ++ ++ ++ ++ Password: ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 127 ++ ++ ++ QLineEdit::PasswordEchoOnEdit ++ ++ ++ ++ ++ ++ ++ Address: ++ ++ ++ ++ ++ ++ ++ 1024 ++ ++ ++ ++ ++ ++ ++ Port: ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ ++ 100 ++ 16777215 ++ ++ ++ ++ 5 ++ ++ ++ ++ ++ ++ ++ Timeout: ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ ++ 100 ++ 16777215 ++ ++ ++ ++ 5 ++ ++ ++ ++ ++ ++ ++ Use Client Initiated backup/restore feature ++ ++ ++ Remote ++ ++ ++ ++ ++ ++ ++ Use Client Initiated backup/restore feature ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Update the tray monitor icon with the status of this component ++ ++ ++ Monitor: ++ ++ ++ ++ ++ ++ ++ Update the tray monitor icon with the status of this component ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Use SetIp: ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ TLS ++ ++ ++ ++ ++ ++ ... ++ ++ ++ ++ ++ ++ ++ CA Certificate File: ++ ++ ++ ++ ++ ++ ++ Enabled ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ ... ++ ++ ++ ++ ++ ++ ++ Key File: ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ... ++ ++ ++ ++ ++ ++ ++ Certificate File: ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ CA Certificate Directory: ++ ++ ++ ++ ++ ++ ++ ... ++ ++ ++ ++ ++ cbTLSEnabled ++ editCaCertificateFile ++ label_5 ++ label_6 ++ editCaCertificateDir ++ label_7 ++ editCertificate ++ label_8 ++ editKey ++ bpCaCertificateFile ++ bpCaCertificateDir ++ bpCertificate ++ bpKey ++ ++ ++ ++ ++ ++ ++ 64 ++ 16777215 ++ ++ ++ ++ ++ 64 ++ 0 ++ ++ ++ ++ ++ ++ ++ ++ :/images/purge.png:/images/purge.png ++ ++ ++ false ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 40 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ editName ++ editDescription ++ editPassword ++ editAddress ++ editPort ++ editTimeout ++ cbRemote ++ cbTLSEnabled ++ editCaCertificateFile ++ bpCaCertificateFile ++ editCaCertificateDir ++ bpCaCertificateDir ++ editCertificate ++ bpCertificate ++ editKey ++ bpKey ++ ++ ++ ++ ++ ++ ++ bpCaCertificateFile ++ clicked() ++ ResConf ++ selectCaCertificateFile() ++ ++ ++ 461 ++ 294 ++ ++ ++ 521 ++ 247 ++ ++ ++ ++ ++ bpCaCertificateDir ++ clicked() ++ ResConf ++ selectCaCertificateDir() ++ ++ ++ 452 ++ 334 ++ ++ ++ 501 ++ 355 ++ ++ ++ ++ ++ bpCertificate ++ clicked() ++ ResConf ++ selectCertificate() ++ ++ ++ 459 ++ 364 ++ ++ ++ 495 ++ 384 ++ ++ ++ ++ ++ bpKey ++ clicked() ++ ResConf ++ selectKey() ++ ++ ++ 461 ++ 395 ++ ++ ++ 481 ++ 410 ++ ++ ++ ++ ++ cbTLSEnabled ++ toggled(bool) ++ editCaCertificateFile ++ setEnabled(bool) ++ ++ ++ 132 ++ 271 ++ ++ ++ 249 ++ 291 ++ ++ ++ ++ ++ cbTLSEnabled ++ toggled(bool) ++ editCaCertificateDir ++ setEnabled(bool) ++ ++ ++ 120 ++ 274 ++ ++ ++ 203 ++ 325 ++ ++ ++ ++ ++ cbTLSEnabled ++ toggled(bool) ++ editCertificate ++ setEnabled(bool) ++ ++ ++ 68 ++ 271 ++ ++ ++ 220 ++ 360 ++ ++ ++ ++ ++ cbTLSEnabled ++ toggled(bool) ++ editKey ++ setEnabled(bool) ++ ++ ++ 51 ++ 275 ++ ++ ++ 288 ++ 392 ++ ++ ++ ++ ++ cbTLSEnabled ++ toggled(bool) ++ bpCaCertificateFile ++ setEnabled(bool) ++ ++ ++ 161 ++ 267 ++ ++ ++ 449 ++ 291 ++ ++ ++ ++ ++ cbTLSEnabled ++ toggled(bool) ++ bpCaCertificateDir ++ setEnabled(bool) ++ ++ ++ 145 ++ 271 ++ ++ ++ 455 ++ 329 ++ ++ ++ ++ ++ cbTLSEnabled ++ toggled(bool) ++ bpCertificate ++ setEnabled(bool) ++ ++ ++ 140 ++ 266 ++ ++ ++ 459 ++ 358 ++ ++ ++ ++ ++ cbTLSEnabled ++ toggled(bool) ++ bpKey ++ setEnabled(bool) ++ ++ ++ 118 ++ 272 ++ ++ ++ 458 ++ 389 ++ ++ ++ ++ ++ ++ selectCaCertificateFile() ++ selectCaCertificateDir() ++ selectCertificate() ++ selectKey() ++ ++ +diff --git a/bacula/src/qt-console/tray-monitor/run.ui b/bacula/src/qt-console/tray-monitor/run.ui +new file mode 100644 +index 000000000..4ed29af13 +--- /dev/null ++++ b/bacula/src/qt-console/tray-monitor/run.ui +@@ -0,0 +1,379 @@ ++ ++ ++ runForm ++ ++ ++ ++ 0 ++ 0 ++ 568 ++ 407 ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ Run job ++ ++ ++ ++ ++ ++ ++ 16777215 ++ 30 ++ ++ ++ ++ ++ 11 ++ ++ ++ ++ <h3>Run a Job</h3> ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ ++ 0 ++ 5 ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ :/images/runit.png ++ ++ ++ ++ ++ ++ ++ 0 ++ ++ ++ ++ Properties ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ QFormLayout::AllNonFixedFieldsGrow ++ ++ ++ ++ ++ Job: ++ ++ ++ jobCombo ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ QComboBox::AdjustToContents ++ ++ ++ ++ ++ ++ ++ When: ++ ++ ++ dateTimeEdit ++ ++ ++ ++ ++ ++ ++ QDateTimeEdit::YearSection ++ ++ ++ yyyy-MM-dd hh:mm:ss ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ <html><head/><body><p>Job statistics computed from the Catalog with previous jobs.</p><p>For accurate information, it is possible to use the bconsole &quot;estimate&quot; command.</p></body></html> ++ ++ ++ Estimate: ++ ++ ++ ++ ++ ++ Job Bytes: ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Job Files: ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Level: ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Advanced ++ ++ ++ ++ ++ ++ Level: ++ ++ ++ levelCombo ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Client: ++ ++ ++ clientCombo ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ FileSet: ++ ++ ++ filesetCombo ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Pool: ++ ++ ++ poolCombo ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Storage: ++ ++ ++ storageCombo ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Catalog: ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Priority: ++ ++ ++ prioritySpin ++ ++ ++ ++ ++ ++ ++ ++ 60 ++ 0 ++ ++ ++ ++ ++ 60 ++ 16777215 ++ ++ ++ ++ ++ 60 ++ 0 ++ ++ ++ ++ 1 ++ ++ ++ 10000 ++ ++ ++ 10 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ ++ ++ ++ ++ 0 ++ 5 ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 40 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ OK ++ ++ ++ ++ ++ ++ ++ Cancel ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/bacula/src/qt-console/tray-monitor/runjob.cpp b/bacula/src/qt-console/tray-monitor/runjob.cpp +new file mode 100644 +index 000000000..e6204ee45 +--- /dev/null ++++ b/bacula/src/qt-console/tray-monitor/runjob.cpp +@@ -0,0 +1,515 @@ ++/* ++ Bacula(R) - The Network Backup Solution ++ ++ Copyright (C) 2000-2017 Kern Sibbald ++ ++ The original author of Bacula is Kern Sibbald, with contributions ++ from many others, a complete list can be found in the file AUTHORS. ++ ++ You may use this file and others of this release according to the ++ license defined in the LICENSE file, which includes the Affero General ++ Public License, v3.0 ("AGPLv3") and some additional permissions and ++ terms pursuant to its AGPLv3 Section 7. ++ ++ This notice must be preserved when any source code is ++ conveyed and/or propagated. ++ ++ Bacula(R) is a registered trademark of Kern Sibbald. ++*/ ++ ++#include "runjob.h" ++#include ++ ++static void fillcombo(QComboBox *cb, alist *lst, bool addempty=true) ++{ ++ if (lst && lst->size() > 0) { ++ QStringList list; ++ char *str; ++ if (addempty) { ++ list << QString(""); ++ } ++ foreach_alist(str, lst) { ++ list << QString(str); ++ } ++ cb->addItems(list); ++ } else { ++ cb->setEnabled(false); ++ } ++} ++ ++RunJob::RunJob(RESMON *r): QDialog(), res(r), tabAdvanced(NULL) ++{ ++ int nbjob; ++ if (res->jobs->size() == 0) { ++ QMessageBox msgBox; ++ msgBox.setText(_("This restricted console does not have access to Backup jobs")); ++ msgBox.setIcon(QMessageBox::Warning); ++ msgBox.exec(); ++ deleteLater(); ++ return; ++ ++ } ++ ++ ui.setupUi(this); ++ setModal(true); ++ connect(ui.cancelButton, SIGNAL(clicked()), this, SLOT(close_cb())); ++ connect(ui.okButton, SIGNAL(clicked()), this, SLOT(runjob())); ++ connect(ui.jobCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(jobChanged(int))); ++ connect(ui.levelCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(levelChanged(int))); ++ ui.dateTimeEdit->setMinimumDate(QDate::currentDate()); ++ ui.dateTimeEdit->setMaximumDate(QDate::currentDate().addDays(7)); ++ ui.dateTimeEdit->setDate(QDate::currentDate()); ++ ui.dateTimeEdit->setTime(QTime::currentTime()); ++ ui.boxEstimate->setVisible(false); ++ ++ res->mutex->lock(); ++ nbjob = res->jobs->size(); ++ fillcombo(ui.jobCombo, res->jobs, (nbjob > 1)); ++ fillcombo(ui.clientCombo, res->clients); ++ fillcombo(ui.filesetCombo,res->filesets); ++ fillcombo(ui.poolCombo, res->pools); ++ fillcombo(ui.storageCombo,res->storages); ++ fillcombo(ui.catalogCombo,res->catalogs); ++ res->mutex->unlock(); ++ connect(ui.tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabChange(int))); ++ QStringList levels; ++ levels << "" << "Incremental" << "Differential" << "Full"; ++ ui.levelCombo->addItems(levels); ++ ++ MONITOR *m = (MONITOR*) GetNextRes(R_MONITOR, NULL); ++ if (!m->display_advanced_options) { ++ tabAdvanced = ui.tabWidget->widget(1); ++ ui.tabWidget->removeTab(1); ++ } ++ ++ show(); ++}; ++ ++void RunJob::tabChange(int idx) ++{ ++ QString q = ui.tabWidget->tabText(idx); ++ if (q.contains("Advanced")) { ++ if (ui.jobCombo->currentText().compare("") == 0) { ++ pm_strcpy(curjob, ""); ++ ui.tab2->setEnabled(false); ++ ++ } else if (ui.jobCombo->currentText().compare(curjob.c_str()) != 0) { ++ task *t = new task(); ++ char *job = bstrdup(ui.jobCombo->currentText().toUtf8().data()); ++ pm_strcpy(curjob, job); // Keep the job name to not refresh the Advanced tab the next time ++ ++ Dmsg1(10, "get defaults for %s\n", job); ++ res->mutex->lock(); ++ bfree_and_null(res->defaults.job); ++ res->defaults.job = job; ++ res->mutex->unlock(); ++ ++ ui.tab2->setEnabled(false); ++ connect(t, SIGNAL(done(task *)), this, SLOT(fill_defaults(task *)), Qt::QueuedConnection); ++ t->init(res, TASK_DEFAULTS); ++ res->wrk->queue(t); ++ } ++ } ++} ++ ++void RunJob::runjob() ++{ ++ POOL_MEM tmp; ++ char *p; ++ ++ p = ui.jobCombo->currentText().toUtf8().data(); ++ if (!p || !*p) { ++ QMessageBox msgBox; ++ msgBox.setText(_("Nothing selected")); ++ msgBox.setIcon(QMessageBox::Warning); ++ msgBox.exec(); ++ return; ++ } ++ ++ Mmsg(command, "run job=\"%s\" yes", p); ++ ++ if (strcmp(p, NPRTB(res->defaults.job)) == 0 || strcmp("", NPRTB(res->defaults.job)) == 0) { ++ p = ui.storageCombo->currentText().toUtf8().data(); ++ if (p && *p && strcmp(p, NPRTB(res->defaults.storage)) != 0) { ++ Mmsg(tmp, " storage=\"%s\"", p); ++ pm_strcat(command, tmp.c_str()); ++ } ++ ++ p = ui.clientCombo->currentText().toUtf8().data(); ++ if (p && *p && strcmp(p, NPRTB(res->defaults.client)) != 0) { ++ Mmsg(tmp, " client=\"%s\"", p); ++ pm_strcat(command, tmp.c_str()); ++ } ++ ++ p = ui.levelCombo->currentText().toUtf8().data(); ++ if (p && *p && strcmp(p, NPRTB(res->defaults.level)) != 0) { ++ Mmsg(tmp, " level=\"%s\"", p); ++ pm_strcat(command, tmp.c_str()); ++ } ++ ++ p = ui.poolCombo->currentText().toUtf8().data(); ++ if (p && *p && strcmp(p, NPRTB(res->defaults.pool)) != 0) { ++ Mmsg(tmp, " pool=\"%s\"", p); ++ pm_strcat(command, tmp.c_str()); ++ } ++ ++ p = ui.filesetCombo->currentText().toUtf8().data(); ++ if (p && *p && strcmp(p, NPRTB(res->defaults.fileset)) != 0) { ++ Mmsg(tmp, " fileset=\"%s\"", p); ++ pm_strcat(command, tmp.c_str()); ++ } ++ ++ if (res->defaults.priority && res->defaults.priority != ui.prioritySpin->value()) { ++ Mmsg(tmp, " priority=\"%d\"", res->defaults.priority); ++ pm_strcat(command, tmp.c_str()); ++ } ++ } ++ ++ QDate dnow = QDate::currentDate(); ++ QTime tnow = QTime::currentTime(); ++ QDate dval = ui.dateTimeEdit->date(); ++ QTime tval = ui.dateTimeEdit->time(); ++ ++ if (dval > dnow || (dval == dnow && tval > tnow)) { ++ Mmsg(tmp, " when=\"%s %s\"", dval.toString("yyyy-MM-dd").toUtf8().data(), tval.toString("hh:mm:00").toUtf8().data()); ++ pm_strcat(command, tmp.c_str()); ++ } ++ ++ if (res->type == R_CLIENT) { ++ pm_strcat(command, " fdcalled=1"); ++ } ++ ++ // Build the command and run it! ++ task *t = new task(); ++ connect(t, SIGNAL(done(task *)), this, SLOT(jobStarted(task *)), Qt::QueuedConnection); ++ t->arg = command.c_str(); ++ t->init(res, TASK_RUN); ++ res->wrk->queue(t); ++} ++ ++void RunJob::jobStarted(task *t) ++{ ++ Dmsg1(10, "%s\n", command.c_str()); ++ Dmsg1(10, "-> jobid=%d\n", t->result.i); ++ deleteLater(); ++ delete t; ++} ++ ++void RunJob::close_cb(task *t) ++{ ++ deleteLater(); ++ delete t; ++} ++ ++void RunJob::close_cb() ++{ ++ task *t = new task(); ++ connect(t, SIGNAL(done(task *)), this, SLOT(close_cb(task *)), Qt::QueuedConnection); ++ t->init(res, TASK_DISCONNECT); ++ res->wrk->queue(t); ++} ++ ++void RunJob::jobChanged(int) ++{ ++ char *p; ++ ui.levelCombo->setCurrentIndex(0); ++ ui.storageCombo->setCurrentIndex(0); ++ ui.filesetCombo->setCurrentIndex(0); ++ ui.clientCombo->setCurrentIndex(0); ++ ui.storageCombo->setCurrentIndex(0); ++ ui.poolCombo->setCurrentIndex(0); ++ ui.catalogCombo->setCurrentIndex(0); ++ ++ p = ui.jobCombo->currentText().toUtf8().data(); ++ if (p && *p) { ++ task *t = new task(); ++ pm_strcpy(info, p); ++ connect(t, SIGNAL(done(task *)), this, SLOT(jobInfo(task *)), Qt::QueuedConnection); ++ t->arg = info.c_str(); // Jobname ++ t->arg2 = NULL; // Level ++ t->init(res, TASK_INFO); ++ res->wrk->queue(t); ++ } ++} ++ ++void RunJob::levelChanged(int) ++{ ++ char *p; ++ p = ui.jobCombo->currentText().toUtf8().data(); ++ if (p && *p) { ++ pm_strcpy(info, p); ++ p = ui.levelCombo->currentText().toUtf8().data(); ++ if (p && *p) { ++ task *t = new task(); ++ pm_strcpy(level, p); ++ connect(t, SIGNAL(done(task *)), this, SLOT(jobInfo(task *)), Qt::QueuedConnection); ++ t->arg = info.c_str(); // Jobname ++ t->arg2 = level.c_str(); // Level ++ t->init(res, TASK_INFO); ++ res->wrk->queue(t); ++ } ++ } ++} ++ ++void RunJob::jobInfo(task *t) ++{ ++ char ed1[50]; ++ res->mutex->lock(); ++ if (res->infos.CorrNbJob == 0) { ++ ui.boxEstimate->setVisible(false); ++ } else { ++ QString t; ++ edit_uint64_with_suffix(res->infos.JobBytes, ed1); ++ strncat(ed1, "B", sizeof(ed1)); ++ ui.labelJobBytes->setText(QString(ed1)); ++ ui.labelJobFiles->setText(QString(edit_uint64_with_commas(res->infos.JobFiles, ed1))); ++ ui.labelJobLevel->setText(QString(job_level_to_str(res->infos.JobLevel))); ++ t = tr("Computed over %1 job%2, the correlation is %3/100.").arg(res->infos.CorrNbJob).arg(res->infos.CorrNbJob>1?"s":"").arg(res->infos.CorrJobBytes); ++ ui.labelJobBytes_2->setToolTip(t); ++ t = tr("Computed over %1 job%2, The correlation is %3/100.").arg(res->infos.CorrNbJob).arg(res->infos.CorrNbJob>1?"s":"").arg(res->infos.CorrJobFiles); ++ ui.labelJobFiles_2->setToolTip(t); ++ ui.boxEstimate->setVisible(true); ++ } ++ res->mutex->unlock(); ++ t->deleteLater(); ++} ++ ++static void set_combo(QComboBox *dest, char *str) ++{ ++ if (str) { ++ int idx = dest->findText(QString(str), Qt::MatchExactly); ++ if (idx >= 0) { ++ dest->setCurrentIndex(idx); ++ } ++ } ++} ++ ++void RunJob::fill_defaults(task *t) ++{ ++ if (t->status == true) { ++ res->mutex->lock(); ++ set_combo(ui.levelCombo, res->defaults.level); ++ set_combo(ui.filesetCombo, res->defaults.fileset); ++ set_combo(ui.clientCombo, res->defaults.client); ++ set_combo(ui.storageCombo, res->defaults.storage); ++ set_combo(ui.poolCombo, res->defaults.pool); ++ set_combo(ui.catalogCombo, res->defaults.catalog); ++ res->mutex->unlock(); ++ } ++ ++ ui.tab2->setEnabled(true); ++ t->deleteLater(); ++} ++ ++RunJob::~RunJob() ++{ ++ Dmsg0(10, "~RunJob()\n"); ++ if (tabAdvanced) { ++ delete tabAdvanced; ++ } ++} ++ ++void TSched::init(const char *cmd_dir) ++{ ++ bool started = (timer >= 0); ++ if (started) { ++ stop(); ++ } ++ ++ bfree_and_null(command_dir); ++ command_dir = bstrdup(cmd_dir); ++ ++ if (started) { ++ start(); ++ } ++} ++ ++TSched::TSched() { ++ timer = -1; ++ command_dir = NULL; ++} ++ ++TSched::~TSched() { ++ if (timer >= 0) { ++ stop(); ++ } ++ bfree_and_null(command_dir); ++} ++ ++#ifndef HAVE_READDIR_R ++int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result); ++#else ++#include ++#endif ++ ++bool TSched::read_command_file(const char *file, alist *lst, btime_t mtime) ++{ ++ POOLMEM *line; ++ bool ret=false; ++ char *p; ++ TSchedJob *s; ++ Dmsg1(50, "open command file %s\n", file); ++ FILE *fp = fopen(file, "r"); ++ if (!fp) { ++ return false; ++ } ++ line = get_pool_memory(PM_FNAME); ++ ++ /* Get the first line, client/component:command */ ++ while (bfgets(line, fp) != NULL) { ++ strip_trailing_junk(line); ++ Dmsg1(50, "%s\n", line); ++ if (line[0] == '#') { ++ continue; ++ } ++ ++ if ((p = strchr(line, ':')) != NULL) { ++ *p=0; ++ s = new TSchedJob(line, p+1, mtime); ++ lst->append(s); ++ ret = true; ++ } ++ } ++ ++ free_pool_memory(line); ++ fclose(fp); ++ return ret; ++} ++ ++#include "lib/plugins.h" ++#include "lib/cmd_parser.h" ++ ++void TSched::timerEvent(QTimerEvent *event) ++{ ++ POOL_MEM tmp, command; ++ TSchedJob *j; ++ alist lst(10, not_owned_by_alist); ++ arg_parser parser; ++ int i; ++ task *t; ++ RESMON *res; ++ scan_for_commands(&lst); ++ ++ foreach_alist(j, (&lst)) { ++ if (parser.parse_cmd(j->command) == bRC_OK) { ++ if ((i = parser.find_arg_with_value("job")) > 0) { ++ QMessageBox msgbox; ++ foreach_res(res, R_CLIENT) { ++ if (strcmp(res->hdr.name, j->component) == 0) { ++ break; ++ } ++ } ++ if (!res) { ++ foreach_res(res, R_DIRECTOR) { ++ if (strcmp(res->hdr.name, j->component) == 0) { ++ break; ++ } ++ } ++ } ++ if (!res) { ++ msgbox.setIcon(QMessageBox::Information); ++ msgbox.setText(QString("Unable to find the component \"%1\" to run the job \"%2\".").arg(j->component, j->command)); ++ msgbox.setStandardButtons(QMessageBox::Ignore); ++ } else { ++ ++ msgbox.setIcon(QMessageBox::Information); ++ msgbox.setText(QString("The job \"%1\" will start automatically in few seconds...").arg(parser.argv[i])); ++ msgbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Ignore); ++ msgbox.setDefaultButton(QMessageBox::Ok); ++ msgbox.button(QMessageBox::Ok)->animateClick(6000); ++ } ++ switch(msgbox.exec()) { ++ case QMessageBox::Ok: ++ Mmsg(command, "%s yes", j->command); ++ ++ if (res->type == R_CLIENT) { ++ pm_strcat(command, " fdcalled=1"); ++ } ++ ++ // Build the command and run it! ++ t = new task(); ++ connect(t, SIGNAL(done(task *)), this, SLOT(jobStarted(task *)), Qt::QueuedConnection); ++ t->arg = command.c_str(); ++ t->init(res, TASK_RUN); ++ res->wrk->queue(t); ++ ++ break; ++ case QMessageBox::Cancel: ++ case QMessageBox::Ignore: ++ break; ++ } ++ } ++ } ++ delete j; ++ } ++} ++ ++void TSched::jobStarted(task *t) ++{ ++ Dmsg1(10, "-> jobid=%d\n", t->result.i); ++ t->deleteLater(); ++} ++ ++ ++bool TSched::scan_for_commands(alist *commands) ++{ ++ int name_max, len; ++ DIR* dp = NULL; ++ POOL_MEM fname(PM_FNAME), fname2(PM_FNAME); ++ bool ret=false, found=false; ++ struct dirent *entry = NULL, *result; ++ struct stat statp; ++ ++ name_max = pathconf(".", _PC_NAME_MAX); ++ if (name_max < 1024) { ++ name_max = 1024; ++ } ++ ++ if (!(dp = opendir(command_dir))) { ++ berrno be; ++ Dmsg2(0, "Failed to open directory %s: ERR=%s\n", ++ command_dir, be.bstrerror()); ++ goto bail_out; ++ } ++ ++ entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000); ++ for ( ;; ) { ++ if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) { ++ if (!found) { ++ goto bail_out; ++ } ++ break; ++ } ++ if (strcmp(result->d_name, ".") == 0 || ++ strcmp(result->d_name, "..") == 0) { ++ continue; ++ } ++ len = strlen(result->d_name); ++ if (len <= 5) { ++ continue; ++ } ++ if (strcmp(result->d_name + len - 5, ".bcmd") != 0) { ++ continue; ++ } ++ ++ Mmsg(fname, "%s/%s", command_dir, result->d_name); ++ ++ if (lstat(fname.c_str(), &statp) != 0 || !S_ISREG(statp.st_mode)) { ++ continue; /* ignore directories & special files */ ++ } ++ ++ if (read_command_file(fname.c_str(), commands, statp.st_mtime)) { ++ Mmsg(fname2, "%s.ok", fname.c_str()); ++ unlink(fname2.c_str()); ++ rename(fname.c_str(), fname2.c_str()); // TODO: We should probably unlink the file ++ } ++ } ++bail_out: ++ if (entry) { ++ free(entry); ++ } ++ if (dp) { ++ closedir(dp); ++ } ++ return ret; ++} +diff --git a/bacula/src/qt-console/tray-monitor/runjob.h b/bacula/src/qt-console/tray-monitor/runjob.h +new file mode 100644 +index 000000000..6333865bd +--- /dev/null ++++ b/bacula/src/qt-console/tray-monitor/runjob.h +@@ -0,0 +1,118 @@ ++/* ++ Bacula(R) - The Network Backup Solution ++ ++ Copyright (C) 2000-2017 Kern Sibbald ++ ++ The original author of Bacula is Kern Sibbald, with contributions ++ from many others, a complete list can be found in the file AUTHORS. ++ ++ You may use this file and others of this release according to the ++ license defined in the LICENSE file, which includes the Affero General ++ Public License, v3.0 ("AGPLv3") and some additional permissions and ++ terms pursuant to its AGPLv3 Section 7. ++ ++ This notice must be preserved when any source code is ++ conveyed and/or propagated. ++ ++ Bacula(R) is a registered trademark of Kern Sibbald. ++*/ ++ ++#ifndef RUN_H ++#define RUN_H ++ ++#include "common.h" ++#include "ui_run.h" ++#include "tray_conf.h" ++#include "task.h" ++ ++class RunJob: public QDialog ++{ ++ Q_OBJECT ++ ++public: ++ RESMON *res; ++ QWidget *tabAdvanced; ++ POOL_MEM command; ++ POOL_MEM info; ++ POOL_MEM level; ++ POOL_MEM curjob; ++ Ui::runForm ui; ++ RunJob(RESMON *r); ++ ~RunJob(); ++ ++public slots: ++ void jobChanged(int); ++ void levelChanged(int); ++ void jobStarted(task *); ++ void jobInfo(task *); ++ void fill_defaults(task *); ++ void tabChange(int idx); ++ void runjob(); ++ /* close the window properly */ ++ void close_cb(task *t); ++ void close_cb(); ++}; ++ ++/* Object that can scan a directory to find jobs */ ++class TSched: public QObject ++{ ++ Q_OBJECT ++private: ++ char *command_dir; ++ bool read_command_file(const char *file, alist *lst, btime_t mtime); ++ int timer; ++ ++public: ++ TSched(); ++ ~TSched(); ++ void init(const char *cmd_dir); ++ bool scan_for_commands(alist *lst); ++ void start() { ++ timer = startTimer(60000); // 1-minute timer ++ }; ++ void stop() { ++ if (timer >= 0) { ++ killTimer(timer); ++ timer = -1; ++ } ++ }; ++public slots: ++ void jobStarted(task *t); ++protected: ++ void timerEvent(QTimerEvent *event); ++ ++}; ++ ++ ++/* Job found in the command directory */ ++class TSchedJob: public QObject ++{ ++ Q_OBJECT ++ ++public: ++ char *component; // Name of the daemon ++ char *command; // job command ++ btime_t create_date; // When the command file was created ++ TSchedJob() : component(NULL), command(NULL) {}; ++ ++ TSchedJob(const char *comp, const char *cmd, btime_t cd) { ++ component = bstrdup(comp); ++ command = bstrdup(cmd); ++ create_date = cd; ++ }; ++ ++ ~TSchedJob() { ++ clear(); ++ }; ++ void clear() { ++ if (component) { ++ bfree_and_null(component); ++ } ++ if (command) { ++ bfree_and_null(command); ++ } ++ create_date = 0; ++ }; ++}; ++ ++#endif +diff --git a/bacula/src/qt-console/tray-monitor/sd-monitor.ui b/bacula/src/qt-console/tray-monitor/sd-monitor.ui +new file mode 100644 +index 000000000..3c00e6c9f +--- /dev/null ++++ b/bacula/src/qt-console/tray-monitor/sd-monitor.ui +@@ -0,0 +1,162 @@ ++ ++ ++ sdStatus ++ ++ ++ ++ 0 ++ 0 ++ 518 ++ 435 ++ ++ ++ ++ Form ++ ++ ++ ++ ++ ++ ++ ++ Storage Daemon Status ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Name: ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Started: ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Version: ++ ++ ++ ++ ++ ++ ++ Plugins: ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Running Jobs ++ ++ ++ ++ ++ ++ QAbstractItemView::SingleSelection ++ ++ ++ false ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Terminated Jobs ++ ++ ++ ++ ++ ++ QAbstractItemView::SingleSelection ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 40 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ :/images/view-refresh.png:/images/view-refresh.png ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/bacula/src/qt-console/tray-monitor/sdstatus.cpp b/bacula/src/qt-console/tray-monitor/sdstatus.cpp +new file mode 100644 +index 000000000..741305afb +--- /dev/null ++++ b/bacula/src/qt-console/tray-monitor/sdstatus.cpp +@@ -0,0 +1,125 @@ ++/* ++ Bacula(R) - The Network Backup Solution ++ ++ Copyright (C) 2000-2017 Kern Sibbald ++ ++ The original author of Bacula is Kern Sibbald, with contributions ++ from many others, a complete list can be found in the file AUTHORS. ++ ++ You may use this file and others of this release according to the ++ license defined in the LICENSE file, which includes the Affero General ++ Public License, v3.0 ("AGPLv3") and some additional permissions and ++ terms pursuant to its AGPLv3 Section 7. ++ ++ This notice must be preserved when any source code is ++ conveyed and/or propagated. ++ ++ Bacula(R) is a registered trademark of Kern Sibbald. ++*/ ++ ++#include "sdstatus.h" ++#include "../util/fmtwidgetitem.h" ++#include "jcr.h" ++ ++void SDStatus::doUpdate() ++{ ++ if (count == 0) { ++ count++; ++ task *t = new task(); ++ status.pushButton->setEnabled(false); ++ connect(t, SIGNAL(done(task *)), this, SLOT(taskDone(task *)), Qt::QueuedConnection); ++ t->init(res, TASK_STATUS); ++ res->wrk->queue(t); ++ status.statusBar->setText(QString("Trying to connect to Storage...")); ++ Dmsg1(50, "doUpdate(%p)\n", res); ++ } ++} ++ ++void SDStatus::taskDone(task *t) ++{ ++ count--; ++ if (!t->status) { ++ status.statusBar->setText(QString(t->errmsg)); ++ ++ } else { ++ status.statusBar->clear(); ++ if (t->type == TASK_STATUS) { ++ char ed1[50]; ++ struct s_last_job *ljob; ++ struct s_running_job *rjob; ++ res->mutex->lock(); ++ status.labelName->setText(QString(res->name)); ++ status.labelVersion->setText(QString(res->version)); ++ status.labelStarted->setText(QString(res->started)); ++ status.labelPlugins->setText(QString(res->plugins)); ++ /* Clear the table first */ ++ Freeze(*status.tableRunning); ++ Freeze(*status.tableTerminated); ++ QStringList headerlistR = (QStringList() << tr("JobId") ++ << tr("Job") << tr("Level") << tr("Client") ++ << tr("Storage") ++ << tr("Files") << tr("Bytes") << tr("Errors")); ++ status.tableRunning->clear(); ++ status.tableRunning->setRowCount(0); ++ status.tableRunning->setColumnCount(headerlistR.count()); ++ status.tableRunning->setHorizontalHeaderLabels(headerlistR); ++ status.tableRunning->setEditTriggers(QAbstractItemView::NoEditTriggers); ++ status.tableRunning->verticalHeader()->hide(); ++ status.tableRunning->setSortingEnabled(true); ++ ++ if (res->running_jobs) { ++ status.tableRunning->setRowCount(res->running_jobs->size()); ++ int row=0; ++ foreach_alist(rjob, res->running_jobs) { ++ int col=0; ++ TableItemFormatter item(*status.tableRunning, row++); ++ item.setNumericFld(col++, QString(edit_uint64(rjob->JobId, ed1))); ++ item.setTextFld(col++, QString(rjob->Job)); ++ item.setJobLevelFld(col++, QString(rjob->JobLevel)); ++ item.setTextFld(col++, QString(rjob->Client)); ++ item.setTextFld(col++, QString(rjob->Storage)); ++ item.setNumericFld(col++, QString(edit_uint64(rjob->JobFiles, ed1))); ++ item.setBytesFld(col++, QString(edit_uint64(rjob->JobBytes, ed1))); ++ item.setNumericFld(col++, QString(edit_uint64(rjob->Errors, ed1))); ++ } ++ } else { ++ Dmsg0(0, "Strange, the list is NULL\n"); ++ } ++ ++ QStringList headerlistT = (QStringList() << tr("JobId") ++ << tr("Job") << tr("Level") ++ << tr("Status") << tr("Files") << tr("Bytes") ++ << tr("Errors")); ++ ++ status.tableTerminated->clear(); ++ status.tableTerminated->setRowCount(0); ++ status.tableTerminated->setColumnCount(headerlistT.count()); ++ status.tableTerminated->setHorizontalHeaderLabels(headerlistT); ++ status.tableTerminated->setEditTriggers(QAbstractItemView::NoEditTriggers); ++ status.tableTerminated->verticalHeader()->hide(); ++ status.tableTerminated->setSortingEnabled(true); ++ ++ if (res->terminated_jobs) { ++ status.tableTerminated->setRowCount(res->terminated_jobs->size()); ++ int row=0; ++ foreach_dlist(ljob, res->terminated_jobs) { ++ int col=0; ++ TableItemFormatter item(*status.tableTerminated, row++); ++ item.setNumericFld(col++, QString(edit_uint64(ljob->JobId, ed1))); ++ item.setTextFld(col++, QString(ljob->Job)); ++ item.setJobLevelFld(col++, QString(ljob->JobLevel)); ++ item.setJobStatusFld(col++, QString(ljob->JobStatus)); ++ item.setNumericFld(col++, QString(edit_uint64(ljob->JobFiles, ed1))); ++ item.setBytesFld(col++, QString(edit_uint64(ljob->JobBytes, ed1))); ++ item.setNumericFld(col++, QString(edit_uint64(ljob->Errors, ed1))); ++ } ++ } else { ++ Dmsg0(0, "Strange, the list is NULL\n"); ++ } ++ res->mutex->unlock(); ++ } ++ Dmsg1(50, " Task %p OK\n", t); ++ } ++ t->deleteLater(); ++ status.pushButton->setEnabled(true); ++} +diff --git a/bacula/src/qt-console/tray-monitor/sdstatus.h b/bacula/src/qt-console/tray-monitor/sdstatus.h +new file mode 100644 +index 000000000..17f0a3fd4 +--- /dev/null ++++ b/bacula/src/qt-console/tray-monitor/sdstatus.h +@@ -0,0 +1,42 @@ ++/* ++ Bacula(R) - The Network Backup Solution ++ ++ Copyright (C) 2000-2017 Kern Sibbald ++ ++ The original author of Bacula is Kern Sibbald, with contributions ++ from many others, a complete list can be found in the file AUTHORS. ++ ++ You may use this file and others of this release according to the ++ license defined in the LICENSE file, which includes the Affero General ++ Public License, v3.0 ("AGPLv3") and some additional permissions and ++ terms pursuant to its AGPLv3 Section 7. ++ ++ This notice must be preserved when any source code is ++ conveyed and/or propagated. ++ ++ Bacula(R) is a registered trademark of Kern Sibbald. ++*/ ++ ++#include "common.h" ++#include "ui_sd-monitor.h" ++#include "task.h" ++#include "status.h" ++ ++class SDStatus: public ResStatus ++{ ++ Q_OBJECT ++ ++public: ++ Ui::sdStatus status; ++ ++ SDStatus(RESMON *d): ResStatus(d) ++ { ++ status.setupUi(this); ++ QObject::connect(status.pushButton, SIGNAL(clicked()), this, SLOT(doUpdate()), Qt::QueuedConnection); ++ }; ++ ~SDStatus() { ++ }; ++public slots: ++ void doUpdate(); ++ void taskDone(task *); ++}; +diff --git a/bacula/src/qt-console/tray-monitor/status.cpp b/bacula/src/qt-console/tray-monitor/status.cpp +new file mode 100644 +index 000000000..8320c5b22 +--- /dev/null ++++ b/bacula/src/qt-console/tray-monitor/status.cpp +@@ -0,0 +1,42 @@ ++/* ++ Bacula(R) - The Network Backup Solution ++ ++ Copyright (C) 2000-2017 Kern Sibbald ++ ++ The original author of Bacula is Kern Sibbald, with contributions ++ from many others, a complete list can be found in the file AUTHORS. ++ ++ You may use this file and others of this release according to the ++ license defined in the LICENSE file, which includes the Affero General ++ Public License, v3.0 ("AGPLv3") and some additional permissions and ++ terms pursuant to its AGPLv3 Section 7. ++ ++ This notice must be preserved when any source code is ++ conveyed and/or propagated. ++ ++ Bacula(R) is a registered trademark of Kern Sibbald. ++*/ ++ ++#include "status.h" ++#include "lib/worker.h" ++ ++void ResStatus::doUpdate() ++{ ++ if (count == 0) { ++ task *t = new task(); ++ connect(t, SIGNAL(done(task *)), this, SLOT(taskDone(task *)), Qt::QueuedConnection); ++ t->init(res, TASK_STATUS); ++ res->wrk->queue(t); ++ Dmsg0(0, "doUpdate()\n"); ++ count++; ++ } ++} ++ ++void ResStatus::taskDone(task *t) ++{ ++ if (!t->status) { ++ Dmsg2(0, " Task %p failed => %s\n", t, t->errmsg); ++ } ++ delete t; ++ count--; ++} +diff --git a/bacula/src/qt-console/tray-monitor/status.h b/bacula/src/qt-console/tray-monitor/status.h +new file mode 100644 +index 000000000..0e0f4ea98 +--- /dev/null ++++ b/bacula/src/qt-console/tray-monitor/status.h +@@ -0,0 +1,44 @@ ++/* ++ Bacula(R) - The Network Backup Solution ++ ++ Copyright (C) 2000-2017 Kern Sibbald ++ ++ The original author of Bacula is Kern Sibbald, with contributions ++ from many others, a complete list can be found in the file AUTHORS. ++ ++ You may use this file and others of this release according to the ++ license defined in the LICENSE file, which includes the Affero General ++ Public License, v3.0 ("AGPLv3") and some additional permissions and ++ terms pursuant to its AGPLv3 Section 7. ++ ++ This notice must be preserved when any source code is ++ conveyed and/or propagated. ++ ++ Bacula(R) is a registered trademark of Kern Sibbald. ++*/ ++ ++#ifndef STATUS_H ++#define STATUS_H ++ ++#include "common.h" ++#include ++#include "tray_conf.h" ++#include "task.h" ++ ++class ResStatus: public QWidget ++{ ++ Q_OBJECT ++ ++public: ++ int count; ++ RESMON *res; ++ ResStatus(RESMON *c): count(0), res(c) { ++ }; ++ virtual ~ResStatus() { ++ }; ++public slots: ++ virtual void doUpdate(); ++ virtual void taskDone(task *t); ++}; ++ ++#endif +diff --git a/bacula/src/qt-console/tray-monitor/task.cpp b/bacula/src/qt-console/tray-monitor/task.cpp +new file mode 100644 +index 000000000..911ba2f3d +--- /dev/null ++++ b/bacula/src/qt-console/tray-monitor/task.cpp +@@ -0,0 +1,951 @@ ++/* ++ Bacula(R) - The Network Backup Solution ++ ++ Copyright (C) 2000-2017 Kern Sibbald ++ ++ The original author of Bacula is Kern Sibbald, with contributions ++ from many others, a complete list can be found in the file AUTHORS. ++ ++ You may use this file and others of this release according to the ++ license defined in the LICENSE file, which includes the Affero General ++ Public License, v3.0 ("AGPLv3") and some additional permissions and ++ terms pursuant to its AGPLv3 Section 7. ++ ++ This notice must be preserved when any source code is ++ conveyed and/or propagated. ++ ++ Bacula(R) is a registered trademark of Kern Sibbald. ++*/ ++ ++#include "task.h" ++#include "jcr.h" ++#define dbglvl 10 ++int authenticate_daemon(JCR *jcr, MONITOR *monitor, RESMON *res); ++ ++static void *handle_task(void *data) ++{ ++ task *t; ++ worker *wrk = (worker *)data; ++ lmgr_init_thread(); ++ ++ wrk->set_running(); ++ Dmsg0(dbglvl, "Worker started\n"); ++ ++ while (!wrk->is_quit_state()) { ++ if (wrk->is_wait_state()) { ++ wrk->wait(); ++ continue; ++ } ++ t = (task *)wrk->dequeue(); ++ if (!t) { ++ continue; ++ } ++ /* Do the work */ ++ switch(t->type) { ++ case TASK_STATUS: ++ t->do_status(); ++ break; ++ case TASK_RESOURCES: ++ t->get_resources(); ++ break; ++ case TASK_DEFAULTS: ++ t->get_job_defaults(); ++ break; ++ case TASK_RUN: ++ t->run_job(); ++ break; ++ case TASK_BWLIMIT: ++ t->set_bandwidth(); ++ break; ++ case TASK_INFO: ++ t->get_job_info(t->arg2); ++ break; ++ case TASK_DISCONNECT: ++ t->disconnect_bacula(); ++ t->mark_as_done(); ++ break; ++ default: ++ Mmsg(t->errmsg, "Unknown task"); ++ t->mark_as_failed(); ++ break; ++ } ++ } ++ Dmsg0(dbglvl, "Worker stoped\n"); ++ lmgr_cleanup_thread(); ++ return NULL; ++} ++ ++bool task::set_bandwidth() ++{ ++ bool ret = false; ++ btimer_t *tid = NULL; ++ if (res->type != R_CLIENT) { ++ mark_as_failed(); ++ Mmsg(errmsg, _("Bandwidth can set only set on Client")); ++ return false; ++ } ++ if (!arg || !*arg) { ++ mark_as_failed(); ++ Mmsg(errmsg, _("Bandwidth parameter is invalid")); ++ return false; ++ } ++ ++ if (res->proxy_sent) { ++ free_bsock(res->bs); ++ } ++ ++ if (!res->bs || !res->bs->is_open() || res->bs->is_error()) { ++ if (!connect_bacula()) { ++ mark_as_failed(); ++ return false; ++ } ++ } ++ ++ tid = start_thread_timer(NULL, pthread_self(), (uint32_t)120); ++ res->bs->fsend("setbandwidth limit=%s\n", NPRTB(arg)); ++ while (get_next_line(res)) { ++ Dmsg1(dbglvl, "-> %s\n", curline); ++ } ++ ++ if (tid) { ++ stop_thread_timer(tid); ++ } ++ ++ /* Do not reuse the same socket */ ++ disconnect_bacula(); ++ ++ if (ret) { ++ mark_as_done(); ++ } else { ++ mark_as_failed(); ++ } ++ return ret; ++} ++ ++RESMON *task::get_res() ++{ ++ return res; ++} ++ ++void task::lock_res() ++{ ++ res->mutex->lock(); ++} ++ ++void task::unlock_res() ++{ ++ res->mutex->unlock(); ++} ++ ++bool task::disconnect_bacula() ++{ ++ free_bsock(res->bs); ++ return true; ++} ++ ++bool task::connect_bacula() ++{ ++ JCR jcr; ++ bool ret = false; ++ memset(&jcr, 0, sizeof(jcr)); ++ curend = curline = NULL; ++ ++ RESMON *r = get_res(); ++ MONITOR *monitor = (MONITOR*)GetNextRes(R_MONITOR, NULL); ++ ++ if (r->type == R_CLIENT) { ++ r->proxy_sent = false; ++ if (r->bs && (r->bs->is_error() || !r->bs->is_open())) { ++ free_bsock(r->bs); ++ } ++ if (!r->bs) { ++ r->bs = new_bsock(); ++ Dmsg0(dbglvl, "Trying to connect to FD\n"); ++ if (r->bs->connect(NULL, r->connect_timeout, 0, 0, _("Client daemon"), ++ r->address, NULL, r->port, 0)) ++ { ++ Dmsg0(dbglvl, "Connect done!\n"); ++ jcr.file_bsock = r->bs; ++ if (!authenticate_daemon(&jcr, monitor, r)) { ++ Dmsg0(dbglvl, "Unable to authenticate\n"); ++ Mmsg(errmsg, "Unable to authenticate with the FileDaemon"); ++ free_bsock(r->bs); ++ return false; ++ } ++ Dmsg0(dbglvl, "Authenticate OK\n"); ++ ret = true; ++ } else { ++ Mmsg(errmsg, "Unable to connect to the FileDaemon"); ++ Dmsg0(dbglvl, "Connect error!\n"); ++ } ++ } else { ++ ret = true; ++ } ++ } ++ if (r->type == R_STORAGE) { ++ if (r->bs && (r->bs->is_error() || !r->bs->is_open())) { ++ free_bsock(r->bs); ++ } ++ if (!r->bs) { ++ r->bs = new_bsock(); ++ Dmsg0(dbglvl, "Trying to connect to FD\n"); ++ if (r->bs->connect(NULL, r->connect_timeout, 0, 0, _("Storage daemon"), ++ r->address, NULL, r->port, 0)) ++ { ++ Dmsg0(dbglvl, "Connect done!\n"); ++ jcr.store_bsock = r->bs; ++ if (!authenticate_daemon(&jcr, monitor, r)) { ++ Dmsg0(dbglvl, "Unable to authenticate\n"); ++ Mmsg(errmsg, "Unable to authenticate with the Storage Daemon"); ++ free_bsock(r->bs); ++ return false; ++ } ++ Dmsg0(dbglvl, "Authenticate OK\n"); ++ ret = true; ++ } else { ++ Mmsg(errmsg, "Unable to connect to the Storage Daemon"); ++ Dmsg0(dbglvl, "Connect error!\n"); ++ } ++ } else { ++ ret = true; ++ } ++ } ++ if (r->type == R_DIRECTOR) { ++ if (r->bs && (r->bs->is_error() || !r->bs->is_open())) { ++ free_bsock(r->bs); ++ } ++ if (!r->bs) { ++ r->bs = new_bsock(); ++ Dmsg0(dbglvl, "Trying to connect to DIR\n"); ++ if (r->bs->connect(NULL, r->connect_timeout, 0, 0, _("Director daemon"), ++ r->address, NULL, r->port, 0)) ++ { ++ Dmsg0(dbglvl, "Connect done!\n"); ++ jcr.dir_bsock = r->bs; ++ if (!authenticate_daemon(&jcr, monitor, r)) { ++ Dmsg0(dbglvl, "Unable to authenticate\n"); ++ Mmsg(errmsg, "Unable to authenticate with the Director"); ++ free_bsock(r->bs); ++ return false; ++ } ++ Dmsg0(dbglvl, "Authenticate OK\n"); ++ ret = true; ++ } else { ++ Mmsg(errmsg, "Unable to connect to the Director"); ++ Dmsg0(dbglvl, "Connect error!\n"); ++ } ++ } else { ++ ret = true; ++ } ++ } ++ return ret; ++} ++ ++bool task::read_status_running(RESMON *r) ++{ ++ bool ret = false; ++ char *start, *end; ++ struct s_running_job *item = NULL; ++ alist *running_jobs = New(alist(10, owned_by_alist)); ++ ++ while (r->bs->recv() >= -1) { ++ if (r->bs->msglen < 0 && ++ r->bs->msglen != BNET_CMD_BEGIN && ++ r->bs->msglen != BNET_CMD_OK) ++ { ++ Dmsg1(dbglvl, "Got Signal %s\n", bnet_sig_to_ascii(r->bs->msglen)); ++ break; ++ } ++ Dmsg2(dbglvl, "RECV -> %s:%d\n", r->bs->msg, r->bs->msglen); ++ start = r->bs->msg; ++ ++ while ((end = strchr(start, '\n')) != NULL) { ++ *end = 0; ++ Dmsg1(dbglvl, "line=[%s]\n", start); ++ if (strncasecmp(start, "jobid=", 6) == 0) { ++ if (item) { ++ Dmsg1(dbglvl, "Append item %ld\n", item->JobId); ++ running_jobs->append(item); ++ } ++ item = (struct s_running_job *)malloc(sizeof(struct s_running_job)); ++ memset(item, 0, sizeof(struct s_running_job)); ++ item->JobId = str_to_uint64(start + 6); ++ ++ } else if (!item) { ++ Dmsg0(dbglvl, "discard line\n"); ++ ++ } else if (strncasecmp(start, "level=", 6) == 0) { ++ item->JobLevel = start[6]; ++ ++ } else if (strncasecmp(start, "type=", 5) == 0) { ++ item->JobType = start[5]; ++ ++ } else if (strncasecmp(start, "status=", 7) == 0) { ++ item->JobStatus = start[7]; ++ ++ } else if (strncasecmp(start, "jobbytes=", 9) == 0) { ++ item->JobBytes = str_to_uint64(start + 9); ++ ++ } else if (strncasecmp(start, "jobfiles=", 9) == 0) { ++ item->JobFiles = str_to_uint64(start + 9); ++ ++ } else if (strncasecmp(start, "job=", 4) == 0) { ++ bstrncpy(item->Job, start + 4, sizeof(item->Job)); ++ ++ } else if (strncasecmp(start, "starttime_epoch=", 16) == 0) { ++ item->start_time = str_to_uint64(start + 16); ++ ++ } else if (strncasecmp(start, "schedtime_epoch=", 16) == 0) { ++ item->sched_time = str_to_uint64(start + 16); ++ ++ } else if (strncasecmp(start, "bytes/sec=", 10) == 0) { ++ item->bytespersec = str_to_uint64(start + 10); ++ ++ } else if (strncasecmp(start, "avebytes_sec=", 13) == 0) { ++ item->bytespersec = str_to_uint64(start + 13); ++ ++ } else if (strncasecmp(start, "errors=", 7) == 0) { ++ item->Errors = str_to_uint64(start + 7); ++ ++ } else if (strncasecmp(start, "readbytes=", 10) == 0) { ++ item->ReadBytes = str_to_uint64(start + 10); ++ ++ } else if (strncasecmp(start, "processing file=", 16) == 0) { ++ bstrncpy(item->CurrentFile, start + 16, sizeof(item->CurrentFile)); ++ ++ } else if (strncasecmp(start, "clientname=", 11) == 0) { ++ bstrncpy(item->Client, start + 11, sizeof(item->Client)); ++ ++ } else if (strncasecmp(start, "fileset=", 8) == 0) { ++ bstrncpy(item->FileSet, start + 8, sizeof(item->FileSet)); ++ ++ } else if (strncasecmp(start, "storage=", 8) == 0) { ++ bstrncpy(item->Storage, start + 8, sizeof(item->Storage)); ++ ++ } else if (strncasecmp(start, "rstorage=", 8) == 0) { ++ bstrncpy(item->RStorage, start + 8, sizeof(item->Storage)); ++ ++ } else if (strncasecmp(start, "sdtls=", 6) == 0) { ++ item->SDtls = str_to_uint64(start + 6); ++ } ++ start = end+1; ++ } ++ r->last_update = time(NULL); ++ ++ if (r->bs->is_error()) { ++ Mmsg(errmsg, "Got error on the socket communication line"); ++ goto bail_out; ++ } ++ } ++ if (item) { ++ Dmsg1(dbglvl, "Append item %ld\n", item->JobId); ++ running_jobs->append(item); ++ } ++ ret = true; ++ ++bail_out: ++ r->mutex->lock(); ++ if (r->running_jobs) { ++ delete r->running_jobs; ++ } ++ r->running_jobs = running_jobs; ++ r->mutex->unlock(); ++ ++ return ret; ++} ++ ++bool task::read_status_terminated(RESMON *r) ++{ ++ bool ret = false; ++ char *start, *end; ++ struct s_last_job *item = NULL; ++ ++ r->mutex->lock(); ++ if (r->terminated_jobs) { ++ delete r->terminated_jobs; ++ } ++ r->terminated_jobs = New(dlist(item, &item->link)); ++ r->mutex->unlock(); ++ ++ while (r->bs->recv() >= -1) { ++ if (r->bs->msglen < 0 && ++ r->bs->msglen != BNET_CMD_BEGIN && ++ r->bs->msglen != BNET_CMD_OK) ++ { ++ Dmsg1(dbglvl, "Got Signal %s\n", bnet_sig_to_ascii(r->bs->msglen)); ++ break; ++ } ++ ++ Dmsg2(dbglvl, "RECV -> %s:%d\n", r->bs->msg, r->bs->msglen); ++ r->mutex->lock(); ++ start = r->bs->msg; ++ ++ while ((end = strchr(start, '\n')) != NULL) { ++ *end = 0; ++ Dmsg1(dbglvl, "line=[%s]\n", start); ++ if (strncasecmp(start, "jobid=", 6) == 0) { ++ if (item) { ++ Dmsg1(dbglvl, "Append item %ld\n", item->JobId); ++ r->terminated_jobs->append(item); ++ } ++ item = (struct s_last_job *)malloc(sizeof(struct s_last_job)); ++ memset(item, 0, sizeof(struct s_last_job)); ++ item->JobId = str_to_uint64(start + 6); ++ ++ } else if (!item) { ++ Dmsg0(dbglvl, "discard line\n"); ++ ++ } else if (strncasecmp(start, "level=", 6) == 0) { ++ item->JobLevel = start[6]; ++ ++ } else if (strncasecmp(start, "type=", 5) == 0) { ++ item->JobType = start[5]; ++ ++ } else if (strncasecmp(start, "status=", 7) == 0) { ++ item->JobStatus = start[7]; ++ ++ } else if (strncasecmp(start, "jobbytes=", 9) == 0) { ++ item->JobBytes = str_to_uint64(start + 9); ++ ++ } else if (strncasecmp(start, "jobfiles=", 9) == 0) { ++ item->JobFiles = str_to_uint64(start + 9); ++ ++ } else if (strncasecmp(start, "job=", 4) == 0) { ++ bstrncpy(item->Job, start + 4, sizeof(item->Job)); ++ ++ } else if (strncasecmp(start, "starttime_epoch=", 16) == 0) { ++ item->start_time = str_to_uint64(start + 16); ++ ++ } else if (strncasecmp(start, "endtime_epoch=", 14) == 0) { ++ item->end_time = str_to_uint64(start + 14); ++ ++ } else if (strncasecmp(start, "errors=", 7) == 0) { ++ item->Errors = str_to_uint64(start + 7); ++ } ++ start = end+1; ++ } ++ r->last_update = time(NULL); ++ r->mutex->unlock(); ++ ++ if (r->bs->is_error()) { ++ Mmsg(errmsg, "Got error on the socket communication line"); ++ goto bail_out; ++ } ++ } ++ if (item) { ++ r->mutex->lock(); ++ Dmsg1(dbglvl, "Append item %ld\n", item->JobId); ++ r->terminated_jobs->append(item); ++ r->mutex->unlock(); ++ } ++ ret = true; ++ ++bail_out: ++ return ret; ++} ++ ++bool task::read_status_header(RESMON *r) ++{ ++ bool ret = false; ++ char *start, *end; ++ ++ while (r->bs->recv() >= -1) { ++ if (r->bs->msglen < 0 && ++ r->bs->msglen != BNET_CMD_BEGIN && ++ r->bs->msglen != BNET_CMD_OK) ++ { ++ Dmsg1(dbglvl, "Got Signal %d\n", r->bs->msglen); ++ break; ++ } ++ ++ Dmsg2(dbglvl, "RECV -> %s:%d\n", r->bs->msg, r->bs->msglen); ++ r->mutex->lock(); ++ start = r->bs->msg; ++ ++ while ((end = strchr(start, '\n')) != NULL) { ++ *end = 0; ++ Dmsg1(dbglvl, "line=[%s]\n", start); ++ if (strncasecmp(start, "name=", 5) == 0) { ++ bstrncpy(r->name, start + 5, sizeof(r->name)); ++ ++ } else if (strncasecmp(start, "version=", 8) == 0) { ++ bstrncpy(r->version, start + 8, sizeof(r->version)); ++ ++ } else if (strncasecmp(start, "plugins=", 8) == 0) { ++ bstrncpy(r->plugins, start + 8, sizeof(r->plugins)); ++ ++ } else if (strncasecmp(start, "bwlimit=", 8) == 0) { ++ r->bwlimit = str_to_uint64(start + 8); ++ ++ } else if (strncasecmp(start, "started=", 8) == 0) { ++ bstrncpy(r->started, start + 8, sizeof(r->started)); ++ ++ } else if (strncasecmp(start, "reloaded=", 9) == 0) { ++ bstrncpy(r->reloaded, start + 9, sizeof(r->reloaded)); ++ } ++ start = end+1; ++ } ++ ++ if (r->bs->is_error()) { ++ r->mutex->unlock(); ++ Mmsg(errmsg, "Got error on the socket communication line"); ++ goto bail_out; ++ ++ } ++ r->last_update = time(NULL); ++ r->mutex->unlock(); ++ } ++ ret = true; ++bail_out: ++ return ret; ++} ++ ++ ++bool task::do_status() ++{ ++ bool ret = false; ++ btimer_t *tid = NULL; ++ ++ /* We don't want to use a proxy session */ ++ if (res->type == R_CLIENT && res->proxy_sent) { ++ free_bsock(res->bs); ++ } ++ if (!res->bs || !res->bs->is_open() || res->bs->is_error()) { ++ if (!connect_bacula()) { ++ goto bail_out; ++ } ++ } ++ /* TODO: */ ++ tid = start_thread_timer(NULL, pthread_self(), (uint32_t)120); ++ if (res->type == R_CLIENT || res->type == R_STORAGE) { ++ Dmsg0(dbglvl, "Send status command header\n"); ++ res->bs->fsend(".status header api=2\n"); ++ // TODO: Update a local set of variables and commit everything when it's done ++ ret = read_status_header(res); ++ ++ if (ret) { ++ res->bs->fsend(".status terminated api=2\n"); ++ ret = read_status_terminated(res); ++ } ++ if (ret) { ++ res->bs->fsend(".status running api=2\n"); ++ ret = read_status_running(res); ++ } ++ } ++ if (res->type == R_DIRECTOR) { ++ Dmsg0(dbglvl, "-> .api 2\n"); ++ res->bs->fsend(".api 2\n"); ++ while (get_next_line(res)) { ++ Dmsg2(dbglvl, "<- %d %s\n", res->bs->msglen, curline); ++ } ++ Dmsg0(dbglvl, "Send status command header\n"); ++ res->bs->fsend(".status dir header\n"); ++ // TODO: Update a local set of variables and commit everything when it's done ++ ret = read_status_header(res); ++ ++ if (ret) { ++ Dmsg0(dbglvl, "Send status command terminated\n"); ++ res->bs->fsend(".status dir terminated\n"); ++ ret = read_status_terminated(res); ++ } ++ if (ret) { ++ Dmsg0(dbglvl, "Send status command running\n"); ++ res->bs->fsend(".status dir running\n"); ++ ret = read_status_running(res); ++ } ++ } ++bail_out: ++ if (tid) { ++ stop_thread_timer(tid); ++ } ++ /* Use a new socket the next time */ ++ disconnect_bacula(); ++ if (ret) { ++ mark_as_done(); ++ } else { ++ mark_as_failed(); ++ } ++ return ret; ++} ++ ++bool task::get_next_line(RESMON *r) ++{ ++ /* We are currently reading a line */ ++ if (curline && curend && r->bs->msglen > 0 && curend < (r->bs->msg + r->bs->msglen - 1)) { ++ curline = curend + 1; /* skip \0 */ ++ if ((curend = strchr(curline, '\n')) != NULL) { ++ *curend = '\0'; ++ } ++ return true; ++ } ++ curline = curend = NULL; ++ do { ++ r->bs->recv(); ++ ++ if (r->bs->msglen < 0) { ++ Dmsg1(dbglvl, "<- %s\n", bnet_sig_to_ascii(r->bs->msglen)); ++ switch(r->bs->msglen) { ++ case BNET_ERROR_MSG: ++ r->bs->recv(); ++ strip_trailing_junk(r->bs->msg); ++ Dmsg1(0, "ERROR: %s\n", r->bs->msg); ++ break; ++ case BNET_MAIN_PROMPT: // stop ++ return false; ++ case BNET_CMD_OK: ++ case BNET_CMD_BEGIN: ++ case BNET_MSGS_PENDING: ++ break; ++ case BNET_TERMINATE: ++ return false; ++ default: // error or question? ++ return false; ++ } ++ ++ } else if (r->bs->msglen == 0) { // strange ++ return false; ++ ++ } else { ++ Dmsg1(10, "<- %s\n", r->bs->msg); ++ curline = r->bs->msg; ++ curend = strchr(curline, '\n'); ++ if (curend) { ++ *curend = 0; ++ } ++ return true; // something to read ++ } ++ } while (!r->bs->is_error()); ++ return false; ++} ++ ++bool task::get_job_defaults() ++{ ++ bool ret = false; ++ btimer_t *tid = NULL; ++ char *p; ++ ++ if (!res->bs || !res->bs->is_open() || res->bs->is_error()) { ++ if (!connect_bacula()) { ++ goto bail_out; ++ } ++ } ++ ++ res->mutex->lock(); ++ bfree_and_null(res->defaults.client); ++ bfree_and_null(res->defaults.pool); ++ bfree_and_null(res->defaults.storage); ++ bfree_and_null(res->defaults.level); ++ bfree_and_null(res->defaults.type); ++ bfree_and_null(res->defaults.fileset); ++ bfree_and_null(res->defaults.catalog); ++ ++ tid = start_thread_timer(NULL, pthread_self(), (uint32_t)120); ++ if (res->type == R_CLIENT && !res->proxy_sent) { ++ res->proxy_sent = true; ++ res->bs->fsend("proxy\n"); ++ while (get_next_line(res)) { ++ if (strncmp(curline, "2000", 4) != 0) { ++ pm_strcpy(errmsg, curline); ++ goto bail_out; ++ } ++ Dmsg2(dbglvl, "<- %d %s\n", res->bs->msglen, curline); ++ } ++ } ++ ++ res->bs->fsend(".api 2\n"); ++ while (get_next_line(res)) { ++ Dmsg2(dbglvl, "<- %d %s\n", res->bs->msglen, curline); ++ } ++ res->bs->fsend(".defaults job=\"%s\"\n", res->defaults.job); ++ while (get_next_line(res)) { ++ Dmsg1(dbglvl, "line = [%s]\n", curline); ++ if ((p = strchr(curline, '=')) == NULL) { ++ continue; ++ } ++ *p++ = 0; ++ if (strcasecmp(curline, "client") == 0) { ++ res->defaults.client = bstrdup(p); ++ ++ } else if (strcasecmp(curline, "pool") == 0) { ++ res->defaults.pool = bstrdup(p); ++ ++ } else if (strcasecmp(curline, "storage") == 0) { ++ res->defaults.storage = bstrdup(p); ++ ++ } else if (strcasecmp(curline, "level") == 0) { ++ res->defaults.level = bstrdup(p); ++ ++ } else if (strcasecmp(curline, "type") == 0) { ++ res->defaults.type = bstrdup(p); ++ ++ } else if (strcasecmp(curline, "fileset") == 0) { ++ res->defaults.fileset = bstrdup(p); ++ ++ } else if (strcasecmp(curline, "catalog") == 0) { ++ res->defaults.catalog = bstrdup(p); ++ ++ } else if (strcasecmp(curline, "priority") == 0) { ++ res->defaults.priority = str_to_uint64(p); ++ } ++ } ++ ret = true; ++bail_out: ++ if (tid) { ++ stop_thread_timer(tid); ++ } ++ if (ret) { ++ mark_as_done(); ++ } else { ++ mark_as_failed(); ++ } ++ res->mutex->unlock(); ++ return ret; ++} ++ ++bool task::get_job_info(const char *level) ++{ ++ bool ret = false; ++ btimer_t *tid = NULL; ++ char *p; ++ ++ if (!res->bs || !res->bs->is_open() || res->bs->is_error()) { ++ if (!connect_bacula()) { ++ goto bail_out; ++ } ++ } ++ res->mutex->lock(); ++ memset(&res->infos, 0, sizeof(res->infos)); ++ ++ tid = start_thread_timer(NULL, pthread_self(), (uint32_t)120); ++ if (res->type == R_CLIENT && !res->proxy_sent) { ++ res->proxy_sent = true; ++ res->bs->fsend("proxy\n"); ++ while (get_next_line(res)) { ++ if (strncmp(curline, "2000", 4) != 0) { ++ pm_strcpy(errmsg, curline); ++ goto bail_out; ++ } ++ Dmsg2(dbglvl, "<- %d %s\n", res->bs->msglen, curline); ++ } ++ } ++ ++ res->bs->fsend(".api 2\n"); ++ while (get_next_line(res)) { ++ Dmsg2(dbglvl, "<- %d %s\n", res->bs->msglen, curline); ++ } ++ if (level) { ++ res->bs->fsend(".estimate job=\"%s\" level=%s\n", arg, level); ++ } else { ++ res->bs->fsend(".estimate job=\"%s\"\n", arg); ++ } ++ while (get_next_line(res)) { ++ Dmsg1(dbglvl, "line = [%s]\n", curline); ++ if ((p = strchr(curline, '=')) == NULL) { ++ continue; ++ } ++ *p++ = 0; ++ if (strcasecmp(curline, "level") == 0) { ++ res->infos.JobLevel = p[0]; ++ ++ } else if (strcasecmp(curline, "jobbytes") == 0) { ++ res->infos.JobBytes = str_to_uint64(p); ++ ++ } else if (strcasecmp(curline, "jobfiles") == 0) { ++ res->infos.JobFiles = str_to_uint64(p); ++ ++ } else if (strcasecmp(curline, "corrbytes") == 0) { ++ res->infos.CorrJobBytes = str_to_uint64(p); ++ ++ } else if (strcasecmp(curline, "corrfiles") == 0) { ++ res->infos.CorrJobFiles = str_to_uint64(p); ++ ++ } else if (strcasecmp(curline, "nbjob") == 0) { ++ res->infos.CorrNbJob = str_to_uint64(p); ++ } ++ } ++ ret = true; ++bail_out: ++ res->mutex->unlock(); ++ if (tid) { ++ stop_thread_timer(tid); ++ } ++ if (ret) { ++ mark_as_done(); ++ } else { ++ mark_as_failed(); ++ } ++ return ret; ++} ++ ++bool task::run_job() ++{ ++ bool ret = false; ++ char *p; ++ btimer_t *tid = NULL; ++ ++ if (!res->bs || !res->bs->is_open() || res->bs->is_error()) { ++ if (!connect_bacula()) { ++ goto bail_out; ++ } ++ } ++ ++ tid = start_thread_timer(NULL, pthread_self(), (uint32_t)120); ++ if (res->type == R_CLIENT && !res->proxy_sent) { ++ res->proxy_sent = true; ++ res->bs->fsend("proxy\n"); ++ while (get_next_line(res)) { ++ if (strncmp(curline, "2000", 4) != 0) { ++ pm_strcpy(errmsg, curline); ++ goto bail_out; ++ } ++ Dmsg2(dbglvl, "<- %d %s\n", res->bs->msglen, curline); ++ } ++ } ++ ++ res->bs->fsend(".api 2\n"); ++ while (get_next_line(res)) { ++ Dmsg2(dbglvl, "<- %d %s\n", res->bs->msglen, curline); ++ } ++ if (res->type == R_DIRECTOR && res->use_setip) { ++ res->bs->fsend("setip\n"); ++ while (get_next_line(res)) { ++ Dmsg2(dbglvl, "<- %d %s\n", res->bs->msglen, curline); ++ } ++ } ++ res->bs->fsend("%s\n", arg); ++ while (get_next_line(res)) { ++ if ((p = strstr(curline, "JobId=")) != NULL && sscanf(p, "JobId=%d\n", &result.i) == 1) { ++ ret = true; ++ } ++ } ++ // Close the socket, it's over or we don't want to reuse it ++ disconnect_bacula(); ++ ++bail_out: ++ ++ if (tid) { ++ stop_thread_timer(tid); ++ } ++ if (ret) { ++ mark_as_done(); ++ } else { ++ mark_as_failed(); ++ } ++ return ret; ++} ++ ++/* Get resources to run a job */ ++bool task::get_resources() ++{ ++ bool ret = false; ++ btimer_t *tid = NULL; ++ ++ if (!res->bs || !res->bs->is_open() || res->bs->is_error()) { ++ if (!connect_bacula()) { ++ goto bail_out; ++ } ++ } ++ ++ res->mutex->lock(); ++ if (res->jobs) { ++ delete res->jobs; ++ } ++ res->jobs = New(alist(10, owned_by_alist)); ++ if (res->clients) { ++ delete res->clients; ++ } ++ res->clients = New(alist(10, owned_by_alist)); ++ if (res->filesets) { ++ delete res->filesets; ++ } ++ res->filesets = New(alist(10, owned_by_alist)); ++ if (res->pools) { ++ delete res->pools; ++ } ++ res->pools = New(alist(10, owned_by_alist)); ++ if (res->storages) { ++ delete res->storages; ++ } ++ res->storages = New(alist(10, owned_by_alist)); ++ if (res->catalogs) { ++ delete res->catalogs; ++ } ++ res->catalogs = New(alist(10, owned_by_alist)); ++ ++ tid = start_thread_timer(NULL, pthread_self(), (uint32_t)120); ++ if (res->type == R_CLIENT && !res->proxy_sent) { ++ res->proxy_sent = true; ++ res->bs->fsend("proxy\n"); ++ while (get_next_line(res)) { ++ if (strncmp(curline, "2000", 4) != 0) { ++ pm_strcpy(errmsg, curline); ++ goto bail_out; ++ } ++ Dmsg2(dbglvl, "<- %d %s\n", res->bs->msglen, curline); ++ } ++ Dmsg2(dbglvl, "<- %d %s\n", res->bs->msglen, curline); ++ } ++ ++ res->bs->fsend(".api 2\n"); ++ while (get_next_line(res)) { ++ Dmsg2(dbglvl, "<- %d %s\n", res->bs->msglen, curline); ++ } ++ ++ res->bs->fsend(".jobs type=B\n"); ++ while (get_next_line(res)) { ++ res->jobs->append(bstrdup(curline)); ++ } ++ ++ res->bs->fsend(".pools\n"); ++ while (get_next_line(res)) { ++ res->pools->append(bstrdup(curline)); ++ } ++ ++ res->bs->fsend(".clients\n"); ++ while (get_next_line(res)) { ++ res->clients->append(bstrdup(curline)); ++ } ++ ++ res->bs->fsend(".filesets\n"); ++ while (get_next_line(res)) { ++ res->filesets->append(bstrdup(curline)); ++ } ++ ++ res->bs->fsend(".storage\n"); ++ while (get_next_line(res)) { ++ res->storages->append(bstrdup(curline)); ++ } ++ ++ res->bs->fsend(".catalog\n"); ++ while (get_next_line(res)) { ++ res->catalogs->append(bstrdup(curline)); ++ } ++ ++bail_out: ++ res->mutex->unlock(); ++ ++ if (tid) { ++ stop_thread_timer(tid); ++ } ++ if (ret) { ++ mark_as_done(); ++ } else { ++ mark_as_failed(); ++ } ++ return ret; ++} ++ ++worker *worker_start() ++{ ++ worker *w = New(worker()); ++ w->start(handle_task, w); ++ return w; ++} ++ ++void worker_stop(worker *w) ++{ ++ if (w) { ++ w->stop(); ++ delete w; ++ } ++} +diff --git a/bacula/src/qt-console/tray-monitor/tray-monitor.conf.in b/bacula/src/qt-console/tray-monitor/tray-monitor.conf.in +index 30aea7db3..3f72921b2 100644 +--- a/bacula/src/qt-console/tray-monitor/tray-monitor.conf.in ++++ b/bacula/src/qt-console/tray-monitor/tray-monitor.conf.in +@@ -1,6 +1,9 @@ + # + # Bacula Tray Monitor Configuration File + # ++# Copyright (C) 2000-2017 Kern Sibbald ++# License: BSD 2-Clause; see file LICENSE-FOSS ++# + + Monitor { + Name = @basename@-mon +diff --git a/bacula/src/qt-console/tray-monitor/tray-monitor.pro.in b/bacula/src/qt-console/tray-monitor/tray-monitor.pro.in +index 92247c0ca..8c414a05a 100644 +--- a/bacula/src/qt-console/tray-monitor/tray-monitor.pro.in ++++ b/bacula/src/qt-console/tray-monitor/tray-monitor.pro.in +@@ -6,6 +6,9 @@ + # + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # ++# Copyright (C) 2000-2017 Kern Sibbald ++# License: BSD 2-Clause; see file LICENSE-FOSS ++# + # CONFIG options for Windows are pulled from win32/qmake.conf + CONFIG += qt + #CONFIG += qt debug +diff --git a/bacula/src/qt-console/tray-monitor/tray-monitor.pro.mingw32.in b/bacula/src/qt-console/tray-monitor/tray-monitor.pro.mingw32.in +index 763c03244..362fff1b3 100644 +--- a/bacula/src/qt-console/tray-monitor/tray-monitor.pro.mingw32.in ++++ b/bacula/src/qt-console/tray-monitor/tray-monitor.pro.mingw32.in +@@ -7,11 +7,16 @@ + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # + # CONFIG options for Windows are pulled from win32/qmake.conf +-CONFIG += qt ++# ++# Copyright (C) 2000-2017 Kern Sibbald ++# License: BSD 2-Clause; see file LICENSE-FOSS ++# ++ ++CONFIG += qt cross-win32 + #CONFIG += qt debug + + cross-win32 { +- LIBS += -mwindows -L../../win32/release32 -lbacula ++ LIBS += -mwindows -L../../win32/release32 -lbacula -lpthread + INCLUDEPATH += ../../win32/compat + } + !cross-win32 { +diff --git a/bacula/src/qt-console/tray-monitor/tray-monitor.pro.mingw64.in b/bacula/src/qt-console/tray-monitor/tray-monitor.pro.mingw64.in +index 39957e67f..20719ba89 100644 +--- a/bacula/src/qt-console/tray-monitor/tray-monitor.pro.mingw64.in ++++ b/bacula/src/qt-console/tray-monitor/tray-monitor.pro.mingw64.in +@@ -7,11 +7,16 @@ + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # + # CONFIG options for Windows are pulled from win32/qmake.conf +-CONFIG += qt ++# ++# Copyright (C) 2000-2017 Kern Sibbald ++# License: BSD 2-Clause; see file LICENSE-FOSS ++# ++ ++CONFIG += qt cross-win32 + #CONFIG += qt debug + + cross-win32 { +- LIBS += -mwindows -L../../win32/release64 -lbacula ++ LIBS += -mwindows -L../../win32/release64 -lbacula -lpthread + INCLUDEPATH += ../../win32/compat + } + !cross-win32 { +-- +2.13.0 + diff --git a/0002-Fix-bug-2293-bad-big-endian-detection-in-lz4.c.patch b/0002-Fix-bug-2293-bad-big-endian-detection-in-lz4.c.patch new file mode 100644 index 0000000..6eb4a16 --- /dev/null +++ b/0002-Fix-bug-2293-bad-big-endian-detection-in-lz4.c.patch @@ -0,0 +1,26 @@ +From 2e3e5dd3d1e7408b7e58f67a618e6579e5b7d302 Mon Sep 17 00:00:00 2001 +From: Kern Sibbald +Date: Mon, 10 Jul 2017 19:10:34 +0200 +Subject: [PATCH 2/4] Fix bug #2293 bad big endian detection in lz4.c + +--- + bacula/src/lib/lz4.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/bacula/src/lib/lz4.c b/bacula/src/lib/lz4.c +index e04c1345c..2ffb24452 100644 +--- a/bacula/src/lib/lz4.c ++++ b/bacula/src/lib/lz4.c +@@ -67,7 +67,8 @@ Note : this source file requires "lz4_encoder.h" + || defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) \ + || defined(__hpux) || defined(__hppa) \ + || defined(_MIPSEB) || defined(__s390__) +-#error "BIG Endian detected but not set" ++// KES -- the following is not a correct assumption ++//#error "BIG Endian detected but not set" + #endif + #endif + +-- +2.13.0 + diff --git a/0004-Remove-two-incorrect-trailing-commas-in-bsock.h.patch b/0004-Remove-two-incorrect-trailing-commas-in-bsock.h.patch new file mode 100644 index 0000000..96fe48f --- /dev/null +++ b/0004-Remove-two-incorrect-trailing-commas-in-bsock.h.patch @@ -0,0 +1,34 @@ +From 54f7bf4f627bb73bf8fdd672d6e723dfdf60d7b4 Mon Sep 17 00:00:00 2001 +From: Kern Sibbald +Date: Mon, 10 Jul 2017 20:24:10 +0200 +Subject: [PATCH 4/4] Remove two incorrect trailing commas in bsock.h + +--- + bacula/src/lib/bsock.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/bacula/src/lib/bsock.h b/bacula/src/lib/bsock.h +index e2de186b5..b18b9bcee 100644 +--- a/bacula/src/lib/bsock.h ++++ b/bacula/src/lib/bsock.h +@@ -289,7 +289,7 @@ enum { + BNET_SIGNAL = -1, + BNET_HARDEOF = -2, + BNET_ERROR = -3, +- BNET_COMMAND = -4, ++ BNET_COMMAND = -4 + }; + + /* +@@ -307,7 +307,7 @@ enum { + BNET_CMD_STO_BLOCK = 4, /* backup FD->SD FD send requested block */ + BNET_CMD_REC_ACK = 5, /* restore FD->SD FD has consumed records from the buffer */ + BNET_CMD_STP_THREAD = 6, /* restore FD->SD SD must stop thread */ +- BNET_CMD_STP_FLOWCTRL = 7, /* backup FD->SD SD must stop sending flowcontrol information */ ++ BNET_CMD_STP_FLOWCTRL = 7 /* backup FD->SD SD must stop sending flowcontrol information */ + }; + + const char *bnet_cmd_to_name(int val); +-- +2.13.0 + diff --git a/bacula.spec b/bacula.spec index 3cd491d..1f4db70 100644 --- a/bacula.spec +++ b/bacula.spec @@ -1,12 +1,9 @@ %global uid 133 %global username bacula -# Temporarily disable tray-monitor due to missing files in the source -#global _with_tray_monitor 1 - Name: bacula Version: 9.0.0 -Release: 1%{?dist} +Release: 2%{?dist} Summary: Cross platform network backup for Linux, Unix, Mac and Windows # See LICENSE for details License: AGPLv3 with exceptions @@ -47,6 +44,11 @@ Patch7: %{name}-9.0.0-non-free-code.patch # http://bugs.bacula.org/view.php?id=2084 Patch10: %{name}-7.0.4-autoconf.patch +# Temporary patches from upstream git +Patch11: 0001-Add-new-tray-monitor-files-that-were-omitted-in-the-.patch +Patch12: 0002-Fix-bug-2293-bad-big-endian-detection-in-lz4.c.patch +Patch13: 0004-Remove-two-incorrect-trailing-commas-in-bsock.h.patch + BuildRequires: desktop-file-utils BuildRequires: perl BuildRequires: perl-generators @@ -272,7 +274,6 @@ based on a client/server architecture. This package contains the bat version of the bacula management console. -%{?_with_tray_monitor: %package traymonitor Summary: Bacula system tray monitor Requires: bacula-libs%{?_isa} = %{version}-%{release} @@ -285,7 +286,6 @@ based on a client/server architecture. This package contains the Gnome and KDE compatible tray monitor to monitor your bacula server. -} %package devel Summary: Bacula development files @@ -317,6 +317,10 @@ Provides check_bacula support for Nagios. %patch6 -p1 %patch7 -p1 %patch10 -p1 + +%patch11 -p2 +%patch12 -p2 +%patch13 -p2 cp %{SOURCE2} %{SOURCE3} %{SOURCE4} %{SOURCE5} . # Remove execution permissions from files we're packaging as docs later on @@ -369,7 +373,6 @@ sed -i 's|^runpath_var=LD_RUN_PATH|runpath_var=DIE_RPATH_DIE|g' libtool make %{?_smp_mflags} make -C examples/nagios/check_bacula -%{?_with_tray_monitor: pushd src/qt-console/tray-monitor %{?qmake_qt4}%{!?qmake_qt4:qmake-qt4} tray-monitor.pro make %{?_smp_mflags} @@ -378,7 +381,6 @@ popd # Convert image to png for tray monitor icon convert %{SOURCE19} bacula-tray-monitor.png -} %install %make_install @@ -398,14 +400,12 @@ desktop-file-install \ --set-key=Categories --set-value="Utility" \ scripts/bat.desktop -%{?_with_tray_monitor: # QT Tray monitor install -p -m 755 -D src/qt-console/tray-monitor/bacula-tray-monitor %{buildroot}%{_sbindir}/bacula-tray-monitor install -p -m 644 -D src/qt-console/tray-monitor/tray-monitor.conf %{buildroot}%{_sysconfdir}/bacula/tray-monitor.conf install -p -m 644 -D manpages/bacula-tray-monitor.1 %{buildroot}%{_mandir}/man1/bacula-tray-monitor.1 install -p -m 644 -D bacula-tray-monitor.png %{buildroot}%{_datadir}/pixmaps/bacula-tray-monitor.png desktop-file-install --dir=%{buildroot}%{_datadir}/applications %{SOURCE14} -} # Logrotate mkdir -p %{buildroot}%{_localstatedir}/log/bacula @@ -709,14 +709,12 @@ fi %{_mandir}/man1/bat.1* %{_sbindir}/bat -%{?_with_tray_monitor: %files traymonitor %config(noreplace) %{_sysconfdir}/bacula/tray-monitor.conf %attr(640,root,root) %{_datadir}/applications/bacula-traymonitor.desktop %{_datadir}/pixmaps/bacula-tray-monitor.png %{_mandir}/man1/bacula-tray-monitor.1* %{_sbindir}/bacula-tray-monitor -} %files devel %{_includedir}/bacula @@ -730,6 +728,10 @@ fi %{_libdir}/nagios/plugins/check_bacula %changelog +* Tue Jul 11 2017 Simone Caronni - 9.0.0-2 +- Fix ppc64le build. +- Fix tray-monitor build. + * Mon Jul 10 2017 Simone Caronni - 9.0.0-1 - Update to 9.0.0, update all patches. - Add new utitilies.