/*
- Bacula® - The Network Backup Solution
+ Bacula(R) - The Network Backup Solution
- Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
+ Copyright (C) 2000-2018 Kern Sibbald
- The main author of Bacula is Kern Sibbald, with contributions from
- many others, a complete list can be found in the file AUTHORS.
- This program is Free Software; you can redistribute it and/or
- modify it under the terms of version two of the GNU General Public
- License as published by the Free Software Foundation and included
- in the file LICENSE.
+ The original author of Bacula is Kern Sibbald, with contributions
+ from many others, a complete list can be found in the file AUTHORS.
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
+ 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.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
+ This notice must be preserved when any source code is
+ conveyed and/or propagated.
- Bacula® is a registered trademark of John Walker.
- The licensor of Bacula is the Free Software Foundation Europe
- (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
- Switzerland, email:ftf@fsfeurope.org.
+ Bacula(R) is a registered trademark of Kern Sibbald.
*/
/*
*
* Requests are any message that does not begin with a digit.
* In affect, they are commands.
*
- * Version $Id$
*/
#include "bacula.h"
/* Forward referenced functions */
static char *find_msg_start(char *msg);
-static char Job_status[] = "Status Job=%127s JobStatus=%d\n";
+static char Job_status[] = "Status JobId=%ld JobStatus=%d\n";
#ifdef needed
-static char Device_update[] = "DevUpd Job=%127s "
+static char Device_update[] = "DevUpd JobId=%127s "
"device=%127s "
"append=%d read=%d num_writers=%d "
"open=%d labeled=%d offline=%d "
static char OK_msg[] = "1000 OK\n";
+
+static void set_jcr_sd_job_status(JCR *jcr, int SDJobStatus)
+{
+ bool set_waittime=false;
+ Dmsg2(800, "set_jcr_sd_job_status(%s, %c)\n", jcr->Job, SDJobStatus);
+ /* if wait state is new, we keep current time for watchdog MaxWaitTime */
+ switch (SDJobStatus) {
+ case JS_WaitMedia:
+ case JS_WaitMount:
+ case JS_WaitMaxJobs:
+ set_waittime = true;
+ default:
+ break;
+ }
+
+ if (job_waiting(jcr)) {
+ set_waittime = false;
+ }
+
+ if (set_waittime) {
+ /* set it before JobStatus */
+ Dmsg0(800, "Setting wait_time\n");
+ jcr->wait_time = time(NULL);
+ }
+ jcr->SDJobStatus = SDJobStatus;
+ if (jcr->SDJobStatus == JS_Incomplete) {
+ jcr->setJobStatus(JS_Incomplete);
+ }
+
+}
+
+/*
+ * See if we are pointing to a message id
+ * Look for: [XYnnnn]
+ */
+static bool is_msgid(char *msg)
+{
+ if (!msg) return false;
+ char *end = strchr(msg, ']');
+ if (!end) return false;
+ if ((end - msg) != 7) return false;
+ if (!B_ISUPPER(msg[1]) || !B_ISUPPER(msg[2])) return false;
+ for (int i=3; i<7; i++) {
+ if (!B_ISDIGIT(msg[i])) return false;
+ }
+ return true;
+}
+
/*
* Get a message
* Call appropriate processing routine
* to the appropriate handler. If the message is
* in any other format, it will be returned.
*
- * E.g. any message beginning with a digit will be passed
+ * E.g. any message beginning with a digit will be passed
* through to the caller.
* All other messages are expected begin with some identifier
* -- for the moment only the first character is checked, but
* at a later time, the whole identifier (e.g. Jmsg, CatReq, ...)
- * could be checked. This is followed by Job=Jobname <user-defined>
+ * could be checked.
+ * This is followed by JobId=nnn <user-defined>
* info. The identifier is used to dispatch the message to the right
* place (Job message, catalog request, ...). The Job is used to lookup
* the JCR so that the action is performed on the correct jcr, and
* the rest of the message is up to the user. Note, DevUpd uses
- * *System* for the Job name, and hence no JCR is obtained. This
+ * *System* for the Job name, and hence no JCR is obtained. This
* is a *rare* case where a jcr is not really needed.
*
*/
int bget_dirmsg(BSOCK *bs)
{
- int32_t n;
+ int32_t n = BNET_TERMINATE;
char Job[MAX_NAME_LENGTH];
+ JobId_t JobId = 0;
char MsgType[20];
- int type, level;
- JCR *jcr;
+ int type;
+ utime_t mtime; /* message time */
+ JCR *jcr = bs->jcr();
char *msg;
- for (;;) {
+ for ( ; !bs->is_stop() && !bs->is_timed_out(); ) {
n = bs->recv();
- Dmsg2(100, "bget_dirmsg %d: %s", n, bs->msg);
+ Dmsg4(200, "bget_dirmsg n=%d msglen=%ld is_stop=%d: %s\n", n, bs->msglen, bs->is_stop(), bs->msg);
- if (is_bnet_stop(bs)) {
+ if (bs->is_stop() || bs->is_timed_out()) {
return n; /* error or terminate */
}
if (n == BNET_SIGNAL) { /* handle signal */
bs->fsend("btime %s\n", edit_uint64(get_current_btime(),ed1));
break;
default:
- Emsg1(M_WARNING, 0, _("bget_dirmsg: unknown bnet signal %d\n"), bs->msglen);
+ Jmsg1(jcr, M_WARNING, 0, _("bget_dirmsg: unknown bnet signal %d\n"), bs->msglen);
return n;
}
continue;
* a message to dispatch, or a catalog request.
* Try to fulfill it.
*/
- if (sscanf(bs->msg, "%020s Job=%127s ", MsgType, Job) != 2) {
- Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
- continue;
- }
- if (strcmp(Job, "*System*") == 0) {
- jcr = NULL; /* No jcr */
- } else if (!(jcr=get_jcr_by_full_name(Job))) {
- Emsg1(M_ERROR, 0, _("Job not found: %s\n"), bs->msg);
+ if ((sscanf(bs->msg, "%020s JobId=%ld ", MsgType, &JobId) != 2) &&
+ (sscanf(bs->msg, "%020s Job=%127s ", MsgType, Job) != 2) &&
+ (sscanf(bs->msg, "%020s Job=x", MsgType) != 1)) {
+ if (is_msgid(strchr(bs->msg, '['))) {
+ return n;
+ }
+ Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
continue;
}
- Dmsg1(900, "Getmsg got jcr 0x%x\n", jcr);
- /* Skip past "Jmsg Job=nnn" */
+ /* Skip past first two fields: "Jmsg JobId=nnn" */
if (!(msg=find_msg_start(bs->msg))) {
- Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
- free_jcr(jcr);
+ Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
continue;
}
/*
* Here we are expecting a message of the following format:
- * Jmsg Job=nnn type=nnn level=nnn Message-string
+ * Jmsg JobId=nnn type=nnn level=nnn Message-string
+ * Note, level should really be mtime, but that changes
+ * the protocol.
*/
if (bs->msg[0] == 'J') { /* Job message */
- if (sscanf(bs->msg, "Jmsg Job=%127s type=%d level=%d",
- Job, &type, &level) != 3) {
- Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
- free_jcr(jcr);
+ if ((sscanf(bs->msg, "Jmsg JobId=%ld type=%d level=%lld",
+ &JobId, &type, &mtime) != 3) &&
+ (sscanf(bs->msg, "Jmsg Job=%127s type=%d level=%lld",
+ Job, &type, &mtime) != 3)) {
+ Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
continue;
}
Dmsg1(900, "Got msg: %s\n", bs->msg);
msg++; /* skip leading space */
}
Dmsg1(900, "Dispatch msg: %s", msg);
- dispatch_message(jcr, type, level, msg);
- free_jcr(jcr);
+ dispatch_message(jcr, type, mtime, msg);
continue;
}
/*
* Here we expact a CatReq message
- * CatReq Job=nn Catalog-Request-Message
+ * CatReq JobId=nn Catalog-Request-Message
*/
if (bs->msg[0] == 'C') { /* Catalog request */
- Dmsg2(900, "Catalog req jcr 0x%x: %s", jcr, bs->msg);
+ Dmsg2(900, "Catalog req jcr=%p: %s", jcr, bs->msg);
catalog_request(jcr, bs);
- Dmsg1(900, "Calling freejcr 0x%x\n", jcr);
- free_jcr(jcr);
continue;
}
if (bs->msg[0] == 'U') { /* SD sending attributes */
- Dmsg2(900, "Catalog upd jcr 0x%x: %s", jcr, bs->msg);
+ Dmsg2(900, "Catalog upd jcr=%p: %s", jcr, bs->msg);
catalog_update(jcr, bs);
- Dmsg1(900, "Calling freejcr 0x%x\n", jcr);
- free_jcr(jcr);
+ continue;
+ }
+ if (bs->msg[0] == 'B') { /* SD sending file spool attributes */
+ Dmsg2(100, "Blast attributes jcr=%p: %s", jcr, bs->msg);
+ char filename[256];
+ if (sscanf(bs->msg, "BlastAttr JobId=%ld File=%255s",
+ &JobId, filename) != 2) {
+ Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
+ continue;
+ }
+ unbash_spaces(filename);
+ if (despool_attributes_from_file(jcr, filename)) {
+ bs->fsend("1000 OK BlastAttr\n");
+ } else {
+ bs->fsend("1990 ERROR BlastAttr\n");
+ }
continue;
}
if (bs->msg[0] == 'M') { /* Mount request */
Dmsg1(900, "Mount req: %s", bs->msg);
mount_request(jcr, bs, msg);
- free_jcr(jcr);
+ continue;
+ }
+ /* Get Progress: files, bytes, bytes/sec */
+ if (bs->msg[0] == 'P') { /* Progress report */
+ uint32_t files, bps;
+ uint64_t bytes;
+ if ((sscanf(bs->msg, "Progress JobId=%ld files=%ld bytes=%lld bps=%ld\n",
+ &JobId, &files, &bytes, &bps) == 4) ||
+ (sscanf(bs->msg, "Progress JobId=x files=%ld bytes=%lld bps=%ld\n",
+ &files, &bytes, &bps) == 3) ||
+ (sscanf(bs->msg, "Progress Job=x files=%ld bytes=%lld bps=%ld\n",
+ &files, &bytes, &bps) == 3)) {
+ Dmsg2(900, "JobId=%d %s", jcr->JobId, bs->msg);
+ /* Save progress data */
+ jcr->JobFiles = files;
+ jcr->JobBytes = bytes;
+ jcr->LastRate = bps;
+ } else {
+ Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
+ }
continue;
}
if (bs->msg[0] == 'S') { /* Status change */
int JobStatus;
- char Job[MAX_NAME_LENGTH];
- if (sscanf(bs->msg, Job_status, &Job, &JobStatus) == 2) {
- jcr->SDJobStatus = JobStatus; /* current status */
+ if (sscanf(bs->msg, Job_status, &JobId, &JobStatus) == 2) {
+ set_jcr_sd_job_status(jcr, JobStatus); /* current status */
} else {
- Emsg1(M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
+ Jmsg1(jcr, M_ERROR, 0, _("Malformed message: %s\n"), bs->msg);
}
- free_jcr(jcr);
continue;
}
#ifdef needed
&dev_append, &dev_read,
&dev_num_writers, &dev_open,
&dev_labeled, &dev_offline, &dev_reserved,
- &dev_max_writers, &dev_autoselect,
- &dev_autochanger,
+ &dev_max_writers, &dev_autoselect,
+ &dev_autochanger,
changer_name.c_str(), media_type.c_str(),
volume_name.c_str(),
&dev_read_time, &dev_write_time, &dev_read_bytes,
#endif
return n;
}
+ return n;
}
static char *find_msg_start(char *msg)
{
int n;
- if (is_bnet_error(bs)) {
+ if (bs->is_error()) {
return false;
}
if ((n = bget_dirmsg(bs)) >= 0) {
return false;
}
Jmsg(jcr, M_FATAL, 0, _("Socket error on %s command: ERR=%s\n"),
- cmd, bnet_strerror(bs));
+ cmd, bs->bstrerror());
return false;
}