]> granicus.if.org Git - icinga2/commitdiff
CLI framework: Add support for unrecognized parameters
authorMichael Friedrich <michael.friedrich@netways.de>
Mon, 13 Oct 2014 16:07:52 +0000 (18:07 +0200)
committerMichael Friedrich <michael.friedrich@netways.de>
Mon, 13 Oct 2014 16:07:52 +0000 (18:07 +0200)
Required for feature enable command for example.

fixes #7371

icinga-app/icinga.cpp
lib/base/clicommand.cpp
lib/base/clicommand.hpp
lib/cli/daemoncommand.cpp
lib/cli/daemoncommand.hpp
lib/cli/pkinewcacommand.cpp
lib/cli/pkinewcacommand.hpp
lib/cli/pkinewcertcommand.cpp
lib/cli/pkinewcertcommand.hpp

index 5de35067ca00a3826478379112e9357b82c42910..a7fcafe9acf759bcd951091ede65efe54cbafb0f 100644 (file)
@@ -121,7 +121,7 @@ int Main(void)
 
        LogSeverity logLevel = Logger::GetConsoleLogSeverity();
        Logger::SetConsoleLogSeverity(LogWarning);
-       
+
        Utility::LoadExtensionLibrary("cli");
 
        po::options_description visibleDesc("Global options");
@@ -138,13 +138,14 @@ int Main(void)
 
        hiddenDesc.add_options()
                ("no-stack-rlimit", "used internally, do not specify manually");
-       
+
        String cmdname;
        CLICommand::Ptr command;
        po::variables_map vm;
+       std::vector<std::string> ap;
 
        try {
-               CLICommand::ParseCommand(argc, argv, visibleDesc, hiddenDesc, vm, cmdname, command, autocomplete);
+               CLICommand::ParseCommand(argc, argv, visibleDesc, hiddenDesc, vm, ap, cmdname, command, autocomplete);
        } catch (const std::exception& ex) {
                std::ostringstream msgbuf;
                msgbuf << "Error while parsing command-line options: " << ex.what();
@@ -158,7 +159,7 @@ int Main(void)
                ConfigCompilerContext::GetInstance()->Reset();
                ConfigCompiler::CompileFile(initconfig);
        }
-       
+
        if (vm.count("define")) {
                BOOST_FOREACH(const String& define, vm["define"].as<std::vector<std::string> >()) {
                        String key, value;
@@ -201,7 +202,7 @@ int Main(void)
                        Log(LogCritical, "cli",  msgbuf.str());
                        return EXIT_FAILURE;
                }
-       
+
                if (setgid(gr->gr_gid) < 0) {
                        std::ostringstream msgbuf;
                        msgbuf << "setgid() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
@@ -237,7 +238,7 @@ int Main(void)
                        Log(LogCritical, "cli",  msgbuf.str());
                        return EXIT_FAILURE;
                }
-       
+
                if (setuid(pw->pw_uid) < 0) {
                        std::ostringstream msgbuf;
                        msgbuf << "setuid() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
@@ -258,13 +259,13 @@ int Main(void)
                        ConfigCompiler::AddIncludeSearchDir(includePath);
                }
        }
-       
+
        Logger::SetConsoleLogSeverity(logLevel);
 
        if (!autocomplete) {
                if (vm.count("log-level")) {
                        String severity = vm["log-level"].as<std::string>();
-       
+
                        LogSeverity logLevel = LogInformation;
                        try {
                                logLevel = Logger::StringToSeverity(severity);
@@ -272,42 +273,42 @@ int Main(void)
                                /* use the default */
                                Log(LogWarning, "icinga", "Invalid log level set. Using default 'information'.");
                        }
-       
+
                        Logger::SetConsoleLogSeverity(logLevel);
                }
-       
+
                if (vm.count("library")) {
                        BOOST_FOREACH(const String& libraryName, vm["library"].as<std::vector<std::string> >()) {
                                (void)Utility::LoadExtensionLibrary(libraryName);
                        }
                }
-       
+
                if (!command || vm.count("help") || vm.count("version")) {
                        String appName = Utility::BaseName(Application::GetArgV()[0]);
-       
+
                        if (appName.GetLength() > 3 && appName.SubStr(0, 3) == "lt-")
                                appName = appName.SubStr(3, appName.GetLength() - 3);
-       
+
                        std::cout << appName << " " << "- The Icinga 2 network monitoring daemon.";
-       
+
                        if (!command || vm.count("help")) {
                                std::cout << std::endl << std::endl
                                    << "Usage:" << std::endl
                                    << "  " << argv[0] << " ";
-                                   
+
                                if (cmdname.IsEmpty())
                                        std::cout << "<command>";
                                else
                                        std::cout << cmdname;
-                                       
+
                                std::cout << " [<arguments>]";
-                               
+
                                if (command) {
                                        std::cout << std::endl << std::endl
                                                  << command->GetDescription();
                                }
                        }
-                       
+
                        if (vm.count("version")) {
                                std::cout << " (Version: " << Application::GetVersion() << ")";
                                std::cout << std::endl
@@ -316,24 +317,24 @@ int Main(void)
                                        << "This is free software: you are free to change and redistribute it." << std::endl
                                        << "There is NO WARRANTY, to the extent permitted by law.";
                        }
-       
+
                        std::cout << std::endl;
-       
+
                        if (vm.count("version")) {
                                std::cout << std::endl;
-       
+
                                Application::DisplayInfoMessage(true);
-       
+
                                return EXIT_SUCCESS;
                        }
                }
-       
+
                if (!command || vm.count("help")) {
                        if (!command) {
                                std::cout << std::endl;
                                CLICommand::ShowCommands(argc, argv, NULL);
                        }
-       
+
                        std::cout << std::endl
                                << visibleDesc << std::endl
                                << "Report bugs at <https://dev.icinga.org/>" << std::endl
@@ -348,7 +349,7 @@ int Main(void)
                CLICommand::ShowCommands(argc, argv, &visibleDesc, &hiddenDesc, true, autoindex);
                rc = 0;
        } else if (command)
-               rc = command->Run(vm);
+               rc = command->Run(vm, ap);
 
 #ifndef _DEBUG
        Application::Exit(rc);
index ea227baec6e3fa453cf5cb1770a134e12649425b..b4dec71299c0eb34171c5ecd03016343dd24b00d 100644 (file)
@@ -65,7 +65,8 @@ RegisterCLICommandHelper::RegisterCLICommandHelper(const String& name, const CLI
 
 bool CLICommand::ParseCommand(int argc, char **argv, po::options_description& visibleDesc,
     po::options_description& hiddenDesc, po::variables_map& vm,
-    String& cmdname, CLICommand::Ptr& command, bool autocomplete)
+    std::vector<std::string>& ap, String& cmdname,
+    CLICommand::Ptr& command, bool autocomplete)
 {
        boost::mutex::scoped_lock lock(l_RegistryMutex);
 
@@ -85,10 +86,10 @@ bool CLICommand::ParseCommand(int argc, char **argv, po::options_description& vi
 
                        if (vname[i] != argv[k])
                                break;
-                       
+
                        if (i >= best_match.size())
                                best_match.push_back(vname[i]);
-                       
+
                        if (i == vname.size() - 1) {
                                cmdname = boost::algorithm::join(vname, " ");
                                command = kv.second;
@@ -97,13 +98,13 @@ bool CLICommand::ParseCommand(int argc, char **argv, po::options_description& vi
                        }
                }
        }
-       
+
 found_command:
        lock.unlock();
 
        po::options_description vdesc("Command options");
-       
-       if (command)    
+
+       if (command)
                command->InitParameters(vdesc, hiddenDesc);
 
        visibleDesc.add(vdesc);
@@ -115,7 +116,13 @@ found_command:
        adesc.add(visibleDesc);
        adesc.add(hiddenDesc);
 
-       po::store(po::parse_command_line(argc - arg_end, argv + arg_end, adesc), vm);
+       po::parsed_options parsed = po::command_line_parser(argc - arg_end, argv + arg_end).
+           options(adesc).allow_unregistered().run();
+
+       ap = collect_unrecognized(parsed.options,
+           po::include_positional);
+
+       po::store(parsed, vm);
        po::notify(vm);
 
        return true;
@@ -136,7 +143,7 @@ void CLICommand::ShowCommands(int argc, char **argv, po::options_description *vi
                const std::vector<String>& vname = kv.first;
 
                arg_begin = 0;
-               
+
                for (int i = 0, k = 1; i < vname.size() && k < argc; i++, k++) {
                        if (strcmp(argv[k], "--no-stack-rlimit") == 0 || strcmp(argv[k], "--autocomplete") == 0) {
                                i--;
@@ -146,11 +153,11 @@ void CLICommand::ShowCommands(int argc, char **argv, po::options_description *vi
 
                        if (vname[i] != argv[k])
                                break;
-                       
+
                        if (i >= best_match.size()) {
                                best_match.push_back(vname[i]);
                        }
-                       
+
                        if (i == vname.size() - 1) {
                                command = kv.second;
                                break;
@@ -171,16 +178,16 @@ void CLICommand::ShowCommands(int argc, char **argv, po::options_description *vi
 
                if (vname.size() < best_match.size())
                        continue;
+
                bool match = true;
+
                for (int i = 0; i < best_match.size(); i++) {
                        if (vname[i] != best_match[i]) {
                                match = false;
                                break;
                        }
                }
+
                if (!match)
                        continue;
 
@@ -199,10 +206,10 @@ void CLICommand::ShowCommands(int argc, char **argv, po::options_description *vi
 
        if (command && autocomplete) {
                po::options_description vdesc("Command options");
-               
+
                if (command)
                        command->InitParameters(vdesc, *hiddenDesc);
-                       
+
                visibleDesc->add(vdesc);
 
                BOOST_FOREACH(const shared_ptr<po::option_description>& odesc, visibleDesc->options()) {
index dbe3ef97c002c4a7b100ac22acba2ed61e78672a..1ba3060656934888591f219541ca70751397db2a 100644 (file)
@@ -42,7 +42,7 @@ public:
        virtual String GetDescription(void) const = 0;
        virtual String GetShortDescription(void) const = 0;
        virtual void InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const = 0;
-       virtual int Run(const boost::program_options::variables_map& vm) const = 0;
+       virtual int Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const = 0;
 
        static CLICommand::Ptr GetByName(const std::vector<String>& name);
        static void Register(const std::vector<String>& name, const CLICommand::Ptr& command);
@@ -50,7 +50,8 @@ public:
 
        static bool ParseCommand(int argc, char **argv, boost::program_options::options_description& visibleDesc,
            boost::program_options::options_description& hiddenDesc,
-           boost::program_options::variables_map& vm, String& cmdname, CLICommand::Ptr& command, bool autocomplete);
+           boost::program_options::variables_map& vm, std::vector<std::string>& ap, String& cmdname,
+            CLICommand::Ptr& command, bool autocomplete);
        static void ShowCommands(int argc, char **argv, boost::program_options::options_description *visibleDesc = NULL,
            boost::program_options::options_description *hiddenDesc = NULL, bool autocomplete = false, int autoindex = -1);
 };
index 00200253eda8278ff9c56a0eb40379358268f912..24286968a2fc366aeddbddbfc5bb354cb926f12c 100644 (file)
@@ -299,7 +299,7 @@ void DaemonCommand::InitParameters(boost::program_options::options_description&
  *
  * @returns An exit status.
  */
-int DaemonCommand::Run(const po::variables_map& vm) const
+int DaemonCommand::Run(const po::variables_map& vm, const std::vector<std::string>& ap) const
 {
        ScriptVariable::Set("UseVfork", true, false, true);
 
@@ -358,7 +358,7 @@ int DaemonCommand::Run(const po::variables_map& vm) const
                SetDaemonIO(errorLog);
                Logger::DisableConsoleLog();
        }
-       
+
 #ifndef _WIN32
        struct sigaction sa;
        memset(&sa, 0, sizeof(sa));
index 713587fd03bcbaf3aa9a4349df44eb704677dc97..6de3bf34fdfb18df61dce1a01faf3567ba4905c0 100644 (file)
@@ -36,12 +36,12 @@ class DaemonCommand : public CLICommand
 {
 public:
        DECLARE_PTR_TYPEDEFS(DaemonCommand);
-    
+
        virtual String GetDescription(void) const;
        virtual String GetShortDescription(void) const;
        virtual void InitParameters(boost::program_options::options_description& visibleDesc,
            boost::program_options::options_description& hiddenDesc) const;
-       virtual int Run(const boost::program_options::variables_map& vm) const;
+       virtual int Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const;
 };
 
 }
index 8c295cff5c919080f1f38985d280149eb80c6b4d..19b4aeed5d2627f53c80ae8e1d87cefa62000718 100644 (file)
@@ -49,7 +49,7 @@ void PKINewCACommand::InitParameters(boost::program_options::options_description
  *
  * @returns An exit status.
  */
-int PKINewCACommand::Run(const boost::program_options::variables_map& vm) const
+int PKINewCACommand::Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const
 {
        String cadir = Application::GetLocalStateDir() + "/lib/icinga2/ca";
 
@@ -57,18 +57,18 @@ int PKINewCACommand::Run(const boost::program_options::variables_map& vm) const
                Log(LogCritical, "base", "CA directory '" + cadir + "' already exists.");
                return 1;
        }
-       
+
        if (!Utility::MkDirP(cadir, 0700)) {
                Log(LogCritical, "base", "Could not create CA directory '" + cadir + "'.");
                return 1;
        }
-       
+
        MakeX509CSR("Icinga CA", cadir + "/ca.key", String(), cadir + "/ca.crt", true);
-       
+
        String serialpath = cadir + "/serial.txt";
 
        Log(LogInformation, "cli", "Initializing serial file in '" + serialpath + "'.");
-               
+
        std::ofstream fp;
        fp.open(serialpath.CStr());
        fp << "01";
index 150852579976a61aed339bf472f35d62bbb50771..b2434ddeab88400cacded58d4577f0da7c950af7 100644 (file)
@@ -35,12 +35,12 @@ class PKINewCACommand : public CLICommand
 {
 public:
        DECLARE_PTR_TYPEDEFS(PKINewCACommand);
-    
+
        virtual String GetDescription(void) const;
        virtual String GetShortDescription(void) const;
        virtual void InitParameters(boost::program_options::options_description& visibleDesc,
            boost::program_options::options_description& hiddenDesc) const;
-       virtual int Run(const boost::program_options::variables_map& vm) const;
+       virtual int Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const;
 
 };
 
index 10c29ff1da2d237fdb53f78969b9f01b4b584928..4c36266f8ebbd82c2ff7e3200003d85f738f3abd 100644 (file)
@@ -52,26 +52,26 @@ void PKINewCertCommand::InitParameters(boost::program_options::options_descripti
  *
  * @returns An exit status.
  */
-int PKINewCertCommand::Run(const boost::program_options::variables_map& vm) const
+int PKINewCertCommand::Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const
 {
        if (!vm.count("cn")) {
                Log(LogCritical, "cli", "Common name (--cn) must be specified.");
                return 1;
        }
-       
+
        if (!vm.count("keyfile")) {
                Log(LogCritical, "cli", "Key file path (--keyfile) must be specified.");
                return 1;
        }
 
        String csrfile, certfile;
-       
+
        if (vm.count("csrfile"))
                csrfile = vm["csrfile"].as<std::string>();
 
        if (vm.count("certfile"))
                certfile = vm["certfile"].as<std::string>();
-       
+
        MakeX509CSR(vm["cn"].as<std::string>(), vm["keyfile"].as<std::string>(), csrfile, certfile);
 
        return 0;
index 0a463e7bc830c3a5d07e9147e6ff093697624060..051d085ce5faa92f8218b6cd714abe84b3518016 100644 (file)
@@ -35,12 +35,12 @@ class PKINewCertCommand : public CLICommand
 {
 public:
        DECLARE_PTR_TYPEDEFS(PKINewCertCommand);
-    
+
        virtual String GetDescription(void) const;
        virtual String GetShortDescription(void) const;
        virtual void InitParameters(boost::program_options::options_description& visibleDesc,
            boost::program_options::options_description& hiddenDesc) const;
-       virtual int Run(const boost::program_options::variables_map& vm) const;
+       virtual int Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const;
 
 };