]> git.ipfire.org Git - thirdparty/bacula.git/commitdiff
Implement worm cassette support
authorKern Sibbald <kern@sibbald.com>
Wed, 17 Oct 2018 09:06:49 +0000 (11:06 +0200)
committerKern Sibbald <kern@sibbald.com>
Wed, 17 Oct 2018 09:06:49 +0000 (11:06 +0200)
15 files changed:
bacula/scripts/Makefile.in
bacula/scripts/isworm [new file with mode: 0755]
bacula/src/dird/catreq.c
bacula/src/stored/Makefile.in
bacula/src/stored/askdir.c
bacula/src/stored/dev.c
bacula/src/stored/dev.h
bacula/src/stored/label.c
bacula/src/stored/record.h
bacula/src/stored/status.c
bacula/src/stored/stored_conf.c
bacula/src/stored/stored_conf.h
bacula/src/stored/tape_dev.h
bacula/src/stored/tape_worm.c [new file with mode: 0644]
bacula/src/stored/vol_mgr.c

index 40ad3e67d9a28fad91b3cc515b48dffad3d661c5..33713723ca164d42ad9a4c3c75bb1af2c49790ec 100755 (executable)
@@ -1,6 +1,5 @@
 #
-#
-# Copyright (C) 2000-2016 Kern Sibbald
+# Copyright (C) 2000-2018 Kern Sibbald
 # License: BSD 2-Clause; see file LICENSE-FOSS
 #
 @MCOMMON@
@@ -40,6 +39,7 @@ install: installdirs
        $(INSTALL_SCRIPT) bacula_config $(DESTDIR)$(scriptdir)/bacula_config
        $(INSTALL_SCRIPT) bacula $(DESTDIR)$(sbindir)/bacula
        $(INSTALL_SCRIPT) tapealert $(DESTDIR)$(scriptdir)/tapealert
+       $(INSTALL_SCRIPT) isworm $(DESTDIR)$(scriptdir)/isworm
        $(INSTALL_SCRIPT) bacula-ctl-dir $(DESTDIR)$(scriptdir)/bacula-ctl-dir
        $(INSTALL_SCRIPT) bacula-ctl-fd $(DESTDIR)$(scriptdir)/bacula-ctl-fd
        $(INSTALL_SCRIPT) bacula-ctl-sd $(DESTDIR)$(scriptdir)/bacula-ctl-sd
diff --git a/bacula/scripts/isworm b/bacula/scripts/isworm
new file mode 100755 (executable)
index 0000000..ba64292
--- /dev/null
@@ -0,0 +1,84 @@
+#!/bin/sh
+#
+# Copyright (C) 2000-2018 Kern Sibbald
+# License: BSD 2-Clause; see file LICENSE-FOSS
+#
+# Bacula interface to get worm status of tape
+#
+#  isworm %l (control device name)
+#
+# Typical output:
+# sdparm --page=0x1D -f /dev/sg0
+#    /dev/st0: HP        Ultrium 5-SCSI    I5AW  [tape]
+# Medium configuration (SSC) mode page:
+#   WORMM       1  [cha: n, def:  1, sav:  1]
+#   WMLR        1  [cha: n, def:  1, sav:  1]
+#   WMFR        2  [cha: n, def:  2, sav:  2]
+#
+# Where WORMM is worm mode
+#       WMLR is worm mode label restrictions
+#          0 - No blocks can be overwritten
+#          1 - Some types of format labels may not be overwritten
+#          2 - All format labels can be overwritten
+#       WMFR is worm mode filemark restrictions
+#          0-1  - Reserved
+#          2    - Any number of filemarks immediately preceding EOD can be
+#                 overwritten except file mark closest to BOP (beginning of
+#                 partition).
+#          3    - Any number of filemarks immediately preceding the EOD
+#                 can be overwritten
+#          4-FF - Reserved
+#
+
+if [ x$1 = x ] ; then
+   echo "First argument missing. Must be device control name."
+   exit 1
+fi
+
+sdparm=`which sdparm`
+if [ x${sdparm} = x ] ; then
+   echo "sdparm program not found, but is required."
+   exit 0
+fi
+
+#
+# This should be the correct way to determine if the tape is WORM
+#   but it does not work for mhvtl.  Comment out the next 5 lines
+#   and the code that follows will detect correctly on mhtvl.
+#
+worm=`$sdparm --page=0x1D -f $1 |grep " *WORMM"|cut -b12-16|sed "s:^ *::"`
+if [ $? = 0 ] ; then
+   echo $worm
+   exit 0
+fi
+
+tapeinfo=`which tapeinfo`
+if [ x${tapeinfo} = x ] ; then
+   echo "tapeinfo program not found, but is required."
+   exit 1
+fi
+
+#
+# Unfortunately IBM and HP handle the Medium Type differently,
+#  so we detect the vendor and get the appropriate Worm flag.
+#
+vendor=`$tapeinfo -f $1|grep "^Vendor ID:"|cut -b13-15`
+if [ x$vendor = xHP ] ; then
+   worm=`$tapeinfo -f $1|grep "^Medium Type: 0x"|cut -b16-16`
+   echo $worm
+   exit 0
+fi
+
+if [ x$vendor = xIBM ] ; then
+   worm=`$tapeinfo -f $1|grep "^Medium Type: 0x"|cut -b17-17`
+   if [ x$worm = xc ]; then
+      echo "1"
+      exit 0
+   fi
+   if [ x$worm = xC ]; then
+      echo "1"
+      exit 0
+   fi
+fi
+echo "0"
+exit 0
index 5e26a9861476b2e9f76589277ae989b591a7c15d..0ef663553658db355afdaab3ab9252d4cd1a7a46 100644 (file)
@@ -47,7 +47,7 @@ static char Update_media[] = "CatReq JobId=%ld UpdateMedia VolName=%s"
    " VolErrors=%u VolWrites=%lld MaxVolBytes=%lld EndTime=%lld VolStatus=%10s"
    " Slot=%d relabel=%d InChanger=%d VolReadTime=%lld VolWriteTime=%lld"
    " VolFirstWritten=%lld VolType=%u VolParts=%d VolCloudParts=%d"
-   " LastPartBytes=%lld Enabled=%d\n";
+   " LastPartBytes=%lld Enabled=%d Recycle=%d\n";
 
 static char Create_jobmedia[] = "CatReq JobId=%ld CreateJobMedia\n";
 
@@ -59,7 +59,7 @@ static char OK_media[] = "1000 OK VolName=%s VolJobs=%u VolFiles=%u"
    " MaxVolJobs=%u MaxVolFiles=%u InChanger=%d VolReadTime=%s"
    " VolWriteTime=%s EndFile=%u EndBlock=%u VolType=%u LabelType=%d"
    " MediaId=%s ScratchPoolId=%s VolParts=%d VolCloudParts=%d"
-   " LastPartBytes=%lld Enabled=%d\n";
+   " LastPartBytes=%lld Enabled=%d Recycle=%d\n";
 
 static char OK_create[] = "1000 OK CreateJobMedia\n";
 
@@ -106,7 +106,8 @@ static int send_volume_info_to_storage_daemon(JCR *jcr, BSOCK *sd, MEDIA_DBR *mr
       mr->VolParts,
       mr->VolCloudParts,
       mr->LastPartBytes,
-      mr->Enabled);
+      mr->Enabled,
+      mr->Recycle);
    unbash_spaces(mr->VolumeName);
    Dmsg2(100, "Vol Info for %s: %s", jcr->Job, sd->msg);
    return stat;
@@ -127,7 +128,7 @@ void catalog_request(JCR *jcr, BSOCK *bs)
    utime_t VolFirstWritten;
    utime_t VolLastWritten;
    int n;
-   int Enabled;
+   int Enabled, Recycle;
    JobId_t JobId = 0;
 
    memset(&sdmr, 0, sizeof(sdmr));
@@ -250,8 +251,8 @@ void catalog_request(JCR *jcr, BSOCK *bs)
       &VolLastWritten, &sdmr.VolStatus, &sdmr.Slot, &label, &sdmr.InChanger,
       &sdmr.VolReadTime, &sdmr.VolWriteTime, &VolFirstWritten,
       &sdmr.VolType, &sdmr.VolParts, &sdmr.VolCloudParts,
-      &sdmr.LastPartBytes, &Enabled);
-    if (n == 26) {
+      &sdmr.LastPartBytes, &Enabled, &Recycle);
+    if (n == 27) {
       db_lock(jcr->db);
       Dmsg3(400, "Update media %s oldStat=%s newStat=%s\n", sdmr.VolumeName,
          mr.VolStatus, sdmr.VolStatus);
@@ -336,6 +337,7 @@ void catalog_request(JCR *jcr, BSOCK *bs)
       mr.VolCloudParts = sdmr.VolCloudParts;
       mr.LastPartBytes = sdmr.LastPartBytes;
       mr.Enabled       = Enabled;  /* byte assignment */
+      mr.Recycle       = Recycle;  /* byte assignment */
       bstrncpy(mr.VolStatus, sdmr.VolStatus, sizeof(mr.VolStatus));
       if (sdmr.VolReadTime >= 0) {
          mr.VolReadTime  = sdmr.VolReadTime;
index 0fdf68f3464cf38621abf4315d3166384736c5db..a0d3d7e2f78e6523cc083b5bb92874ee18f3bde2 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Copyright (C) 2000-2017 Kern Sibbald
+# Copyright (C) 2000-2018 Kern Sibbald
 # License: BSD 2-Clause; see file LICENSE-FOSS
 #
 @MCOMMON@
@@ -78,7 +78,7 @@ LIBBACSD_SRCS = \
    init_dev.c label.c lock.c match_bsr.c mount.c \
    null_dev.c os.c parse_bsr.c read.c read_records.c \
    record_read.c record_util.c record_write.c reserve.c \
-   scan.c sd_plugins.c spool.c tape_alert.c vol_mgr.c wait.c \
+   scan.c sd_plugins.c spool.c tape_alert.c tape_worm.c vol_mgr.c wait.c \
    fifo_dev.c file_dev.c tape_dev.c vtape_dev.c
 
 LIBBACSD_OBJS = $(LIBBACSD_SRCS:.c=.o)
index e9766e4f4ecd3db037dbba46629656b4513a7430..81b142ff191fb254c2a76812ddee9fb5fdbbd322 100644 (file)
@@ -37,7 +37,7 @@ static char Update_media[] = "CatReq JobId=%ld UpdateMedia VolName=%s"
    " VolErrors=%u VolWrites=%u MaxVolBytes=%s EndTime=%s VolStatus=%s"
    " Slot=%d relabel=%d InChanger=%d VolReadTime=%s VolWriteTime=%s"
    " VolFirstWritten=%s VolType=%u VolParts=%d VolCloudParts=%d"
-   " LastPartBytes=%lld Enabled=%d\n";
+   " LastPartBytes=%lld Enabled=%d Recycle=%d\n";
 static char Create_jobmedia[] = "CatReq JobId=%ld CreateJobMedia\n";
 static char FileAttributes[] = "UpdCat JobId=%ld FileAttributes ";
 
@@ -50,7 +50,8 @@ static char OK_media[] = "1000 OK VolName=%127s VolJobs=%u VolFiles=%lu"
    " Slot=%ld MaxVolJobs=%lu MaxVolFiles=%lu InChanger=%ld"
    " VolReadTime=%lld VolWriteTime=%lld EndFile=%lu EndBlock=%lu"
    " VolType=%lu LabelType=%ld MediaId=%lld ScratchPoolId=%lld"
-   " VolParts=%d VolCloudParts=%d LastPartBytes=%lld Enabled=%d\n";
+   " VolParts=%d VolCloudParts=%d LastPartBytes=%lld Enabled=%d"
+   " Recycle=%d\n";
 
 
 static char OK_create[] = "1000 OK CreateJobMedia\n";
@@ -59,6 +60,8 @@ static bthread_mutex_t vol_info_mutex = BTHREAD_MUTEX_PRIORITY(PRIO_SD_VOL_INFO)
 
 #ifdef needed
 
+Note: if you turn this on, be sure to add the Recycle Flag
+
 static char Device_update[] = "DevUpd JobId=%ld device=%s "
    "append=%d read=%d num_writers=%d "
    "open=%d labeled=%d offline=%d "
@@ -204,7 +207,7 @@ static bool do_get_volume_info(DCR *dcr)
     BSOCK *dir = jcr->dir_bsock;
     VOLUME_CAT_INFO vol;
     int n;
-    int32_t Enabled;
+    int32_t Enabled, Recycle;
     int32_t InChanger;
 
     dcr->setVolCatInfo(false);
@@ -226,9 +229,9 @@ static bool do_get_volume_info(DCR *dcr)
                &vol.EndFile, &vol.EndBlock, &vol.VolCatType,
                &vol.LabelType, &vol.VolMediaId, &vol.VolScratchPoolId,
                &vol.VolCatParts, &vol.VolCatCloudParts,
-               &vol.VolLastPartBytes, &Enabled);
+               &vol.VolLastPartBytes, &Enabled, &Recycle);
     Dmsg2(dbglvl, "<dird n=%d %s", n, dir->msg);
-    if (n != 30) {
+    if (n != 31) {
        Dmsg1(dbglvl, "get_volume_info failed: ERR=%s", dir->msg);
        /*
         * Note, we can get an error here either because there is
@@ -241,6 +244,7 @@ static bool do_get_volume_info(DCR *dcr)
     }
     vol.InChanger = InChanger;        /* bool in structure */
     vol.VolEnabled = Enabled;         /* bool in structure */
+    vol.VolRecycle = Recycle;         /* bool in structure */
     vol.is_valid = true;
     vol.VolCatBytes = vol.VolCatAmetaBytes + vol.VolCatAdataBytes;
     unbash_spaces(vol.VolCatName);
@@ -424,7 +428,7 @@ bool dir_update_volume_info(DCR *dcr, bool label, bool update_LastWritten,
    DEVICE *dev = dcr->ameta_dev;
    VOLUME_CAT_INFO vol;
    char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50], ed7[50], ed8[50];
-   int InChanger;
+   int InChanger, Enabled, Recycle;
    bool ok = false;
    POOL_MEM VolumeName;
 
@@ -458,9 +462,16 @@ bool dir_update_volume_info(DCR *dcr, bool label, bool update_LastWritten,
 // if (update_LastWritten) {
       vol.VolLastWritten = time(NULL);
 // }
+   /* worm cannot be recycled, ensure catalog correct */
+   if (dev->is_worm() && vol.VolRecycle) {
+      Jmsg(jcr, M_INFO, 0, _("WORM cassette detected: setting Recycle=No on Volume=\"%s\"\n"));
+      vol.VolRecycle = false;
+   }
    pm_strcpy(VolumeName, vol.VolCatName);
    bash_spaces(VolumeName);
    InChanger = vol.InChanger;
+   Enabled = vol.VolEnabled;
+   Recycle = vol.VolRecycle;
    /* Insanity test */
    if (vol.VolCatHoleBytes > (((uint64_t)2)<<60)) {
       Pmsg1(010, "VolCatHoleBytes too big: %lld. Reset to zero.\n",
@@ -488,7 +499,8 @@ bool dir_update_volume_info(DCR *dcr, bool label, bool update_LastWritten,
       vol.VolCatParts,
       vol.VolCatCloudParts,
       vol.VolLastPartBytes,
-      vol.VolEnabled);
+      Enabled,
+      Recycle);
     Dmsg1(100, ">dird %s", dir->msg);
 
    /* Do not lock device here because it may be locked from label */
index 95eb4753c038534e2d339a8e02003d7a27f6d11f..dc098280c8486d23f63d9beedadc08f20d1781da 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula(R) - The Network Backup Solution
 
-   Copyright (C) 2000-2017 Kern Sibbald
+   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.
@@ -1048,3 +1048,8 @@ int DEVICE::delete_alerts()
 {
    return 0;
 }
+
+bool DEVICE::get_tape_worm(DCR *dcr)
+{
+   return false;
+}
index 12b5e42753a0ea36f92f92b4f1e0f96c8f59a5e3..dc80cb790c4a5c6b729d3c400e908a380af1a3b3 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula(R) - The Network Backup Solution
 
-   Copyright (C) 2000-2017 Kern Sibbald
+   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.
@@ -208,6 +208,7 @@ struct VOLUME_CAT_INFO {
    bool     InChanger;                /* Set if vol in current magazine */
    bool     is_valid;                 /* set if this data is valid */
    bool     VolEnabled;               /* set if volume enabled */
+   bool     VolRecycle;               /* set if volume can be recycled */
    char VolCatStatus[20];             /* Volume status */
    char VolCatName[MAX_NAME_LENGTH];  /* Desired volume to mount */
 };
@@ -265,6 +266,7 @@ public:
    bool autoselect;                   /* Autoselect in autochanger */
    bool read_only;                    /* Device is read only */
    bool initiated;                    /* set when init_dev() called */
+   bool m_is_worm;                    /* set for worm tape */
    bool m_shstore;                    /* Shares storage can be used */
    bool m_shstore_lock;               /* set if shared lock set */
    bool m_shstore_user_lock;          /* set if user set shared lock */
@@ -349,6 +351,7 @@ public:
    int has_cap(int cap) const { return capabilities & cap; }
    void clear_cap(int cap) { capabilities &= ~cap; }
    void set_cap(int cap) { capabilities |= cap; }
+   void set_worm(bool is_worm) { m_is_worm = is_worm; }
    bool do_checksum() const { return (capabilities & CAP_BLOCKCHECKSUM) != 0; }
    int is_autochanger() const { return capabilities & CAP_AUTOCHANGER; }
    int requires_mount() const { return capabilities & CAP_REQMOUNT; }
@@ -363,6 +366,7 @@ public:
    bool is_fifo() const { return dev_type == B_FIFO_DEV; }
    bool is_vtl() const  { return dev_type == B_VTL_DEV; }
    bool is_vtape() const  { return dev_type == B_VTAPE_DEV; }
+   bool is_worm() const { return m_is_worm; }
    bool is_open() const { return m_fd >= 0; }
    int is_offline() const { return state & ST_OFFLINE; }
    int is_labeled() const { return state & ST_LABEL; }
@@ -564,6 +568,7 @@ public:
    virtual char *print_addr(char *buf, int32_t maxlen, boffset_t addr);
    virtual bool do_size_checks(DCR *dcr, DEV_BLOCK *block); /* in dev.c */
 
+   virtual bool get_tape_worm(DCR *dcr);
    virtual bool get_tape_alerts(DCR *dcr);
    virtual void show_tape_alerts(DCR *dcr, alert_list_type type,
       alert_list_which which, alert_cb alert_callback);
index 236cc70067618f58169f55a32e5c4f80cfc2b70e..c061e52a4e9b8b634a83c6ec9cc907d94655aeb1 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula(R) - The Network Backup Solution
 
-   Copyright (C) 2000-2017 Kern Sibbald
+   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.
@@ -74,6 +74,7 @@ int DEVICE::read_dev_volume_label(DCR *dcr)
       block->adata, num_reserved(), print_name(), VolName,
       VolHdr.VolumeName[0]?VolHdr.VolumeName:"*NULL*");
 
+
    if (!is_open()) {
       if (!open_device(dcr, OPEN_READ_ONLY)) {
          Leave(dbglvl);
@@ -85,6 +86,8 @@ int DEVICE::read_dev_volume_label(DCR *dcr)
    clear_append();
    clear_read();
    label_type = B_BACULA_LABEL;
+   set_worm(get_tape_worm(dcr));
+   Dmsg1(dbglvl, "==== worm=%d ====\n", is_worm());
 
    if (!rewind(dcr)) {
       Mmsg(jcr->errmsg, _("Couldn't rewind %s device %s: ERR=%s\n"),
@@ -535,6 +538,12 @@ bool DEVICE::rewrite_volume_label(DCR *dcr, bool recycle)
    Enter(100);
    ASSERT2(dcr->VolumeName[0], "Empty Volume name");
    ASSERT(!dcr->block->adata);
+   if (is_worm()) {
+      Jmsg3(jcr, M_FATAL, 0,  _("Cannot relabel worm %s device %s Volume \"%s\"\n"),
+             print_type(), print_name(), dcr->VolumeName);
+      Leave(100);
+      return false;
+   }
    if (!open_device(dcr, OPEN_READ_WRITE)) {
        Jmsg4(jcr, M_WARNING, 0, _("Open %s device %s Volume \"%s\" failed: ERR=%s\n"),
              print_type(), print_name(), dcr->VolumeName, bstrerror());
@@ -784,13 +793,14 @@ void create_volume_header(DEVICE *dev, const char *VolName,
       bstrncpy(dev->VolHdr.Id, BaculaS3CloudId, sizeof(dev->VolHdr.Id));
       dev->VolHdr.VerNum = BaculaS3CloudVersion;
       dev->VolHdr.BlockSize = dev->max_block_size;
+      dev->VolHdr.MaxPartSize = dev->max_part_size;
    } else {
       bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
       dev->VolHdr.VerNum = BaculaTapeVersion;
       dev->VolHdr.BlockSize = dev->max_block_size;
    }
 
-   if (dev->has_cap(CAP_STREAM) && no_prelabel) {
+   if ((dev->has_cap(CAP_STREAM) && no_prelabel) || dev->is_worm()) {
       /* We do not want to re-label so write VOL_LABEL now */
       dev->VolHdr.LabelType = VOL_LABEL;
    } else {
index 3c5cd1802651bf1da54f0b525c09560019f2e641..b0aa0dc809452897e3912d4577d35e347bfe0701 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula(R) - The Network Backup Solution
 
-   Copyright (C) 2000-2017 Kern Sibbald
+   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.
@@ -201,7 +201,7 @@ struct Volume_Label {
   uint32_t  BlockSize;                /* Basic block size */
 
   /* For Cloud */
-  uint64_t  ChunkSize;                /* Basic chunk size */
+  uint64_t  MaxPartSize;              /* Maximum Part Size */
 
 };
 
index 28ee9280265dbc85523a86d681d0fae09c059e4c..f03aa44836cb8fc81d20e9db8f891e8bda92ce2d 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula(R) - The Network Backup Solution
 
-   Copyright (C) 2000-2017 Kern Sibbald
+   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.
@@ -129,9 +129,7 @@ void output_status(STATUS_PKT *sp)
    list_volumes(sendit, (void *)sp);
    if (!sp->api) sendit("====\n\n", 6, sp);
 
-
    list_spool_stats(sendit, (void *)sp);
-
    if (!sp->api) sendit("====\n\n", 6, sp);
 
    if (chk_dbglvl(10)) {
@@ -670,20 +668,22 @@ void send_device_status(DEVICE *dev, STATUS_PKT *sp)
 
    len = Mmsg(msg, _("Device state:\n"));
    sendit(msg, len, sp);
-   len = Mmsg(msg, "   %sOPENED %sTAPE %sLABEL %sMALLOC %sAPPEND %sREAD %sEOT %sWEOT %sEOF %sNEXTVOL %sSHORT %sMOUNTED\n",
+   len = Mmsg(msg, "   %sOPENED %sTAPE %sLABEL %sAPPEND %sREAD %sEOT %sWEOT %sEOF %sWORM %sNEXTVOL %sSHORT %sMOUNTED %sMALLOC\n",
       dev->is_open() ? "" : "!",
       dev->is_tape() ? "" : "!",
       dev->is_labeled() ? "" : "!",
-      dev->state & ST_MALLOC ? "" : "!",
       dev->can_append() ? "" : "!",
       dev->can_read() ? "" : "!",
       dev->at_eot() ? "" : "!",
       dev->state & ST_WEOT ? "" : "!",
       dev->at_eof() ? "" : "!",
-      dev->state & ST_NEXTVOL ? "" : "!",
-      dev->state & ST_SHORT ? "" : "!",
-      dev->state & ST_MOUNTED ? "" : "!");
+      dev->is_worm() ?  "" : "!",
+      dev->state & ST_NEXTVOL ?  "" : "!",
+      dev->state & ST_SHORT ?  "" : "!",
+      dev->state & ST_MOUNTED ?  "" : "!",
+      dev->state & ST_MALLOC ?  "" : "!");
    sendit(msg, len, sp);
+
    len = Mmsg(msg, _("   Writers=%d reserves=%d blocked=%d enabled=%d usage=%s\n"), dev->num_writers,
               dev->num_reserved(), dev->blocked(), dev->enabled,
                edit_uint64_with_commas(dev->usage, b1));
index 19997f8c6a8e2b0e7c00c0db825b0254f948d282..1752d3ddc9011b860d3a8285e2896209fd227491 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula(R) - The Network Backup Solution
 
-   Copyright (C) 2000-2017 Kern Sibbald
+   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.
@@ -140,6 +140,7 @@ static RES_ITEM dev_items[] = {
    {"ChangerCommand",        store_strname,ITEM(res_dev.changer_command), 0, 0, 0},
    {"AlertCommand",          store_strname,ITEM(res_dev.alert_command), 0, 0, 0},
    {"LockCommand",           store_strname,ITEM(res_dev.lock_command), 0, 0, 0},
+   {"WormCommand",           store_strname,ITEM(res_dev.worm_command), 0, 0, 0},
    {"MaximumChangerWait",    store_time,   ITEM(res_dev.max_changer_wait), 0, ITEM_DEFAULT, 5 * 60},
    {"MaximumOpenWait",       store_time,   ITEM(res_dev.max_open_wait), 0, ITEM_DEFAULT, 5 * 60},
    {"MaximumNetworkBufferSize", store_pint32, ITEM(res_dev.max_network_buffer_size), 0, 0, 0},
@@ -509,6 +510,9 @@ void dump_resource(int type, RES *rres, void sendit(void *sock, const char *fmt,
       sendit(sock, "        spool_directory=%s\n", NPRT(res->res_dev.spool_directory));
       sendit(sock, "        max_spool_size=%lld max_job_spool_size=%lld\n",
          res->res_dev.max_spool_size, res->res_dev.max_job_spool_size);
+      if (res->res_dev.worm_command) {
+         sendit(sock, "         worm command=%s\n", res->res_dev.worm_command);
+      }
       if (res->res_dev.changer_res) {
          sendit(sock, "         changer=%p\n", res->res_dev.changer_res);
       }
@@ -757,6 +761,9 @@ void free_resource(RES *sres, int type)
       if (res->res_dev.alert_command) {
          free(res->res_dev.alert_command);
       }
+      if (res->res_dev.worm_command) {
+         free(res->res_dev.worm_command);
+      }
       if (res->res_dev.lock_command) {
          free(res->res_dev.lock_command);
       }
index f081e9464930a2b19b046afbc57c99816853bc28..26512887d34238e6799dee21463259e8e7d43b13 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula(R) - The Network Backup Solution
 
-   Copyright (C) 2000-2017 Kern Sibbald
+   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.
@@ -169,6 +169,7 @@ public:
    char *changer_command;             /* Changer command  -- external program */
    char *alert_command;               /* Alert command -- external program */
    char *lock_command;                /* Share storage lock command -- external program */
+   char *worm_command;                /* Worm detection command -- external program */
    char *spool_directory;             /* Spool file directory */
    uint32_t dev_type;                 /* device type */
    uint32_t label_type;               /* label type */
index b6d9a74a78cf4d9c59af7a286a60dcc3e9405f21..e729b6f4ae091b0e79add6aef895cbfd064c894f 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula(R) - The Network Backup Solution
 
-   Copyright (C) 2000-2017 Kern Sibbald
+   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.
@@ -60,6 +60,7 @@ public:
    bool end_of_volume(DCR *dcr);
    char *print_addr(char *buf, int32_t buf_len);
    char *print_addr(char *buf, int32_t maxlen, boffset_t addr);
+   bool get_tape_worm(DCR *dcr);
    bool get_tape_alerts(DCR *dcr);
    void show_tape_alerts(DCR *dcr, alert_list_type type,
       alert_list_which which, alert_cb alert_callback);
diff --git a/bacula/src/stored/tape_worm.c b/bacula/src/stored/tape_worm.c
new file mode 100644 (file)
index 0000000..e7dd583
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+   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.
+*/
+/*
+ *
+ *  Routines for getting tape worm status
+ *
+ *   Written by Kern Sibbald, September MMXVIII
+ *
+ */
+
+#include "bacula.h"                   /* pull in global headers */
+#include "stored.h"                   /* pull in Storage Deamon headers */
+
+
+static const int dbglvl = 50;
+
+
+bool tape_dev::get_tape_worm(DCR *dcr)
+{
+   JCR *jcr = dcr->jcr;
+
+   if (!job_canceled(jcr) && dcr->device->worm_command &&
+       dcr->device->control_name) {
+      POOLMEM *wormcmd;
+      int status = 1;
+      bool is_worm = false;
+      int worm_val = 0;
+      BPIPE *bpipe;
+      char line[MAXSTRING];
+      const char *fmt = " %d";
+
+      wormcmd = get_pool_memory(PM_FNAME);
+      wormcmd = edit_device_codes(dcr, wormcmd, dcr->device->worm_command, "");
+      /* Wait maximum 5 minutes */
+      bpipe = open_bpipe(wormcmd, 60 * 5, "r");
+      if (bpipe) {
+         while (fgets(line, (int)sizeof(line), bpipe->rfd)) {
+            is_worm = false;
+            if (bsscanf(line, fmt, &worm_val) == 1) {
+               if (worm_val > 0) {
+                  is_worm = true;
+               }
+            }
+         }
+         status = close_bpipe(bpipe);
+         free_pool_memory(wormcmd);
+         return is_worm;
+      } else {
+         status = errno;
+      }
+      if (status != 0) {
+         berrno be;
+         Jmsg(jcr, M_WARNING, 0, _("3997 Bad worm command status: %s: ERR=%s.\n"),
+              wormcmd, be.bstrerror(status));
+         Dmsg2(dbglvl, _("3997 Bad worm command status: %s: ERR=%s.\n"),
+              wormcmd, be.bstrerror(status));
+      }
+
+      Dmsg1(400, "worm script status=%d\n", status);
+      free_pool_memory(wormcmd);
+   } else {
+      if (!dcr->device->worm_command) {
+         Dmsg1(dbglvl, "Cannot get tape worm status: no Worm Command specified for device %s\n",
+            print_name());
+         Dmsg1(dbglvl, "Cannot get tape worm status: no Worm Command specified for device %s\n",
+            print_name());
+
+      }
+      if (!dcr->device->control_name) {
+         Dmsg1(dbglvl, "Cannot get tape worm status: no Control Device specified for device %s\n",
+            print_name());
+         Dmsg1(dbglvl, "Cannot get tape worm status: no Control Device specified for device %s\n",
+            print_name());
+      }
+   }
+   return false;
+}
index 7e5f64adb4bdeb45605c83191eea44643345cb1d..c8e0c6fe90f562944775d48d83021cf29044d104 100644 (file)
@@ -238,9 +238,9 @@ void list_volumes(void sendit(const char *msg, int len, void *sarg), void *arg)
          len = Mmsg(msg, "Reserved volume: %s on %s device %s\n", vol->vol_name,
                   dev->print_type(), dev->print_name());
          sendit(msg.c_str(), len, arg);
-         len = Mmsg(msg, "    Reader=%d writers=%d reserves=%d volinuse=%d\n",
+         len = Mmsg(msg, "    Reader=%d writers=%d reserves=%d volinuse=%d worm=%d\n",
             dev->can_read()?1:0, dev->num_writers, dev->num_reserved(),
-            vol->is_in_use());
+            vol->is_in_use(), dev->is_worm());
          sendit(msg.c_str(), len, arg);
       } else {
          len = Mmsg(msg, "Volume %s no device. volinuse=%d\n", vol->vol_name,