summaryrefslogtreecommitdiff
path: root/bin/bbackupd
diff options
context:
space:
mode:
Diffstat (limited to 'bin/bbackupd')
-rw-r--r--bin/bbackupd/BackupClientContext.cpp14
-rw-r--r--bin/bbackupd/BackupClientContext.h5
-rw-r--r--bin/bbackupd/BackupClientDirectoryRecord.cpp5
-rw-r--r--bin/bbackupd/BackupDaemon.cpp216
-rw-r--r--bin/bbackupd/BackupDaemon.h5
-rw-r--r--bin/bbackupd/Win32ServiceFunctions.cpp69
-rw-r--r--bin/bbackupd/bbackupd.cpp12
7 files changed, 223 insertions, 103 deletions
diff --git a/bin/bbackupd/BackupClientContext.cpp b/bin/bbackupd/BackupClientContext.cpp
index ae4e1cad..25852b19 100644
--- a/bin/bbackupd/BackupClientContext.cpp
+++ b/bin/bbackupd/BackupClientContext.cpp
@@ -57,9 +57,7 @@ BackupClientContext::BackupClientContext(BackupDaemon &rDaemon, TLSContext &rTLS
mpExcludeFiles(0),
mpExcludeDirs(0),
mbIsManaged(false),
- mTimeMgmtEpoch(0),
- mMaximumDiffTime(600),
- mKeepAliveTime(0)
+ mTimeMgmtEpoch(0)
{
}
@@ -511,6 +509,9 @@ void BackupClientContext::ManageDiffProcess()
#ifdef PLATFORM_CYGWIN
::signal(SIGALRM, TimerSigHandler);
+#elif defined WIN32
+ // no support for SIGVTALRM
+ SetTimerHandler(TimerSigHandler);
#else
::signal(SIGVTALRM, TimerSigHandler);
#endif // PLATFORM_CYGWIN
@@ -599,7 +600,10 @@ void BackupClientContext::UnManageDiffProcess()
void BackupClientContext::DoKeepAlive()
{
if (!mpConnection)
+ {
+ ::syslog(LOG_ERR, "DoKeepAlive() called with no connection!");
return;
+ }
mpConnection->QueryGetIsAlive();
}
@@ -620,10 +624,10 @@ time_t BackupClientContext::GetTimeMgmtEpoch()
int BackupClientContext::GetMaximumDiffingTime()
{
- return mMaximumDiffTime;
+ return sMaximumDiffTime;
}
int BackupClientContext::GetKeepaliveTime()
{
- return mKeepAliveTime;
+ return sKeepAliveTime;
}
diff --git a/bin/bbackupd/BackupClientContext.h b/bin/bbackupd/BackupClientContext.h
index 234868db..a0cf6e1f 100644
--- a/bin/bbackupd/BackupClientContext.h
+++ b/bin/bbackupd/BackupClientContext.h
@@ -208,11 +208,6 @@ private:
bool mbIsManaged;
// unix time when diff was started
time_t mTimeMgmtEpoch;
- // maximum time to spend diffing, in seconds
- int mMaximumDiffTime;
- // maximum time of SSL inactivity (keep-alive interval), in seconds
- int mKeepAliveTime;
-
};
diff --git a/bin/bbackupd/BackupClientDirectoryRecord.cpp b/bin/bbackupd/BackupClientDirectoryRecord.cpp
index 49193ccf..5a566d84 100644
--- a/bin/bbackupd/BackupClientDirectoryRecord.cpp
+++ b/bin/bbackupd/BackupClientDirectoryRecord.cpp
@@ -9,7 +9,10 @@
#include "Box.h"
-#include <dirent.h>
+#ifdef HAVE_DIRENT_H
+ #include <dirent.h>
+#endif
+
#include <errno.h>
#include <string.h>
diff --git a/bin/bbackupd/BackupDaemon.cpp b/bin/bbackupd/BackupDaemon.cpp
index a6d25f0f..01e5bf36 100644
--- a/bin/bbackupd/BackupDaemon.cpp
+++ b/bin/bbackupd/BackupDaemon.cpp
@@ -11,8 +11,10 @@
#include <stdio.h>
#include <string.h>
-#include <unistd.h>
+#ifdef HAVE_UNISTD_H
+ #include <unistd.h>
+#endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
@@ -35,6 +37,9 @@
#include <cstdio>
#include <sys/mnttab.h>
#endif
+#ifdef HAVE_PROCESS_H
+ #include <process.h>
+#endif
#include "Configuration.h"
#include "IOStream.h"
@@ -78,6 +83,25 @@ static const time_t MAX_SLEEP_TIME = 1024;
// This prevents repetative cycles of load on the server
#define SYNC_PERIOD_RANDOM_EXTRA_TIME_SHIFT_BY 6
+#ifdef WIN32
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: HelperThread()
+// Purpose: Background thread function, called by Windows,
+// calls the BackupDaemon's RunHelperThread method
+// to listen for and act on control communications
+// Created: 18/2/04
+//
+// --------------------------------------------------------------------------
+unsigned int WINAPI HelperThread(LPVOID lpParam)
+{
+ ((BackupDaemon *)lpParam)->RunHelperThread();
+
+ return 0;
+}
+#endif
+
// --------------------------------------------------------------------------
//
// Function
@@ -99,6 +123,20 @@ BackupDaemon::BackupDaemon()
{
mNotificationsSent[l] = false;
}
+
+#ifdef WIN32
+ // Create a thread to handle the named pipe
+ HANDLE hThread;
+ unsigned int dwThreadId;
+
+ hThread = (HANDLE) _beginthreadex(
+ NULL, // default security attributes
+ 0, // use default stack size
+ HelperThread, // thread function
+ this, // argument to thread function
+ 0, // use default creation flags
+ &dwThreadId); // returns the thread identifier
+#endif
}
// --------------------------------------------------------------------------
@@ -185,11 +223,12 @@ void BackupDaemon::SetupInInitialProcess()
if(GetConfiguration().KeyExists("CommandSocket"))
{
printf(
- "============================================================================================\n" \
- "SECURITY WARNING: This platform cannot check the credentials of connections to the\n" \
- "command socket. This is a potential DoS security problem.\n" \
- "Remove the CommandSocket directive from the bbackupd.conf file if bbackupctl is not used.\n" \
- "============================================================================================\n"
+ "==============================================================================\n"
+ "SECURITY WARNING: This platform cannot check the credentials of connections to\n"
+ "the command socket. This is a potential DoS security problem.\n"
+ "Remove the CommandSocket directive from the bbackupd.conf file if bbackupctl\n"
+ "is not used.\n"
+ "==============================================================================\n"
);
}
}
@@ -221,30 +260,13 @@ void BackupDaemon::DeleteAllLocations()
}
#ifdef WIN32
-// --------------------------------------------------------------------------
-//
-// Function
-// Name: HelperThread()
-// Purpose: Background thread function, called by Windows,
-// calls the BackupDaemon's RunHelperThread method
-// to listen for and act on control communications
-// Created: 18/2/04
-//
-// --------------------------------------------------------------------------
-unsigned int WINAPI HelperThread( LPVOID lpParam )
-{
- printf( "Parameter = %lu.\n", *(DWORD*)lpParam );
- ((BackupDaemon *)lpParam)->RunHelperThread();
-
- return 0;
-}
-
void BackupDaemon::RunHelperThread(void)
{
mpCommandSocketInfo = new CommandSocketInfo;
this->mReceivedCommandConn = false;
- while ( !IsTerminateWanted() )
+ // loop until the parent process exits
+ while (TRUE)
{
try
{
@@ -359,24 +381,21 @@ void BackupDaemon::RunHelperThread(void)
void BackupDaemon::Run()
{
#ifdef WIN32
-
- // Create a thread to handle the named pipe
- HANDLE hThread;
- unsigned int dwThreadId;
-
- hThread = (HANDLE) _beginthreadex(
- NULL, // default security attributes
- 0, // use default stack size
- HelperThread, // thread function
- this, // argument to thread function
- 0, // use default creation flags
- &dwThreadId); // returns the thread identifier
-
// init our own timer for file diff timeouts
InitTimer();
-#else // ! WIN32
+ try
+ {
+ Run2();
+ }
+ catch(...)
+ {
+ FiniTimer();
+ throw;
+ }
+ FiniTimer();
+#else // ! WIN32
// Ignore SIGPIPE (so that if a command connection is broken, the daemon doesn't terminate)
::signal(SIGPIPE, SIG_IGN);
@@ -390,8 +409,6 @@ void BackupDaemon::Run()
::unlink(socketName);
mpCommandSocketInfo->mListeningSocket.Listen(Socket::TypeUNIX, socketName);
}
-
-#endif // WIN32
// Handle things nicely on exceptions
try
@@ -402,23 +419,28 @@ void BackupDaemon::Run()
{
if(mpCommandSocketInfo != 0)
{
- delete mpCommandSocketInfo;
+ try
+ {
+ delete mpCommandSocketInfo;
+ }
+ catch(...)
+ {
+ ::syslog(LOG_WARNING,
+ "Error closing command socket "
+ "after exception, ignored.");
+ }
mpCommandSocketInfo = 0;
}
throw;
}
-
+
// Clean up
if(mpCommandSocketInfo != 0)
{
delete mpCommandSocketInfo;
mpCommandSocketInfo = 0;
}
-
-#ifdef WIN32
- // clean up windows specific stuff.
- FiniTimer();
#endif
}
@@ -482,8 +504,8 @@ void BackupDaemon::Run2()
BackupClientContext::ClientStoreMarker_NotKnown;
// haven't contacted the store yet
- DeserializeStoreObjectInfo(clientStoreMarker, lastSyncTime,
- nextSyncTime);
+ bool deserialised = DeserializeStoreObjectInfo(clientStoreMarker,
+ lastSyncTime, nextSyncTime);
// --------------------------------------------------------------------------------------------
@@ -585,6 +607,17 @@ void BackupDaemon::Run2()
// but this should be OK, because the changes only upload should upload no data.
syncPeriodEndExtended += SecondsToBoxTime((time_t)(356*24*3600));
}
+
+ // Delete the serialised store object file,
+ // so that we don't try to reload it after a
+ // partially completed backup
+ if(deserialised && !DeleteStoreObjectInfo())
+ {
+ ::syslog(LOG_ERR, "Failed to delete the "
+ "StoreObjectInfoFile, backup cannot "
+ "continue safely.");
+ continue;
+ }
// Do sync
bool errorOccurred = false;
@@ -751,7 +784,12 @@ void BackupDaemon::Run2()
"to retry...",
errorString, errorCode,
errorSubCode);
- ::sleep(100);
+ ::sleep(10);
+ nextSyncTime = currentSyncStartTime +
+ SecondsToBoxTime(90) +
+ Random::RandomInt(
+ updateStoreInterval >>
+ SYNC_PERIOD_RANDOM_EXTRA_TIME_SHIFT_BY);
}
}
@@ -863,7 +901,7 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla
#ifdef WIN32
// Really could use some interprocess protection, mutex etc
// any side effect should be too bad???? :)
- DWORD timeout = BoxTimeToMilliSeconds(RequiredDelay);
+ DWORD timeout = (DWORD)BoxTimeToMilliSeconds(RequiredDelay);
while ( this->mReceivedCommandConn == false )
{
@@ -1065,25 +1103,23 @@ void BackupDaemon::WaitOnCommandSocket(box_time_t RequiredDelay, bool &DoSyncFla
// --------------------------------------------------------------------------
void BackupDaemon::CloseCommandConnection()
{
+#ifndef WIN32
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
}
+#endif
}
@@ -1100,7 +1136,11 @@ 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.
-
+
+#ifdef __MINGW32__
+#warning race condition: what happens if socket is closed?
+#endif
+
if (mpCommandSocketInfo != NULL &&
#ifdef WIN32
mpCommandSocketInfo->mListeningSocket.IsConnected()
@@ -1114,7 +1154,7 @@ void BackupDaemon::SendSyncStartOrFinish(bool SendStart)
{
#ifdef WIN32
mpCommandSocketInfo->mListeningSocket.Write(message,
- strlen(message));
+ (int)strlen(message));
#else
mpCommandSocketInfo->mpConnectedSocket->Write(message,
strlen(message));
@@ -1711,7 +1751,10 @@ void BackupDaemon::SetState(int State)
char newStateSize = sprintf(newState, "state %d\n", State);
#ifdef WIN32
- #warning FIX ME: race condition
+ #ifndef _MSC_VER
+ #warning FIX ME: race condition
+ #endif
+
// what happens if the socket is closed by the other thread before
// we can write to it? Null pointer deref at best.
if (mpCommandSocketInfo &&
@@ -2196,7 +2239,7 @@ void BackupDaemon::SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time
// Created: 2005/04/11
//
// --------------------------------------------------------------------------
-void BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_time_t & theLastSyncTime, box_time_t & theNextSyncTime)
+bool BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_time_t & theLastSyncTime, box_time_t & theNextSyncTime)
{
//
//
@@ -2208,7 +2251,7 @@ void BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_
//
if(!GetConfiguration().KeyExists("StoreObjectInfoFile"))
{
- return;
+ return false;
}
std::string StoreObjectInfoFile =
@@ -2216,7 +2259,7 @@ void BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_
if (StoreObjectInfoFile.size() <= 0)
{
- return;
+ return false;
}
try
@@ -2236,7 +2279,7 @@ void BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_
"is not a valid or compatible serialised "
"archive. Will re-cache from store.",
StoreObjectInfoFile.c_str());
- return;
+ return false;
}
//
@@ -2251,7 +2294,7 @@ void BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_
"is not a valid or compatible serialised "
"archive. Will re-cache from store.",
StoreObjectInfoFile.c_str());
- return;
+ return false;
}
//
@@ -2264,11 +2307,11 @@ void BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_
if (iVersion != STOREOBJECTINFO_VERSION)
{
::syslog(LOG_WARNING, "Store object info file '%s' "
- "version [%d] unsupported. "
+ "version %d unsupported. "
"Will re-cache from store.",
StoreObjectInfoFile.c_str(),
iVersion);
- return;
+ return false;
}
//
@@ -2283,7 +2326,7 @@ void BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_
::syslog(LOG_WARNING, "Store object info file '%s' "
"out of date. Will re-cache from store",
StoreObjectInfoFile.c_str());
- return;
+ return false;
}
//
@@ -2331,12 +2374,7 @@ void BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_
"version [%d]", StoreObjectInfoFile.c_str(),
iVersion);
- if (::unlink(StoreObjectInfoFile.c_str()) != 0)
- {
- ::syslog(LOG_ERR, "Failed to delete the old "
- "store object info file '%s': %s",
- StoreObjectInfoFile.c_str(), strerror(errno));
- }
+ return true;
}
catch (...)
{
@@ -2352,4 +2390,38 @@ void BackupDaemon::DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_
"Will re-cache from store.",
StoreObjectInfoFile.c_str());
}
+
+ return false;
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: BackupDaemon::DeleteStoreObjectInfo()
+// Purpose: Deletes the serialised state file, to prevent us
+// from using it again if a backup is interrupted.
+//
+// Created: 2006/02/12
+//
+// --------------------------------------------------------------------------
+
+bool BackupDaemon::DeleteStoreObjectInfo() const
+{
+ if(!GetConfiguration().KeyExists("StoreObjectInfoFile"))
+ {
+ return false;
+ }
+
+ std::string StoreObjectInfoFile =
+ GetConfiguration().GetKeyValue("StoreObjectInfoFile");
+
+ if (::unlink(StoreObjectInfoFile.c_str()) != 0)
+ {
+ ::syslog(LOG_ERR, "Failed to delete the old "
+ "store object info file '%s': %s",
+ StoreObjectInfoFile.c_str(), strerror(errno));
+ return false;
+ }
+
+ return true;
}
diff --git a/bin/bbackupd/BackupDaemon.h b/bin/bbackupd/BackupDaemon.h
index 8693fe9e..3bd15fad 100644
--- a/bin/bbackupd/BackupDaemon.h
+++ b/bin/bbackupd/BackupDaemon.h
@@ -45,10 +45,11 @@ public:
BackupDaemon();
~BackupDaemon();
+private:
// methods below do partial (specialized) serialization of client state only
void SerializeStoreObjectInfo(int64_t aClientStoreMarker, box_time_t theLastSyncTime, box_time_t theNextSyncTime) const;
- void DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_time_t & theLastSyncTime, box_time_t & theNextSyncTime);
-private:
+ bool DeserializeStoreObjectInfo(int64_t & aClientStoreMarker, box_time_t & theLastSyncTime, box_time_t & theNextSyncTime);
+ bool DeleteStoreObjectInfo() const;
BackupDaemon(const BackupDaemon &);
public:
diff --git a/bin/bbackupd/Win32ServiceFunctions.cpp b/bin/bbackupd/Win32ServiceFunctions.cpp
index 89f02f62..b74c7e09 100644
--- a/bin/bbackupd/Win32ServiceFunctions.cpp
+++ b/bin/bbackupd/Win32ServiceFunctions.cpp
@@ -14,10 +14,12 @@
#include "Box.h"
-//#include <stdio.h>
-//#include <stdlib.h>
-#include <unistd.h>
-//#include <windows.h>
+#ifdef HAVE_UNISTD_H
+ #include <unistd.h>
+#endif
+#ifdef HAVE_PROCESS_H
+ #include <process.h>
+#endif
extern void TerminateService(void);
extern unsigned int WINAPI RunService(LPVOID lpParameter);
@@ -31,18 +33,23 @@ HANDLE gStopServiceEvent = 0;
#define SERVICE_NAME "boxbackup"
+void ShowMessage(char *s)
+{
+ MessageBox(0, s, "Box Backup Message",
+ MB_OK | MB_SETFOREGROUND | MB_DEFAULT_DESKTOP_ONLY);
+}
+
void ErrorHandler(char *s, DWORD err)
{
char buf[256];
memset(buf, 0, sizeof(buf));
- snprintf(buf, sizeof(buf)-1, "%s (%d)", s, err);
+ _snprintf(buf, sizeof(buf)-1, "%s (%d)", s, err);
::syslog(LOG_ERR, "%s", buf);
MessageBox(0, buf, "Error",
MB_OK | MB_SETFOREGROUND | MB_DEFAULT_DESKTOP_ONLY);
ExitProcess(err);
}
-
void WINAPI ServiceControlHandler( DWORD controlCode )
{
switch ( controlCode )
@@ -88,7 +95,7 @@ void WINAPI ServiceControlHandler( DWORD controlCode )
VOID ServiceMain(DWORD argc, LPTSTR *argv)
{
- // initialise service status
+ // initialise service status
gServiceStatus.dwServiceType = SERVICE_WIN32;
gServiceStatus.dwCurrentState = SERVICE_STOPPED;
gServiceStatus.dwControlsAccepted = 0;
@@ -178,14 +185,19 @@ void InstallService(void)
scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);
- if (!scm) return;
+ if (!scm)
+ {
+ syslog(LOG_ERR, "Failed to open service control manager: "
+ "error %d", GetLastError());
+ return;
+ }
char cmd[MAX_PATH];
GetModuleFileName(NULL, cmd, sizeof(cmd)-1);
cmd[sizeof(cmd)-1] = 0;
char cmd_args[MAX_PATH];
- snprintf(cmd_args, sizeof(cmd_args)-1, "%s --service", cmd);
+ _snprintf(cmd_args, sizeof(cmd_args)-1, "%s --service", cmd);
cmd_args[sizeof(cmd_args)-1] = 0;
newService = CreateService(
@@ -194,12 +206,31 @@ void InstallService(void)
"Box Backup",
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
- SERVICE_DEMAND_START,
+ SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,
cmd_args,
0,0,0,0,0);
- if (newService) CloseServiceHandle(newService);
+ if (!newService)
+ {
+ ::syslog(LOG_ERR, "Failed to create Box Backup service: "
+ "error %d", GetLastError());
+ return;
+ }
+
+ ::syslog(LOG_INFO, "Created Box Backup service");
+
+ SERVICE_DESCRIPTION desc;
+ desc.lpDescription = "Backs up your data files over the Internet";
+
+ if (!ChangeServiceConfig2(newService, SERVICE_CONFIG_DESCRIPTION,
+ &desc))
+ {
+ ::syslog(LOG_WARNING, "Failed to set description for "
+ "Box Backup service: error %d", GetLastError());
+ }
+
+ CloseServiceHandle(newService);
CloseServiceHandle(scm);
}
@@ -210,23 +241,31 @@ void RemoveService(void)
scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);
- if (!scm) return;
+ if (!scm)
+ {
+ syslog(LOG_ERR, "Failed to open service control manager: "
+ "error %d", GetLastError());
+ return;
+ }
service = OpenService(scm, SERVICE_NAME, SERVICE_ALL_ACCESS|DELETE);
ControlService(service, SERVICE_CONTROL_STOP, &status);
if (!service)
{
- printf("Failed to open service manager");
+ syslog(LOG_ERR, "Failed to open Box Backup service: "
+ "error %d", GetLastError());
return;
}
+
if (DeleteService(service))
{
- printf("Service removed");
+ syslog(LOG_INFO, "Box Backup service deleted");
}
else
{
- printf("Failed to remove service");
+ syslog(LOG_ERR, "Failed to remove Box Backup service: "
+ "error %d", GetLastError());
}
CloseServiceHandle(service);
diff --git a/bin/bbackupd/bbackupd.cpp b/bin/bbackupd/bbackupd.cpp
index 1c870317..089b2d09 100644
--- a/bin/bbackupd/bbackupd.cpp
+++ b/bin/bbackupd/bbackupd.cpp
@@ -48,13 +48,19 @@ int main(int argc, const char *argv[])
InstallService();
return 0;
}
-
+
+ bool runAsWin32Service = false;
+ if (argc == 2 && ::strcmp(argv[1], "--service") == 0)
+ {
+ runAsWin32Service = true;
+ }
+
// Under win32 we must initialise the Winsock library
// before using sockets
WSADATA info;
- if (WSAStartup(MAKELONG(1, 1), &info) == SOCKET_ERROR)
+ if (WSAStartup(0x0101, &info) == SOCKET_ERROR)
{
// box backup will not run without sockets
::syslog(LOG_ERR, "Failed to initialise Windows Sockets");
@@ -65,7 +71,7 @@ int main(int argc, const char *argv[])
int ExitCode = 0;
- if (argc == 2 && ::strcmp(argv[1], "--service") == 0)
+ if (runAsWin32Service)
{
syslog(LOG_INFO,"Starting Box Backup Service");
OurService();