Busybox - modutils - 1、lsmod

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

4、depmod
5、modprobe
6、modinfo
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值