[Box Backup-commit] COMMIT r1310 - box/chris/general/lib/server
boxbackup-dev@fluffy.co.uk
boxbackup-dev@fluffy.co.uk
Sat, 03 Mar 2007 21:34:46 +0000
Author: chris
Date: 2007-03-03 21:34:46 +0000 (Sat, 03 Mar 2007)
New Revision: 1310
Modified:
box/chris/general/lib/server/Daemon.cpp
box/chris/general/lib/server/Daemon.h
Log:
Initialise and use logging.
Allow Daemons to be instantiated more than once in a program.
Add new Daemon::Main that takes parsed options instead of argv.
Stop Daemon::Main from exiting the parent after forking.
Stop Daemon::Main from interfering with the parent's signal handlers.
(copied from chris/merge)
Modified: box/chris/general/lib/server/Daemon.cpp
===================================================================
--- box/chris/general/lib/server/Daemon.cpp 2007-03-03 21:29:49 UTC (rev 1309)
+++ box/chris/general/lib/server/Daemon.cpp 2007-03-03 21:34:46 UTC (rev 1310)
@@ -33,6 +33,7 @@
#include "Guards.h"
#include "UnixUser.h"
#include "FileModificationTime.h"
+#include "Logging.h"
#include "MemLeakFindOn.h"
@@ -48,11 +49,11 @@
//
// --------------------------------------------------------------------------
Daemon::Daemon()
- : mpConfiguration(0),
+ : mpConfiguration(NULL),
mReloadConfigWanted(false),
mTerminateWanted(false)
{
- if(spDaemon != 0)
+ if(spDaemon != NULL)
{
THROW_EXCEPTION(ServerException, AlreadyDaemonConstructed)
}
@@ -79,56 +80,139 @@
delete mpConfiguration;
mpConfiguration = 0;
}
+
+ ASSERT(spDaemon == this);
+ spDaemon = NULL;
}
// --------------------------------------------------------------------------
//
// Function
// Name: Daemon::Main(const char *, int, const char *[])
-// Purpose: Starts the daemon off -- equivalent of C main() function
+// Purpose: Parses command-line options, and then calls
+// Main(std::string& configFile, bool singleProcess)
+// to start the daemon.
// Created: 2003/07/29
//
// --------------------------------------------------------------------------
int Daemon::Main(const char *DefaultConfigFile, int argc, const char *argv[])
{
+ // Find filename of config file
+ mConfigFileName = DefaultConfigFile;
+ bool haveConfigFile = false;
+ bool singleProcess = false;
+ int masterLevel = Log::NOTICE; // need an int to do math with
+ char c;
+
+ while((c = getopt(argc, (char * const *)argv, "c:Dqv")) != -1)
+ {
+ switch(c)
+ {
+ case 'c':
+ {
+ mConfigFileName = optarg;
+ haveConfigFile = true;
+ }
+ break;
+
+ case 'D':
+ {
+ singleProcess = true;
+ }
+ break;
+
+ case 'q':
+ {
+ if(masterLevel == Log::NOTHING)
+ {
+ BOX_FATAL("Too many '-q': "
+ "Cannot reduce logging "
+ "level any more");
+ return 2;
+ }
+ masterLevel--;
+ }
+ break;
+
+ case 'v':
+ {
+ if(masterLevel == Log::EVERYTHING)
+ {
+ BOX_FATAL("Too many '-v': "
+ "Cannot increase logging "
+ "level any more");
+ return 2;
+ }
+ masterLevel++;
+ }
+ break;
+
+ case '?':
+ {
+ BOX_FATAL("Unknown option on command line: "
+ << "'" << optopt << "'");
+ return 2;
+ }
+ break;
+
+ default:
+ {
+ BOX_FATAL("Unknown error in getopt: returned "
+ << "'" << c << "'");
+ return 1;
+ }
+ }
+ }
+
+ if (argc > optind && !haveConfigFile)
+ {
+ mConfigFileName = argv[optind]; optind++;
+ }
+
+ if (argc > optind && ::strcmp(argv[optind], "SINGLEPROCESS") == 0)
+ {
+ singleProcess = true; optind++;
+ }
+
+ if (argc > optind)
+ {
+ BOX_FATAL("Unknown parameter on command line: "
+ << "'" << std::string(argv[optind]) << "'");
+ return 2;
+ }
+
+ Logging::SetGlobalLevel((Log::Level)masterLevel);
+
+ return Main(mConfigFileName, singleProcess);
+}
+
+// --------------------------------------------------------------------------
+//
+// Function
+// Name: Daemon::Main(const std::string& rConfigFileName,
+// bool singleProcess)
+// Purpose: Starts the daemon off -- equivalent of C main() function
+// Created: 2003/07/29
+//
+// --------------------------------------------------------------------------
+int Daemon::Main(const std::string &rConfigFileName, bool singleProcess)
+{
// Banner (optional)
{
const char *banner = DaemonBanner();
if(banner != 0)
{
- printf("%s", banner);
+ BOX_NOTICE(banner);
}
}
std::string pidFileName;
+ mConfigFileName = rConfigFileName;
+ bool asDaemon = !singleProcess;
+
try
{
- // Find filename of config file
- 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)
- {
- mConfigFileName = argv[2];
- }
- else
- {
- mConfigFileName = argv[1];
- }
- }
-
- // Test mode with no daemonisation?
- bool asDaemon = true;
- if(argc >= 3)
- {
- if(::strcmp(argv[2], "SINGLEPROCESS") == 0)
- {
- asDaemon = false;
- }
- }
-
// Load the configuration file.
std::string errors;
std::auto_ptr<Configuration> pconfig;
@@ -144,16 +228,9 @@
if(e.GetType() == CommonException::ExceptionType &&
e.GetSubType() == CommonException::OSFileOpenError)
{
- fprintf(stderr, "%s: failed to start: "
- "failed to open configuration file: "
- "%s\n", DaemonName(),
- mConfigFileName.c_str());
-#ifdef WIN32
- ::syslog(LOG_ERR, "%s: failed to start: "
- "failed to open configuration file: "
- "%s", DaemonName(),
- mConfigFileName.c_str());
-#endif
+ BOX_FATAL("Failed to start: failed to open "
+ "configuration file: "
+ << mConfigFileName);
return 1;
}
@@ -164,14 +241,8 @@
if(pconfig.get() == 0 || !errors.empty())
{
// Tell user about errors
- fprintf(stderr, "%s: Errors in config file %s:\n%s",
- DaemonName(), mConfigFileName.c_str(),
- errors.c_str());
-#ifdef WIN32
- ::syslog(LOG_ERR, "%s: Errors in config file %s:\n%s",
- DaemonName(), mConfigFileName.c_str(),
- errors.c_str());
-#endif
+ BOX_FATAL("Failed to start: errors in configuration "
+ "file: " << mConfigFileName << ": " << errors);
// And give up
return 1;
}
@@ -183,18 +254,6 @@
// Let the derived class have a go at setting up stuff in the initial process
SetupInInitialProcess();
-#ifndef WIN32
- // Set signal handler
- struct sigaction sa;
- sa.sa_handler = SignalHandler;
- sa.sa_flags = 0;
- sigemptyset(&sa.sa_mask); // macro
- if(::sigaction(SIGHUP, &sa, NULL) != 0 || ::sigaction(SIGTERM, &sa, NULL) != 0)
- {
- THROW_EXCEPTION(ServerException, DaemoniseFailed)
- }
-#endif // !WIN32
-
// Server configuration
const Configuration &serverConfig(
mpConfiguration->GetSubConfiguration("Server"));
@@ -232,7 +291,7 @@
default:
// parent
- _exit(0);
+ // _exit(0);
return 0;
break;
@@ -269,14 +328,24 @@
break;
}
}
-#endif // ! WIN32
- // open the log
- ::openlog(DaemonName(), LOG_PID, LOG_LOCAL6);
+ // Set signal handler
+ // Don't do this in the parent, since it might be anything
+ // (e.g. test/bbackupd)
+
+ struct sigaction sa;
+ sa.sa_handler = SignalHandler;
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask); // macro
+ if(::sigaction(SIGHUP, &sa, NULL) != 0 || ::sigaction(SIGTERM, &sa, NULL) != 0)
+ {
+ THROW_EXCEPTION(ServerException, DaemoniseFailed)
+ }
+#endif // !WIN32
// Log the start message
- ::syslog(LOG_INFO, "Starting daemon (config: %s) (version "
- BOX_VERSION ")", mConfigFileName.c_str());
+ BOX_NOTICE("Starting daemon, version " << BOX_VERSION
+ << ", config: " << mConfigFileName);
// Write PID to file
char pid[32];
@@ -289,7 +358,7 @@
if(::write(pidFile, pid, pidsize) != pidsize)
{
- ::syslog(LOG_ERR, "can't write pid file");
+ BOX_FATAL("can't write pid file");
THROW_EXCEPTION(ServerException, DaemoniseFailed)
}
@@ -330,37 +399,24 @@
// And definitely don't try and send anything to those file descriptors
// -- this has in the past sent text to something which isn't expecting it.
TRACE_TO_STDOUT(false);
+ Logging::ToConsole(false);
}
}
catch(BoxException &e)
{
- fprintf(stderr, "%s: failed to start: exception %s (%d/%d)\n",
- DaemonName(), e.what(), e.GetType(), e.GetSubType());
-#ifdef WIN32
- ::syslog(LOG_ERR, "%s: failed to start: "
- "exception %s (%d/%d)\n", DaemonName(),
- e.what(), e.GetType(), e.GetSubType());
-#endif
+ BOX_FATAL("Failed to start: exception " << e.what()
+ << " (" << e.GetType()
+ << "/" << e.GetSubType() << ")");
return 1;
}
catch(std::exception &e)
{
- fprintf(stderr, "%s: failed to start: exception %s\n",
- DaemonName(), e.what());
-#ifdef WIN32
- ::syslog(LOG_ERR, "%s: failed to start: exception %s\n",
- DaemonName(), e.what());
-#endif
+ BOX_FATAL("Failed to start: exception " << e.what());
return 1;
}
catch(...)
{
- fprintf(stderr, "%s: failed to start: unknown exception\n",
- DaemonName());
-#ifdef WIN32
- ::syslog(LOG_ERR, "%s: failed to start: unknown exception\n",
- DaemonName());
-#endif
+ BOX_FATAL("Failed to start: unknown error");
return 1;
}
@@ -373,7 +429,7 @@
if (WSAStartup(0x0101, &info) == SOCKET_ERROR)
{
// will not run without sockets
- ::syslog(LOG_ERR, "Failed to initialise Windows Sockets");
+ BOX_FATAL("Failed to initialise Windows Sockets");
THROW_EXCEPTION(CommonException, Internal)
}
#endif
@@ -390,9 +446,8 @@
if(mReloadConfigWanted && !mTerminateWanted)
{
// Need to reload that config file...
- ::syslog(LOG_INFO, "Reloading configuration "
- "(config: %s)",
- mConfigFileName.c_str());
+ BOX_NOTICE("Reloading configuration file: "
+ << mConfigFileName);
std::string errors;
std::auto_ptr<Configuration> pconfig =
Configuration::LoadAndVerify(
@@ -403,10 +458,9 @@
if(pconfig.get() == 0 || !errors.empty())
{
// Tell user about errors
- ::syslog(LOG_ERR, "Errors in config "
- "file %s:\n%s",
- mConfigFileName.c_str(),
- errors.c_str());
+ BOX_FATAL("Error in configuration "
+ << "file: " << mConfigFileName
+ << ": " << errors);
// And give up
retcode = 1;
break;
@@ -430,25 +484,23 @@
::unlink(pidFileName.c_str());
// Log
- ::syslog(LOG_INFO, "Terminating daemon");
+ BOX_NOTICE("Terminating daemon");
}
catch(BoxException &e)
{
- ::syslog(LOG_ERR, "%s: terminating due to exception %s "
- "(%d/%d)", DaemonName(), e.what(), e.GetType(),
- e.GetSubType());
+ BOX_FATAL("Terminating due to exception " << e.what()
+ << " (" << e.GetType()
+ << "/" << e.GetSubType() << ")");
retcode = 1;
}
catch(std::exception &e)
{
- ::syslog(LOG_ERR, "%s: terminating due to exception %s",
- DaemonName(), e.what());
+ BOX_FATAL("Terminating due to exception " << e.what());
retcode = 1;
}
catch(...)
{
- ::syslog(LOG_ERR, "%s: terminating due to unknown exception",
- DaemonName());
+ BOX_FATAL("Terminating due to unknown exception");
retcode = 1;
}
Modified: box/chris/general/lib/server/Daemon.h
===================================================================
--- box/chris/general/lib/server/Daemon.h 2007-03-03 21:29:49 UTC (rev 1309)
+++ box/chris/general/lib/server/Daemon.h 2007-03-03 21:34:46 UTC (rev 1310)
@@ -41,6 +41,7 @@
public:
int Main(const char *DefaultConfigFile, int argc, const char *argv[]);
+ int Main(const std::string &rConfigFile, bool singleProcess);
virtual void Run();
const Configuration &GetConfiguration() const;