]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/dird/getmsg.c
Restore win32 dir from Branch-5.2 and update it
[bacula/bacula] / bacula / src / dird / getmsg.c
index 44c8992a0459e4b1539afdd5bcd3b1fc6e308947..18b54e961d8159153b462e9fa401a041ac9a7538 100644 (file)
@@ -1,3 +1,21 @@
+/*
+   Bacula(R) - The Network Backup Solution
+
+   Copyright (C) 2000-2018 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.
+*/
 /*
  *
  *   Bacula Director -- routines to receive network data and
  *       Requests are any message that does not begin with a digit.
  *       In affect, they are commands.
  *
- *   Version $Id$
  */
-/*
-   Bacula® - The Network Backup Solution
-
-   Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
-
-   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 plus additions
-   that are listed in the file LICENSE.
-
-   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 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.
-
-   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.
-*/
 
 #include "bacula.h"
 #include "dird.h"
@@ -54,9 +44,9 @@
 /* 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 "
@@ -70,6 +60,54 @@ static char Device_update[]   = "DevUpd Job=%127s "
 
 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
@@ -82,34 +120,37 @@ static char OK_msg[] = "1000 OK\n";
  *  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(900, "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 */
@@ -121,7 +162,7 @@ int bget_dirmsg(BSOCK *bs)
             bs->fsend(OK_msg);/* send response */
             return n;              /* end of data */
          case BNET_TERMINATE:
-            bs->m_terminated = 1;
+            bs->set_terminated();
             return n;
          case BNET_POLL:
             bs->fsend(OK_msg); /* send response */
@@ -142,7 +183,7 @@ int bget_dirmsg(BSOCK *bs)
             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;
@@ -159,34 +200,34 @@ int bget_dirmsg(BSOCK *bs)
        *  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);
@@ -198,43 +239,71 @@ int bget_dirmsg(BSOCK *bs)
             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') {        /* Catalog update */
-         Dmsg2(900, "Catalog upd jcr 0x%x: %s", jcr, bs->msg);
+      if (bs->msg[0] == 'U') {        /* SD sending attributes */
+         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
@@ -253,8 +322,8 @@ int bget_dirmsg(BSOCK *bs)
              &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,
@@ -298,6 +367,7 @@ int bget_dirmsg(BSOCK *bs)
 #endif
       return n;
    }
+   return n;
 }
 
 static char *find_msg_start(char *msg)
@@ -322,7 +392,7 @@ bool response(JCR *jcr, BSOCK *bs, char *resp, const char *cmd, e_prtmsg prtmsg)
 {
    int n;
 
-   if (is_bnet_error(bs)) {
+   if (bs->is_error()) {
       return false;
    }
    if ((n = bget_dirmsg(bs)) >= 0) {
@@ -336,6 +406,6 @@ bool response(JCR *jcr, BSOCK *bs, char *resp, const char *cmd, e_prtmsg prtmsg)
       return false;
    }
    Jmsg(jcr, M_FATAL, 0, _("Socket error on %s command: ERR=%s\n"),
-         cmd, bnet_strerror(bs));
+         cmd, bs->bstrerror());
    return false;
 }