#include "../include/dbmaintenancethread.h"\r
#include "../include/freenet/freenetmasterthread.h"\r
#include "../include/threadwrapper/threadedexecutor.h"\r
+#include "../include/db/sqlite3db.h"\r
\r
#include <Poco/Util/HelpFormatter.h>\r
#include <Poco/FileChannel.h>\r
#include <Poco/FormattingChannel.h>\r
#include <Poco/PatternFormatter.h>\r
#include <iostream>\r
+#include <string>\r
+#include <cstring>\r
\r
#ifdef _WIN32\r
#include <direct.h>\r
#include <unistd.h>\r
#endif\r
\r
-//debug\r
-#include <Poco/ScopedLock.h>\r
-#include <Poco/Runnable.h>\r
-#include <Poco/Thread.h>\r
-#include <Poco/ThreadPool.h>\r
-#include "../include/threadwrapper/cancelablerunnable.h"\r
-#include "../include/threadwrapper/cancelablethread.h"\r
-\r
-Poco::FastMutex m1;\r
-class TestRunner:public CancelableRunnable\r
+FMSApp::FMSApp():m_displayhelp(false),m_showoptions(false),m_setoption(false),m_logtype("file"),m_workingdirectory("")\r
{\r
-public:\r
- void run()\r
+ // get current working dir so we can go to it later\r
+ char wd[1024];\r
+ char *wdptr=NULL;\r
+ memset(wd,0,1024);\r
+ wdptr=getcwd(wd,1023);\r
+ if(wdptr)\r
{\r
- do\r
- {\r
-\r
- }while(!IsCancelled());\r
+ m_workingdirectory=wdptr;\r
}\r
-};\r
-\r
-FMSApp::FMSApp():m_displayhelp(false),m_logtype("file")\r
-{\r
-\r
}\r
\r
void FMSApp::defineOptions(Poco::Util::OptionSet &options)\r
ServerApplication::defineOptions(options);\r
\r
// add command line options here\r
- options.addOption(Poco::Util::Option("help","?","display help for command line arguments",false).repeatable(false).callback(Poco::Util::OptionCallback<FMSApp>(this,&FMSApp::handleHelp)));\r
- options.addOption(Poco::Util::Option("log","l","select type of log output (file|stdout|stderr)",false,"type",true).repeatable(false).callback(Poco::Util::OptionCallback<FMSApp>(this,&FMSApp::handleLogOption)));\r
+ options.addOption(Poco::Util::Option("help","?","Display help for command line arguments.",false).repeatable(false).callback(Poco::Util::OptionCallback<FMSApp>(this,&FMSApp::handleHelp)));\r
+ options.addOption(Poco::Util::Option("log","l","Select type of log output (file|stdout|stderr).",false,"type",true).repeatable(false).callback(Poco::Util::OptionCallback<FMSApp>(this,&FMSApp::handleLogOption)));\r
+ options.addOption(Poco::Util::Option("showoptions","","Show all options that can be set and their current values.",false).repeatable(false).callback(Poco::Util::OptionCallback<FMSApp>(this,&FMSApp::handleShowOptions)));\r
+ options.addOption(Poco::Util::Option("setoption","","Set an option. Values are not validated, so be sure to set them correctly.",false,"option=value",true).repeatable(true).callback(Poco::Util::OptionCallback<FMSApp>(this,&FMSApp::handleSetOption)));\r
}\r
\r
void FMSApp::displayHelp()\r
}\r
}\r
\r
+void FMSApp::handleSetOption(const std::string &name, const std::string &value)\r
+{\r
+ std::vector<std::string> valueparts;\r
+ StringFunctions::Split(value,"=",valueparts);\r
+\r
+ if(valueparts.size()==2)\r
+ {\r
+ m_setoptions[valueparts[0]]=valueparts[1];\r
+ }\r
+ else\r
+ {\r
+ std::cout << "Expected option=value but found " << value << std::endl;\r
+ }\r
+\r
+ m_setoption=true;\r
+}\r
+\r
+void FMSApp::handleShowOptions(const std::string &name, const std::string &value)\r
+{\r
+ m_showoptions=true;\r
+}\r
+\r
void FMSApp::initialize(Poco::Util::Application &self)\r
{\r
ServerApplication::initialize(self);\r
\r
- // set working directory to program directory\r
- int rval=chdir(config().getString("application.dir").c_str());\r
+ // set working directory - fall back on application.dir if working directory isn't set\r
+ // if we are runing as a service, then working directory needs to be set to the application directory\r
+ if(m_workingdirectory=="" || config().getBool("application.runAsService",false)==true)\r
+ {\r
+ m_workingdirectory=config().getString("application.dir");\r
+ }\r
+ int rval=chdir(m_workingdirectory.c_str());\r
\r
SetupDB();\r
SetupDefaultOptions();\r
}\r
}\r
\r
- setLogger(Poco::Logger::create("logfile",formatter,initiallevel));\r
+ setLogger(Poco::Logger::create("logfile",formatter,Poco::Message::PRIO_INFORMATION));\r
+ Poco::Logger::get("logfile").information("LogLevel set to "+tempval);\r
+ Poco::Logger::get("logfile").setLevel(initiallevel);\r
}\r
\r
int FMSApp::main(const std::vector<std::string> &args)\r
\r
// running as a daemon would reset the working directory to / before calling main\r
// so we need to set the working directory again\r
- // set working directory to program directory\r
- int rval=chdir(config().getString("application.dir").c_str());\r
+ int rval=chdir(m_workingdirectory.c_str());\r
\r
- if(m_displayhelp==false)\r
+ if(VerifyDB()==false)\r
+ {\r
+ std::cout << "The FMS database failed verification. It is most likely corrupt!" << std::endl;\r
+ logger().fatal("The FMS database failed verification. It is most likely corrupt!");\r
+ }\r
+ else if(m_displayhelp)\r
+ {\r
+ }\r
+ else if(m_showoptions)\r
+ {\r
+ showOptions();\r
+ }\r
+ else if(m_setoption)\r
+ {\r
+ setOptions();\r
+ }\r
+ else\r
{\r
logger().information("FMS startup v"FMS_VERSION);\r
\r
+ std::string tempval="";\r
+ Option::Instance()->Get("VacuumOnStartup",tempval);\r
+ if(tempval=="true")\r
+ {\r
+ logger().information("VACUUMing database");\r
+ SQLite3DB::DB::Instance()->Execute("VACUUM;");\r
+ }\r
+\r
StartThreads();\r
\r
if(isInteractive()==true)\r
\r
waitForTerminationRequest();\r
\r
+ if(isInteractive()==true)\r
+ {\r
+ std::cout << "Please wait while FMS shuts down." << std::endl << std::endl;\r
+ }\r
+\r
+ logger().trace("FMSApp::main cancelling threads");\r
m_threads.Cancel();\r
+ logger().trace("FMSApp::main joining threads");\r
m_threads.Join();\r
\r
logger().information("FMS shutdown");\r
return FMSApp::EXIT_OK;\r
}\r
\r
+void FMSApp::setOptions()\r
+{\r
+ for(std::map<std::string,std::string>::iterator i=m_setoptions.begin(); i!=m_setoptions.end(); i++)\r
+ {\r
+ std::string tempval="";\r
+ if(Option::Instance()->Get((*i).first,tempval))\r
+ {\r
+ Option::Instance()->Set((*i).first,(*i).second);\r
+ std::cout << "Option " << (*i).first << " set to " << (*i).second << std::endl;\r
+ }\r
+ else\r
+ {\r
+ std::cout << "Unknown option " << (*i).first << std::endl;\r
+ }\r
+ }\r
+}\r
+\r
+void FMSApp::showOptions()\r
+{\r
+ SQLite3DB::Statement st=SQLite3DB::DB::Instance()->Prepare("SELECT Option, OptionValue FROM tblOption;");\r
+ st.Step();\r
+ while(st.RowReturned())\r
+ {\r
+ std::string option="";\r
+ std::string optionvalue="";\r
+ st.ResultText(0,option);\r
+ st.ResultText(1,optionvalue);\r
+\r
+ std::cout << option << " = " << optionvalue << std::endl;\r
+\r
+ st.Step();\r
+ }\r
+}\r
+\r
void FMSApp::StartThreads()\r
{\r
std::string tempval="";\r
\r
// always start the DB maintenance thread\r
+ logger().trace("FMSApp::StartThreads starting DBMaintenanceThread");\r
m_threads.Start(new DBMaintenanceThread());\r
\r
Option::Instance()->Get("StartHTTP",tempval);\r
if(tempval=="true")\r
{\r
+ logger().trace("FMSApp::StartThreads starting HTTPThread");\r
m_threads.Start(new HTTPThread());\r
+ if(isInteractive())\r
+ {\r
+ std::cout << "Started HTTP Thread" << std::endl;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ logger().trace("FMSApp::StartThreads not starting HTTPThread");\r
}\r
\r
tempval="";\r
Option::Instance()->Get("StartNNTP",tempval);\r
if(tempval=="true")\r
{\r
+ logger().trace("FMSApp::StartThreads starting NNTPListener");\r
m_threads.Start(new NNTPListener());\r
+ if(isInteractive())\r
+ {\r
+ std::cout << "Started NNTP Thread" << std::endl;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ logger().trace("FMSApp::StartThreads not starting NNTPListener");\r
}\r
\r
tempval="";\r
Option::Instance()->Get("StartFreenetUpdater",tempval);\r
if(tempval=="true")\r
{\r
+ logger().trace("FMSApp::StartThreads starting FreenetMasterThread");\r
m_threads.Start(new FreenetMasterThread());\r
+ if(isInteractive())\r
+ {\r
+ std::cout << "Started Freenet FCP Thread" << std::endl;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ logger().trace("FMSApp::StartThreads not starting FreenetMasterThread");\r
}\r
\r
}\r