query_module系统调用及示例

query_module 函数详解

1. 函数介绍

query_module 是 Linux 系统中用于查询内核模块信息的系统调用。可以把内核模块想象成”系统功能的插件”——就像你可以为浏览器安装插件来扩展功能一样,Linux 内核也可以通过加载不同的模块来扩展功能。

query_module 就像一个”模块信息查询器”,它允许你查看系统中已加载的内核模块的详细信息,包括模块名称、引用计数、依赖关系等。

2. 函数原型

#include <linux/module.h>

int query_module(const char *name, int which, void *buf, 
                 size_t bufsize, size_t *ret);

3. 功能

query_module 函数用于查询内核模块的各种信息。它可以获取模块列表、模块引用计数、模块符号信息、模块依赖关系等。

4. 参数

  • name: 要查询的模块名称(NULL 表示查询所有模块)
  • which: 查询类型(指定要获取的信息类型)
  • buf: 指向缓冲区的指针,用于存储返回的信息
  • bufsize: 缓冲区大小
  • ret: 指向返回值的指针

5. 查询类型(which 参数)

类型说明
QM_MODULES1获取模块名称列表
QM_REFS2获取模块引用计数
QM_SYMBOLS3获取模块符号信息
QM_INFO4获取模块详细信息
QM_MODINFO5获取模块信息(新版本)

6. module_info 结构体

struct module_info {
    unsigned long   addr;          /* 模块地址 */
    unsigned long   size;          /* 模块大小 */
    unsigned long   flags;         /* 模块标志 */
    long            refcnt;        /* 引用计数 */
    unsigned char   usecount;      /* 使用计数 */
};

7. 返回值

  • 成功: 返回 0
  • 失败: 返回 -1,并设置相应的 errno 错误码

8. 常见错误码

  • EPERM: 权限不足(通常需要 root 权限)
  • EINVAL: 参数无效
  • ENOENT: 指定的模块不存在
  • ENOMEM: 内存不足
  • EFAULT: 参数指针无效
  • ENOSYS: 系统不支持此调用

9. 相似函数或关联函数

  • lsmod: 命令行工具列出模块
  • insmod: 加载内核模块
  • rmmod: 卸载内核模块
  • modprobe: 智能加载内核模块
  • /proc/modules: 模块信息文件
  • /sys/module/: 模块 sysfs 接口
  • kmod: 内核模块管理工具

10. 示例代码

示例1:基础用法 – 查询模块列表

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/module.h>
#include <errno.h>
#include <string.h>

// 注意:query_module 在现代 Linux 系统中可能不可用
// 这里提供概念性示例和现代替代方案

int main() {
    printf("=== query_module 基础示例 ===\n\n");
    
    printf("注意: query_module 是已废弃的系统调用\n");
    printf("在现代 Linux 系统中通常不可用\n\n");
    
    printf("功能说明:\n");
    printf("query_module 用于查询内核模块信息:\n");
    printf("1. QM_MODULES: 获取模块名称列表\n");
    printf("2. QM_REFS: 获取模块引用计数\n");
    printf("3. QM_SYMBOLS: 获取模块符号信息\n");
    printf("4. QM_INFO: 获取模块详细信息\n");
    printf("5. QM_MODINFO: 获取模块信息(新版本)\n");
    
    printf("\n=== 现代替代方案 ===\n");
    printf("1. 使用 /proc/modules 文件\n");
    printf("2. 使用 lsmod 命令\n");
    printf("3. 使用 modinfo 命令\n");
    printf("4. 使用 /sys/module/ 接口\n");
    
    return 0;
}

示例2:现代替代方案 – 模块信息查询

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>

// 通过 /proc/modules 获取模块信息
int get_modules_via_proc() {
    printf("=== 通过 /proc/modules 获取模块信息 ===\n");
    
    FILE *fp = fopen("/proc/modules", "r");
    if (!fp) {
        perror("打开 /proc/modules 失败");
        return -1;
    }
    
    printf("%-25s %-10s %-8s %-15s %s\n", 
           "模块名称", "大小", "使用数", "被谁使用", "状态");
    printf("%-25s %-10s %-8s %-15s %s\n", 
           "--------", "----", "----", "------", "----");
    
    char line[512];
    int count = 0;
    
    while (fgets(line, sizeof(line), fp) && count < 20) {
        char module_name[64];
        unsigned long size;
        int use_count;
        char used_by[256];
        char status[32];
        char address[32];
        
        // 解析 /proc/modules 格式
        int parsed = sscanf(line, "%63s %lu %d %255s %31s %31s",
                           module_name, &size, &use_count, used_by, status, address);
        
        if (parsed >= 4) {
            printf("%-25s %-10lu %-8d %-15s %s\n", 
                   module_name, size, use_count, used_by, 
                   parsed >= 5 ? status : "-");
            count++;
        }
    }
    
    fclose(fp);
    
    if (count == 0) {
        printf("没有模块信息\n");
    } else {
        printf("\n显示了前 %d 个模块\n", count);
    }
    
    return 0;
}

// 通过 /sys/module/ 获取模块详细信息
int get_module_details_via_sysfs() {
    printf("\n=== 通过 /sys/module/ 获取模块详细信息 ===\n");
    
    // 检查 /sys/module/ 目录
    if (access("/sys/module", F_OK) != 0) {
        printf("系统不支持 /sys/module/ 接口\n");
        return -1;
    }
    
    // 列出几个模块的详细信息
    const char *modules[] = {"usbcore", "tcp", "ext4", "loop", NULL};
    
    for (int i = 0; modules[i]; i++) {
        char module_path[256];
        snprintf(module_path, sizeof(module_path), "/sys/module/%s", modules[i]);
        
        if (access(module_path, F_OK) == 0) {
            printf("\n模块: %s\n", modules[i]);
            
            // 检查模块参数
            char param_path[256];
            snprintf(param_path, sizeof(param_path), "%s/parameters", module_path);
            if (access(param_path, F_OK) == 0) {
                printf("  ✓ 支持参数配置\n");
            }
            
            // 检查模块引用
            char refcnt_path[256];
            snprintf(refcnt_path, sizeof(refcnt_path), "%s/refcnt", module_path);
            FILE *refcnt_fp = fopen(refcnt_path, "r");
            if (refcnt_fp) {
                char refcnt[32];
                if (fgets(refcnt, sizeof(refcnt), refcnt_fp)) {
                    printf("  引用计数: %s", refcnt);
                }
                fclose(refcnt_fp);
            }
            
            // 检查模块状态
            char initstate_path[256];
            snprintf(initstate_path, sizeof(initstate_path), "%s/initstate", module_path);
            FILE *initstate_fp = fopen(initstate_path, "r");
            if (initstate_fp) {
                char initstate[32];
                if (fgets(initstate, sizeof(initstate), initstate_fp)) {
                    printf("  初始化状态: %s", initstate);
                }
                fclose(initstate_fp);
            }
        }
    }
    
    return 0;
}

// 模拟 query_module 功能
void simulate_query_module() {
    printf("\n=== 模拟 query_module 功能 ===\n");
    
    printf("QM_MODULES (获取模块列表):\n");
    printf("  模块1: usbcore\n");
    printf("  模块2: tcp\n");
    printf("  模块3: ext4\n");
    printf("  模块4: loop\n");
    printf("  模块5: sd_mod\n");
    
    printf("\nQM_INFO (获取模块详细信息):\n");
    printf("  模块名称: usbcore\n");
    printf("  地址: 0xffffffffc0000000\n");
    printf("  大小: 123456 字节\n");
    printf("  引用计数: 5\n");
    printf("  状态: Live\n");
    
    printf("\nQM_REFS (获取引用计数):\n");
    printf("  usbcore: 5\n");
    printf("  tcp: 3\n");
    printf("  ext4: 2\n");
    printf("  loop: 1\n");
    
    printf("\nQM_SYMBOLS (获取符号信息):\n");
    printf("  usb_register: 0xffffffffc0001000\n");
    printf("  usb_deregister: 0xffffffffc0002000\n");
    printf("  usb_submit_urb: 0xffffffffc0003000\n");
}

int main() {
    printf("=== 内核模块查询系统 ===\n\n");
    
    // 显示系统信息
    printf("系统信息:\n");
    printf("  用户 ID: %d\n", getuid());
    printf("  进程 ID: %d\n", getpid());
    
    // 检查权限
    if (getuid() != 0) {
        printf("  注意: 某些模块信息需要 root 权限\n");
    }
    printf("\n");
    
    // 通过 /proc/modules 获取信息
    get_modules_via_proc();
    
    // 通过 /sys/module/ 获取详细信息
    get_module_details_via_sysfs();
    
    // 模拟 query_module 功能
    simulate_query_module();
    
    printf("\n=== 现代模块管理工具 ===\n");
    printf("常用的模块管理命令:\n");
    printf("1. lsmod              # 列出已加载模块\n");
    printf("2. modinfo module     # 显示模块信息\n");
    printf("3. insmod module.ko   # 加载模块\n");
    printf("4. rmmod module       # 卸载模块\n");
    printf("5. modprobe module    # 智能加载模块\n");
    printf("6. depmod             # 生成模块依赖\n");
    printf("\n");
    
    printf("模块信息文件:\n");
    printf("1. /proc/modules      # 已加载模块列表\n");
    printf("2. /proc/devices      # 设备号信息\n");
    printf("3. /sys/module/       # 模块 sysfs 接口\n");
    printf("4. /lib/modules/       # 模块文件目录\n");
    
    return 0;
}

示例3:完整的模块管理工具

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>

// 配置结构体
struct module_config {
    int list_modules;      // 列出模块
    int show_details;       // 显示详细信息
    int verbose;            // 详细输出
    int show_refs;          // 显示引用计数
    int show_symbols;       // 显示符号信息
    char *module_name;       // 指定模块名称
    char *search_pattern;    // 搜索模式
};

// 模块信息结构体
struct module_info {
    char name[256];
    unsigned long size;
    int ref_count;
    char used_by[512];
    char status[32];
    unsigned long address;
};

// 通过 /proc/modules 解析模块信息
int parse_proc_modules(struct module_info *modules, int max_modules) {
    FILE *fp = fopen("/proc/modules", "r");
    if (!fp) {
        return -1;
    }
    
    int count = 0;
    char line[1024];
    
    while (fgets(line, sizeof(line), fp) && count < max_modules) {
        struct module_info *mod = &modules[count];
        char extra[512];
        
        // 解析 /proc/modules 格式
        int parsed = sscanf(line, "%255s %lu %d %511s %31s %31s",
                           mod->name, &mod->size, &mod->ref_count, 
                           mod->used_by, mod->status, extra);
        
        if (parsed >= 4) {
            count++;
        }
    }
    
    fclose(fp);
    return count;
}

// 显示模块列表
void show_module_list(struct module_info *modules, int count, 
                     const struct module_config *config) {
    printf("=== 内核模块列表 ===\n");
    printf("%-25s %-12s %-8s %-20s %s\n", 
           "模块名称", "大小", "引用数", "被谁使用", "状态");
    printf("%-25s %-12s %-8s %-20s %s\n", 
           "--------", "----", "----", "------", "----");
    
    int displayed = 0;
    for (int i = 0; i < count && displayed < 50; i++) {
        struct module_info *mod = &modules[i];
        
        // 如果指定了搜索模式,进行过滤
        if (config->search_pattern) {
            if (strstr(mod->name, config->search_pattern) == NULL) {
                continue;
            }
        }
        
        // 如果指定了模块名称,精确匹配
        if (config->module_name) {
            if (strcmp(mod->name, config->module_name) != 0) {
                continue;
            }
        }
        
        printf("%-25s %-12lu %-8d %-20s %s\n", 
               mod->name, mod->size, mod->ref_count, 
               mod->used_by, mod->status);
        displayed++;
    }
    
    if (displayed == 0) {
        printf("没有找到匹配的模块\n");
    } else if (displayed < count) {
        printf("\n显示了 %d 个匹配模块 (总共 %d 个)\n", displayed, count);
    }
}

// 显示模块详细信息
void show_module_details(struct module_info *modules, int count, 
                        const struct module_config *config) {
    printf("\n=== 模块详细信息 ===\n");
    
    int found = 0;
    for (int i = 0; i < count; i++) {
        struct module_info *mod = &modules[i];
        
        // 检查是否匹配
        if (config->module_name) {
            if (strcmp(mod->name, config->module_name) != 0) {
                continue;
            }
        } else if (config->search_pattern) {
            if (strstr(mod->name, config->search_pattern) == NULL) {
                continue;
            }
        }
        
        printf("\n模块: %s\n", mod->name);
        printf("  大小: %lu 字节 (%.2f KB)\n", mod->size, (double)mod->size / 1024);
        printf("  引用计数: %d\n", mod->ref_count);
        printf("  被谁使用: %s\n", mod->used_by);
        printf("  状态: %s\n", mod->status);
        
        // 显示 sysfs 信息
        char sysfs_path[256];
        snprintf(sysfs_path, sizeof(sysfs_path), "/sys/module/%s", mod->name);
        
        if (access(sysfs_path, F_OK) == 0) {
            printf("  Sysfs 路径: %s\n", sysfs_path);
            
            // 检查参数
            char param_path[256];
            snprintf(param_path, sizeof(param_path), "%s/parameters", sysfs_path);
            if (access(param_path, F_OK) == 0) {
                printf("  ✓ 支持运行时参数配置\n");
            }
            
            // 检查引用计数
            char refcnt_path[256];
            snprintf(refcnt_path, sizeof(refcnt_path), "%s/refcnt", sysfs_path);
            FILE *refcnt_fp = fopen(refcnt_path, "r");
            if (refcnt_fp) {
                char refcnt[32];
                if (fgets(refcnt, sizeof(refcnt), refcnt_fp)) {
                    printf("  当前引用计数: %s", refcnt);
                }
                fclose(refcnt_fp);
            }
        }
        
        found++;
        if (config->module_name) {
            break;  // 只显示指定模块
        }
        
        if (found >= 5) {
            printf("\n只显示前 5 个匹配模块的详细信息\n");
            break;
        }
    }
    
    if (found == 0) {
        if (config->module_name) {
            printf("未找到模块: %s\n", config->module_name);
        } else if (config->search_pattern) {
            printf("未找到匹配模式 '%s' 的模块\n", config->search_pattern);
        } else {
            printf("没有模块信息\n");
        }
    }
}

// 显示系统模块统计
void show_module_statistics(struct module_info *modules, int count) {
    printf("\n=== 模块统计信息 ===\n");
    printf("总模块数: %d\n", count);
    
    if (count > 0) {
        // 统计引用计数
        int total_refs = 0;
        int max_refs = 0;
        int zero_refs = 0;
        unsigned long total_size = 0;
        
        for (int i = 0; i < count; i++) {
            total_refs += modules[i].ref_count;
            total_size += modules[i].size;
            
            if (modules[i].ref_count > max_refs) {
                max_refs = modules[i].ref_count;
            }
            
            if (modules[i].ref_count == 0) {
                zero_refs++;
            }
        }
        
        printf("总大小: %.2f MB\n", (double)total_size / (1024 * 1024));
        printf("平均引用计数: %.2f\n", (double)total_refs / count);
        printf("最大引用计数: %d\n", max_refs);
        printf("零引用模块数: %d\n", zero_refs);
        
        // 显示最常见的模块
        printf("\n最常用的模块:\n");
        int shown = 0;
        for (int i = 0; i < count && shown < 5; i++) {
            if (modules[i].ref_count > 0) {
                printf("  %s (%d 引用)\n", modules[i].name, modules[i].ref_count);
                shown++;
            }
        }
    }
}

// 显示帮助信息
void show_help(const char *program_name) {
    printf("用法: %s [选项]\n", program_name);
    printf("\n选项:\n");
    printf("  -l, --list              列出所有模块\n");
    printf("  -d, --details           显示模块详细信息\n");
    printf("  -r, --refs              显示引用计数\n");
    printf("  -n, --name=MODULE       指定模块名称\n");
    printf("  -s, --search=PATTERN    搜索模块名称\n");
    printf("  -v, --verbose           详细输出\n");
    printf("  -S, --statistics         显示统计信息\n");
    printf("  -h, --help              显示此帮助信息\n");
    printf("\n示例:\n");
    printf("  %s -l                          # 列出所有模块\n", program_name);
    printf("  %s -d -n usbcore               # 显示 usbcore 模块详细信息\n", program_name);
    printf("  %s -l -s usb                   # 列出包含 usb 的模块\n", program_name);
    printf("  %s -S                          # 显示模块统计信息\n", program_name);
    printf("  %s -d -s network                # 显示网络相关模块详情\n", program_name);
}

int main(int argc, char *argv[]) {
    struct module_config config = {
        .list_modules = 0,
        .show_details = 0,
        .verbose = 0,
        .show_refs = 0,
        .show_symbols = 0,
        .module_name = NULL,
        .search_pattern = NULL
    };
    
    printf("=== 内核模块查询工具 ===\n\n");
    
    // 解析命令行参数
    static struct option long_options[] = {
        {"list",        no_argument,       0, 'l'},
        {"details",     no_argument,       0, 'd'},
        {"refs",        no_argument,       0, 'r'},
        {"symbols",     no_argument,       0, 'y'},
        {"name",        required_argument, 0, 'n'},
        {"search",      required_argument, 0, 's'},
        {"verbose",     no_argument,       0, 'v'},
        {"statistics",  no_argument,       0, 'S'},
        {"help",        no_argument,       0, 'h'},
        {0, 0, 0, 0}
    };
    
    int opt;
    while ((opt = getopt_long(argc, argv, "ldryn:s:vSh", long_options, NULL)) != -1) {
        switch (opt) {
            case 'l':
                config.list_modules = 1;
                break;
            case 'd':
                config.show_details = 1;
                break;
            case 'r':
                config.show_refs = 1;
                break;
            case 'y':
                config.show_symbols = 1;
                break;
            case 'n':
                config.module_name = optarg;
                break;
            case 's':
                config.search_pattern = optarg;
                break;
            case 'v':
                config.verbose = 1;
                break;
            case 'S':
                config.list_modules = 1;
                break;
            case 'h':
                show_help(argv[0]);
                return 0;
            default:
                fprintf(stderr, "使用 '%s --help' 查看帮助信息\n", argv[0]);
                return 1;
        }
    }
    
    // 如果没有指定操作,默认列出模块
    if (!config.list_modules && !config.show_details && 
        !config.show_refs && !config.show_symbols) {
        config.list_modules = 1;
    }
    
    // 显示系统信息
    if (config.verbose) {
        printf("系统信息:\n");
        printf("  用户 ID: %d\n", getuid());
        printf("  进程 ID: %d\n", getpid());
        printf("  当前目录: %s\n", getcwd(NULL, 0));
        printf("\n");
    }
    
    // 读取模块信息
    struct module_info modules[500];
    int module_count = parse_proc_modules(modules, 500);
    
    if (module_count == -1) {
        printf("错误: 无法读取模块信息\n");
        printf("可能的原因:\n");
        printf("1. 系统不支持 /proc/modules\n");
        printf("2. 权限不足\n");
        printf("3. 内核不支持模块\n");
        return 1;
    }
    
    if (config.verbose) {
        printf("读取到 %d 个模块\n\n", module_count);
    }
    
    // 执行相应操作
    if (config.list_modules) {
        show_module_list(modules, module_count, &config);
    }
    
    if (config.show_details) {
        show_module_details(modules, module_count, &config);
    }
    
    if (optind == 1) {  // 如果没有指定参数,显示统计信息
        show_module_statistics(modules, module_count);
    }
    
    printf("\n=== 模块管理最佳实践 ===\n");
    printf("模块安全建议:\n");
    printf("1. 只加载可信的模块\n");
    printf("2. 定期更新模块\n");
    printf("3. 监控模块加载活动\n");
    printf("4. 限制模块加载权限\n");
    printf("5. 使用签名验证模块\n");
    printf("\n");
    
    printf("模块性能优化:\n");
    printf("1. 卸载不用的模块\n");
    printf("2. 优化模块参数\n");
    printf("3. 监控模块内存使用\n");
    printf("4. 使用模块黑名单\n");
    printf("5. 合理配置模块依赖\n");
    printf("\n");
    
    printf("现代替代方案:\n");
    printf("1. /proc/modules: 模块列表信息\n");
    printf("2. /sys/module/: 模块 sysfs 接口\n");
    printf("3. modinfo: 模块详细信息\n");
    printf("4. lsmod: 列出模块\n");
    printf("5. modprobe: 智能模块加载\n");
    printf("6. rmmod: 卸载模块\n");
    
    return 0;
}

编译和运行说明

# 编译示例程序
gcc -o query_module_example1 example1.c
gcc -o query_module_example2 example2.c
gcc -o query_module_example3 example3.c

# 运行示例
./query_module_example1
./query_module_example2
./query_module_example3 --help
./query_module_example3 -l
./query_module_example3 -d -n usbcore
./query_module_example3 -l -s usb
./query_module_example3 -S

系统要求检查

# 检查模块支持
ls /proc/modules
ls /sys/module/

# 检查模块工具
which lsmod
which modinfo
which modprobe
which rmmod

# 查看内核模块目录
ls /lib/modules/$(uname -r)/kernel/

# 检查内核配置
grep -i module /boot/config-$(uname -r)

重要注意事项

  1. 已废弃query_module 在现代 Linux 系统中已废弃
  2. 权限要求: 某些模块信息需要 root 权限
  3. 系统依赖: 需要内核支持模块和相应的文件系统接口
  4. 错误处理: 始终检查返回值和 errno
  5. 兼容性: 不同内核版本可能有差异

实际应用场景

  1. 系统监控: 监控内核模块加载和卸载
  2. 安全审计: 审计系统中加载的模块
  3. 性能分析: 分析模块对系统性能的影响
  4. 故障诊断: 诊断模块相关的问题
  5. 自动化管理: 自动化模块管理脚本

现代替代方案详解

使用 /proc/modules

// 读取模块列表
int read_module_list() {
    FILE *fp = fopen("/proc/modules", "r");
    if (!fp) return -1;
    
    char line[1024];
    while (fgets(line, sizeof(line), fp)) {
        char name[256], used_by[256], status[32];
        unsigned long size;
        int ref_count;
        
        if (sscanf(line, "%255s %lu %d %255s %31s", 
                  name, &size, &ref_count, used_by, status) >= 4) {
            printf("%-20s %8lu %3d %s\n", name, size, ref_count, used_by);
        }
    }
    
    fclose(fp);
    return 0;
}

使用 /sys/module/ 接口

// 读取模块详细信息
int read_module_details(const char *module_name) {
    char path[256];
    
    // 读取引用计数
    snprintf(path, sizeof(path), "/sys/module/%s/refcnt", module_name);
    FILE *fp = fopen(path, "r");
    if (fp) {
        char refcnt[32];
        if (fgets(refcnt, sizeof(refcnt), fp)) {
            printf("引用计数: %s", refcnt);
        }
        fclose(fp);
    }
    
    return 0;
}

使用命令行工具

# 列出模块
lsmod

# 显示模块信息
modinfo module_name

# 加载模块
sudo modprobe module_name

# 卸载模块
sudo rmmod module_name

# 生成依赖关系
sudo depmod

最佳实践

// 安全的模块信息查询函数
int safe_query_modules(struct module_info *modules, int max_count) {
    // 验证参数
    if (!modules || max_count <= 0) {
        errno = EINVAL;
        return -1;
    }
    
    // 检查文件存在性
    if (access("/proc/modules", F_OK) != 0) {
        errno = ENOENT;
        return -1;
    }
    
    // 读取模块信息
    return parse_proc_modules(modules, max_count);
}

// 模块安全检查
int validate_module_security(const char *module_name) {
    // 检查模块名称合法性
    if (!module_name || strlen(module_name) == 0) {
        return -1;
    }
    
    // 检查是否在黑名单中
    // 这里简化处理,实际应用中可以检查 /etc/modprobe.d/blacklist.conf
    const char *blacklisted[] = {"firewire-sbp2", "usbmouse", NULL};
    for (int i = 0; blacklisted[i]; i++) {
        if (strcmp(module_name, blacklisted[i]) == 0) {
            printf("警告: 模块 '%s' 在黑名单中\n", module_name);
            return -1;
        }
    }
    
    return 0;
}

这些示例展示了 query_module 函数的概念以及现代 Linux 系统中查询内核模块信息的各种替代方案,帮助你全面了解 Linux 系统中的模块管理机制。

query_module系统调用及示例-CSDN博客

此条目发表在linux文章分类目录。将固定链接加入收藏夹。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注