[Xorp-hackers] Possible fix for XORP bug 603

Justin Fletcher jfletcher@vyatta.com
Tue, 25 Apr 2006 19:00:34 -0700 (PDT)


You may get an invalid <[Enter]> and | options in help, as in:

DUT-2> show ospf4 ?
Possible completions:
  <[Enter]>       Execute this command   <==***Should not be displayed***
  database        Show LSA database
  neighbor        Show Neighbors
  |               Pipe through this command  <==***Should not be displayed***

As these command fail with "ERROR: no matching command" if the command is executed, I've come up with possible fix which only displays these options if the command is valid, using the same mechanism as that which generated the error message in the first place.

In cli_client.cc, add the command validation:

--- cli_client.cc.bak   2006-04-25 02:13:13.000000000 +0000
+++ cli_client.cc       2006-04-25 02:16:25.000000000 +0000
@@ -35,6 +35,10 @@
 #include "cli_command_pipe.hh"
 #include "cli_private.hh"
 
+#include "rtrmgr/op_commands.hh"
+
+extern OpCommandList* ocl;
+
 #ifdef HOST_OS_WINDOWS
 #define isatty(x) (x).is_console()
 #endif
@@ -1315,6 +1319,7 @@
        word_end--;                     // XXX: exclude the '?' character
 
     bool can_execute = false, can_pipe = false;
+    bool cmd_valid = false;            // Is command valid?
     list<CliCommand *>::iterator iter;
     for (iter = curr_cli_command->child_command_list().begin();
         iter != curr_cli_command->child_command_list().end();
@@ -1326,13 +1331,25 @@
            is_found = true;
     }
     if (is_found) {
+
+       // Is command valid?
+
+       // Build temporary command with '?' stripped off
+
+       string command_name = line;
+       command_name.erase(word_end - 1, 2);
+       cout << "command_name: '" << command_name << "'" << endl;
+       if (ocl->op_command_valid(command_name)) {
+           cmd_valid = true;
+       }
+
        cli_print("\nPossible completions:\n");
-       if (can_execute) {
+       if (can_execute && cmd_valid) {
            cli_print(c_format("  %-15s %s\r\n",
                               "<[Enter]>", "Execute this command"));
        }
        cli_print(command_help_string);
-       if (can_pipe) {
+       if (can_pipe && cmd_valid) {
            cli_print(c_format("  %-15s %s\r\n",
                               "|", "Pipe through this command"));
        }

and add the validator functions to op_commands:

--- op_commands.hh.bak  2006-04-25 02:21:50.000000000 +0000
+++ op_commands.hh      2006-04-25 02:22:58.000000000 +0000
@@ -206,6 +206,7 @@
     void set_slave_config_tree(SlaveConfigTree* sct) { _slave_config_tree = sct; }
     bool check_variable_name(const string& variable_name) const;
     OpCommand* find_op_command(const list<string>& command_parts);
+    bool op_command_valid(const string& command_name);
     OpCommand* add_op_command(const OpCommand& op_command);
     bool command_match(const list<string>& command_parts,
                       bool exact_match) const;

--- op_commands.cc.bak  2006-04-25 02:20:43.000000000 +0000
+++ op_commands.cc      2006-04-25 02:20:16.000000000 +0000
@@ -696,6 +696,17 @@
 }
 
 bool
+OpCommandList::op_command_valid(const string& command_name)
+{
+    list<OpCommand*>::const_iterator iter;
+    for (iter = _op_commands.begin(); iter != _op_commands.end(); ++iter) {
+       if ((*iter)->command_name() == command_name)
+           return true;
+    }
+    return false;
+}
+
+bool
 OpCommandList::command_match(const list<string>& command_parts,
                             bool exact_match) const
 {

Finally, there's a global variable to tie the two together:

--- xorpsh_main.cc.bak  2006-04-25 02:25:47.000000000 +0000
+++ xorpsh_main.cc      2006-04-25 02:27:27.000000000 +0000
@@ -72,6 +72,7 @@
 static void signal_handler(int signal_value);
 static void exit_handler(CliClient*);
 
+OpCommandList *ocl;            // Global command list
 
 static void
 announce_waiting()
@@ -892,6 +893,7 @@
        string xname = "xorpsh" + c_format("-%d-%s", getpid(), hostname);
        XorpShell xorpsh(eventloop, xname, xorp_binary_root_dir(),
                         template_dir, xrl_targets_dir, verbose);
+       ocl = xorpsh.op_cmd_list();
        xorpsh.run(commands);
     } catch (const InitError& e) {
        XLOG_ERROR("xorpsh exiting due to an init error: %s", e.why().c_str());

What I don't like about this is that it requires a global variable to access the command list from the help function.  What I do like about this is that it works!

Suggestions? Alternatives? Just do it? :-)

Justin Fletcher
Vyatta