From: Kern Sibbald Date: Wed, 17 Oct 2018 09:06:49 +0000 (+0200) Subject: Implement worm cassette support X-Git-Tag: Release-9.4.0~49 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9cc790cdc74865445ca0926877c824232242be0d;p=thirdparty%2Fbacula.git Implement worm cassette support --- diff --git a/bacula/scripts/Makefile.in b/bacula/scripts/Makefile.in index 40ad3e67d9..33713723ca 100755 --- a/bacula/scripts/Makefile.in +++ b/bacula/scripts/Makefile.in @@ -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 index 0000000000..ba64292be5 --- /dev/null +++ b/bacula/scripts/isworm @@ -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 diff --git a/bacula/src/dird/catreq.c b/bacula/src/dird/catreq.c index 5e26a98614..0ef6635536 100644 --- a/bacula/src/dird/catreq.c +++ b/bacula/src/dird/catreq.c @@ -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; diff --git a/bacula/src/stored/Makefile.in b/bacula/src/stored/Makefile.in index 0fdf68f346..a0d3d7e2f7 100644 --- a/bacula/src/stored/Makefile.in +++ b/bacula/src/stored/Makefile.in @@ -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) diff --git a/bacula/src/stored/askdir.c b/bacula/src/stored/askdir.c index e9766e4f4e..81b142ff19 100644 --- a/bacula/src/stored/askdir.c +++ b/bacula/src/stored/askdir.c @@ -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, "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 */ diff --git a/bacula/src/stored/dev.c b/bacula/src/stored/dev.c index 95eb4753c0..dc098280c8 100644 --- a/bacula/src/stored/dev.c +++ b/bacula/src/stored/dev.c @@ -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; +} diff --git a/bacula/src/stored/dev.h b/bacula/src/stored/dev.h index 12b5e42753..dc80cb790c 100644 --- a/bacula/src/stored/dev.h +++ b/bacula/src/stored/dev.h @@ -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); diff --git a/bacula/src/stored/label.c b/bacula/src/stored/label.c index 236cc70067..c061e52a4e 100644 --- a/bacula/src/stored/label.c +++ b/bacula/src/stored/label.c @@ -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 { diff --git a/bacula/src/stored/record.h b/bacula/src/stored/record.h index 3c5cd18026..b0aa0dc809 100644 --- a/bacula/src/stored/record.h +++ b/bacula/src/stored/record.h @@ -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 */ }; diff --git a/bacula/src/stored/status.c b/bacula/src/stored/status.c index 28ee928026..f03aa44836 100644 --- a/bacula/src/stored/status.c +++ b/bacula/src/stored/status.c @@ -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)); diff --git a/bacula/src/stored/stored_conf.c b/bacula/src/stored/stored_conf.c index 19997f8c6a..1752d3ddc9 100644 --- a/bacula/src/stored/stored_conf.c +++ b/bacula/src/stored/stored_conf.c @@ -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); } diff --git a/bacula/src/stored/stored_conf.h b/bacula/src/stored/stored_conf.h index f081e94649..26512887d3 100644 --- a/bacula/src/stored/stored_conf.h +++ b/bacula/src/stored/stored_conf.h @@ -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 */ diff --git a/bacula/src/stored/tape_dev.h b/bacula/src/stored/tape_dev.h index b6d9a74a78..e729b6f4ae 100644 --- a/bacula/src/stored/tape_dev.h +++ b/bacula/src/stored/tape_dev.h @@ -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 index 0000000000..e7dd5838a5 --- /dev/null +++ b/bacula/src/stored/tape_worm.c @@ -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; +} diff --git a/bacula/src/stored/vol_mgr.c b/bacula/src/stored/vol_mgr.c index 7e5f64adb4..c8e0c6fe90 100644 --- a/bacula/src/stored/vol_mgr.c +++ b/bacula/src/stored/vol_mgr.c @@ -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,