busybox 1_35_stable
命令:insmod、rmmod、lsmod、depmod、modprobe、modinfo
hs:~/gitwork/busybox$ ls modutils/
Config.in depmod.c insmod.c Kbuild.src modinfo.c modprobe-small.c modutils.c rmmod.c
Config.src depmod_process.sh Kbuild lsmod.c modprobe.c modutils-24.c modutils.h
上面的命令来源有两个。一个是分别对应的.c文件,一个是modprobe-small.c文件中。通过是否使用宏:CONFIG_MODPROBE_SMALL 来决定。默认是使用modprobe-small.c中的命令。
可以看出只有 lsmod modprobe depmod insmod rmmod几个命令。
1、lsmod
1.1、modprobe-small --> lsmod
#if ENABLE_LSMOD
int lsmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int lsmod_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
{
xprint_and_close_file(xfopen_for_read("/proc/modules"));
return EXIT_SUCCESS;
}
#endif
函数很简单,就调用了 xprint_and_close_file和xfopen_for_read两个函数。
从函数名字可以大致看出以只读方式打开/proc/modules文件,打印出文件内容并关闭文件。
先看结果:执行 cat /proc/modules 和 ./busybox lsmod。
两条命令输出一致,即 busybox -> modprobe-small中的lsmod只是打印/proc/modules文件中的内容。
1.2、非modprobe-small中的 lsmod
- 配置
执行 make menuconfig
Linux Module Utilities —>
[ ] Simplified modutils
如上去掉选择,保存。
- 重新生成busybox 执行,./busybox lsmod。输出结果不同于1.1中的单纯打印。与ubuntu中的lsmod输出结果一致。
// modutils/lsmod.c
int lsmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int lsmod_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
{
#if ENABLE_FEATURE_LSMOD_PRETTY_2_6_OUTPUT
char *token[4];
parser_t *parser = config_open("/proc/modules");
init_unicode();
printf("%-24sSize Used by", "Module");
check_tainted();
if (ENABLE_FEATURE_2_4_MODULES
&& get_linux_version_code() < KERNEL_VERSION(2,6,0)
) {
while (config_read(parser, token, 4, 3, "# \t", PARSE_NORMAL)) {
if (token[3] != NULL && token[3][0] == '[') {
token[3]++;
token[3][strlen(token[3])-1] = '\0';
} else
token[3] = (char *) "";
# if ENABLE_UNICODE_SUPPORT
{
uni_stat_t uni_stat;
char *uni_name = unicode_conv_to_printable(&uni_stat, token[0]);
unsigned pad_len = (uni_stat.unicode_width > 19) ? 0 : 19 - uni_stat.unicode_width;
printf("%s%*s %8s %2s %s\n", uni_name, pad_len, "", token[1], token[2], token[3]);
free(uni_name);
}
# else
printf("%-19s %8s %2s %s\n", token[0], token[1], token[2], token[3]);
# endif
}
} else {
while (config_read(parser, token, 4, 4, "# \t", PARSE_NORMAL & ~PARSE_GREEDY)) {
// N.B. token[3] is either '-' (module is not used by others)
// or comma-separated list ended by comma
// so trimming the trailing char is just what we need!
if (token[3][0])
token[3][strlen(token[3]) - 1] = '\0';
# if ENABLE_UNICODE_SUPPORT
{
uni_stat_t uni_stat;
char *uni_name = unicode_conv_to_printable(&uni_stat, token[0]);
unsigned pad_len = (uni_stat.unicode_width > 19) ? 0 : 19 - uni_stat.unicode_width;
printf("%s%*s %8s %2s %s\n", uni_name, pad_len, "", token[1], token[2], token[3]);
free(uni_name);
}
# else
printf("%-19s %8s %2s %s\n", token[0], token[1], token[2], token[3]);
# endif
}
}
if (ENABLE_FEATURE_CLEAN_UP)
config_close(parser);
#else
check_tainted();
xprint_and_close_file(xfopen_for_read("/proc/modules"));
#endif
return EXIT_SUCCESS;
}
函数也很简单:config_open函数打开/proc/modules文件。
while中config_read循环读取一行并解析成4个元素,分别是模块名、大小、使用者PID和使用者名。
config_close关闭文件。
总结:lsmod命令只是把/proc/modules文件中的内容按照一定格式打印出来,可以合理猜测 lsusb lspci等类似命令同理。
2、insmod
// modutils/insmod.c
int insmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int insmod_main(int argc UNUSED_PARAM, char **argv)
{
char *filename;
int rc;
/* Compat note:
* 2.6 style insmod has no options and required filename
* (not module name - .ko can't be omitted).
* 2.4 style insmod can take module name without .o
* and performs module search in default directories
* or in $MODPATH.
*/
IF_FEATURE_2_4_MODULES(
getopt32(argv, INSMOD_OPTS INSMOD_ARGS);
argv += optind - 1;
);
filename = *++argv;
if (!filename)
bb_show_usage();
rc = bb_init_module(filename, parse_cmdline_module_options(argv, /*quote_spaces:*/ 0));
if (rc)
bb_error_msg("can't insert '%s': %s", filename, moderror(rc));
return rc;
}
// modutils/modutils.c
#define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts)
int FAST_FUNC bb_init_module(const char *filename, const char *options)
{
size_t image_size;
char *image;
int rc;
bool mmaped;
if (!options)
options = "";
//TODO: audit bb_init_module_24 to match error code convention
#if ENABLE_FEATURE_2_4_MODULES
if (get_linux_version_code() < KERNEL_VERSION(2,6,0))
return bb_init_module_24(filename, options);
#endif
/*
* First we try finit_module if available. Some kernels are configured
* to only allow loading of modules off of secure storage (like a read-
* only rootfs) which needs the finit_module call. If it fails, we fall
* back to normal module loading to support compressed modules.
*/
# ifdef __NR_finit_module
{
int fd = open(filename, O_RDONLY | O_CLOEXEC);
if (fd >= 0) {
rc = finit_module(fd, options, 0) != 0;
close(fd);
if (rc == 0)
return rc;
}
}
# endif
image_size = INT_MAX - 4095;
mmaped = 0;
image = try_to_mmap_module(filename, &image_size);
if (image) {
mmaped = 1;
} else {
errno = ENOMEM; /* may be changed by e.g. open errors below */
image = xmalloc_open_zipped_read_close(filename, &image_size);
if (!image)
return -errno;
}
errno = 0;
init_module(image, image_size, options);
rc = errno;
if (mmaped)
munmap(image, image_size);
else
free(image);
return rc;
}
代码比较容易看出,执行insmod xxx.ko命令后:
1、先打开ko文件
2、执行mmap,映射到内存中。
3、执行init_module(系统调用 __NR_init_module
)
3、rmmod
// modutils/rmmod.c
int rmmod_main(int argc UNUSED_PARAM, char **argv)
{
int n, err;
unsigned flags = O_NONBLOCK | O_EXCL;
/* Parse command line. */
n = getopt32(argv, "wfas"); // -s ignored
argv += optind;
if (n & 1) // --wait
flags &= ~O_NONBLOCK;
if (n & 2) // --force
flags |= O_TRUNC;
if (n & 4) {
/* Unload _all_ unused modules via NULL delete_module() call */
err = bb_delete_module(NULL, flags);
if (err && err != EFAULT)
bb_simple_perror_msg_and_die("rmmod");
return EXIT_SUCCESS;
}
if (!*argv)
bb_show_usage();
n = ENABLE_FEATURE_2_4_MODULES && get_linux_version_code() < KERNEL_VERSION(2,6,0);
while (*argv) {
char modname[MODULE_NAME_LEN];
const char *bname;
bname = bb_basename(*argv++);
if (n)
safe_strncpy(modname, bname, MODULE_NAME_LEN);
else
filename2modname(bname, modname);
err = bb_delete_module(modname, flags);
if (err)
bb_perror_msg_and_die("can't unload module '%s'",
modname);
}
return EXIT_SUCCESS;
}
// modutils/modutils.c
#define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags)
int FAST_FUNC bb_delete_module(const char *module, unsigned int flags)
{
errno = 0;
delete_module(module, flags);
return errno;
}
执行rmmod命令后比较简单:就是执行了系统调用 __NR_delete_module