diff options
author | Richard Kettlewell <rjk@terraraq.org.uk> | 2018-02-15 20:27:38 +0000 |
---|---|---|
committer | Richard Kettlewell <rjk@terraraq.org.uk> | 2018-07-27 18:26:58 +0100 |
commit | 40456b4f710fe5b8cf5a25b8ac412dc5c7094957 (patch) | |
tree | 5e9113e3317b1f942402c71347d1ba52cba8fbd9 | |
parent | 39c681b56df58660f23d10258a410a648266b0b7 (diff) |
Store directories (normally) have to be mount points
This can be disabled with new options to store and store-pattern.
fixes #42
-rw-r--r-- | doc/CHANGES.html | 14 | ||||
-rw-r--r-- | doc/rsbackup.5 | 10 | ||||
-rw-r--r-- | src/ConfDirective.cc | 31 | ||||
-rw-r--r-- | src/Store.cc | 10 | ||||
-rw-r--r-- | src/Store.h | 10 | ||||
-rw-r--r-- | src/rsbackup.cc | 2 | ||||
-rwxr-xr-x | tests/glob-store | 4 | ||||
-rwxr-xr-x | tests/setup.sh | 6 |
8 files changed, 70 insertions, 17 deletions
diff --git a/doc/CHANGES.html b/doc/CHANGES.html index 9ccd666..ad2564e 100644 --- a/doc/CHANGES.html +++ b/doc/CHANGES.html @@ -15,6 +15,20 @@ href="https://github.com/ewxrjk/rsbackup">rsbackup in git</a> for detailed change history.</p> + <h2>Changes In rsbackup 5.1</h2> + + <ul> + + <li>Store directories are now normally required to be mount + points. See the description of <code>store</code> + and <code>store-pattern</code> + in <a href="rsbackup.5.html">rsbackup(5)</a> for options to + restore the previous behavior. + Fixes <a href="https://github.com/ewxrjk/rsbackup/issues/42">issue + #42</a>.</li> + + </ul> + <h2>Changes In rsbackup 5.0</h2> <ul> diff --git a/doc/rsbackup.5 b/doc/rsbackup.5 index c6609d6..c5b0de5 100644 --- a/doc/rsbackup.5 +++ b/doc/rsbackup.5 @@ -101,14 +101,20 @@ If true, backups are public. Normally backups must only be accessible by the calling user. This option suppresses the check. .TP -.B store \fIPATH\fR +.B store \fR[\fB--mounted|--no-mounted\fR] \fIPATH\fR A path at which a backup device may be mounted. This can be used multiple times. +.IP +With the \fB--mounted\fR option (which is the default), +\fIPATH\fR must be a mount point. +With \fB--no-mounted\fR it need not be a mount point. .TP -.B store\-pattern \fIPATTERN\fR +.B store\-pattern \fR[\fB-mounted|-nomounted\fR] \fIPATTERN\fR A \fBglob\fR(7) pattern matching paths at which a backup device may be mounted. This can be used multiple times. +.IP +See the description of \fBstore\fR above for the meanings of the options. .SS "Report Directives" These are global directives that affect only the HTML report. .TP diff --git a/src/ConfDirective.cc b/src/ConfDirective.cc index c10f762..7cef053 100644 --- a/src/ConfDirective.cc +++ b/src/ConfDirective.cc @@ -139,22 +139,43 @@ void ColorDirective::set_packed(ConfContext &cc, size_t n, int radix) const { // Global directives ---------------------------------------------------------- +size_t parseStoreArguments(const ConfContext &cc, bool &mounted) { + mounted = true; + size_t i = 1; + while(i < cc.bits.size() && cc.bits[i][0] == '-') { + if(cc.bits[i] == "--mounted") + mounted = true; + else if(cc.bits[i] == "--no-mounted") + mounted = false; + else + throw SyntaxError("unrecognized store option"); + ++i; + } + if(i >= cc.bits.size()) + throw SyntaxError("missing store path"); + return i; +} + /** @brief The @c store directive */ static const struct StoreDirective: public ConfDirective { - StoreDirective(): ConfDirective("store", 1, 1) {} + StoreDirective(): ConfDirective("store", 1, INT_MAX) {} void set(ConfContext &cc) const override { - cc.conf->stores[cc.bits[1]] = new Store(cc.bits[1]); + bool mounted; + size_t i = parseStoreArguments(cc, mounted); + cc.conf->stores[cc.bits[i]] = new Store(cc.bits[i], mounted); } } store_directive; /** @brief The @c store-pattern directive */ static const struct StorePatternDirective: public ConfDirective { - StorePatternDirective(): ConfDirective("store-pattern", 1, 1) {} + StorePatternDirective(): ConfDirective("store-pattern", 1, INT_MAX) {} void set(ConfContext &cc) const override { std::vector<std::string> files; - globFiles(files, cc.bits[1], GLOB_NOCHECK); + bool mounted; + size_t i = parseStoreArguments(cc, mounted); + globFiles(files, cc.bits[i], GLOB_NOCHECK); for(auto &file: files) - cc.conf->stores[file] = new Store(file); + cc.conf->stores[file] = new Store(file, mounted); } } store_pattern_directive; diff --git a/src/Store.cc b/src/Store.cc index 5add94f..543c7cd 100644 --- a/src/Store.cc +++ b/src/Store.cc @@ -1,4 +1,4 @@ -// Copyright © 2011, 2012 Richard Kettlewell. +// Copyright © 2011-13, 2015-18 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 @@ -34,6 +34,14 @@ void Store::identify() { return; // already identified if(stat(path.c_str(), &sb) < 0) throw BadStore("store '" + path + "' does not exist"); + if(mounted) { + const std::string parent_path = path + "/.."; + struct stat parent_sb; + if(stat(parent_path.c_str(), &parent_sb) < 0) + throw FatalStoreError("cannot stat '" + parent_path); + if(sb.st_dev == parent_sb.st_dev) + throw UnavailableStore("store '" + path + "' is not mounted"); + } // Make sure backup devices are mounted preDeviceAccess(); // Read the device name diff --git a/src/Store.h b/src/Store.h index 82a4058..d812719 100644 --- a/src/Store.h +++ b/src/Store.h @@ -1,5 +1,5 @@ // -*-C++-*- -// Copyright © 2011, 2012, 2014, 2015 Richard Kettlewell. +// Copyright © 2011, 2012, 2014, 2015, 2018 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 @@ -32,7 +32,8 @@ public: /** @brief Constructor * @param path_ Location of store */ - Store(const std::string &path_): path(path_) {} + Store(const std::string &path_, bool mounted_): + path(path_), mounted(mounted_) {} /** @brief Possible states */ enum State { @@ -43,9 +44,12 @@ public: Enabled = 2, }; - /** @param Location of store */ + /** @brief Location of store */ std::string path; + /** @brief True if path must be a mount point */ + bool mounted; + /** @param Device mounted at this store * * Set to null pointer before checking, or if no device is mounted here diff --git a/src/rsbackup.cc b/src/rsbackup.cc index 8c6c0e1..e1896d2 100644 --- a/src/rsbackup.cc +++ b/src/rsbackup.cc @@ -58,7 +58,7 @@ int main(int argc, char **argv) { for(auto &s: command.stores) { auto it = config.stores.find(s); if(it == config.stores.end()) - config.stores[s] = new Store(s); + config.stores[s] = new Store(s, false/*TODO*/); else it->second->state = Store::Enabled; } diff --git a/tests/glob-store b/tests/glob-store index 5d24749..20c7c12 100755 --- a/tests/glob-store +++ b/tests/glob-store @@ -1,5 +1,5 @@ #! /bin/sh -# Copyright © 2011, 2012, 2014, 2015 Richard Kettlewell. +# Copyright © 2011, 2012, 2014, 2015, 2018 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 @@ -22,7 +22,7 @@ export EXPECT_STATUS=ok sed < ${WORKSPACE}/config > ${WORKSPACE}/config.new \ '/^store /d'; -echo "store-pattern ${WORKSPACE}/store*" >>${WORKSPACE}/config.new +echo "store-pattern --no-mounted ${WORKSPACE}/store*" >>${WORKSPACE}/config.new mv -f ${WORKSPACE}/config.new ${WORKSPACE}/config echo "| Create backup for everything using glob-pattern directive" diff --git a/tests/setup.sh b/tests/setup.sh index b521208..c82d4cc 100755 --- a/tests/setup.sh +++ b/tests/setup.sh @@ -1,4 +1,4 @@ -# Copyright © 2011, 2012, 2014-17 Richard Kettlewell. +# Copyright © 2011, 2012, 2014-18 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 @@ -41,12 +41,12 @@ setup() { mkdir ${WORKSPACE}/store1 echo device1 > ${WORKSPACE}/store1/device-id - echo "store ${WORKSPACE}/store1" >> ${WORKSPACE}/config + echo "store --no-mounted ${WORKSPACE}/store1" >> ${WORKSPACE}/config echo "device \"device1\"" >> ${WORKSPACE}/config mkdir ${WORKSPACE}/store2 echo device2 > ${WORKSPACE}/store2/device-id - echo "store ${WORKSPACE}/store2" >>${WORKSPACE}/config + echo "store --no-mounted ${WORKSPACE}/store2" >>${WORKSPACE}/config echo "device device2" >> ${WORKSPACE}/config echo "public true" >> ${WORKSPACE}/config |