00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "deployer-funcs.hpp"
00023 #include <rtt/Logger.hpp>
00024 #include <cstdio>
00025 #include <iostream>
00026 #include <sstream>
00027 #include <string>
00028 #include <functional>
00029 #include <boost/program_options.hpp>
00030 #include <boost/program_options/positional_options.hpp>
00031 #include <boost/assign/list_of.hpp>
00032 #include <boost/algorithm/string/case_conv.hpp>
00033
00034 #if defined(ORO_BUILD_LOGGING) && defined(OROSEM_LOG4CPP_LOGGING)
00035
00036 #include <log4cpp/Category.hh>
00037 #include <log4cpp/FileAppender.hh>
00038 #include <log4cpp/PatternLayout.hh>
00039 #include <log4cpp/PropertyConfigurator.hh>
00040 #endif
00041
00042 namespace po = boost::program_options;
00043
00044 using namespace RTT;
00045 using namespace std;
00046
00047 #define ORO_xstr(s) ORO_str(s)
00048 #define ORO_str(s) #s
00049
00050 namespace OCL
00051 {
00052
00053
00054 std::map<std::string, RTT::Logger::LogLevel> logMap =
00055 boost::assign::map_list_of
00056 ("never", RTT::Logger::Debug)
00057 ("fatal", RTT::Logger::Fatal)
00058 ("critical", RTT::Logger::Critical)
00059 ("error", RTT::Logger::Error)
00060 ("warning", RTT::Logger::Warning)
00061 ("info", RTT::Logger::Info)
00062 ("debug", RTT::Logger::Debug)
00063 ("realtime", RTT::Logger::RealTime);
00064
00065 int deployerParseCmdLine(int argc,
00066 char** argv,
00067 std::string& siteFile,
00068 std::vector<std::string>& scriptFiles,
00069 std::string& name,
00070 bool& requireNameService,
00071 po::variables_map& vm,
00072 po::options_description* otherOptions)
00073 {
00074 std::string logLevel("info");
00075 po::options_description options;
00076 po::options_description allowed("Allowed options");
00077 po::positional_options_description pos;
00078 allowed.add_options()
00079 ("help,h",
00080 "Show program usage")
00081 ("version",
00082 "Show program version")
00083 ("daemon,d",
00084 "Makes this program a daemon such that it runs in the background.")
00085 ("start,s",
00086 po::value< std::vector<std::string> >(&scriptFiles),
00087 "Deployment XML or script file (eg 'config-file.xml' or 'script.ops')")
00088 ("site-file",
00089 po::value<std::string>(&siteFile),
00090 "Site deployment XML file (eg 'Deployer-site.cpf' or 'Deployer-site.xml')")
00091 ("log-level,l",
00092 po::value<std::string>(&logLevel),
00093 "Level at which to log from RTT (case-insensitive) Never,Fatal,Critical,Error,Warning,Info,Debug,Realtime")
00094 ("no-consolelog",
00095 "Turn off RTT logging to the console (will still log to 'orocos.log')")
00096 ("require-name-service",
00097 "Require CORBA name service")
00098 ("DeployerName",
00099 po::value<std::string>(&name),
00100 "Name of deployer component (the --DeployerName flag is optional). If you provide a script or XML file name, that will be run instead.")
00101 ;
00102 pos.add("DeployerName", 1);
00103
00104
00105 options.add(allowed);
00106 if (NULL != otherOptions)
00107 {
00108 options.add(*otherOptions);
00109 }
00110
00111 try
00112 {
00113 po::store(po::command_line_parser(argc, argv).
00114 options(options).positional(pos).run(),
00115 vm);
00116 po::notify(vm);
00117
00118
00119 if (vm.count("help"))
00120 {
00121 std::cout << options << std::endl;
00122 return 1;
00123 }
00124
00125
00126 if (vm.count("version"))
00127 {
00128 std::cout<< " OROCOS Toolchain version '" ORO_xstr(RTT_VERSION) "'";
00129 #ifdef __GNUC__
00130 std::cout << " ( GCC " ORO_xstr(__GNUC__) "." ORO_xstr(__GNUC_MINOR__) "." ORO_xstr(__GNUC_PATCHLEVEL__) " )";
00131 #endif
00132 #ifdef OROPKG_OS_LXRT
00133 std::cout<<" -- LXRT/RTAI.";
00134 #endif
00135 #ifdef OROPKG_OS_GNULINUX
00136 std::cout<<" -- GNU/Linux.";
00137 #endif
00138 #ifdef OROPKG_OS_XENOMAI
00139 std::cout<<" -- Xenomai.";
00140 #endif
00141 std::cout << endl;
00142 return 1;
00143 }
00144
00145 if (vm.count("daemon"))
00146 {
00147 if (fork() != 0 )
00148 return 1;
00149 }
00150
00151
00152 if (vm.count("no-consolelog"))
00153 {
00154 RTT::Logger::Instance()->mayLogStdOut(false);
00155 log(Warning) << "Console logging disabled" << endlog();
00156 }
00157
00158 if (vm.count("require-name-service"))
00159 {
00160 requireNameService = true;
00161 log(Info) << "CORBA name service required." << endlog();
00162 }
00163
00164
00165 logLevel = boost::algorithm::to_lower_copy(logLevel);
00166 if (vm.count("log-level"))
00167 {
00168 if (0 != logMap.count(logLevel))
00169 {
00170 RTT::Logger::Instance()->setLogLevel(logMap[logLevel]);
00171 }
00172 else
00173 {
00174 std::cout << "Did not understand log level: "
00175 << logLevel << std::endl
00176 << options << std::endl;
00177 return -1;
00178 }
00179 }
00180 if (vm.count("DeployerName")) {
00181 if (name.rfind(".xml") == 4 ||
00182 name.rfind(".cpf") == 4 ||
00183 name.rfind(".osd") == 4 ||
00184 name.rfind(".ops") == 4 ) {
00185 scriptFiles.push_back(name);
00186 name.clear();
00187 }
00188 }
00189 }
00190 catch (std::logic_error e)
00191 {
00192 std::cerr << "Exception:" << e.what() << std::endl << options << std::endl;
00193 return -1;
00194 }
00195
00196 return 0;
00197 }
00198
00199 #ifdef ORO_BUILD_RTALLOC
00200
00201 void validate(boost::any& v,
00202 const std::vector<std::string>& values,
00203 memorySize* target_type, int)
00204 {
00205
00206
00207
00208 po::validators::check_first_occurrence(v);
00209
00210
00211 const std::string& memSize = po::validators::get_single_string(values);
00212
00213
00214
00215
00216
00217
00218
00219
00220 float value=0;
00221 char units='\0';
00222 if (2 == sscanf(memSize.c_str(), "%f%c", &value, &units))
00223 {
00224 float multiplier=1;
00225 if (islower(units))
00226 {
00227 units = toupper(units);
00228 }
00229 switch (units)
00230 {
00231 case 'G':
00232 multiplier *= 1024;
00233
00234 case 'M':
00235 multiplier *= 1024;
00236
00237 case 'K':
00238 multiplier *= 1024;
00239 break;
00240 default:
00241 std::stringstream e;
00242 e << "Invalid units in rtalloc-mem-size option: " << memSize
00243 << ". Valid units: 'k','m','g' (case-insensitive).";
00244 throw po::invalid_option_value(e.str());
00245 }
00246 value *= multiplier;
00247 }
00248 else if (1 == sscanf(memSize.c_str(), "%f", &value))
00249 {
00250
00251 }
00252 else
00253 {
00254 throw po::invalid_option_value("Could not parse rtalloc-mem-size option: " + memSize);
00255 }
00256
00257
00258
00259
00260
00261
00262 if (! (0 <= value) )
00263 {
00264 std::stringstream e;
00265 e << "Invalid memory size of " << value << " given. Value must be >= 0.";
00266 throw po::invalid_option_value(e.str());
00267 }
00268
00269 v = memorySize((size_t)value);
00270 }
00271
00272
00273 boost::program_options::options_description deployerRtallocOptions(memorySize& rtallocMemorySize)
00274 {
00275 boost::program_options::options_description rtallocOptions("Real-time memory allocation options");
00276 rtallocOptions.add_options()
00277 ("rtalloc-mem-size",
00278 po::value<memorySize>(&rtallocMemorySize)->default_value(rtallocMemorySize),
00279 "Amount of memory to provide for real-time memory allocations (e.g. 10000, 1K, 4.3m)\n"
00280 "NB the minimum size depends on TLSF build options, but it is several kilobytes.")
00281 ;
00282 return rtallocOptions;
00283 }
00284
00285 #endif // ORO_BUILD_RTALLOC
00286
00287
00288 #if defined(ORO_BUILD_LOGGING) && defined(OROSEM_LOG4CPP_LOGGING)
00289
00290 boost::program_options::options_description deployerRttLog4cppOptions(std::string& rttLog4cppConfigFile)
00291 {
00292 po::options_description rttLog4cppOptions("RTT/Log4cpp options");
00293 rttLog4cppOptions.add_options()
00294 ("rtt-log4cpp-config-file",
00295 po::value<std::string>(&rttLog4cppConfigFile),
00296 std::string("Log4cpp configuration file to support RTT category '" + RTT::Logger::log4cppCategoryName + "'\n"+
00297 "WARNING Configure only this category. Use deployment files to configure realtime logging!").c_str())
00298 ;
00299 return rttLog4cppOptions;
00300 }
00301
00302 int deployerConfigureRttLog4cppCategory(const std::string& rttLog4cppConfigFile)
00303 {
00304
00305
00306 if (!rttLog4cppConfigFile.empty())
00307 {
00308 try
00309 {
00310 log4cpp::PropertyConfigurator::configure(rttLog4cppConfigFile);
00311 }
00312 catch (log4cpp::ConfigureFailure& e)
00313 {
00314 std::cerr << "ERROR: Unable to read/parse log4cpp configuration file\n"
00315 << e.what() << std::endl;
00316 return false;
00317 }
00318 }
00319 else
00320 {
00321
00322 log4cpp::PatternLayout* layout=0;
00323 log4cpp::Appender* appender=0;
00324 appender = new log4cpp::FileAppender(RTT::Logger::log4cppCategoryName,
00325 "orocos.log");
00326
00327 layout = new log4cpp::PatternLayout();
00328
00329 layout->setConversionPattern("%d{%Y%m%dT%T.%l} [%p] %m%n");
00330 appender->setLayout(layout);
00331
00332 log4cpp::Category& category =
00333 log4cpp::Category::getInstance(RTT::Logger::log4cppCategoryName);
00334 category.setAppender(appender);
00335
00336 }
00337 return true;
00338 }
00339
00340 #endif // OROSEM_LOG4CPP_LOGGING
00341
00342
00343 }