diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Command.cc | 6 | ||||
-rw-r--r-- | src/Command.h | 8 | ||||
-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 | 27 |
6 files changed, 72 insertions, 20 deletions
diff --git a/src/Command.cc b/src/Command.cc index 672830b..4ab38cd 100644 --- a/src/Command.cc +++ b/src/Command.cc @@ -1,4 +1,4 @@ -// Copyright © 2011-16 Richard Kettlewell. +// Copyright © 2011-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 @@ -36,6 +36,7 @@ enum { LOG_VERBOSITY = 266, DUMP_CONFIG = 267, FORGET_ONLY = 268, + UNMOUNTED_STORE = 269, }; const struct option Command::options[] = { @@ -48,6 +49,7 @@ const struct option Command::options[] = { { "prune", no_argument, nullptr, 'p' }, { "prune-incomplete", no_argument, nullptr, 'P' }, { "store", required_argument, nullptr, 's' }, + { "unmounted-store", required_argument, nullptr, UNMOUNTED_STORE }, { "retire-device", no_argument, nullptr, RETIRE_DEVICE }, { "retire", no_argument, nullptr, RETIRE }, { "config", required_argument, nullptr, 'c' }, @@ -99,6 +101,7 @@ const char *Command::helpString() { "Additional options:\n" " --logs all|errors|recent|latest|failed Log verbosity in report\n" " --store, -s DIR Override directory(s) to store backups in\n" +" --unmounted-store DIR Override directory(s) to store backups in\n" " --config, -c PATH Set config file (default: /etc/rsbackup/config)\n" " --wait, -w Wait until running rsbackup finishes\n" " --force, -f Don't prompt when retiring\n" @@ -148,6 +151,7 @@ void Command::parse(int argc, const char *const *argv) { case 'p': prune = true; break; case 'P': pruneIncomplete = true; break; case 's': stores.push_back(optarg); enable_warning(WARNING_STORE); break; + case UNMOUNTED_STORE: unmountedStores.push_back(optarg); enable_warning(WARNING_STORE); break; case 'c': configPath = optarg; break; case 'w': wait = true; break; case 'n': act = false; enable_warning(WARNING_VERBOSE); break; diff --git a/src/Command.h b/src/Command.h index 656ab10..e20c1d5 100644 --- a/src/Command.h +++ b/src/Command.h @@ -1,5 +1,5 @@ // -*-C++-*- -// Copyright © 2011, 2012, 2014-2016 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 @@ -95,6 +95,12 @@ public: /** @brief Explicitly specified stores */ std::vector<std::string> stores; + /** @brief Explicitly specified stores + * + * These ones don't have to be mount points. + */ + std::vector<std::string> unmountedStores; + /** @brief Wait if lock cannot be held * * The default is @c false. 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..2e153bb 100644 --- a/src/rsbackup.cc +++ b/src/rsbackup.cc @@ -1,4 +1,4 @@ -// Copyright © 2011-15 Richard Kettlewell. +// Copyright © 2011-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 @@ -31,6 +31,8 @@ #include <cerrno> #include <sstream> +static void commandLineStores(const std::vector<std::string> & stores, bool mounted); + int main(int argc, char **argv) { try { if(setlocale(LC_CTYPE, "") == nullptr) @@ -52,16 +54,11 @@ int main(int argc, char **argv) { } // Override stores - if(command.stores.size() != 0) { + if(command.stores.size() != 0 || command.unmountedStores.size() != 0) { for(auto &s: config.stores) s.second->state = Store::Disabled; - for(auto &s: command.stores) { - auto it = config.stores.find(s); - if(it == config.stores.end()) - config.stores[s] = new Store(s); - else - it->second->state = Store::Enabled; - } + commandLineStores(command.stores, true); + commandLineStores(command.unmountedStores, false); } // Take the lock, if one is defined. @@ -194,3 +191,15 @@ int main(int argc, char **argv) { } exit(!!errors); } + +static void commandLineStores(const std::vector<std::string> &stores, + bool mounted) { + for(auto &s: stores) { + auto it = config.stores.find(s); + if(it == config.stores.end()) + config.stores[s] = new Store(s, mounted); + else + it->second->state = Store::Enabled; + } + +} |