]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/stored/dircmd.c
Check pool memory size for truncate op
[bacula/bacula] / bacula / src / stored / dircmd.c
index a53efa31c3cb443e4e22fdb178df95e1333652a0..fcb8c38d1846154586503959bfb4b7f3213b98eb 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2001-2008 Free Software Foundation Europe e.V.
+   Copyright (C) 2001-2009 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.
@@ -61,6 +61,8 @@ extern bool init_done;
 static char derrmsg[]     = "3900 Invalid command\n";
 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();
@@ -81,6 +83,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);
@@ -116,6 +119,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},
@@ -150,7 +154,7 @@ void *handle_connection_request(void *arg)
    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;
    }
@@ -160,7 +164,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;
    }
@@ -175,6 +179,7 @@ void *handle_connection_request(void *arg)
    if (sscanf(bs->msg, "Hello Start Job %127s", name) == 1) {
       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;
    }
@@ -322,7 +327,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);
       }
@@ -657,8 +663,9 @@ static bool mount_cmd(JCR *jcr)
             /* 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);
@@ -752,6 +759,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;
 
@@ -810,6 +820,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());
@@ -841,6 +852,7 @@ static bool unmount_cmd(JCR *jcr)
             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());
@@ -863,6 +875,58 @@ static bool unmount_cmd(JCR *jcr)
    return true;
 }
 
+/*
+ * 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.
+ *
+ */
+static bool action_on_purge_cmd(JCR *jcr)
+{
+   POOL_MEM devname;
+   POOL_MEM volumename;
+   BSOCK *dir = jcr->dir_bsock;
+   DEVICE *dev;
+   DCR *dcr;
+   int action;
+
+   devname.check_size(dir->msglen+1);
+   volumename.check_size(dir->msglen+1);
+
+   if (sscanf(dir->msg, "action_on_purge %127s vol=%s action=%d",
+              devname.c_str(), volumename.c_str(), &action) != 3) {
+      dir->fsend(_("3916 Error scanning action_on_purge command\n"));
+      goto done;
+   }
+   unbash_spaces(volumename.c_str());
+   unbash_spaces(devname.c_str());
+
+   /* FIXME: autochanger, drive = 0? how can we avoid that? we only work on
+    * files 
+    */
+   if ((dcr = find_device(jcr, devname, 0)) == NULL) {
+      dir->fsend(_("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
+      goto done;
+   }
+
+   dev = dcr->dev;
+
+   /* Store the VolumeName for opening and re-labeling the volume */
+   bstrncpy(dcr->VolumeName, volumename.c_str(), sizeof(dcr->VolumeName));
+   bstrncpy(dev->VolHdr.VolumeName, volumename.c_str(), sizeof(dev->VolHdr.VolumeName));
+
+   /* Re-write the label with the recycle flag */
+   if (rewrite_volume_label(dcr, true)) {
+      dir->fsend(_("3917 Volume recycled\n"));
+   } else {
+      dir->fsend(_("3918 Recycle failed\n"));
+   }
+
+done:
+   dir->signal(BNET_EOD);
+   return true;
+}
+
 /*
  * Release command from Director. This rewinds the device and if
  *   configured does a offline and ensures that Bacula will
@@ -934,13 +998,65 @@ 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)
 {
-   /* If getting the bootstrap file succeeds, we do not need
-    *  the FD because we will be reading.
-    */
-   jcr->need_fd = false;
    return get_bootstrap_file(jcr, jcr->dir_bsock);
 }
 
@@ -961,7 +1077,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) {