Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4430111
  • 博文数量: 252
  • 博客积分: 5347
  • 博客等级: 大校
  • 技术积分: 13838
  • 用 户 组: 普通用户
  • 注册时间: 2009-09-30 10:13
文章分类
文章存档

2022年(12)

2017年(11)

2016年(7)

2015年(14)

2014年(20)

2012年(9)

2011年(20)

2010年(153)

2009年(6)

分类: LINUX

2011-03-29 19:57:02

        在quagga中有很多的命令,利用这些下面分析一下命令是怎么被读取和执行的。在quagga中定义的命令都是利用宏定义实现的,这个宏定义还是有点复杂,下面是命令的宏定义语句。

#define DEFUN(funcname, cmdname, cmdstr, helpstr) \

  DEFUN_CMD_FUNC_DECL(funcname) \

  DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) \

  DEFUN_CMD_FUNC_TEXT(funcname)

第一个funcname是函数的名称,第二个是注册的命令的名字,第三个是在vtysh终端下输入的命令字符串,第四个是帮助信息,当输入“?”时,显示出来。

#define DEFUN_CMD_FUNC_DECL(funcname) \

  static int funcname (struct cmd_element *, struct vty *, int, const char *[]);

 

#define(funcname, cmdname, cmdstr, helpstr, attrs, dnum) \

  struct cmd_element cmdname = \

  { \

    .string = cmdstr, \

    .func = funcname, \

    .doc = helpstr, \

    .attr = attrs, \

    .daemon = dnum, \

  };

 

#define DEFUN_CMD_FUNC_TEXT(funcname) \

  static int funcname \

    (struct cmd_element *self __attribute__ ((unused)), \

     struct vty *vty __attribute__ ((unused)), \

     int argc __attribute__ ((unused)), \

     const char *argv[] __attribute__ ((unused)) )

 

 

假设我们这里有一个下面宏定义:

DEFUN (vtysh_show_hello, vtysh_show_hello_cmd,
"show hello", 
  " hello1\n"
  " hello2\n"
)
{
  printf("hello\n");
  return CMD_SUCCESS; 
  }

看一下它是如何展开的:

首先看一下下面的这个结构体,在宏DEFUN_CMD_ELEMENT中使用到。

struct cmd_element

{

  const char *string;                  /* Command specification by string. */

  int (*func) (struct cmd_element *, struct vty *, int, const char *[]);

  const char *doc;                    /* Documentation of this command. */

  int daemon;                   /* Daemon to which this command belong. */

  vector strvec;           /* Pointing out each description vector. */

  unsigned int cmdsize;              /* Command index count. */

  char *config;                   /* Configuration string */

  vector subconfig;            /* Sub configuration string */

  u_char attr;                     /* Command attributes */

};

 

#define DEFUN(funcname, cmdname, cmdstr, helpstr) \

  int funcname (struct cmd_element *, struct vty *, int, char **); \

  struct cmd_element cmdname = \

  { \

  cmdstr, \

  funcname, \

  helpstr \

  }; \

  int funcname \

  (struct cmd_element *self, struct vty *vty, int argc, char **argv)

 

还有一个结构struct vty应定义在vty.h中。根据宏定义DEFUN,可展开如下:

int vtysh_show_hello (struct cmd_element *, struct vty *, int, char **); 

struct cmd_element vtysh_show_hello_cmd =

{

  "show hello",

  vtysh_show_hello,

  " hello1\n hello2\n"

};

 

int vtysh_show_hello (struct cmd_element *self, struct vty *vty, int argc, char **argv)

{
  printf("hello\n");

  return CMD_SUCCESS;  

}

 

vty_main.c中,包含有一个main()函数,

假设我们定义了一个函数的宏定义,这里摘自quagga里面。

DEFUN (show_version,

       show_version_cmd,

       "show version",

       SHOW_STR

       "Displays zebra version\n")

{

  vty_out (vty, "Quagga %s (%s).%s", QUAGGA_VERSION, host.name?host.name:"",

          VTY_NEWLINE);

  vty_out (vty, "%s%s", QUAGGA_COPYRIGHT, VTY_NEWLINE);

 

  return CMD_SUCCESS;

}

 

上面已经分析了这个函数是怎么一步一步展开的,我们在定义一个命令的时候,也必须要在某一个节点下安装这个命令。使用下面的语句。

cmd_initint terminal)函数中。

install_node (&view_node, NULL);

 

void

install_node (struct cmd_node *node,

             int (*func) (struct vty *))

{

  vector_set_index (cmdvec, node->node, node);

  node->func = func;

  node->cmd_vector = vector_init (VECTOR_MIN_SIZE);

}

Cmdvec变量在cmd_init函数一开始时进行了初始化,

cmdvec = vector_init (VECTOR_MIN_SIZE);

vecto_init函数中分配了内存,并且返回vector结构。一个命令要在某个结点下安装。

install_element (VIEW_NODE, &show_version_cmd);

/* Install a command into a node.  安装一个命令到一个节点*/

void

install_element (enum node_type ntype, struct cmd_element *cmd)

{

  struct cmd_node *cnode;

 

  /* cmd_init hasn't been called */

  if (!cmdvec)

    return;

 

  cnode = vector_slot (cmdvec, ntype);

 

  if (cnode == NULL)

    {

      fprintf (stderr, "Command node %d doesn't exist, please check it\n",

              ntype);

      exit (1);

    }

 

  vector_set (cnode->cmd_vector, cmd);//在该节点下最小的空位置设置,cmd_element结构体的值,在这处理输入的命令时,调用相对应的处理命令

 

  cmd->strvec = cmd_make_descvec (cmd->string, cmd->doc);

  cmd->cmdsize = cmd_cmdsize (cmd->strvec);

}

这样加上上面用宏定义的命令和注册命令的流程,一个完整的命令就算完成了。

 

当我们在命令行中输入一个命令时,我们看一下它的流程是什么 ,也就是最后是怎么调用到我们定义的命令的处理函数。在vty_main.c函数中,有一个main()函数,在这个函数中对输入的命令行进行了处理。我们只看其中最主要的一个部分,也就是一个无限循环,在这个无限循环中我们可以看到vtysh_rl_gets()函数不断的读取命令行中的输入,如果有输入的话,就会调用vtysh_execute (line_read);函数对输入的命令行进行处理

* Main command loop. */

  while (vtysh_rl_gets ())

vtysh_execute (line_read);

 

void

vtysh_execute (const char *line)

{

  vtysh_execute_func (line, 1);

}

 

static void

vtysh_execute_func (const char *line, int pager)

{

……………………

saved_ret = ret = cmd_execute_command (vline, vty, &cmd, 1);

…………………

}

 

int

cmd_execute_command (vector vline, struct vty *vty, struct cmd_element **cmd, int vtysh)

{

……………….

saved_ret = ret = cmd_execute_command_real (vline, vty, cmd);//真正的命令行处理函数

………………

}

在这个函数中,调用了我们定义的命令的处理函数

static int

cmd_execute_command_real (vector vline, struct vty *vty,

                       struct cmd_element **cmd)

{

…………………………..

//找到与已经安装的命令匹配的命令,

for (i = 0; i < vector_active (cmd_vector); i++)

    if ((cmd_element = vector_slot (cmd_vector, i)))

      {

       if (match == vararg_match || index >= cmd_element->cmdsize)

         {

           matched_element = cmd_element;

#if 0

           printf ("DEBUG: %s\n", cmd_element->string);

#endif

           matched_count++;

         }

       else

         {

           incomplete_count++;

         }

      }

/* Argument treatment  对输入的参数进行处理*/

  varflag = 0;

  argc = 0;

 

  for (i = 0; i < vector_active (vline); i++)

    {

      if (varflag)

       argv[argc++] = vector_slot (vline, i);

      else

       {

         vector descvec = vector_slot (matched_element->strvec, i);

 

         if (vector_active (descvec) == 1)

           {

             struct desc *desc = vector_slot (descvec, 0);

 

             if (CMD_VARARG (desc->cmd))

              varflag = 1;

 

             if (varflag || CMD_VARIABLE (desc->cmd) || CMD_OPTION (desc->cmd))

              argv[argc++] = vector_slot (vline, i);

           }

         else

           argv[argc++] = vector_slot (vline, i);

       }

 

      if (argc >= CMD_ARGC_MAX)

       return CMD_ERR_EXEED_ARGC_MAX;

    }

 

  /* For vtysh execution. */

  if (cmd)

    *cmd = matched_element;

 

  if (matched_element->daemon)

    return CMD_SUCCESS_DAEMON;

return (*matched_element->func) (matched_element, vty, argc, argv);//最后调用处理函数,也就是我们使用DEFUN宏定义的命令

}

阅读(11149) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~