diff options
author | Chris Wilson <chris+github@qwirx.com> | 2014-02-07 15:44:07 +0000 |
---|---|---|
committer | Chris Wilson <chris+github@qwirx.com> | 2014-02-07 15:44:07 +0000 |
commit | e370cf08364620cac777affb07088b59260025b2 (patch) | |
tree | a408fc0f8bb5b7313316707e6e8fa984a7219637 /bin/bbstoreaccounts | |
parent | 40b353bbe608ba440287650d6c276887e1e7c2f0 (diff) |
Split bbstoreaccounts commands out into a separate class.
Allows us to call them from tests without shelling out, making debugging
easier.
Diffstat (limited to 'bin/bbstoreaccounts')
-rw-r--r-- | bin/bbstoreaccounts/bbstoreaccounts.cpp | 504 |
1 files changed, 15 insertions, 489 deletions
diff --git a/bin/bbstoreaccounts/bbstoreaccounts.cpp b/bin/bbstoreaccounts/bbstoreaccounts.cpp index f2292ca1..bcff886b 100644 --- a/bin/bbstoreaccounts/bbstoreaccounts.cpp +++ b/bin/bbstoreaccounts/bbstoreaccounts.cpp @@ -18,12 +18,6 @@ #include <sys/types.h> -#include <algorithm> -#include <cstring> -#include <iostream> -#include <ostream> -#include <vector> - #include "box_getopt.h" #include "BackupStoreAccounts.h" #include "BackupStoreAccountDatabase.h" @@ -43,476 +37,6 @@ #include <cstring> -// max size of soft limit as percent of hard limit -#define MAX_SOFT_LIMIT_SIZE 97 - -bool sMachineReadableOutput = false; - -void CheckSoftHardLimits(int64_t SoftLimit, int64_t HardLimit) -{ - if(SoftLimit > HardLimit) - { - BOX_FATAL("Soft limit must be less than the hard limit."); - exit(1); - } - if(SoftLimit > ((HardLimit * MAX_SOFT_LIMIT_SIZE) / 100)) - { - BOX_WARNING("We recommend setting the soft limit below " << - MAX_SOFT_LIMIT_SIZE << "% of the hard limit, or " << - HumanReadableSize((HardLimit * MAX_SOFT_LIMIT_SIZE) - / 100) << " in this case."); - } -} - -int BlockSizeOfDiscSet(int discSetNum) -{ - // Get controller, check disc set number - RaidFileController &controller(RaidFileController::GetController()); - if(discSetNum < 0 || discSetNum >= controller.GetNumDiscSets()) - { - BOX_FATAL("Disc set " << discSetNum << " does not exist."); - exit(1); - } - - // Return block size - return controller.GetDiscSet(discSetNum).GetBlockSize(); -} - -std::string BlockSizeToString(int64_t Blocks, int64_t MaxBlocks, int discSetNum) -{ - return FormatUsageBar(Blocks, Blocks * BlockSizeOfDiscSet(discSetNum), - MaxBlocks * BlockSizeOfDiscSet(discSetNum), - sMachineReadableOutput); -} - -int64_t SizeStringToBlocks(const char *string, int discSetNum) -{ - // Find block size - int blockSize = BlockSizeOfDiscSet(discSetNum); - - // Get number - char *endptr = (char*)string; - int64_t number = strtol(string, &endptr, 0); - if(endptr == string || number == LONG_MIN || number == LONG_MAX) - { - BOX_FATAL("'" << string << "' is not a valid number."); - exit(1); - } - - // Check units - switch(*endptr) - { - case 'M': - case 'm': - // Units: Mb - return (number * 1024*1024) / blockSize; - break; - - case 'G': - case 'g': - // Units: Gb - return (number * 1024*1024*1024) / blockSize; - break; - - case 'B': - case 'b': - // Units: Blocks - // Easy! Just return the number specified. - return number; - break; - - default: - BOX_FATAL(string << " has an invalid units specifier " - "(use B for blocks, M for MB, G for GB, eg 2GB)"); - exit(1); - break; - } -} - -bool OpenAccount(Configuration &rConfig, int32_t ID, std::string &rRootDirOut, - int &rDiscSetOut, std::auto_ptr<UnixUser> apUser, NamedLock* pLock); - -int SetLimit(Configuration &rConfig, int32_t ID, const char *SoftLimitStr, - const char *HardLimitStr) -{ - std::string rootDir; - int discSetNum; - std::auto_ptr<UnixUser> user; // used to reset uid when we return - NamedLock writeLock; - - if(!OpenAccount(rConfig, ID, rootDir, discSetNum, user, &writeLock)) - { - BOX_ERROR("Failed to open account " << BOX_FORMAT_ACCOUNT(ID) - << " to change limits."); - return 1; - } - - // Load the info - std::auto_ptr<BackupStoreInfo> info(BackupStoreInfo::Load(ID, rootDir, - discSetNum, false /* Read/Write */)); - - // Change the limits - int64_t softlimit = SizeStringToBlocks(SoftLimitStr, discSetNum); - int64_t hardlimit = SizeStringToBlocks(HardLimitStr, discSetNum); - CheckSoftHardLimits(softlimit, hardlimit); - info->ChangeLimits(softlimit, hardlimit); - - // Save - info->Save(); - - BOX_NOTICE("Limits on account " << BOX_FORMAT_ACCOUNT(ID) << - " changed to " << softlimit << " soft, " << - hardlimit << " hard."); - - return 0; -} - -int SetAccountName(Configuration &rConfig, int32_t ID, - const std::string& rNewAccountName) -{ - std::string rootDir; - int discSetNum; - std::auto_ptr<UnixUser> user; // used to reset uid when we return - NamedLock writeLock; - - if(!OpenAccount(rConfig, ID, rootDir, discSetNum, user, &writeLock)) - { - BOX_ERROR("Failed to open account " << BOX_FORMAT_ACCOUNT(ID) - << " to change name."); - return 1; - } - - // Load the info - std::auto_ptr<BackupStoreInfo> info(BackupStoreInfo::Load(ID, - rootDir, discSetNum, false /* Read/Write */)); - - info->SetAccountName(rNewAccountName); - - // Save - info->Save(); - - BOX_NOTICE("Account " << BOX_FORMAT_ACCOUNT(ID) << - " name changed to " << rNewAccountName); - - return 0; -} - -int AccountInfo(Configuration &rConfig, int32_t ID) -{ - std::string rootDir; - int discSetNum; - std::auto_ptr<UnixUser> user; // used to reset uid when we return - - if(!OpenAccount(rConfig, ID, rootDir, discSetNum, user, - NULL /* no write lock needed for this read-only operation */)) - { - BOX_ERROR("Failed to open account " << BOX_FORMAT_ACCOUNT(ID) - << " to display info."); - return 1; - } - - // Load it in - std::auto_ptr<BackupStoreInfo> info(BackupStoreInfo::Load(ID, - rootDir, discSetNum, true /* ReadOnly */)); - - // Then print out lots of info - std::cout << FormatUsageLineStart("Account ID", sMachineReadableOutput) << - BOX_FORMAT_ACCOUNT(ID) << std::endl; - std::cout << FormatUsageLineStart("Account Name", sMachineReadableOutput) << - info->GetAccountName() << std::endl; - std::cout << FormatUsageLineStart("Last object ID", sMachineReadableOutput) << - BOX_FORMAT_OBJECTID(info->GetLastObjectIDUsed()) << std::endl; - std::cout << FormatUsageLineStart("Used", sMachineReadableOutput) << - BlockSizeToString(info->GetBlocksUsed(), - info->GetBlocksHardLimit(), discSetNum) << std::endl; - std::cout << FormatUsageLineStart("Current files", - sMachineReadableOutput) << - BlockSizeToString(info->GetBlocksInCurrentFiles(), - info->GetBlocksHardLimit(), discSetNum) << std::endl; - std::cout << FormatUsageLineStart("Old files", sMachineReadableOutput) << - BlockSizeToString(info->GetBlocksInOldFiles(), - info->GetBlocksHardLimit(), discSetNum) << std::endl; - std::cout << FormatUsageLineStart("Deleted files", sMachineReadableOutput) << - BlockSizeToString(info->GetBlocksInDeletedFiles(), - info->GetBlocksHardLimit(), discSetNum) << std::endl; - std::cout << FormatUsageLineStart("Directories", sMachineReadableOutput) << - BlockSizeToString(info->GetBlocksInDirectories(), - info->GetBlocksHardLimit(), discSetNum) << std::endl; - std::cout << FormatUsageLineStart("Soft limit", sMachineReadableOutput) << - BlockSizeToString(info->GetBlocksSoftLimit(), - info->GetBlocksHardLimit(), discSetNum) << std::endl; - std::cout << FormatUsageLineStart("Hard limit", sMachineReadableOutput) << - BlockSizeToString(info->GetBlocksHardLimit(), - info->GetBlocksHardLimit(), discSetNum) << std::endl; - std::cout << FormatUsageLineStart("Client store marker", sMachineReadableOutput) << - info->GetLastObjectIDUsed() << std::endl; - std::cout << FormatUsageLineStart("Live Files", sMachineReadableOutput) << - info->GetNumFiles() << std::endl; - std::cout << FormatUsageLineStart("Old Files", sMachineReadableOutput) << - info->GetNumOldFiles() << std::endl; - std::cout << FormatUsageLineStart("Deleted Files", sMachineReadableOutput) << - info->GetNumDeletedFiles() << std::endl; - std::cout << FormatUsageLineStart("Directories", sMachineReadableOutput) << - info->GetNumDirectories() << std::endl; - std::cout << FormatUsageLineStart("Enabled", sMachineReadableOutput) << - (info->IsAccountEnabled() ? "yes" : "no") << std::endl; - - return 0; -} - -int SetAccountEnabled(Configuration &rConfig, int32_t ID, bool enabled) -{ - std::string rootDir; - int discSetNum; - std::auto_ptr<UnixUser> user; // used to reset uid when we return - NamedLock writeLock; - - if(!OpenAccount(rConfig, ID, rootDir, discSetNum, user, &writeLock)) - { - BOX_ERROR("Failed to open account " << BOX_FORMAT_ACCOUNT(ID) - << " to change enabled flag."); - return 1; - } - - // Load it in - std::auto_ptr<BackupStoreInfo> info(BackupStoreInfo::Load(ID, - rootDir, discSetNum, false /* ReadOnly */)); - info->SetAccountEnabled(enabled); - info->Save(); - return 0; -} - -int DeleteAccount(Configuration &rConfig, int32_t ID, bool AskForConfirmation) -{ - std::string rootDir; - int discSetNum; - std::auto_ptr<UnixUser> user; // used to reset uid when we return - NamedLock writeLock; - - // Obtain a write lock, as the daemon user - if(!OpenAccount(rConfig, ID, rootDir, discSetNum, user, &writeLock)) - { - BOX_ERROR("Failed to open account " << BOX_FORMAT_ACCOUNT(ID) - << " for deletion."); - return 1; - } - - // Check user really wants to do this - if(AskForConfirmation) - { - BOX_WARNING("Really delete account " << - BOX_FORMAT_ACCOUNT(ID) << "? (type 'yes' to confirm)"); - char response[256]; - if(::fgets(response, sizeof(response), stdin) == 0 || ::strcmp(response, "yes\n") != 0) - { - BOX_NOTICE("Deletion cancelled."); - return 0; - } - } - - // Back to original user, but write lock is maintained - user.reset(); - - std::auto_ptr<BackupStoreAccountDatabase> db(BackupStoreAccountDatabase::Read(rConfig.GetKeyValue("AccountDatabase").c_str())); - - // Delete from account database - db->DeleteEntry(ID); - - // Write back to disc - db->Write(); - - // Remove the store files... - - // First, become the user specified in the config file - std::string username; - { - const Configuration &rserverConfig(rConfig.GetSubConfiguration("Server")); - if(rserverConfig.KeyExists("User")) - { - username = rserverConfig.GetKeyValue("User"); - } - } - - // Become the right user - if(!username.empty()) - { - // Username specified, change... - user.reset(new UnixUser(username)); - user->ChangeProcessUser(true /* temporary */); - // Change will be undone when user goes out of scope - } - - // Secondly, work out which directories need wiping - std::vector<std::string> toDelete; - RaidFileController &rcontroller(RaidFileController::GetController()); - RaidFileDiscSet discSet(rcontroller.GetDiscSet(discSetNum)); - for(RaidFileDiscSet::const_iterator i(discSet.begin()); i != discSet.end(); ++i) - { - if(std::find(toDelete.begin(), toDelete.end(), *i) == toDelete.end()) - { - toDelete.push_back((*i) + DIRECTORY_SEPARATOR + rootDir); - } - } - -#ifdef WIN32 - // Cannot remove files while holding a lock on them - writeLock.ReleaseLock(); -#endif - - int retcode = 0; - - // Thirdly, delete the directories... - for(std::vector<std::string>::const_iterator d(toDelete.begin()); d != toDelete.end(); ++d) - { - BOX_NOTICE("Deleting store directory " << (*d) << "..."); - // Just use the rm command to delete the files - std::string cmd("rm -rf "); - cmd += *d; - // Run command - if(::system(cmd.c_str()) != 0) - { - BOX_ERROR("Failed to delete files in " << (*d) << - ", delete them manually."); - retcode = 1; - } - } - - // Success! - return retcode; -} - -bool OpenAccount(Configuration &rConfig, int32_t ID, std::string &rRootDirOut, - int &rDiscSetOut, std::auto_ptr<UnixUser> apUser, NamedLock* pLock) -{ - // Load in the account database - std::auto_ptr<BackupStoreAccountDatabase> db(BackupStoreAccountDatabase::Read(rConfig.GetKeyValue("AccountDatabase").c_str())); - - // Exists? - if(!db->EntryExists(ID)) - { - BOX_ERROR("Account " << BOX_FORMAT_ACCOUNT(ID) << - " does not exist."); - return false; - } - - // Get info from the database - BackupStoreAccounts acc(*db); - acc.GetAccountRoot(ID, rRootDirOut, rDiscSetOut); - - // Get the user under which the daemon runs - std::string username; - { - const Configuration &rserverConfig(rConfig.GetSubConfiguration("Server")); - if(rserverConfig.KeyExists("User")) - { - username = rserverConfig.GetKeyValue("User"); - } - } - - // Become the right user - if(!username.empty()) - { - // Username specified, change... - apUser.reset(new UnixUser(username)); - apUser->ChangeProcessUser(true /* temporary */); - // Change will be undone when apUser goes out of scope - // in the caller. - } - - if(pLock) - { - acc.LockAccount(ID, *pLock); - } - - return true; -} - -int CheckAccount(Configuration &rConfig, int32_t ID, bool FixErrors, bool Quiet) -{ - std::string rootDir; - int discSetNum; - std::auto_ptr<UnixUser> user; // used to reset uid when we return - NamedLock writeLock; - - if(!OpenAccount(rConfig, ID, rootDir, discSetNum, user, &writeLock)) - { - BOX_ERROR("Failed to open account " << BOX_FORMAT_ACCOUNT(ID) - << " for checking."); - return 1; - } - - // Check it - BackupStoreCheck check(rootDir, discSetNum, ID, FixErrors, Quiet); - check.Check(); - - return check.ErrorsFound()?1:0; -} - -int CreateAccount(Configuration &rConfig, int32_t ID, int32_t DiscNumber, - int32_t SoftLimit, int32_t HardLimit) -{ - // Load in the account database - std::auto_ptr<BackupStoreAccountDatabase> db(BackupStoreAccountDatabase::Read(rConfig.GetKeyValue("AccountDatabase").c_str())); - - // Already exists? - if(db->EntryExists(ID)) - { - BOX_ERROR("Account " << BOX_FORMAT_ACCOUNT(ID) << - " already exists."); - return 1; - } - - // Get the user under which the daemon runs - std::string username; - { - const Configuration &rserverConfig(rConfig.GetSubConfiguration("Server")); - if(rserverConfig.KeyExists("User")) - { - username = rserverConfig.GetKeyValue("User"); - } - } - - // Create it. - BackupStoreAccounts acc(*db); - acc.Create(ID, DiscNumber, SoftLimit, HardLimit, username); - - BOX_NOTICE("Account " << BOX_FORMAT_ACCOUNT(ID) << " created."); - - return 0; -} - -int HousekeepAccountNow(Configuration &rConfig, int32_t ID) -{ - std::string rootDir; - int discSetNum; - std::auto_ptr<UnixUser> user; // used to reset uid when we return - - if(!OpenAccount(rConfig, ID, rootDir, discSetNum, user, - NULL /* housekeeping locks the account itself */)) - { - BOX_ERROR("Failed to open account " << BOX_FORMAT_ACCOUNT(ID) - << " for housekeeping."); - return 1; - } - - HousekeepStoreAccount housekeeping(ID, rootDir, discSetNum, NULL); - bool success = housekeeping.DoHousekeeping(); - - if(!success) - { - BOX_ERROR("Failed to lock account " << BOX_FORMAT_ACCOUNT(ID) - << " for housekeeping: perhaps a client is " - "still connected?"); - return 1; - } - else - { - BOX_TRACE("Finished housekeeping on account " << - BOX_FORMAT_ACCOUNT(ID)); - return 0; - } -} - void PrintUsageAndExit() { printf( @@ -565,6 +89,7 @@ int main(int argc, const char *argv[]) // Filename for configuration file? std::string configFilename = BOX_GET_DEFAULT_BBACKUPD_CONFIG_FILE; int logLevel = Log::EVERYTHING; + bool machineReadableOutput = false; // See if there's another entry on the command line int c; @@ -588,7 +113,7 @@ int main(int argc, const char *argv[]) case 'm': // enable machine readable output - sMachineReadableOutput = true; + machineReadableOutput = true; break; case '?': @@ -615,7 +140,7 @@ int main(int argc, const char *argv[]) BOX_ERROR("Invalid configuration file " << configFilename << ":" << errs); } - + // Initialise the raid file controller RaidFileController &rcontroller(RaidFileController::GetController()); rcontroller.Initialise(config->GetKeyValue("RaidFileConf").c_str()); @@ -634,6 +159,7 @@ int main(int argc, const char *argv[]) } std::string command = argv[0]; + BackupStoreAccountsControl control(*config, machineReadableOutput); // Now do the command. if(command == "create") @@ -651,17 +177,17 @@ int main(int argc, const char *argv[]) } // Decode limits - softlimit = SizeStringToBlocks(argv[3], discnum); - hardlimit = SizeStringToBlocks(argv[4], discnum); - CheckSoftHardLimits(softlimit, hardlimit); + softlimit = control.SizeStringToBlocks(argv[3], discnum); + hardlimit = control.SizeStringToBlocks(argv[4], discnum); + control.CheckSoftHardLimits(softlimit, hardlimit); // Create the account... - return CreateAccount(*config, id, discnum, softlimit, hardlimit); + return control.CreateAccount(id, discnum, softlimit, hardlimit); } else if(command == "info") { // Print information on this account - return AccountInfo(*config, id); + return control.PrintAccountInfo(id); } else if(command == "enabled") { @@ -686,7 +212,7 @@ int main(int argc, const char *argv[]) PrintUsageAndExit(); } - return SetAccountEnabled(*config, id, enabled); + return control.SetAccountEnabled(id, enabled); } else if(command == "setlimit") { @@ -697,7 +223,7 @@ int main(int argc, const char *argv[]) return 1; } - return SetLimit(*config, id, argv[2], argv[3]); + return control.SetLimit(id, argv[2], argv[3]); } else if(command == "name") { @@ -708,7 +234,7 @@ int main(int argc, const char *argv[]) return 1; } - return SetAccountName(*config, id, argv[2]); + return control.SetAccountName(id, argv[2]); } else if(command == "delete") { @@ -718,7 +244,7 @@ int main(int argc, const char *argv[]) { askForConfirmation = false; } - return DeleteAccount(*config, id, askForConfirmation); + return control.DeleteAccount(id, askForConfirmation); } else if(command == "check") { @@ -744,11 +270,11 @@ int main(int argc, const char *argv[]) } // Check the account - return CheckAccount(*config, id, fixErrors, quiet); + return control.CheckAccount(id, fixErrors, quiet); } else if(command == "housekeep") { - return HousekeepAccountNow(*config, id); + return control.HousekeepAccountNow(id); } else { |