<li>The new <code>rsync-timeout</code> option allows a time
limit to be imposed on a backup.</li>
+ <li>The new <code>check-file</code> option allows backups of a
+ volume to be suppressed when it is not available (for instance,
+ becuase it is only sometimes mounted).</li>
+
<li><code>--verbose</code> (and therefore
<code>--dry-run</code>) is now more verbose.</li>
.B traverse
Traverse mount points.
This suppresses the rsync \fB\-\-one\-file\-system\fR option.
+.TP
+.B check-file \fIPATH\fR
+Checks that \fIPATH\fR exists before backing up the volume.
+\fIPATH\fR may be either an absolute path or a relative path (to the
+root of the volume).
+It need not be inside the volume though the usual use would be to
+check for a file which is always present there.
.PP
In addition, the following directives can be used within a volume
stanza, and apply to just that volume:
if(bits.size() != 2)
throw SyntaxError("wrong number of arguments to 'devices'");
if(host == NULL)
- throw SyntaxError("'host' command without 'volume'");
+ throw SyntaxError("'devices' command without 'volume'");
context->devicePattern = bits[1];
+ } else if(bits[0] == "check-file") {
+ if(bits.size() != 2)
+ throw SyntaxError("wrong number of arguments to 'check-file'");
+ if(volume == NULL)
+ throw SyntaxError("'check-file' command without 'volume'");
+ volume->checkFile = bits[1];
} else {
throw SyntaxError("unknown command '" + bits[0] + "'");
}
/** @brief Traverse mount points if true */
bool traverse;
+ /** @brief File to check before backing up */
+ std::string checkFile;
+
/** @brief Return true if volume is selected */
bool selected() const { return isSelected; }
*/
static bool valid(const std::string &n);
+ /** @brief Test if volume available
+ * @return true if volume is available
+ */
+ bool available() const;
+
/** @brief Known backups of this volume */
backups_type backups;
enum BackupRequirement {
AlreadyBackedUp,
NotThisDevice,
+ NotAvailable,
BackupRequired
-}l;
+};
// See whether VOLUME needs a backup on DEVICE
static BackupRequirement needsBackup(Volume *volume, Device *device) {
&& backup->deviceName == device->name)
return AlreadyBackedUp; // Already backed up
}
+ if(!volume->available())
+ return NotAvailable;
return BackupRequired;
}
volume->name.c_str(),
device->name.c_str());
break;
+ case NotAvailable:
+ if(command.verbose)
+ IO::out.writef("INFO: %s:%s is not available\n",
+ host->name.c_str(),
+ volume->name.c_str());
+ break;
case NotThisDevice:
if(command.verbose)
IO::out.writef("INFO: %s:%s excluded from %s by device pattern\n",
-// Copyright © 2011 Richard Kettlewell.
+// Copyright © 2011, 2012 Richard Kettlewell.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <config.h>
#include "Conf.h"
+#include "Subprocess.h"
+#include <cstdio>
void Volume::select(bool sense) {
isSelected = sense;
}
return result;
}
+
+bool Volume::available() const {
+ if(!checkFile.size())
+ return true;
+ std::vector<std::string> cmd;
+ cmd.push_back("ssh");
+ if(parent->parent->sshTimeout > 0) {
+ char buffer[64];
+ snprintf(buffer, sizeof buffer, "%d", parent->parent->sshTimeout);
+ cmd.push_back(std::string("-oConnectTimeout=") + buffer);
+ }
+ cmd.push_back(parent->userAndHost());
+ cmd.push_back("test");
+ cmd.push_back("-e");
+ cmd.push_back(checkFile[0] == '/' ? checkFile : path + "/" + checkFile);
+ Subprocess sp(cmd);
+ sp.nullChildFD(1);
+ sp.nullChildFD(2);
+ int rc = sp.runAndWait(false);
+ return rc == 0;
+}
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-TESTS=backup prune retire-device retire-volume store
+TESTS=backup prune retire-device retire-volume store check-file
EXTRA_DIST=${TESTS} setup.sh hook
TESTS_ENVIRONMENT=bash
#! /bin/bash
-# Copyright © 2011 Richard Kettlewell.
+# Copyright © 2011, 2012 Richard Kettlewell.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
--- /dev/null
+#! /bin/bash
+# Copyright © 2011, 2012 Richard Kettlewell.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+set -e
+. ${srcdir:-.}/setup.sh
+
+setup
+
+echo "| Backup is skipped if check-file missing"
+rm -f volume1/file1
+RSBACKUP_TODAY=1980-01-03 s ${RSBACKUP} --backup --verbose
+absent store1/host1/volume1
+compare volume2 store1/host1/volume2/1980-01-03
+absent store1/host1/volume3
+compare volume3 store2/host1/volume3/1980-01-03
+s ${RSBACKUP} -T -
+
+cleanup
echo " min-backups 1" >> config
echo " pre-backup-hook ${srcdir:-.}/hook" >> config
echo " post-backup-hook ${srcdir:-.}/hook" >> config
+ echo " check-file file1" >> config
echo " volume volume2 $PWD/volume2" >> config
echo " min-backups 2" >> config
echo " volume volume3 $PWD/volume3" >> config