全部博文(252)
分类: 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_init(int 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宏定义的命令
}