浅析busybox查找命令和调用相应命令函数的实现流程框架
libbb/appletlib.c
=>main
=>applet_name
= argv[0];//如果为符号链接,比如ln -s busybox ls,那么argv[0]就等于"ls"
=>applet_name
= bb_basename(applet_name);//去掉绝对路径的'/‘,返回实际找到文件名给applet_name
=>parse_config_file();//调用libbb/appletlib.c中的函数
=>run_applet_and_exit
run_applet_and_exit
=>find_applet_by_name调用的是libbb/appletlib.c中的函数,
=>使用bsearch库函数,二分法、折半查找转换后的argv[0]是否为命令,因为busybox可能是经过ln符号链接了的命令,比如ln
-s busybox vi
void FAST_FUNC run_applet_and_exit(const
char *name,
char **argv)
{
int applet
= find_applet_by_name(name);
if (applet
>= 0)//name就是命令,那么说明一定是ln -s符号链接了的命令,那么直接执行[luther.gliethttp]
run_applet_no_and_exit(applet, argv);
if (!strncmp(name,
"busybox", 7))
exit(busybox_main(argv));//执行到这里说明是以busybox
ls方式传递的命令.
}
busybox_main
=>如果输入的为
busybox --install
-s 创建所有命令的符号链接
busybox --install
-h 创建所有命令的硬链接
=>autoconf.h配置文件中指定
#define CONFIG_BUSYBOX_EXEC_PATH
"/proc/self/exe"
const char bb_busybox_exec_path[] ALIGN1
= CONFIG_BUSYBOX_EXEC_PATH;
install_links(busybox, argv[2]
&&
strcmp(argv[2],
"-s")
== 0);
static void install_links(const
char *busybox,
int use_symbolic_links)
{
/* directory table
* this should be consistent w/ the enum,
* busybox.h::bb_install_loc_t, or else... */
static
const char usr_bin
[] ALIGN1
= "/usr/bin";
static
const char usr_sbin[] ALIGN1
= "/usr/sbin";
static
const char
*const install_dir[]
= {
&usr_bin
[8],
/* "", equivalent to "/" for concat_path_file() */
&usr_bin
[4],
/* "/bin" */
&usr_sbin[4],
/* "/sbin" */
usr_bin,
usr_sbin
};
int
(*lf)(const
char *,
const char
*);
char
*fpc;
unsigned i;
int rc;
lf = link;a//库函数-硬链接
if (use_symbolic_links)
lf = symlink;//库函数-符号链接
for
(i = 0; i
< ARRAY_SIZE(applet_main); i++)
{
fpc = concat_path_file(
install_dir[APPLET_INSTALL_LOC(i)],
//根据busybox默认的策略,计算第i个命令所应对应的安装目录[luther.gliethttp]
APPLET_NAME(i));
// debug: bb_error_msg("%slinking %s to busybox",
// use_symbolic_links ? "sym" : "", fpc);
rc = lf(busybox, fpc);//创建之
if
(rc != 0
&&
errno != EEXIST)
{
bb_simple_perror_msg(fpc);
}
free(fpc);
}
}
=>run_applet_no_and_exit
=>exit(applet_main[applet_no](argc,
argv));最终执行命令函数
void FAST_FUNC run_applet_no_and_exit(int applet_no,
char **argv)
{
int argc
= 1;
while
(argv[argc])//因为前面做了argv++的调整,所以这里做一次动态计算argc值
argc++;
/* Reinit some shared global data */
xfunc_error_retval =
EXIT_FAILURE;
applet_name = APPLET_NAME(applet_no);
if (argc
== 2
&&
strcmp(argv[1],
"--help")
== 0)
{
/* Special case. POSIX says "test --help"
* should be no different from e.g. "test --foo". */
//TODO: just compare applet_no with APPLET_NO_test
if
(!ENABLE_TEST
||
strcmp(applet_name,
"test")
!= 0)
bb_show_usage();
}
if (ENABLE_FEATURE_SUID)
check_suid(applet_no);
exit(applet_main[applet_no](argc,
argv));//好了执行applet_main命令数组中对应的处理函数[luther.gliethttp].
}
浅析busybox查找命令和调用相应命令函数的实现流程框架