deployer-funcs.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002  Copyright (c) 2008 S Roderick <xxxkiwi DOT xxxnet AT macxxx DOT comxxx>
00003                                (remove the x's above)
00004 
00005  ***************************************************************************
00006  *   This library is free software; you can redistribute it and/or         *
00007  *   modify it under the terms of the GNU Lesser General Public            *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2.1 of the License, or (at your option) any later version.    *
00010  *                                                                         *
00011  *   This library is distributed in the hope that it will be useful,       *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00014  *   Lesser General Public License for more details.                       *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Lesser General Public      *
00017  *   License along with this library; if not, write to the Free Software   *
00018  *   Foundation, Inc., 59 Temple Place,                                    *
00019  *   Suite 330, Boston, MA  02111-1307  USA                                *
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 // to configure RTT's use of log4cpp
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 // map lowercase strings to levels
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");   // set to valid default
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         // collate options
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         // deal with options
00119                 if (vm.count("help"))
00120                 {
00121                         std::cout << options << std::endl;
00122                         return 1;
00123                 }
00124 
00125         // version info
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         // turn off all console logging
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                 // verify that is a valid logging level
00165                 logLevel = boost::algorithm::to_lower_copy(logLevel);   // always lower case
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 //    using namespace boost::program_options;
00206 
00207     // Make sure no previous assignment to 'a' was made.
00208     po::validators::check_first_occurrence(v);
00209     // Extract the first string from 'values'. If there is more than
00210     // one string, it's an error, and exception will be thrown.
00211     const std::string& memSize = po::validators::get_single_string(values);
00212 
00213     /* parse the string. Support "number" or "numberX" where
00214        X is one of {k,K,m,M,g,G} with the expected meaning of X
00215 
00216        e.g.
00217 
00218        1024, 1k, 3.4M, 4.5G
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                 // fall through
00234             case 'M':
00235                 multiplier *= 1024;
00236                 // fall through
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         // nothing to do
00251     }
00252     else
00253     {
00254         throw po::invalid_option_value("Could not parse rtalloc-mem-size option: " + memSize);
00255     }
00256 
00257     // provide some basic sanity checking
00258     // Note that TLSF has its own internal checks on the value.
00259     // TLSF's minimum size varies with build options, but it is
00260     // several kilobytes at least (6-8k on Mac OS X Snow Leopard
00261     // with 64-bit build, ~3k on Ubuntu Jaunty with 32-bit build).
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     // configure where RTT::Logger's file logging goes to (which is through
00305     // log4cpp, but not through OCL's log4cpp-derived real-time logging!)
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         // setup default of logging to 'orocos.log' file
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         // encode as (ISO date) "yyyymmddTHH:MM:SS.ms category message"
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         // appender and layout are now owned by category - do not delete!
00336     }
00337     return true;
00338 }
00339 
00340 #endif  //  OROSEM_LOG4CPP_LOGGING
00341 
00342 // namespace
00343 }


ocl
Author(s): OCL Development Team
autogenerated on Thu Jan 2 2014 11:38:08