From: Eric Bollengier Date: Fri, 31 Mar 2023 15:03:24 +0000 (+0200) Subject: Fix #10020 #9757 Improve Volume Protection code and fix the unprotection code X-Git-Tag: Beta-15.0.0~204 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a75efc977045f16400b4e7c84f7787384ac966ae;p=thirdparty%2Fbacula.git Fix #10020 #9757 Improve Volume Protection code and fix the unprotection code 31-Mar 13:55 zog8-sd JobId 12: Marking Volume "Test10018" as read-only. Retention set to 31-Mar-2023 13:55 (10 secs). --- diff --git a/bacula/src/stored/block_util.c b/bacula/src/stored/block_util.c index a1fc5eccd..7a173b1ae 100644 --- a/bacula/src/stored/block_util.c +++ b/bacula/src/stored/block_util.c @@ -684,10 +684,11 @@ bool is_user_volume_size_reached(DCR *dcr, bool quiet) } if (dev->device->set_vol_read_only) { + btime_t now = time(NULL); uint32_t when = MAX(dev->device->min_volume_protection_time, dev->VolCatInfo.VolRetention); dev->VolCatInfo.UseProtect = 1; /* Set volume as immutable/read only */ - if (dev->set_atime(dev->m_fd, dev->getVolCatName(), time(NULL) + when) < 0) { + if (dev->set_atime(dev->m_fd, dev->getVolCatName(), now + when) < 0) { Jmsg(dcr->jcr, M_WARNING, 0, _("Failed to set the volume %s on device %s in atime retention, ERR=%s.\n"), dev->getVolCatName(), dev->print_name(), dev->errmsg); } @@ -697,12 +698,13 @@ bool is_user_volume_size_reached(DCR *dcr, bool quiet) Jmsg(dcr->jcr, M_WARNING, 0, _("Failed to set the volume %s on device %s in read-only, ERR=%s.\n"), dev->getVolCatName(), dev->print_name(), be.bstrerror()); } else { - char buf[128]; - edit_utime(when, buf, sizeof(buf)); - if (!quiet) { - Jmsg(dcr->jcr, M_INFO, 0, _("Marking Volume \"%s\" as read-only. Retention set to %s.\n"), buf, - dev->getVolCatName()); - } + char buf[128], buf2[128]; + strip_trailing_junk(edit_utime(when, buf, sizeof(buf))); + bstrftime(buf2, sizeof(buf2), now+when); + + Jmsg(dcr->jcr, M_INFO, 0, _("Marking Volume \"%s\" as read-only. Retention set to %s (%s).\n"), + dev->getVolCatName(), buf2, buf); + dev->VolCatInfo.Protected = 1; events_send_msg(dcr->jcr, "SJ0003", EVENTS_TYPE_VOLUME, me->hdr.name, (intptr_t)dcr->jcr, "Mark Volume \"%s\" as read-only. retention %s.", dev->getVolCatName(), buf);; @@ -717,10 +719,8 @@ bool is_user_volume_size_reached(DCR *dcr, bool quiet) Jmsg(dcr->jcr, M_WARNING, 0, _("Failed to set the volume %s on device %s as immutable, ERR=%s.\n"), dev->getVolCatName(), dev->print_name(), dev->errmsg); } else { - if (!quiet) { - Jmsg(dcr->jcr, M_INFO, 0, _("Marking Volume \"%s\" as immutable\n"), - dev->getVolCatName()); - } + Jmsg(dcr->jcr, M_INFO, 0, _("Marking Volume \"%s\" as immutable\n"), + dev->getVolCatName()); events_send_msg(dcr->jcr, "SJ0003", EVENTS_TYPE_VOLUME, me->hdr.name, (intptr_t)dcr->jcr, "Mark Volume \"%s\" as immutable", dev->getVolCatName());; dev->VolCatInfo.Protected = 1; diff --git a/bacula/src/stored/dircmd.c b/bacula/src/stored/dircmd.c index cee028dd6..3610cb30b 100644 --- a/bacula/src/stored/dircmd.c +++ b/bacula/src/stored/dircmd.c @@ -1376,7 +1376,8 @@ static bool volumeprotect_cmd(JCR *jcr) /* Set volume as immutable/read only */ pm_strcpy(tmp, ""); uint32_t when = MAX(dev->device->min_volume_protection_time, retention); - if (dev->set_atime(-1, volume, time(NULL) + when) < 0) { + btime_t now = time(NULL); + if (dev->set_atime(-1, volume, now + when) < 0) { berrno be; Mmsg(tmp, _(" Failed to set the volume %s on device %s in atime retention, ERR=%s.\n"), volume, dev->print_name(), be.bstrerror()); @@ -1387,11 +1388,13 @@ static bool volumeprotect_cmd(JCR *jcr) dir->fsend(_("3900 Failed to set the volume %s on device %s in read-only, ERR=%s.%s\n"), volume, dev->print_name(), be.bstrerror(), tmp.c_str()); } else { - char buf[128]; - dir->fsend(_("3000 Marking volume \"%s\" as read-only. Retention set to %s.\n"), - volume, edit_utime(when, buf, sizeof(buf))); + char buf[128], buf2[128]; + dir->fsend(_("3000 Marking volume \"%s\" as read-only. Retention set to %s (%s).\n"), + volume, + bstrftime(buf2, sizeof(buf2), now+when), + strip_trailing_junk(edit_utime(when, buf, sizeof(buf)))); events_send_msg(jcr, "SJ0003", EVENTS_TYPE_VOLUME, me->hdr.name, (intptr_t)jcr, - "Mark volume \"%s\" as read-only, retention %s", volume, buf); + "Mark volume \"%s\" as read-only, retention %s (%s)", volume, buf2, buf); } } else { dir->fsend(_("3900 Device %s not configured for ReadOnly or Immutable\n"), dev->device->hdr.name); diff --git a/bacula/src/stored/file_dev.c b/bacula/src/stored/file_dev.c index c6845461e..6026d8b8e 100644 --- a/bacula/src/stored/file_dev.c +++ b/bacula/src/stored/file_dev.c @@ -199,27 +199,47 @@ bool file_dev::open_device(DCR *dcr, int omode) /* Use system open() */ if ((m_fd = ::open(archive_name.c_str(), mode|O_CLOEXEC|append, 0640)) < 0) { /* Open may fail if we want to write to the Immutable volume */ - if (errno == EPERM && check_for_immutable(getVolCatName())) { - /* Volume has immutable flag set, we need to clear it */ - if (!check_volume_protection_time(getVolCatName())) { - /* Volume cannot be reused yet */ - MmsgD1(dbglvl, errmsg, _("Cannot open Volume %s for writing/truncating, " - "because Minimum Volume Protection Time hasn't expired yet\n"), - getVolCatName()); - } else { - /* Flag can be cleared, volume can probably be reused */ - if (clear_immutable(getVolCatName(), &errmsg)) { - /* It should be now possible to open the device with desired mode */ - if ((m_fd = ::open(archive_name.c_str(), mode|O_CLOEXEC|append, 0640)) < 0) { + if (errno == EACCES && use_protect()) { + bool immutable = check_for_immutable(getVolCatName()); + bool readonly = check_for_read_only(-1, getVolCatName()); + Dmsg3(DT_VOLUME|40, "volume=%s immutable=%d readonly=%d\n", getVolCatName(), immutable, readonly); + if (immutable || readonly) { + /* Volume has immutable flag set, we need to clear it */ + if (!check_volume_protection_time(getVolCatName())) { + /* Volume cannot be reused yet */ + MmsgD1(dbglvl, errmsg, _("Cannot open Volume %s for writing/truncating, " + "because Minimum Volume Protection Time hasn't expired yet\n"), + getVolCatName()); + } else { + bool tryopen = false; + /* Flag can be cleared, volume can probably be reused */ + if (immutable && clear_immutable(getVolCatName(), &errmsg)) { + tryopen = true; + } + if (readonly && set_writable(-1, getVolCatName())) { + tryopen = true; + } + if (tryopen) { /* It should be now possible to open the device with desired mode */ + if ((m_fd = ::open(archive_name.c_str(), mode|O_CLOEXEC|append, 0640)) < 0) { + berrno be; + dev_errno = errno; + MmsgD3(40, errmsg, _("Could not open(%s,%s,0640): ERR=%s\n"), + archive_name.c_str(), mode_to_str(omode), be.bstrerror()); + } // else open is ok + + } else { // Cannot clear the flags berrno be; - dev_errno = errno; - MmsgD3(40, errmsg, _("Could not open(%s,%s,0640): ERR=%s\n"), - archive_name.c_str(), mode_to_str(omode), be.bstrerror()); + MmsgD2(40, errmsg, _("Could not clear volume protection on %s ERR=%s\n"), + getVolCatName(), be.bstrerror()); } } + } else { // not immutable or readonly, other issue + berrno be; + dev_errno = errno; + MmsgD3(40, errmsg, _("Could not open(%s,%s,0640): ERR=%s\n"), + archive_name.c_str(), mode_to_str(omode), be.bstrerror()); } - } else { - /* Volume is not immutable, that should succeed */ + } else { // Not a permission issue on this device berrno be; dev_errno = errno; MmsgD3(40, errmsg, _("Could not open(%s,%s,0640): ERR=%s\n"),