diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/backupclient/BackupDaemonConfigVerify.cpp | 2 | ||||
-rw-r--r-- | lib/common/Archive.h | 161 | ||||
-rw-r--r-- | lib/common/CommonException.txt | 1 | ||||
-rw-r--r-- | lib/common/ExcludeList.cpp | 181 | ||||
-rw-r--r-- | lib/common/ExcludeList.h | 6 | ||||
-rw-r--r-- | lib/server/Daemon.cpp | 88 | ||||
-rw-r--r-- | lib/server/Daemon.h | 13 |
7 files changed, 437 insertions, 15 deletions
diff --git a/lib/backupclient/BackupDaemonConfigVerify.cpp b/lib/backupclient/BackupDaemonConfigVerify.cpp index f1d5bd16..89ad4d54 100644 --- a/lib/backupclient/BackupDaemonConfigVerify.cpp +++ b/lib/backupclient/BackupDaemonConfigVerify.cpp @@ -85,6 +85,7 @@ static const ConfigurationVerifyKey verifyrootkeys[] = {"CommandSocket", 0, 0, 0}, // not compulsory to have this {"KeepAliveTime", 0, ConfigTest_IsInt, 0}, // optional + {"StoreObjectInfoFile", 0, 0, 0}, // optional {"NotifyScript", 0, 0, 0}, // optional script to run when backup needs attention, eg store full @@ -103,4 +104,3 @@ const ConfigurationVerify BackupDaemonConfigVerify = ConfigTest_Exists | ConfigTest_LastEntry, 0 }; - diff --git a/lib/common/Archive.h b/lib/common/Archive.h new file mode 100644 index 00000000..b70f12c4 --- /dev/null +++ b/lib/common/Archive.h @@ -0,0 +1,161 @@ +// -------------------------------------------------------------------------- +// +// File +// Name: Archive.h +// Purpose: Backup daemon state archive +// Created: 2005/04/11 +// +// -------------------------------------------------------------------------- + +#ifndef ARCHIVE__H +#define ARCHIVE__H + +#include <vector> +#include <string> +#include <memory> + +#include "IOStream.h" +#include "Guards.h" + +#define ARCHIVE_GET_SIZE(hdr) (( ((uint8_t)((hdr)[0])) | ( ((uint8_t)((hdr)[1])) << 8)) >> 2) + +#define ARCHIVE_MAGIC_VALUE_RECURSE 0x4449525F +#define ARCHIVE_MAGIC_VALUE_NOOP 0x5449525F + +class Archive +{ +public: + Archive(IOStream &Stream, int Timeout) + : mrStream(Stream) + { + mTimeout = Timeout; + } +private: + // no copying + Archive(const Archive &); + Archive & operator=(const Archive &); +public: + ~Archive() + { + } + // + // + // + void Write(bool Item) + { + Write((int) Item); + } + void Write(int Item) + { + int32_t privItem = htonl(Item); + mrStream.Write(&privItem, sizeof(privItem)); + } + void Write(int64_t Item) + { + int64_t privItem = box_hton64(Item); + mrStream.Write(&privItem, sizeof(privItem)); + } + void Write(uint64_t Item) + { + uint64_t privItem = box_hton64(Item); + mrStream.Write(&privItem, sizeof(privItem)); + } + void Write(uint8_t Item) + { + int privItem = Item; + Write(privItem); + } + void Write(const std::string &Item) + { + int size = Item.size(); + Write(size); + mrStream.Write(Item.c_str(), size); + } + // + // + // + void Read(bool &rItemOut) + { + int privItem; + Read(privItem); + + if (privItem) + { + rItemOut = true; + } + else + { + rItemOut = false; + } + } + void Read(int &rItemOut) + { + int32_t privItem; + if(!mrStream.ReadFullBuffer(&privItem, sizeof(privItem), 0 /* not interested in bytes read if this fails */)) + { + THROW_EXCEPTION(CommonException, ArchiveBlockIncompleteRead) + } + rItemOut = ntohl(privItem); + } + void Read(int64_t &rItemOut) + { + int64_t privItem; + if(!mrStream.ReadFullBuffer(&privItem, sizeof(privItem), 0 /* not interested in bytes read if this fails */)) + { + THROW_EXCEPTION(CommonException, ArchiveBlockIncompleteRead) + } + rItemOut = box_ntoh64(privItem); + } + void Read(uint64_t &rItemOut) + { + uint64_t privItem; + if(!mrStream.ReadFullBuffer(&privItem, sizeof(privItem), 0 /* not interested in bytes read if this fails */)) + { + THROW_EXCEPTION(CommonException, ArchiveBlockIncompleteRead) + } + rItemOut = box_ntoh64(privItem); + } + void Read(uint8_t &rItemOut) + { + int privItem; + Read(privItem); + rItemOut = privItem; + } + void Read(std::string &rItemOut) + { + int size; + Read(size); + + // Assume most strings are relatively small + char buf[256]; + if(size < (int) sizeof(buf)) + { + // Fetch rest of pPayload, relying on the Protocol to error on stupidly large sizes for us + if(!mrStream.ReadFullBuffer(buf, size, 0 /* not interested in bytes read if this fails */, mTimeout)) + { + THROW_EXCEPTION(CommonException, ArchiveBlockIncompleteRead) + } + // assign to this string, storing the header and the extra payload + rItemOut.assign(buf, size); + } + else + { + // Block of memory to hold it + MemoryBlockGuard<char*> dataB(size); + char *ppayload = dataB; + + // Fetch rest of pPayload, relying on the Protocol to error on stupidly large sizes for us + if(!mrStream.ReadFullBuffer(ppayload, size, 0 /* not interested in bytes read if this fails */, mTimeout)) + { + THROW_EXCEPTION(CommonException, ArchiveBlockIncompleteRead) + } + // assign to this string, storing the header and the extra pPayload + rItemOut.assign(ppayload, size); + } + } +private: + IOStream &mrStream; + int mTimeout; +}; + +#endif // ARCHIVE__H diff --git a/lib/common/CommonException.txt b/lib/common/CommonException.txt index f852b7d7..5fa443d0 100644 --- a/lib/common/CommonException.txt +++ b/lib/common/CommonException.txt @@ -43,3 +43,4 @@ KEventErrorRemove 35 KQueueNotSupportedOnThisPlatform 36 IOStreamGetLineNotEnoughDataToIgnore 37 Bad value passed to IOStreamGetLine::IgnoreBufferedData() TempDirPathTooLong 38 Your temporary directory path is too long. Check the TMP and TEMP environment variables. +ArchiveBlockIncompleteRead 39 The Store Object Info File is too short or corrupted, and will be rewritten automatically when the next backup completes. diff --git a/lib/common/ExcludeList.cpp b/lib/common/ExcludeList.cpp index 556a2079..9b2e3acb 100644 --- a/lib/common/ExcludeList.cpp +++ b/lib/common/ExcludeList.cpp @@ -17,6 +17,7 @@ #include "ExcludeList.h" #include "Utils.h" #include "Configuration.h" +#include "Archive.h" #include "MemLeakFindOn.h" @@ -130,6 +131,8 @@ void ExcludeList::AddRegexEntries(const std::string &rEntries) // Store in list of regular expressions mRegex.push_back(pregex); + // Store in list of regular expression string for Serialize + mRegexStr.push_back(i->c_str()); } catch(...) { @@ -213,7 +216,183 @@ void ExcludeList::SetAlwaysIncludeList(ExcludeList *pAlwaysInclude) mpAlwaysInclude = pAlwaysInclude; } +// -------------------------------------------------------------------------- +// +// Function +// Name: ExcludeList::Deserialize(Archive & rArchive) +// Purpose: Deserializes this object instance from a stream of bytes, using an Archive abstraction. +// +// Created: 2005/04/11 +// +// -------------------------------------------------------------------------- +void ExcludeList::Deserialize(Archive & rArchive) +{ + // + // + // + mDefinite.clear(); - +#ifndef PLATFORM_REGEX_NOT_SUPPORTED + // free regex memory + while(mRegex.size() > 0) + { + regex_t *pregex = mRegex.back(); + mRegex.pop_back(); + // Free regex storage, and the structure itself + ::regfree(pregex); + delete pregex; + } + mRegexStr.clear(); +#endif + // Clean up exceptions list + if(mpAlwaysInclude != 0) + { + delete mpAlwaysInclude; + mpAlwaysInclude = 0; + } + + // + // + // + int64_t iCount = 0; + rArchive.Read(iCount); + + if (iCount > 0) + { + for (int v = 0; v < iCount; v++) + { + // load each one + std::string strItem; + rArchive.Read(strItem); + mDefinite.insert(strItem); + } + } + + // + // + // +#ifndef PLATFORM_REGEX_NOT_SUPPORTED + rArchive.Read(iCount); + + if (iCount > 0) + { + for (int v = 0; v < iCount; v++) + { + std::string strItem; + rArchive.Read(strItem); + + // Allocate memory + regex_t* pregex = new regex_t; + + try + { + // Compile + if(::regcomp(pregex, strItem.c_str(), + REG_EXTENDED | REG_NOSUB) != 0) + { + THROW_EXCEPTION(CommonException, + BadRegularExpression) + } + + // Store in list of regular expressions + mRegex.push_back(pregex); + + // Store in list of regular expression strings + // for Serialize + mRegexStr.push_back(strItem); + } + catch(...) + { + delete pregex; + throw; + } + } + } +#endif // PLATFORM_REGEX_NOT_SUPPORTED + + // + // + // + int64_t aMagicMarker = 0; + rArchive.Read(aMagicMarker); + + if (aMagicMarker == ARCHIVE_MAGIC_VALUE_NOOP) + { + // NOOP + } + else if (aMagicMarker == ARCHIVE_MAGIC_VALUE_RECURSE) + { + mpAlwaysInclude = new ExcludeList; + if (!mpAlwaysInclude) + { + throw std::bad_alloc(); + } + + mpAlwaysInclude->Deserialize(rArchive); + } + else + { + // there is something going on here + THROW_EXCEPTION(CommonException, Internal) + } +} + +// -------------------------------------------------------------------------- +// +// Function +// Name: ExcludeList::Serialize(Archive & rArchive) +// Purpose: Serializes this object instance into a stream of bytes, using an Archive abstraction. +// +// Created: 2005/04/11 +// +// -------------------------------------------------------------------------- +void ExcludeList::Serialize(Archive & rArchive) const +{ + // + // + // + int64_t iCount = mDefinite.size(); + rArchive.Write(iCount); + + for (std::set<std::string>::const_iterator i = mDefinite.begin(); + i != mDefinite.end(); i++) + { + rArchive.Write(*i); + } + + // + // + // +#ifndef PLATFORM_REGEX_NOT_SUPPORTED + // don't even try to save compiled regular expressions, + // use string copies instead. + ASSERT(mRegex.size() == mRegexStr.size()); + + iCount = mRegexStr.size(); + rArchive.Write(iCount); + + for (std::vector<std::string>::const_iterator i = mRegexStr.begin(); + i != mRegexStr.end(); i++) + { + rArchive.Write(*i); + } +#endif // PLATFORM_REGEX_NOT_SUPPORTED + + // + // + // + if (!mpAlwaysInclude) + { + int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_NOOP; + rArchive.Write(aMagicMarker); + } + else + { + int64_t aMagicMarker = ARCHIVE_MAGIC_VALUE_RECURSE; // be explicit about whether recursion follows + rArchive.Write(aMagicMarker); + + mpAlwaysInclude->Serialize(rArchive); + } +} diff --git a/lib/common/ExcludeList.h b/lib/common/ExcludeList.h index 5324d226..720b6788 100644 --- a/lib/common/ExcludeList.h +++ b/lib/common/ExcludeList.h @@ -19,6 +19,8 @@ typedef int regex_t; #endif +class Archive; + // -------------------------------------------------------------------------- // // Class @@ -33,6 +35,9 @@ public: ExcludeList(); ~ExcludeList(); + void Deserialize(Archive & rArchive); + void Serialize(Archive & rArchive) const; + void AddDefiniteEntries(const std::string &rEntries); void AddRegexEntries(const std::string &rEntries); @@ -55,6 +60,7 @@ private: std::set<std::string> mDefinite; #ifdef HAVE_REGEX_H std::vector<regex_t *> mRegex; + std::vector<std::string> mRegexStr; // save original regular expression string-based source for Serialize #endif // For exceptions to the excludes diff --git a/lib/server/Daemon.cpp b/lib/server/Daemon.cpp index a4dfdaec..9c820b22 100644 --- a/lib/server/Daemon.cpp +++ b/lib/server/Daemon.cpp @@ -9,14 +9,15 @@ #include "Box.h" +#include <errno.h> #include <stdio.h> #include <unistd.h> #include <signal.h> #include <string.h> #include <stdarg.h> -#ifndef WIN32 -#include <syslog.h> +#ifdef HAVE_SYSLOG_H + #include <syslog.h> #endif #include "Daemon.h" @@ -24,6 +25,7 @@ #include "ServerException.h" #include "Guards.h" #include "UnixUser.h" +#include "FileModificationTime.h" #include "MemLeakFindOn.h" @@ -92,22 +94,21 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) } std::string pidFileName; - const char *configfile = 0; try { // Find filename of config file - configfile = DefaultConfigFile; + mConfigFileName = DefaultConfigFile; if(argc >= 2) { // First argument is config file, or it's -c and the next arg is the config file if(::strcmp(argv[1], "-c") == 0 && argc >= 3) { - configfile = argv[2]; + mConfigFileName = argv[2]; } else { - configfile = argv[1]; + mConfigFileName = argv[1]; } } @@ -123,19 +124,25 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) // Load the configuration file. std::string errors; - std::auto_ptr<Configuration> pconfig = Configuration::LoadAndVerify(configfile, GetConfigVerify(), errors); + std::auto_ptr<Configuration> pconfig = + Configuration::LoadAndVerify( + mConfigFileName.c_str(), + GetConfigVerify(), errors); // Got errors? if(pconfig.get() == 0 || !errors.empty()) { // Tell user about errors - fprintf(stderr, "%s: Errors in config file %s:\n%s", DaemonName(), configfile, errors.c_str()); + fprintf(stderr, "%s: Errors in config file %s:\n%s", + DaemonName(), mConfigFileName.c_str(), + errors.c_str()); // And give up return 1; } // Store configuration mpConfiguration = pconfig.release(); + mLoadedConfigModifiedTime = GetConfigFileModifiedTime(); // Server configuration const Configuration &serverConfig(mpConfiguration->GetSubConfiguration("Server")); @@ -228,7 +235,8 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) // open the log ::openlog(DaemonName(), LOG_PID, LOG_LOCAL6); // Log the start message - ::syslog(LOG_INFO, "Starting daemon (config: %s) (version " BOX_VERSION ")", configfile); + ::syslog(LOG_INFO, "Starting daemon (config: %s) (version " + BOX_VERSION ")", mConfigFileName.c_str()); #ifndef WIN32 // Write PID to file @@ -306,15 +314,23 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) if(mReloadConfigWanted && !mTerminateWanted) { // Need to reload that config file... - ::syslog(LOG_INFO, "Reloading configuration (config: %s)", configfile); + ::syslog(LOG_INFO, "Reloading configuration " + "(config: %s)", + mConfigFileName.c_str()); std::string errors; - std::auto_ptr<Configuration> pconfig = Configuration::LoadAndVerify(configfile, GetConfigVerify(), errors); + std::auto_ptr<Configuration> pconfig = + Configuration::LoadAndVerify( + mConfigFileName.c_str(), + GetConfigVerify(), errors); // Got errors? if(pconfig.get() == 0 || !errors.empty()) { // Tell user about errors - ::syslog(LOG_ERR, "Errors in config file %s:\n%s", configfile, errors.c_str()); + ::syslog(LOG_ERR, "Errors in config " + "file %s:\n%s", + mConfigFileName.c_str(), + errors.c_str()); // And give up return 1; } @@ -325,6 +341,8 @@ int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[]) // Store configuration mpConfiguration = pconfig.release(); + mLoadedConfigModifiedTime = + GetConfigFileModifiedTime(); // Stop being marked for loading config again mReloadConfigWanted = false; @@ -547,3 +565,49 @@ void Daemon::SetProcessTitle(const char *format, ...) #endif // HAVE_SETPROCTITLE } + + +// -------------------------------------------------------------------------- +// +// Function +// Name: Daemon::GetConfigFileModifiedTime() +// Purpose: Returns the timestamp when the configuration file +// was last modified +// +// Created: 2006/01/29 +// +// -------------------------------------------------------------------------- + +box_time_t Daemon::GetConfigFileModifiedTime() const +{ + struct stat st; + + if(::stat(GetConfigFileName().c_str(), &st) != 0) + { + if (errno == ENOENT) + { + return 0; + } + THROW_EXCEPTION(CommonException, OSFileError) + } + + return FileModificationTime(st); +} + +// -------------------------------------------------------------------------- +// +// Function +// Name: Daemon::GetLoadedConfigModifiedTime() +// Purpose: Returns the timestamp when the configuration file +// had been last modified, at the time when it was +// loaded +// +// Created: 2006/01/29 +// +// -------------------------------------------------------------------------- + +box_time_t Daemon::GetLoadedConfigModifiedTime() const +{ + return mLoadedConfigModifiedTime; +} + diff --git a/lib/server/Daemon.h b/lib/server/Daemon.h index a7b9488b..dbc83e98 100644 --- a/lib/server/Daemon.h +++ b/lib/server/Daemon.h @@ -16,6 +16,10 @@ #ifndef DAEMON__H #define DAEMON__H +#include <string> + +#include "BoxTime.h" + class Configuration; class ConfigurationVerify; @@ -40,7 +44,8 @@ public: virtual void Run(); const Configuration &GetConfiguration() const; - + const std::string &GetConfigFileName() const {return mConfigFileName;} + virtual const char *DaemonName() const; virtual const char *DaemonBanner() const; virtual const ConfigurationVerify *GetConfigVerify() const; @@ -57,12 +62,18 @@ public: virtual void EnterChild(); static void SetProcessTitle(const char *format, ...); + +protected: + box_time_t GetLoadedConfigModifiedTime() const; private: static void SignalHandler(int sigraised); + box_time_t GetConfigFileModifiedTime() const; private: + std::string mConfigFileName; Configuration *mpConfiguration; + box_time_t mLoadedConfigModifiedTime; bool mReloadConfigWanted; bool mTerminateWanted; static Daemon *spDaemon; |