[Box Backup-dev] COMMIT r232 - box/chris/boxi/bin/bbackupd
boxbackup-dev@fluffy.co.uk
boxbackup-dev@fluffy.co.uk
Wed, 14 Dec 2005 23:54:13 +0000 (GMT)
Author: chris
Date: 2005-12-14 23:54:01 +0000 (Wed, 14 Dec 2005)
New Revision: 232
Modified:
box/chris/boxi/bin/bbackupd/BackupClientContext.cpp
box/chris/boxi/bin/bbackupd/BackupClientContext.h
box/chris/boxi/bin/bbackupd/BackupClientDirectoryRecord.cpp
box/chris/boxi/bin/bbackupd/BackupClientDirectoryRecord.h
box/chris/boxi/bin/bbackupd/BackupDaemon.cpp
box/chris/boxi/bin/bbackupd/BackupDaemon.h
Log:
* bbackupd/BackupDaemon.h
* bbackupd/BackupDaemon.cpp
- Moved command socket management (connect, wait, disconnect) to a separate
class, CommandSocketManager, to make it accessible from other classes
(win32 stuff should be moved as well, but not tonight)
* bbackupd/BackupClientContext.h
* bbackupd/BackupClientContext.cpp
- Use the LocationResolver interface to resolve paths to locations,
making BackupClientContext independent of BackupDaemon
* bbackupd/BackupClientDirectoryRecord.h
* bbackupd/BackupClientDirectoryRecord.cpp
- Use RunStatusProvider, SysadminNotifier and ProgressNotifier to report
backup progress, making BackupClientDirectoryRecord independent of
BackupDaemon
- Use CommandSocketManager to process command socket commands during a
backup run, allowing a sync to be stopped midway by bbackupctl on Unixes
(thread does this on win32)
Modified: box/chris/boxi/bin/bbackupd/BackupClientContext.cpp
===================================================================
--- box/chris/boxi/bin/bbackupd/BackupClientContext.cpp 2005-12-14 23:47:44 UTC (rev 231)
+++ box/chris/boxi/bin/bbackupd/BackupClientContext.cpp 2005-12-14 23:54:01 UTC (rev 232)
@@ -33,9 +33,10 @@
// Created: 2003/10/08
//
// --------------------------------------------------------------------------
-BackupClientContext::BackupClientContext(BackupDaemon &rDaemon, TLSContext &rTLSContext, const std::string &rHostname,
- int32_t AccountNumber, bool ExtendedLogging)
- : mrDaemon(rDaemon),
+BackupClientContext::BackupClientContext(LocationResolver &rResolver,
+ TLSContext &rTLSContext, const std::string &rHostname,
+ int32_t AccountNumber, bool ExtendedLogging)
+ : mrResolver(rResolver),
mrTLSContext(rTLSContext),
mHostname(rHostname),
mAccountNumber(AccountNumber),
@@ -424,7 +425,8 @@
{
// Location name -- look up in daemon's records
std::string locPath;
- if(!mrDaemon.FindLocationPathName(elementName.GetClearFilename(), locPath))
+ if(!mrResolver.FindLocationPathName(elementName.GetClearFilename(),
+ locPath))
{
// Didn't find the location... so can't give the local filename
return false;
Modified: box/chris/boxi/bin/bbackupd/BackupClientContext.h
===================================================================
--- box/chris/boxi/bin/bbackupd/BackupClientContext.h 2005-12-14 23:47:44 UTC (rev 231)
+++ box/chris/boxi/bin/bbackupd/BackupClientContext.h 2005-12-14 23:54:01 UTC (rev 232)
@@ -26,6 +26,23 @@
// --------------------------------------------------------------------------
//
// Class
+// Name: LocationResolver
+// Purpose: Interface for classes that can resolve locations to paths,
+// like BackupDaemon
+// Created: 2003/10/08
+//
+// --------------------------------------------------------------------------
+class LocationResolver {
+ public:
+ virtual ~LocationResolver() { }
+ virtual bool FindLocationPathName(const std::string &rLocationName,
+ std::string &rPathOut) const = 0;
+};
+
+
+// --------------------------------------------------------------------------
+//
+// Class
// Name: BackupClientContext
// Purpose:
// Created: 2003/10/08
@@ -34,8 +51,9 @@
class BackupClientContext
{
public:
- BackupClientContext(BackupDaemon &rDaemon, TLSContext &rTLSContext, const std::string &rHostname,
- int32_t AccountNumber, bool ExtendedLogging);
+ BackupClientContext(LocationResolver &rResolver, TLSContext &rTLSContext,
+ const std::string &rHostname, int32_t AccountNumber,
+ bool ExtendedLogging);
~BackupClientContext();
private:
BackupClientContext(const BackupClientContext &);
@@ -135,7 +153,7 @@
BackupStoreFilenameClear *pLeafname = 0); // not const as may connect to server
private:
- BackupDaemon &mrDaemon;
+ LocationResolver &mrResolver;
TLSContext &mrTLSContext;
std::string mHostname;
int32_t mAccountNumber;
@@ -153,4 +171,3 @@
#endif // BACKUPCLIENTCONTEXT__H
-
Modified: box/chris/boxi/bin/bbackupd/BackupClientDirectoryRecord.cpp
===================================================================
--- box/chris/boxi/bin/bbackupd/BackupClientDirectoryRecord.cpp 2005-12-14 23:47:44 UTC (rev 231)
+++ box/chris/boxi/bin/bbackupd/BackupClientDirectoryRecord.cpp 2005-12-14 23:54:01 UTC (rev 232)
@@ -101,8 +101,14 @@
void BackupClientDirectoryRecord::SyncDirectory(BackupClientDirectoryRecord::SyncParams &rParams, int64_t ContainingDirectoryID,
const std::string &rLocalPath, bool ThisDirHasJustBeenCreated)
{
+ rParams.GetProgressNotifier().NotifyScanDirectory(this, rLocalPath);
+
+ // Check for connections and commands on the command socket
+ if (rParams.mpCommandSocket)
+ rParams.mpCommandSocket->Wait(0);
+
// Signal received by daemon?
- if(rParams.mrDaemon.StopRun())
+ if(rParams.StopRun())
{
// Yes. Stop now.
THROW_EXCEPTION(BackupStoreException, SignalReceived)
@@ -133,8 +139,8 @@
{
// The directory has probably been deleted, so just ignore this error.
// In a future scan, this deletion will be noticed, deleted from server, and this object deleted.
- TRACE1("Stat failed for '%s' (directory)\n",
- rLocalPath.c_str());
+ rParams.GetProgressNotifier().NotifyDirStatFailed(
+ this, rLocalPath, strerror(errno));
return;
}
// Store inode number in map so directories are tracked in case they're renamed
@@ -162,6 +168,7 @@
std::vector<std::string> dirs;
std::vector<std::string> files;
bool downloadDirectoryRecordBecauseOfFutureFiles = false;
+
// BLOCK
{
// read the contents...
@@ -210,6 +217,10 @@
{
// Report the error (logs and
// eventual email to administrator)
+ rParams.GetProgressNotifier().NotifyFileStatFailed(this,
+ filename, strerror(errno));
+
+ // FIXME move to NotifyFileStatFailed()
SetErrorWhenReadingFilesystemObject(
rParams, filename.c_str());
@@ -268,8 +279,8 @@
// Log that this has happened
if(!rParams.mHaveLoggedWarningAboutFutureFileTimes)
{
- ::syslog(LOG_ERR, "Some files have modification times excessively in the future. Check clock syncronisation.\n");
- ::syslog(LOG_ERR, "Example file (only one shown) : %s\n", filename.c_str());
+ rParams.GetProgressNotifier().NotifyFileModifiedInFuture(
+ this, filename);
rParams.mHaveLoggedWarningAboutFutureFileTimes = true;
}
}
@@ -522,6 +533,8 @@
struct stat st;
if(::lstat(filename.c_str(), &st) != 0)
{
+ rParams.GetProgressNotifier().NotifyFileStatFailed(this,
+ filename, strerror(errno));
THROW_EXCEPTION(CommonException, OSFileError)
}
@@ -693,6 +706,8 @@
{
// Connection errors should just be passed on to the main handler, retries
// would probably just cause more problems.
+ rParams.GetProgressNotifier().NotifyFileUploadException(this,
+ filename, e);
throw;
}
catch(BoxException &e)
@@ -702,7 +717,8 @@
// Log it.
SetErrorWhenReadingFilesystemObject(rParams, filename.c_str());
// Log error.
- ::syslog(LOG_ERR, "Error code when uploading was (%d/%d), %s", e.GetType(), e.GetSubType(), e.what());
+ rParams.GetProgressNotifier().NotifyFileUploadException(this,
+ filename, e);
}
// Update structures if the file was uploaded successfully.
@@ -715,6 +731,11 @@
}
}
}
+ else
+ {
+ rParams.GetProgressNotifier().NotifyFileSkippedServerFull(this,
+ filename);
+ }
}
else if(en != 0 && en->GetAttributesHash() != attributesHash)
{
@@ -796,6 +817,9 @@
}
}
}
+
+ rParams.GetProgressNotifier().NotifyFileSynchronised(this, filename,
+ fileSize);
}
// Erase contents of files to save space when recursing
@@ -1070,6 +1094,8 @@
int64_t BackupClientDirectoryRecord::UploadFile(BackupClientDirectoryRecord::SyncParams &rParams, const std::string &rFilename, const BackupStoreFilename &rStoreFilename,
int64_t FileSize, box_time_t ModificationTime, box_time_t AttributesHash, bool NoPreviousVersionOnServer)
{
+ rParams.GetProgressNotifier().NotifyFileUploading(this, rFilename);
+
// Get the connection
BackupProtocolClient &connection(rParams.mrContext.GetConnection());
@@ -1090,7 +1116,11 @@
if(diffFromID != 0)
{
- // Found an old version -- get the index
+ // Found an old version
+ rParams.GetProgressNotifier().NotifyFileUploadingPatch(this,
+ rFilename);
+
+ // Get the index
std::auto_ptr<IOStream> blockIndexStream(connection.ReceiveStream());
// Diff the file
@@ -1139,7 +1169,7 @@
&& subtype == BackupProtocolClientError::Err_StorageLimitExceeded)
{
// The hard limit was exceeded on the server, notify!
- rParams.mrDaemon.NotifySysadmin(BackupDaemon::NotifyEvent_StoreFull);
+ rParams.NotifySysadmin(BackupDaemon::NotifyEvent_StoreFull);
}
}
@@ -1147,6 +1177,8 @@
throw;
}
+ rParams.GetProgressNotifier().NotifyFileUploaded(this, rFilename, FileSize);
+
// Return the new object ID of this file
return objID;
}
@@ -1167,7 +1199,8 @@
::memset(mStateChecksum, 0, sizeof(mStateChecksum));
// Log the error
- ::syslog(LOG_ERR, "Backup object failed, error when reading %s", Filename);
+ rParams.GetProgressNotifier().NotifyFileReadFailed(this,
+ Filename, strerror(errno));
// Mark that an error occured in the parameters object
rParams.mReadErrorsOnFilesystemObjects = true;
@@ -1183,14 +1216,20 @@
// Created: 8/3/04
//
// --------------------------------------------------------------------------
-BackupClientDirectoryRecord::SyncParams::SyncParams(BackupDaemon &rDaemon, BackupClientContext &rContext)
- : mSyncPeriodStart(0),
+BackupClientDirectoryRecord::SyncParams::SyncParams(
+ RunStatusProvider &rRunStatusProvider,
+ SysadminNotifier &rSysadminNotifier,
+ ProgressNotifier &rProgressNotifier,
+ BackupClientContext &rContext)
+ : mrRunStatusProvider(rRunStatusProvider),
+ mrSysadminNotifier(rSysadminNotifier),
+ mrProgressNotifier(rProgressNotifier),
+ mSyncPeriodStart(0),
mSyncPeriodEnd(0),
mMaxUploadWait(0),
mMaxFileTimeInFuture(99999999999999999LL),
mFileTrackingSizeThreshold(16*1024),
mDiffingUploadSizeThreshold(16*1024),
- mrDaemon(rDaemon),
mrContext(rContext),
mReadErrorsOnFilesystemObjects(false),
mUploadAfterThisTimeInTheFuture(99999999999999999LL),
@@ -1210,6 +1249,3 @@
BackupClientDirectoryRecord::SyncParams::~SyncParams()
{
}
-
-
-
Modified: box/chris/boxi/bin/bbackupd/BackupClientDirectoryRecord.h
===================================================================
--- box/chris/boxi/bin/bbackupd/BackupClientDirectoryRecord.h 2005-12-14 23:47:44 UTC (rev 231)
+++ box/chris/boxi/bin/bbackupd/BackupClientDirectoryRecord.h 2005-12-14 23:54:01 UTC (rev 232)
@@ -20,10 +20,99 @@
class BackupClientContext;
class BackupDaemon;
+class CommandSocketManager;
+
// --------------------------------------------------------------------------
//
// Class
+// Name: RunStatusProvider
+// Purpose: Provides a StopRun() method which returns true if the current
+// backup should be halted.
+// Created: 2005/11/15
+//
+// --------------------------------------------------------------------------
+class RunStatusProvider
+{
+ public:
+ virtual ~RunStatusProvider() { }
+ virtual bool StopRun() = 0;
+};
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: SysadminNotifier
+// Purpose: Provides a NotifySysadmin() method to send mail to the sysadmin
+// Created: 2005/11/15
+//
+// --------------------------------------------------------------------------
+class SysadminNotifier
+{
+ public:
+ virtual ~SysadminNotifier() { }
+ virtual void NotifySysadmin(int Event) = 0;
+};
+
+// --------------------------------------------------------------------------
+//
+// Class
+// Name: ProgressNotifier
+// Purpose: Provides methods for the backup library to inform the user
+// interface about its progress with the backup
+// Created: 2005/11/20
+//
+// --------------------------------------------------------------------------
+class BackupClientDirectoryRecord;
+
+class ProgressNotifier
+{
+ public:
+ virtual ~ProgressNotifier() { }
+ virtual void NotifyScanDirectory(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath) = 0;
+ virtual void NotifyDirStatFailed(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ const std::string& rErrorMsg) = 0;
+ virtual void NotifyFileStatFailed(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ const std::string& rErrorMsg) = 0;
+ virtual void NotifyFileReadFailed(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ const std::string& rErrorMsg) = 0;
+ virtual void NotifyFileModifiedInFuture(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath) = 0;
+ virtual void NotifyFileSkippedServerFull(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath) = 0;
+ virtual void NotifyFileUploadException(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ const BoxException& rException) = 0;
+ virtual void NotifyFileUploading(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath) = 0;
+ virtual void NotifyFileUploadingPatch(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath) = 0;
+ virtual void NotifyFileUploaded(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ int64_t FileSize) = 0;
+ virtual void NotifyFileSynchronised(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ int64_t FileSize) = 0;
+};
+
+// --------------------------------------------------------------------------
+//
+// Class
// Name: BackupClientDirectoryRecord
// Purpose: Implementation of record about directory for backup client
// Created: 2003/10/08
@@ -55,14 +144,21 @@
class SyncParams
{
public:
- SyncParams(BackupDaemon &rDaemon, BackupClientContext &rContext);
+ SyncParams(
+ RunStatusProvider &rRunStatusProvider,
+ SysadminNotifier &rSysadminNotifier,
+ ProgressNotifier &rProgressNotifier,
+ BackupClientContext &rContext);
~SyncParams();
private:
// No copying
SyncParams(const SyncParams&);
SyncParams &operator=(const SyncParams&);
+ RunStatusProvider &mrRunStatusProvider;
+ SysadminNotifier &mrSysadminNotifier;
+ ProgressNotifier &mrProgressNotifier;
+
public:
-
// Data members are public, as accessors are not justified here
box_time_t mSyncPeriodStart;
box_time_t mSyncPeriodEnd;
@@ -70,13 +166,23 @@
box_time_t mMaxFileTimeInFuture;
int32_t mFileTrackingSizeThreshold;
int32_t mDiffingUploadSizeThreshold;
- BackupDaemon &mrDaemon;
BackupClientContext &mrContext;
bool mReadErrorsOnFilesystemObjects;
-
+ CommandSocketManager* mpCommandSocket;
+
// Member variables modified by syncing process
box_time_t mUploadAfterThisTimeInTheFuture;
bool mHaveLoggedWarningAboutFutureFileTimes;
+
+ bool StopRun() { return mrRunStatusProvider.StopRun(); }
+ void NotifySysadmin(int Event)
+ {
+ mrSysadminNotifier.NotifySysadmin(Event);
+ }
+ ProgressNotifier& GetProgressNotifier() const
+ {
+ return mrProgressNotifier;
+ }
};
void SyncDirectory(SyncParams &rParams, int64_t ContainingDirectoryID, const std::string &rLocalPath,
@@ -111,5 +217,3 @@
};
#endif // BACKUPCLIENTDIRECTORYRECORD__H
-
-
Modified: box/chris/boxi/bin/bbackupd/BackupDaemon.cpp
===================================================================
--- box/chris/boxi/bin/bbackupd/BackupDaemon.cpp 2005-12-14 23:47:44 UTC (rev 231)
+++ box/chris/boxi/bin/bbackupd/BackupDaemon.cpp 2005-12-14 23:54:01 UTC (rev 232)
@@ -79,7 +79,7 @@
//
// --------------------------------------------------------------------------
BackupDaemon::BackupDaemon()
- : mState(BackupDaemon::State_Initialising),
+ : mState(State_Initialising),
mpCommandSocketInfo(0),
mDeleteUnusedRootDirEntriesAfter(0)
{
@@ -223,7 +223,7 @@
// Created: 18/2/04
//
// --------------------------------------------------------------------------
-unsigned int WINAPI HelperThread( LPVOID lpParam )
+unsigned int cdecl HelperThread( LPVOID lpParam )
{
printf( "Parameter = %lu.\n", *(DWORD*)lpParam );
((BackupDaemon *)lpParam)->RunHelperThread();
@@ -285,15 +285,13 @@
else if(command == "sync")
{
// Sync now!
- this->mDoSyncFlagOut = true;
- this->mSyncIsForcedOut = false;
+ SetSyncRequested();
sendOK = true;
}
else if(command == "force-sync")
{
// Sync now (forced -- overrides any SyncAllowScript)
- this->mDoSyncFlagOut = true;
- this->mSyncIsForcedOut = true;
+ SetSyncForced();
sendOK = true;
}
else if(command == "reload")
@@ -377,10 +375,8 @@
if(conf.KeyExists("CommandSocket"))
{
// Yes, create a local UNIX socket
- mpCommandSocketInfo = new CommandSocketInfo;
const char *socketName = conf.GetKeyValue("CommandSocket").c_str();
- ::unlink(socketName);
- mpCommandSocketInfo->mListeningSocket.Listen(Socket::TypeUNIX, socketName);
+ mpCommandSocketInfo = new CommandSocketManager(conf, this, socketName);
}
#endif // WIN32
@@ -428,9 +424,10 @@
TLSContext tlsContext;
const Configuration &conf(GetConfiguration());
std::string certFile(conf.GetKeyValue("CertificateFile"));
- std::string keyFile(conf.GetKeyValue("PrivateKeyFile"));
- std::string caFile(conf.GetKeyValue("TrustedCAsFile"));
- tlsContext.Initialise(false /* as client */, certFile.c_str(), keyFile.c_str(), caFile.c_str());
+ std::string keyFile (conf.GetKeyValue("PrivateKeyFile"));
+ std::string caFile (conf.GetKeyValue("TrustedCAsFile"));
+ tlsContext.Initialise(false /* as client */, certFile.c_str(),
+ keyFile.c_str(), caFile.c_str());
// Set up the keys for various things
BackupClientCryptoKeys_Setup(conf.GetKeyValue("KeysFile").c_str());
@@ -476,8 +473,6 @@
{
// Flags used below
bool storageLimitExceeded = false;
- bool doSync = false;
- bool doSyncForcedByCommand = false;
// Is a delay necessary?
{
@@ -501,7 +496,8 @@
if(mpCommandSocketInfo != 0)
{
// A command socket exists, so sleep by handling connections with it
- WaitOnCommandSocket(requiredDelay, doSync, doSyncForcedByCommand);
+ TRACE1("Wait on command socket, delay = %lld\n", requiredDelay);
+ mpCommandSocketInfo->Wait(requiredDelay);
}
else
{
@@ -511,36 +507,45 @@
}
}
- } while((!automaticBackup || (currentTime < nextSyncTime)) && !doSync && !StopRun());
+ } while((!automaticBackup || (currentTime < nextSyncTime))
+ && !mSyncRequested && !mSyncForced && !StopRun());
}
// Time of sync start, and if it's time for another sync (and we're doing automatic syncs), set the flag
box_time_t currentSyncStartTime = GetCurrentBoxTime();
if(automaticBackup && currentSyncStartTime >= nextSyncTime)
{
- doSync = true;
+ mSyncRequested = true;
}
+ bool doSync = mSyncForced;
+
// Use a script to see if sync is allowed now?
- if(!doSyncForcedByCommand && doSync && !StopRun())
+ if(mSyncRequested && !StopRun())
{
int d = UseScriptToSeeIfSyncAllowed();
if(d > 0)
{
// Script has asked for a delay
nextSyncTime = GetCurrentBoxTime() + SecondsToBoxTime((uint32_t)d);
- doSync = false;
}
+ else
+ {
+ doSync = true;
+ }
}
// Ready to sync? (but only if we're not supposed to be stopping)
if(doSync && !StopRun())
{
+ mSyncRequested = false;
+ mSyncForced = false;
+
// Touch a file to record times in filesystem
TouchFileInWorkingDir("last_sync_start");
// Tell anything connected to the command socket
- SendSyncStartOrFinish(true /* start */);
+ mpCommandSocketInfo->SendSyncStartOrFinish(true /* start */);
// Reset statistics on uploads
BackupStoreFile::ResetStats();
@@ -581,13 +586,15 @@
conf.GetKeyValueInt("AccountNumber"), conf.GetKeyValueBool("ExtendedLogging"));
// Set up the sync parameters
- BackupClientDirectoryRecord::SyncParams params(*this, clientContext);
+ BackupClientDirectoryRecord::SyncParams params(*this, *this,
+ *this, clientContext);
params.mSyncPeriodStart = syncPeriodStart;
params.mSyncPeriodEnd = syncPeriodEndExtended; // use potentially extended end time
params.mMaxUploadWait = maxUploadWait;
params.mFileTrackingSizeThreshold = conf.GetKeyValueInt("FileTrackingSizeThreshold");
params.mDiffingUploadSizeThreshold = conf.GetKeyValueInt("DiffingUploadSizeThreshold");
params.mMaxFileTimeInFuture = SecondsToBoxTime((uint32_t)conf.GetKeyValueInt("MaxFileTimeInFuture"));
+ params.mpCommandSocket = mpCommandSocketInfo;
// Set store marker
clientContext.SetClientStoreMarker(clientStoreMarker);
@@ -723,7 +730,22 @@
"to retry...",
errorString, errorCode,
errorSubCode);
- ::sleep(10);
+
+ // Sleep somehow. There are choices on how this should be
+ // done, depending on the state of the control connection
+
+ if(mpCommandSocketInfo != 0)
+ {
+ // A command socket exists, so sleep by handling
+ // connections with it
+ mpCommandSocketInfo->Wait(100 * 1000 * 1000);
+ }
+ else
+ {
+ // No command socket or connection, just do a
+ // normal sleep
+ ::sleep(100);
+ }
}
}
@@ -734,7 +756,7 @@
BackupStoreFile::ResetStats();
// Tell anything connected to the command socket
- SendSyncStartOrFinish(false /* finish */);
+ mpCommandSocketInfo->SendSyncStartOrFinish(false /* finish */);
// Touch a file to record times in filesystem
TouchFileInWorkingDir("last_sync_finish");
@@ -820,288 +842,6 @@
}
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupDaemon::WaitOnCommandSocket(box_time_t, bool &, bool &)
-// Purpose: Waits on a the command socket for a time of UP TO the required time
-// but may be much less, and handles a command if necessary.
-// Created: 18/2/04
-//
-// --------------------------------------------------------------------------
-void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFlagOut, bool &SyncIsForcedOut)
-{
-#ifdef WIN32
- // Really could use some interprocess protection, mutex etc
- // any side effect should be too bad???? :)
- DWORD timeout = BoxTimeToMilliSeconds(RequiredDelay);
-
- while ( this->mReceivedCommandConn == false )
- {
- Sleep(1);
-
- if ( timeout == 0 )
- {
- DoSyncFlagOut = false;
- SyncIsForcedOut = false;
- return;
- }
- timeout--;
- }
- this->mReceivedCommandConn = false;
- DoSyncFlagOut = this->mDoSyncFlagOut;
- SyncIsForcedOut = this->mSyncIsForcedOut;
-
- return;
-#else // ! WIN32
- ASSERT(mpCommandSocketInfo != 0);
- if(mpCommandSocketInfo == 0) {::sleep(1); return;} // failure case isn't too bad
-
- TRACE1("Wait on command socket, delay = %lld\n", RequiredDelay);
-
- try
- {
- // Timeout value for connections and things
- int timeout = ((int)BoxTimeToMilliSeconds(RequiredDelay)) + 1;
- // Handle bad boundary cases
- if(timeout <= 0) timeout = 1;
- if(timeout == INFTIM) timeout = 100000;
-
- // Wait for socket connection, or handle a command?
- if(mpCommandSocketInfo->mpConnectedSocket.get() == 0)
- {
- // No connection, listen for a new one
- mpCommandSocketInfo->mpConnectedSocket.reset(mpCommandSocketInfo->mListeningSocket.Accept(timeout).release());
-
- if(mpCommandSocketInfo->mpConnectedSocket.get() == 0)
- {
- // If a connection didn't arrive, there was a timeout, which means we've
- // waited long enough and it's time to go.
- return;
- }
- else
- {
-#ifdef PLATFORM_CANNOT_FIND_PEER_UID_OF_UNIX_SOCKET
- bool uidOK = true;
- ::syslog(LOG_ERR, "On this platform, no security check can be made on the credientials of peers connecting to the command socket. (bbackupctl)");
-#else
- // Security check -- does the process connecting to this socket have
- // the same UID as this process?
- bool uidOK = false;
- // BLOCK
- {
- uid_t remoteEUID = 0xffff;
- gid_t remoteEGID = 0xffff;
- if(mpCommandSocketInfo->mpConnectedSocket->GetPeerCredentials(remoteEUID, remoteEGID))
- {
- // Credentials are available -- check UID
- if(remoteEUID == ::getuid())
- {
- // Acceptable
- uidOK = true;
- }
- }
- }
-#endif // PLATFORM_CANNOT_FIND_PEER_UID_OF_UNIX_SOCKET
-
- // Is this an acceptable connection?
- if(!uidOK)
- {
- // Dump the connection
- ::syslog(LOG_ERR, "Incoming command connection from peer had different user ID than this process, or security check could not be completed.");
- mpCommandSocketInfo->mpConnectedSocket.reset();
- return;
- }
- else
- {
- // Log
- ::syslog(LOG_INFO, "Connection from command socket");
-
- // Send a header line summarising the configuration and current state
- const Configuration &conf(GetConfiguration());
- char summary[256];
- int summarySize = sprintf(summary, "bbackupd: %d %d %d %d\nstate %d\n",
- conf.GetKeyValueBool("AutomaticBackup"),
- conf.GetKeyValueInt("UpdateStoreInterval"),
- conf.GetKeyValueInt("MinimumFileAge"),
- conf.GetKeyValueInt("MaxUploadWait"),
- mState);
- mpCommandSocketInfo->mpConnectedSocket->Write(summary, summarySize);
-
- // Set the timeout to something very small, so we don't wait too long on waiting
- // for any incoming data
- timeout = 10; // milliseconds
- }
- }
- }
-
- // So there must be a connection now.
- ASSERT(mpCommandSocketInfo->mpConnectedSocket.get() != 0);
-
- // Is there a getline object ready?
- if(mpCommandSocketInfo->mpGetLine == 0)
- {
- // Create a new one
- mpCommandSocketInfo->mpGetLine = new IOStreamGetLine(*(mpCommandSocketInfo->mpConnectedSocket.get()));
- }
-
- // Ping the remote side, to provide errors which will mean the socket gets closed
- mpCommandSocketInfo->mpConnectedSocket->Write("ping\n", 5);
-
- // Wait for a command or something on the socket
- std::string command;
- while(mpCommandSocketInfo->mpGetLine != 0 && !mpCommandSocketInfo->mpGetLine->IsEOF()
- && mpCommandSocketInfo->mpGetLine->GetLine(command, false /* no preprocessing */, timeout))
- {
- TRACE1("Receiving command '%s' over command socket\n", command.c_str());
-
- bool sendOK = false;
- bool sendResponse = true;
-
- // Command to process!
- if(command == "quit" || command == "")
- {
- // Close the socket.
- CloseCommandConnection();
- sendResponse = false;
- }
- else if(command == "sync")
- {
- // Sync now!
- DoSyncFlagOut = true;
- SyncIsForcedOut = false;
- sendOK = true;
- }
- else if(command == "force-sync")
- {
- // Sync now (forced -- overrides any SyncAllowScript)
- DoSyncFlagOut = true;
- SyncIsForcedOut = true;
- sendOK = true;
- }
- else if(command == "reload")
- {
- // Reload the configuration
- SetReloadConfigWanted();
- sendOK = true;
- }
- else if(command == "terminate")
- {
- // Terminate the daemon cleanly
- SetTerminateWanted();
- sendOK = true;
- }
-
- // Send a response back?
- if(sendResponse)
- {
- mpCommandSocketInfo->mpConnectedSocket->Write(sendOK?"ok\n":"error\n", sendOK?3:6);
- }
-
- // Set timeout to something very small, so this just checks for data which is waiting
- timeout = 1;
- }
-
- // Close on EOF?
- if(mpCommandSocketInfo->mpGetLine != 0 && mpCommandSocketInfo->mpGetLine->IsEOF())
- {
- CloseCommandConnection();
- }
- }
- catch(...)
- {
- // If an error occurs, and there is a connection active, just close that
- // connection and continue. Otherwise, let the error propagate.
- if(mpCommandSocketInfo->mpConnectedSocket.get() == 0)
- {
- throw;
- }
- else
- {
- // Close socket and ignore error
- CloseCommandConnection();
- }
- }
-#endif // WIN32
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupDaemon::CloseCommandConnection()
-// Purpose: Close the command connection, ignoring any errors
-// Created: 18/2/04
-//
-// --------------------------------------------------------------------------
-void BackupDaemon::CloseCommandConnection()
-{
- try
- {
- TRACE0("Closing command connection\n");
-
-#ifdef WIN32
- mpCommandSocketInfo->mListeningSocket.Close();
-#else
- if(mpCommandSocketInfo->mpGetLine)
- {
- delete mpCommandSocketInfo->mpGetLine;
- mpCommandSocketInfo->mpGetLine = 0;
- }
- mpCommandSocketInfo->mpConnectedSocket.reset();
-#endif
- }
- catch(...)
- {
- // Ignore any errors
- }
-}
-
-
-// --------------------------------------------------------------------------
-//
-// File
-// Name: BackupDaemon.cpp
-// Purpose: Send a start or finish sync message to the command socket, if it's connected.
-//
-// Created: 18/2/04
-//
-// --------------------------------------------------------------------------
-void BackupDaemon::SendSyncStartOrFinish(bool SendStart)
-{
- // The bbackupctl program can't rely on a state change, because it may never
- // change if the server doesn't need to be contacted.
-
- if (mpCommandSocketInfo != NULL &&
-#ifdef WIN32
- mpCommandSocketInfo->mListeningSocket.IsConnected()
-#else
- mpCommandSocketInfo->mpConnectedSocket.get() != 0
-#endif
- )
- {
- const char* message = SendStart ? "start-sync\n" : "finish-sync\n";
- try
- {
-#ifdef WIN32
- mpCommandSocketInfo->mListeningSocket.Write(message,
- strlen(message));
-#else
- mpCommandSocketInfo->mpConnectedSocket->Write(message,
- strlen(message));
-#endif
- }
- catch(...)
- {
- CloseCommandConnection();
- }
- }
-}
-
-
-
-
#ifndef HAVE_STRUCT_STATFS_F_MNTONNAME
// string comparison ordering for when mount points are handled
// by code, rather than the OS.
@@ -1663,7 +1403,7 @@
// Created: 11/12/03
//
// --------------------------------------------------------------------------
-void BackupDaemon::SetState(int State)
+void BackupDaemon::SetState(state_t State)
{
// Two little checks
if(State == mState) return;
@@ -1679,6 +1419,11 @@
// If there's a command socket connected, then inform it -- disconnecting from the
// command socket if there's an error
+ if (mpCommandSocketInfo != 0)
+ {
+ mpCommandSocketInfo->SendStateUpdate(mState);
+ }
+
char newState[64];
char newStateSize = sprintf(newState, "state %d\n", State);
@@ -1864,35 +1609,3 @@
mpExcludeFiles = 0;
}
}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupDaemon::CommandSocketInfo::CommandSocketInfo()
-// Purpose: Constructor
-// Created: 18/2/04
-//
-// --------------------------------------------------------------------------
-BackupDaemon::CommandSocketInfo::CommandSocketInfo()
- : mpGetLine(0)
-{
-}
-
-
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: BackupDaemon::CommandSocketInfo::~CommandSocketInfo()
-// Purpose: Destructor
-// Created: 18/2/04
-//
-// --------------------------------------------------------------------------
-BackupDaemon::CommandSocketInfo::~CommandSocketInfo()
-{
- if(mpGetLine)
- {
- delete mpGetLine;
- mpGetLine = 0;
- }
-}
Modified: box/chris/boxi/bin/bbackupd/BackupDaemon.h
===================================================================
--- box/chris/boxi/bin/bbackupd/BackupDaemon.h 2005-12-14 23:47:44 UTC (rev 231)
+++ box/chris/boxi/bin/bbackupd/BackupDaemon.h 2005-12-14 23:54:01 UTC (rev 232)
@@ -15,18 +15,13 @@
#include <memory>
#include "Daemon.h"
-#include "BoxTime.h"
-#include "Socket.h"
-#include "SocketListen.h"
-#include "SocketStream.h"
-#include "WinNamedPipeStream.h"
+#include "CommandSocketManager.h"
+#include "BackupClientContext.h"
+#include "BackupClientDirectoryRecord.h"
-class BackupClientDirectoryRecord;
-class BackupClientContext;
class Configuration;
class BackupClientInodeToIDMap;
class ExcludeList;
-class IOStreamGetLine;
// --------------------------------------------------------------------------
//
@@ -36,7 +31,8 @@
// Created: 2003/10/08
//
// --------------------------------------------------------------------------
-class BackupDaemon : public Daemon
+class BackupDaemon : public Daemon, CommandListener, LocationResolver,
+ RunStatusProvider, SysadminNotifier, ProgressNotifier
{
public:
BackupDaemon();
@@ -50,20 +46,11 @@
virtual const char *DaemonBanner() const;
const ConfigurationVerify *GetConfigVerify() const;
- bool FindLocationPathName(const std::string &rLocationName, std::string &rPathOut) const;
+ bool FindLocationPathName(const std::string &rLocationName,
+ std::string &rPathOut) const;
- enum
- {
- // Add stuff to this, make sure the textual equivalents in SetState() are changed too.
- State_Initialising = -1,
- State_Idle = 0,
- State_Connected = 1,
- State_Error = 2,
- State_StorageLimitExceeded = 3
- };
+ state_t GetState() {return mState;}
- int GetState() {return mState;}
-
// Allow other classes to call this too
enum
{
@@ -94,12 +81,8 @@
void MakeMapBaseName(unsigned int MountNumber, std::string &rNameOut) const;
- void SetState(int State);
+ void SetState(state_t State);
- void WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFlagOut, bool &SyncIsForcedOut);
- void CloseCommandConnection();
- void SendSyncStartOrFinish(bool SendStart);
-
void TouchFileInWorkingDir(const char *Filename);
void DeleteUnusedRootDirEntries(BackupClientContext &rContext);
@@ -111,7 +94,6 @@
int UseScriptToSeeIfSyncAllowed();
-private:
class Location
{
public:
@@ -129,7 +111,7 @@
ExcludeList *mpExcludeDirs;
};
- int mState; // what the daemon is currently doing
+ state_t mState; // what the daemon is currently doing
std::vector<Location *> mLocations;
@@ -137,28 +119,9 @@
std::vector<BackupClientInodeToIDMap *> mCurrentIDMaps;
std::vector<BackupClientInodeToIDMap *> mNewIDMaps;
- // For the command socket
- class CommandSocketInfo
- {
- public:
- CommandSocketInfo();
- ~CommandSocketInfo();
- private:
- CommandSocketInfo(const CommandSocketInfo &); // no copying
- CommandSocketInfo &operator=(const CommandSocketInfo &);
- public:
-#ifdef WIN32
- WinNamedPipeStream mListeningSocket;
-#else
- SocketListen<SocketStream, 1 /* listen backlog */> mListeningSocket;
- std::auto_ptr<SocketStream> mpConnectedSocket;
-#endif
- IOStreamGetLine *mpGetLine;
- };
-
- // Using a socket?
- CommandSocketInfo *mpCommandSocketInfo;
-
+ // Using a socket?
+ CommandSocketManager *mpCommandSocketInfo;
+
// Stop notifications being repeated.
bool mNotificationsSent[NotifyEvent__MAX + 1];
@@ -166,12 +129,81 @@
box_time_t mDeleteUnusedRootDirEntriesAfter; // time to delete them
std::vector<std::pair<int64_t,std::string> > mUnusedRootDirEntries;
+ bool mSyncRequested;
+ bool mSyncForced;
+
+ void SetReloadConfigWanted() { this->Daemon::SetReloadConfigWanted(); }
+ void SetTerminateWanted() { this->Daemon::SetTerminateWanted(); }
+ void SetSyncRequested() { mSyncRequested = true; }
+ void SetSyncForced() { mSyncForced = true; }
+
+ bool StopRun() { return this->Daemon::StopRun(); }
+
+ /* ProgressNotifier implementation */
+ virtual void NotifyScanDirectory(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath) { }
+ virtual void NotifyDirStatFailed(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ const std::string& rErrorMsg)
+ {
+ TRACE2("Stat failed for '%s' (directory): %s\n",
+ rLocalPath.c_str(), rErrorMsg.c_str());
+ }
+ virtual void NotifyFileStatFailed(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ const std::string& rErrorMsg)
+ {
+ TRACE1("Stat failed for '%s' (contents)\n", rLocalPath.c_str());
+ }
+ virtual void NotifyFileReadFailed(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ const std::string& rErrorMsg)
+ {
+ ::syslog(LOG_ERR, "Backup object failed, error when reading %s",
+ rLocalPath.c_str());
+ }
+ virtual void NotifyFileModifiedInFuture(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath)
+ {
+ ::syslog(LOG_ERR, "Some files have modification times "
+ "excessively in the future. Check clock syncronisation.\n");
+ ::syslog(LOG_ERR, "Example file (only one shown) : %s\n",
+ rLocalPath.c_str());
+ }
+ virtual void NotifyFileSkippedServerFull(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath) { }
+ virtual void NotifyFileUploadException(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ const BoxException& rException)
+ {
+ ::syslog(LOG_ERR, "Error code when uploading was (%d/%d), %s",
+ rException.GetType(), rException.GetSubType(), rException.what());
+ }
+ virtual void NotifyFileUploading(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath) { }
+ virtual void NotifyFileUploadingPatch(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath) { }
+ virtual void NotifyFileUploaded(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ int64_t FileSize) { }
+ virtual void NotifyFileSynchronised(
+ const BackupClientDirectoryRecord* pDirRecord,
+ const std::string& rLocalPath,
+ int64_t FileSize) { }
+
#ifdef WIN32
public:
void RunHelperThread(void);
-
- private:
- bool mDoSyncFlagOut, mSyncIsForcedOut, mReceivedCommandConn;
#endif
};