分类: LINUX
2012-02-11 12:13:26
common/main.c:
/****************************************************************************
* returns:
* 1 - command executed, repeatable
* 0 - command executed but not repeatable, interrupted commands are
* always considered not repeatable
* -1 - not executed (unrecognized, bootd recursion or too many args)
* (If cmd is NULL or "" or longer than CFG_CBSIZE-1 it is
* considered unrecognized)
*
* WARNING:
*
* We must create a temporary copy of the command since the command we get
* may be the result from getenv(), which returns a pointer directly to
* the environment data, which may change magicly when the command we run
* creates or modifies environment variables (like "bootp" does).
*/
int run_command (const char *cmd, int flag)
{
cmd_tbl_t *cmdtp;
char cmdbuf[CFG_CBSIZE]; /* working copy of cmd */
char *token; /* start of token in cmdbuf */
char *sep; /* end of token (separator) in cmdbuf */
char finaltoken[CFG_CBSIZE];
char *str = cmdbuf;
char *argv[CFG_MAXARGS + 1]; /* NULL terminated */
int argc, inquotes;
int repeatable = 1;
int rc = 0;
#ifdef DEBUG_PARSER
printf ("[RUN_COMMAND] cmd[%p]=/"", cmd);
puts (cmd ? cmd : "NULL"); /* use puts - string may be loooong */
puts ("/"/n");
#endif
clear_ctrlc(); /* forget any previous Control C */
/*先是对命令的有效性进行检测*/
if (!cmd || !*cmd) {
return -1; /* empty command */
}
if (strlen(cmd) >= CFG_CBSIZE) {
puts ("## Command too long!/n");
return -1;
}
strcpy (cmdbuf, cmd); /*备份command*/
/* Process separators and check for invalid
* repeatable commands
*/
#ifdef DEBUG_PARSER
printf ("[PROCESS_SEPARATORS] %s/n", cmd);
#endif
while (*str) { /*看前面的定义,str指向cmdbuf */
/*
* Find separator, or string end
* Allow simple escape of ';' by writing "/;"
*/
/*下面这个for是对u-boot的特殊语法的解析,这里就不分析了*/
for (inquotes = 0, sep = str; *sep; sep++) {
if ((*sep=='/'') &&
(*(sep-1) != '//'))
inquotes=!inquotes;
if (!inquotes &&
(*sep == ';') && /* separator */
( sep != str) && /* past string start */
(*(sep-1) != '//')) /* and NOT escaped */
break;
}
/*
* Limit the token to data between separators
*/
token = str;
if (*sep) {
str = sep + 1; /* start of command for next pass */
*sep = '/0';
}
else
str = sep; /* no more commands for next pass */
#ifdef DEBUG_PARSER
printf ("token: /"%s/"/n", token);
#endif
/* find macros in this token and replace them */
process_macros (token, finaltoken);
/* Extract arguments */
argc = parse_line (finaltoken, argv); /*获取参数*/
/* Look up command in command table */
if ((cmdtp = find_cmd(argv[0])) == NULL) { /*获取对应的command*/
printf ("Unknown command '%s' - try 'help'/n", argv[0]);
rc = -1; /* give up after bad command */
continue;
}
/* found - check max args */
if (argc > cmdtp->maxargs) { /*检测command语法是否正确*/
printf ("Usage:/n%s/n", cmdtp->usage);
rc = -1;
continue;
}
#if (CONFIG_COMMANDS & CFG_CMD_BOOTD)
/* avoid "bootd" recursion */
if (cmdtp->cmd == do_bootd) {
#ifdef DEBUG_PARSER
printf ("[%s]/n", finaltoken);
#endif
if (flag & CMD_FLAG_BOOTD) {
puts ("'bootd' recursion detected/n");
rc = -1;
continue;
}
else
flag |= CMD_FLAG_BOOTD;
}
#endif /* CFG_CMD_BOOTD */
/* OK - call function to do the command */
if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) { /*执行具体的command*/
rc = -1;
}
repeatable &= cmdtp->repeatable;
/* Did the user stop this? */
if (had_ctrlc ())
return 0; /* if stopped then not repeatable */
}
return rc ? rc : repeatable;
}
这个函数主要是对用户输入的命令进行语法分析,从中获取命令,参数等信息,并查找一张系统保存的命令表,找到该命令对应的处理函数。并调用它来处理这个命令。
下面先详细分析这张系统的命令表是如何生成的,接着在以一个命令为例,来结束整篇文章。
首先看的是命令表中存的每个命令的属性
include/command.h:
struct cmd_tbl_s {
char *name; /* Command Name */
int maxargs; /* maximum number of arguments */
int repeatable; /* autorepeat allowed? */
/* Implementation function */
int (*cmd)(struct cmd_tbl_s *, int, int, char *[]);
char *usage; /* Usage message (short) */
#ifdef CFG_LONGHELP
char *help; /* Help message (long) */
#endif
#ifdef CONFIG_AUTO_COMPLETE
/* do auto completion on the arguments */
int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);
#endif
};
这个就不解释了,英文的已经很详细了。
接着看如何定义命令:
include/command.h:
#define Struct_Section __attribute__ ((unused,section (".u_boot_cmd")))
#ifdef CFG_LONGHELP
/*每个命令就用这个宏来定义,并加进系统命令表中*/
#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) /
cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}
/*它定义一个command变量,并把它放入".u_boot_cmd"节中*/
#else /* no long help info */
#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) /
cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage}
#endif /* CFG_LONGHELP */
最后看定义command的示例:
common/command.c:
U_BOOT_CMD(
version, 1, 1, do_version,
"version - print monitor version/n",
NULL
);
这定义了一个名字为version的command, 对应的函数为do_version, 也就是说如果用户输入命令:version,u-boot将执行do_version函数。
至于为什么要用这种方式来定义一个命令列表,大家可以看一下这个文件:
doc/README.commands:
**** Behinde the scene ******
The structure created is named with a special prefix (__u_boot_cmd_)
and placed by the linker in a special section.
This makes it possible for the final link to extract all commands
compiled into any object code and construct a static array so the
command can be found in an array starting at __u_boot_cmd_start.
If a new board is defined do not forget to define the command section
by writing in u-boot.lds ($(TOPDIR)/board/boardname/u-boot.lds) these
3 lines:
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
呵呵, __u_boot_cmd_start就是命令表的首地址,__u_boot_cmd_end就是结束地址, 而程序中就是靠这两个变量来从命令表中查询命令的。
懂了这些东西之后,我们也就知道了怎么去添加我们自定义的命令了。同时我们也可以去查看u-boot下提供了哪些命令了。