]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/stored/dircmd.c
Add extra lock debug code but turned off
[bacula/bacula] / bacula / src / stored / dircmd.c
index 9901774a71c28fd0aaaad07ac22b3cdb898b0ccc..05cfdf4319fe55b5f273314740146775d9d1d06e 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2001-2008 Free Software Foundation Europe e.V.
+   Copyright (C) 2001-2010 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.
@@ -20,7 +20,7 @@
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   Bacula® is a registered trademark of John Walker.
+   Bacula® is a registered trademark of Kern Sibbald.
    The licensor of Bacula is the Free Software Foundation Europe
    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
    Switzerland, email:ftf@fsfeurope.org.
@@ -43,8 +43,6 @@
  *
  *     Kern Sibbald, May MMI
  *
- *   Version $Id$
- *
  */
 
 #include "bacula.h"
 
 /* Imported variables */
 extern BSOCK *filed_chan;
-extern int r_first, r_last;
-extern struct s_res resources[];
 extern struct s_last_job last_job;
 extern bool init_done;
 
 /* Static variables */
-static char derrmsg[]     = "3900 Invalid command\n";
+static char derrmsg[]     = "3900 Invalid command:";
 static char OKsetdebug[]  = "3000 OK setdebug=%d\n";
 static char invalid_cmd[] = "3997 Invalid command for a Director with Monitor directive enabled.\n";
+static char OK_bootstrap[]    = "3000 OK bootstrap\n";
+static char ERROR_bootstrap[] = "3904 Error bootstrap\n";
 
 /* Imported functions */
 extern void terminate_child();
@@ -83,6 +81,7 @@ static bool setdebug_cmd(JCR *jcr);
 static bool cancel_cmd(JCR *cjcr);
 static bool mount_cmd(JCR *jcr);
 static bool unmount_cmd(JCR *jcr);
+//static bool action_on_purge_cmd(JCR *jcr);
 static bool bootstrap_cmd(JCR *jcr);
 static bool changer_cmd(JCR *sjcr);
 static bool do_label(JCR *jcr, int relabel);
@@ -97,7 +96,7 @@ static void send_dir_busy_message(BSOCK *dir, DEVICE *dev);
 struct s_cmds {
    const char *cmd;
    bool (*func)(JCR *jcr);
-   int monitoraccess; /* specify if monitors have access to this function */
+   bool monitoraccess;                      /* set if monitors can access this cmd */
 };
 
 /*
@@ -118,6 +117,7 @@ static struct s_cmds cmds[] = {
    {"status",      status_cmd,      1},
    {".status",     qstatus_cmd,     1},
    {"unmount",     unmount_cmd,     0},
+//   {"action_on_purge",  action_on_purge_cmd,    0},
    {"use storage=", use_cmd,        0},
    {"run",         run_cmd,         0},
 // {"query",       query_cmd,       0},
@@ -149,9 +149,10 @@ void *handle_connection_request(void *arg)
    bool found, quit;
    int bnet_stat = 0;
    char name[500];
+   char tbuf[100];
 
    if (bs->recv() <= 0) {
-      Emsg0(M_ERROR, 0, _("Connection request failed.\n"));
+      Emsg1(M_ERROR, 0, _("Connection request from %s failed.\n"), bs->who());
       bs->close();
       return NULL;
    }
@@ -161,7 +162,7 @@ void *handle_connection_request(void *arg)
     */
    if (bs->msglen < 25 || bs->msglen > (int)sizeof(name)) {
       Dmsg1(000, "<filed: %s", bs->msg);
-      Emsg1(M_ERROR, 0, _("Invalid connection. Len=%d\n"), bs->msglen);
+      Emsg2(M_ERROR, 0, _("Invalid connection from %s. Len=%d\n"), bs->who(), bs->msglen);
       bs->close();
       return NULL;
    }
@@ -174,7 +175,9 @@ void *handle_connection_request(void *arg)
       Dmsg1(000, "<filed: %s", bs->msg);
    }
    if (sscanf(bs->msg, "Hello Start Job %127s", name) == 1) {
-      Dmsg0(110, "Got a FD connection\n");
+      Dmsg1(110, "Got a FD connection at %s\n", bstrftimes(tbuf, sizeof(tbuf), 
+            (utime_t)time(NULL)));
+      Dmsg1(50, "%s", bs->msg);
       handle_filed_connection(bs, name);
       return NULL;
    }
@@ -182,7 +185,8 @@ void *handle_connection_request(void *arg)
    /* 
     * This is a connection from the Director, so setup a JCR 
     */
-   Dmsg0(110, "Got a DIR connection\n");
+   Dmsg1(110, "Got a DIR connection at %s\n", bstrftimes(tbuf, sizeof(tbuf), 
+         (utime_t)time(NULL)));
    jcr = new_jcr(sizeof(JCR), stored_free_jcr); /* create Job Control Record */
    jcr->dir_bsock = bs;               /* save Director bsock */
    jcr->dir_bsock->set_jcr(jcr);
@@ -228,14 +232,16 @@ void *handle_connection_request(void *arg)
            Dmsg1(200, "Do command: %s\n", cmds[i].cmd);
            if (!cmds[i].func(jcr)) { /* do command */
               quit = true; /* error, get out */
-              Dmsg1(190, "Command %s reqeusts quit\n", cmds[i].cmd);
+              Dmsg1(190, "Command %s requests quit\n", cmds[i].cmd);
            }
            found = true;             /* indicate command found */
            break;
         }
       }
       if (!found) {                   /* command not found */
-        bs->fsend(derrmsg);
+        POOL_MEM err_msg;
+        Mmsg(err_msg, "%s %s\n", derrmsg, bs->msg);
+        bs->fsend(err_msg.c_str());
         break;
       }
    }
@@ -257,7 +263,16 @@ static bool die_cmd(JCR *jcr)
 #ifdef DEVELOPER
    JCR *djcr = NULL;
    int a;
-   Pmsg0(000, "I have been requested to die ...");
+   BSOCK *dir = jcr->dir_bsock;
+   pthread_mutex_t m=PTHREAD_MUTEX_INITIALIZER;
+
+   if (strstr(dir->msg, "deadlock")) {
+      Pmsg0(000, "I have been requested to deadlock ...\n");
+      P(m);
+      P(m);
+   }
+   
+   Pmsg1(000, "I have been requested to die ... (%s)\n", dir->msg);
    a = djcr->JobId;   /* ref NULL pointer */
 #endif
    return 0;
@@ -301,14 +316,18 @@ static bool cancel_cmd(JCR *cjcr)
       } else {
          oldStatus = jcr->JobStatus;
          set_jcr_job_status(jcr, JS_Canceled);
+         Dmsg2(800, "Cancel JobId=%d %p\n", jcr->JobId, jcr);
          if (!jcr->authenticated && oldStatus == JS_WaitFD) {
             pthread_cond_signal(&jcr->job_start_wait); /* wake waiting thread */
          }
          if (jcr->file_bsock) {
-            bnet_sig(jcr->file_bsock, BNET_TERMINATE);
+            jcr->file_bsock->signal(BNET_TERMINATE);
+            jcr->file_bsock->set_terminated();
+            Dmsg2(800, "Term bsock jid=%d %p\n", jcr->JobId, jcr);
          } else {
             /* Still waiting for FD to connect, release it */
             pthread_cond_signal(&jcr->job_start_wait); /* wake waiting job */
+            Dmsg2(800, "Signal FD connect jid=%d %p\n", jcr->JobId, jcr);
          }
          /* If thread waiting on mount, wake him */
          if (jcr->dcr && jcr->dcr->dev && jcr->dcr->dev->waiting_for_mount()) {
@@ -321,7 +340,8 @@ static bool cancel_cmd(JCR *cjcr)
             Dmsg1(100, "JobId=%u broadcast wait_device_release\n", (uint32_t)jcr->JobId);
             pthread_cond_broadcast(&wait_device_release);
          }
-         Jmsg(jcr, M_INFO, 0, _("Job %s marked to be canceled.\n"), jcr->Job);
+         Jmsg(jcr, M_INFO, 0, _("JobId=%d Job=\"%s\" marked to be canceled.\n"), 
+            (int)jcr->JobId, jcr->Job);
          dir->fsend(_("3000 Job %s marked to be canceled.\n"), jcr->Job);
          free_jcr(jcr);
       }
@@ -385,7 +405,7 @@ static bool do_label(JCR *jcr, int relabel)
       if (dcr) {
          dev = dcr->dev;
          dev->dlock();                 /* Use P to avoid indefinite block */
-         if (!dev->is_open()) {
+         if (!dev->is_open() && !dev->is_busy()) {
             Dmsg1(400, "Can %slabel. Device is not open\n", relabel?"re":"");
             label_volume_if_ok(dcr, oldname, newname, poolname, slot, relabel);
             dev->close();
@@ -455,7 +475,7 @@ static void label_volume_if_ok(DCR *dcr, char *oldname,
       dev->truncating = true;         /* let open() know we will truncate it */
    }
    /* Set old volume name for open if relabeling */
-   bstrncpy(dcr->VolCatInfo.VolCatName, volname, sizeof(dcr->VolCatInfo.VolCatName));
+   dcr->setVolCatName(volname);
    if (dev->open(dcr, mode) < 0) {
       dir->fsend(_("3910 Unable to open device %s: ERR=%s\n"),
          dev->print_name(), dev->bstrerror());
@@ -466,7 +486,7 @@ static void label_volume_if_ok(DCR *dcr, char *oldname,
    label_status = read_dev_volume_label(dcr);
    
    /* Set new volume name */
-   bstrncpy(dcr->VolCatInfo.VolCatName, newname, sizeof(dcr->VolCatInfo.VolCatName));
+   dcr->setVolCatName(newname);
    switch(label_status) {
    case VOL_NAME_ERROR:
    case VOL_VERSION_ERROR:
@@ -515,6 +535,7 @@ bail_out:
    if (!dev->is_open()) {
       dev->clear_volhdr();
    }
+   volume_unused(dcr);                   /* no longer using volume */
    give_back_device_lock(dev, &hold);
    return;
 }
@@ -548,6 +569,7 @@ static bool read_label(DCR *dcr)
       ok = false;
       break;
    }
+   volume_unused(dcr);
    give_back_device_lock(dev, &hold);
    return ok;
 }
@@ -647,14 +669,16 @@ static bool mount_cmd(JCR *jcr)
       if (dcr) {
          dev = dcr->dev;
          dev->dlock();                 /* Use P to avoid indefinite block */
-         Dmsg1(100, "mount cmd blocked=%d\n", dev->blocked());
+         Dmsg2(100, "mount cmd blocked=%d must_unload=%d\n", dev->blocked(), 
+            dev->must_unload());
          switch (dev->blocked()) {         /* device blocked? */
          case BST_WAITING_FOR_SYSOP:
             /* Someone is waiting, wake him */
             Dmsg0(100, "Waiting for mount. Attempting to wake thread\n");
             dev->set_blocked(BST_MOUNT);
-            dir->fsend("3001 OK mount. Device=%s\n", 
-               dev->print_name());
+            dir->fsend("3001 OK mount requested. %sDevice=%s\n", 
+                       slot>0?_("Specified slot ignored. "):"",
+                       dev->print_name());
             pthread_cond_broadcast(&dev->wait_next_vol);
             Dmsg1(100, "JobId=%u broadcast wait_device_release\n", (uint32_t)dcr->jcr->JobId);
             pthread_cond_broadcast(&wait_device_release);
@@ -668,8 +692,8 @@ static bool mount_cmd(JCR *jcr)
             }
             /* We freed the device, so reopen it and wake any waiting threads */
             if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
-               dir->fsend(_("3901 open device failed: ERR=%s\n"),
-                  dev->bstrerror());
+               dir->fsend(_("3901 Unable to open device %s: ERR=%s\n"),
+                  dev->print_name(), dev->bstrerror());
                if (dev->blocked() == BST_UNMOUNTED) {
                   /* We blocked the device, so unblock it */
                   Dmsg0(100, "Unmounted. Unblocking device\n");
@@ -725,8 +749,8 @@ static bool mount_cmd(JCR *jcr)
                }
             } else if (dev->is_tape()) {
                if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
-                  dir->fsend(_("3901 open device failed: ERR=%s\n"),
-                     dev->bstrerror());
+                  dir->fsend(_("3901 Unable to open device %s: ERR=%s\n"),
+                     dev->print_name(), dev->bstrerror());
                   break;
                }
                read_label(dcr);
@@ -748,6 +772,9 @@ static bool mount_cmd(JCR *jcr)
             } else { /* must be file */
                dir->fsend(_("3906 File device %s is always mounted.\n"),
                   dev->print_name());
+               pthread_cond_broadcast(&dev->wait_next_vol);
+               Dmsg1(100, "JobId=%u broadcast wait_device_release\n", (uint32_t)dcr->jcr->JobId);
+               pthread_cond_broadcast(&wait_device_release);
             }
             break;
 
@@ -806,6 +833,7 @@ static bool unmount_cmd(JCR *jcr)
             if (!unload_autochanger(dcr, -1)) {
                /* ***FIXME**** what is this ????  */
                dev->close();
+               free_volume(dev);
             }
             if (dev->is_unmountable() && !dev->unmount(0)) {
                dir->fsend(_("3907 %s"), dev->bstrerror());
@@ -834,9 +862,10 @@ static bool unmount_cmd(JCR *jcr)
              */
             /*  block_device(dev, BST_UNMOUNTED); replace with 2 lines below */
             dev->set_blocked(BST_UNMOUNTED);
-            dev->no_wait_id = 0;
+            clear_thread_id(dev->no_wait_id);
             if (!unload_autochanger(dcr, -1)) {
                dev->close();
+               free_volume(dev);
             }
             if (dev->is_unmountable() && !dev->unmount(0)) {
                dir->fsend(_("3907 %s"), dev->bstrerror());
@@ -859,6 +888,46 @@ static bool unmount_cmd(JCR *jcr)
    return true;
 }
 
+#if 0
+/*
+ * The truncate command will recycle a volume. The director can call this
+ * after purging a volume so that disk space will not be wasted. Only useful
+ * for File Storage, of course.
+ *
+ *
+ * It is currently disabled
+ */
+static bool action_on_purge_cmd(JCR *jcr)
+{
+   BSOCK *dir = jcr->dir_bsock;
+
+   char devname[MAX_NAME_LENGTH];
+   char volumename[MAX_NAME_LENGTH];
+   int action;
+
+   /* TODO: Need to find a free device and ask for slot to the director */
+   if (sscanf(dir->msg, 
+              "action_on_purge %127s vol=%127s action=%d",
+              devname, volumename, &action)!= 5) 
+   {
+      dir->fsend(_("3916 Error scanning action_on_purge command\n"));
+      goto done;
+   }
+   unbash_spaces(volumename);
+   unbash_spaces(devname);
+
+   /* Check if action is correct */
+   if (action & AOP_TRUNCTATE) {
+
+   } 
+   /* ... */
+
+done:
+   dir->signal(BNET_EOD);
+   return true;
+}
+#endif
+
 /*
  * Release command from Director. This rewinds the device and if
  *   configured does a offline and ensures that Bacula will
@@ -911,9 +980,8 @@ static bool release_cmd(JCR *jcr)
          } else if (dev->is_busy()) {
             send_dir_busy_message(dir, dev);
          } else {                     /* device not being used */
-            Dmsg0(90, "Device not in use, releaseing\n");
-            unload_autochanger(dcr, -1);
-            release_volume(dcr);
+            Dmsg0(90, "Device not in use, releasing\n");
+            dcr->release_volume();
             dir->fsend(_("3022 Device %s released.\n"), 
                dev->print_name());
          }
@@ -931,6 +999,62 @@ static bool release_cmd(JCR *jcr)
    return true;
 }
 
+static pthread_mutex_t bsr_mutex = PTHREAD_MUTEX_INITIALIZER;
+static uint32_t bsr_uniq = 0;
+
+static bool get_bootstrap_file(JCR *jcr, BSOCK *sock)
+{
+   POOLMEM *fname = get_pool_memory(PM_FNAME);
+   FILE *bs;
+   bool ok = false;
+
+   if (jcr->RestoreBootstrap) {
+      unlink(jcr->RestoreBootstrap);
+      free_pool_memory(jcr->RestoreBootstrap);
+   }
+   P(bsr_mutex);
+   bsr_uniq++;
+   Mmsg(fname, "%s/%s.%s.%d.bootstrap", me->working_directory, me->hdr.name,
+      jcr->Job, bsr_uniq);
+   V(bsr_mutex);
+   Dmsg1(400, "bootstrap=%s\n", fname);
+   jcr->RestoreBootstrap = fname;
+   bs = fopen(fname, "a+b");           /* create file */
+   if (!bs) {
+      berrno be;
+      Jmsg(jcr, M_FATAL, 0, _("Could not create bootstrap file %s: ERR=%s\n"),
+         jcr->RestoreBootstrap, be.bstrerror());
+      goto bail_out;
+   }
+   Dmsg0(10, "=== Bootstrap file ===\n");
+   while (sock->recv() >= 0) {
+       Dmsg1(10, "%s", sock->msg);
+       fputs(sock->msg, bs);
+   }
+   fclose(bs);
+   Dmsg0(10, "=== end bootstrap file ===\n");
+   jcr->bsr = parse_bsr(jcr, jcr->RestoreBootstrap);
+   if (!jcr->bsr) {
+      Jmsg(jcr, M_FATAL, 0, _("Error parsing bootstrap file.\n"));
+      goto bail_out;
+   }
+   if (debug_level >= 10) {
+      dump_bsr(jcr->bsr, true);
+   }
+   /* If we got a bootstrap, we are reading, so create read volume list */
+   create_restore_volume_list(jcr);
+   ok = true;
+
+bail_out:
+   unlink(jcr->RestoreBootstrap);
+   free_pool_memory(jcr->RestoreBootstrap);
+   jcr->RestoreBootstrap = NULL;
+   if (!ok) {
+      sock->fsend(ERROR_bootstrap);
+      return false;
+   }
+   return sock->fsend(OK_bootstrap);
+}
 
 static bool bootstrap_cmd(JCR *jcr)
 {
@@ -954,7 +1078,10 @@ static bool changer_cmd(JCR *jcr)
     */
    bool safe_cmd = false;
 
-   if (sscanf(dir->msg, "autochanger list %127s", devname.c_str()) == 1) {
+   if (sscanf(dir->msg, "autochanger listall %127s", devname.c_str()) == 1) {
+      cmd = "listall";
+      safe_cmd = ok = true;
+   } else if (sscanf(dir->msg, "autochanger list %127s", devname.c_str()) == 1) {
       cmd = "list";
       safe_cmd = ok = true;
    } else if (sscanf(dir->msg, "autochanger slots %127s", devname.c_str()) == 1) {