如何在用户态C程序中获取Linux内核模块版本信息?
在用户态C程序中获取Linux内核模块的MODULE_VERSION信息
当然可以实现,下面给你三种靠谱的方案,按需选择:
方案一:读取sysfs接口(优先推荐,最简单高效)
内核模块加载后,Linux会自动在/sys/module/<你的模块名>/version路径下生成一个文本文件,里面直接存着MODULE_VERSION定义的版本号。直接读取这个文件就行,不需要额外依赖,权限要求也低(普通用户一般就能读)。
代码示例:
#include <stdio.h> #include <stdlib.h> #include <string.h> // 替换成你的模块名 #define MODULE_NAME "my_test_driver" #define SYSFS_VERSION_PATH "/sys/module/" MODULE_NAME "/version" char* get_module_version_sysfs() { FILE* fp = fopen(SYSFS_VERSION_PATH, "r"); if (!fp) { perror("Failed to open sysfs version file"); return NULL; } // 分配足够的内存存版本号(256字节足够大部分场景) char* version = malloc(256); if (!version) { perror("Failed to allocate memory"); fclose(fp); return NULL; } if (fgets(version, 256, fp) == NULL) { perror("Failed to read version string"); free(version); fclose(fp); return NULL; } // 去掉换行符 version[strcspn(version, "\n")] = '\0'; fclose(fp); return version; } int main() { char* ver = get_module_version_sysfs(); if (ver) { printf("Module version: %s\n", ver); free(ver); } return 0; }
方案二:调用modinfo命令解析输出
如果你不想直接操作文件,也可以通过popen调用系统自带的modinfo命令,捕获它的输出后提取版本号。这种方式不用关心底层实现,但依赖系统有modinfo工具。
代码示例:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MODULE_NAME "my_test_driver" char* get_module_version_modinfo() { char cmd[256]; // 用-F参数直接指定输出version字段,省得自己解析全量输出 snprintf(cmd, sizeof(cmd), "modinfo -F version " MODULE_NAME); FILE* fp = popen(cmd, "r"); if (!fp) { perror("Failed to run modinfo command"); return NULL; } char* version = malloc(256); if (!version) { perror("Failed to allocate memory"); pclose(fp); return NULL; } if (fgets(version, 256, fp) == NULL) { perror("Failed to read modinfo output"); free(version); pclose(fp); return NULL; } version[strcspn(version, "\n")] = '\0'; pclose(fp); return version; } int main() { char* ver = get_module_version_modinfo(); if (ver) { printf("Module version: %s\n", ver); free(ver); } return 0; }
方案三:直接解析内核模块的ELF文件
MODULE_VERSION宏会把版本信息存在内核模块(.ko文件)的.modinfo节里,内容是version=xxx这样的键值对。如果模块还没加载,或者你想直接读模块文件本身,可以用这种方式,需要依赖libelf库来解析ELF格式。
代码示例(编译时要链接libelf:gcc -o get_ver get_ver.c -lelf):
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <libelf.h> #include <gelf.h> // 替换成你的模块文件路径 #define MODULE_FILE "/home/user/my_test_driver.ko" char* get_module_version_elf() { // 初始化ELF库版本 if (elf_version(EV_CURRENT) == EV_NONE) { fprintf(stderr, "ELF library version mismatch\n"); return NULL; } int fd = open(MODULE_FILE, O_RDONLY); if (fd < 0) { perror("Failed to open module file"); return NULL; } Elf* elf = elf_begin(fd, ELF_C_READ, NULL); if (!elf) { perror("Failed to initialize ELF handle"); close(fd); return NULL; } Elf_Scn* scn = NULL; GElf_Shdr shdr; // 遍历所有节,找到.modinfo while ((scn = elf_nextscn(elf, scn)) != NULL) { gelf_getshdr(scn, &shdr); char* section_name = elf_strptr(elf, elf_getshdrstrndx(elf), shdr.sh_name); if (strcmp(section_name, ".modinfo") == 0) { Elf_Data* data = elf_getdata(scn, NULL); if (!data) { perror("Failed to read .modinfo section data"); elf_end(elf); close(fd); return NULL; } // 查找version=字段 char* modinfo_buf = (char*)data->d_buf; char* version_start = strstr(modinfo_buf, "version="); if (!version_start) { fprintf(stderr, "Version info not found in .modinfo section\n"); elf_end(elf); close(fd); return NULL; } // 跳过"version="前缀,复制版本号 version_start += strlen("version="); char* version = strdup(version_start); if (!version) { perror("Failed to duplicate version string"); elf_end(elf); close(fd); return NULL; } elf_end(elf); close(fd); return version; } } fprintf(stderr, ".modinfo section not found in module file\n"); elf_end(elf); close(fd); return NULL; } int main() { char* ver = get_module_version_elf(); if (ver) { printf("Module version: %s\n", ver); free(ver); } return 0; }
内容的提问来源于stack exchange,提问作者rickastley
相关产品推荐
相关产品推荐

