Linux内核模块:如何让/proc文件返回整数而非ASCII字符
关于/proc模块返回ASCII字符而非数字的问题分析与解决
我是C语言与内核编程新手,编写了一个创建/proc/test_file的Linux内核模块。执行cat /proc/test_file时,期望返回变量my_number的整数值42,但实际返回ASCII字符*(十进制ASCII值为42)。以下是初始代码和修改后的可行代码,分析问题原因及修正方法如下:
问题原因分析
- 直接拷贝二进制数据的错误:初始代码中通过
copy_to_user直接将int类型变量my_number的二进制内存内容拷贝到用户空间。my_number=42作为32位int存储的二进制值是0x0000002A,用户空间的cat工具会把这段数据当作ASCII字符流解析,取低字节的0x2A对应ASCII字符*,因此输出不符合预期。 - 缺少格式化转换步骤:/proc文件的核心是向用户空间返回可读的文本内容,而初始代码没有将整数42转换为字符串"42",直接传递了二进制数值,导致解析错误。
修正方法说明
- 采用seq_file接口处理文本输出:内核提供的
seq_file机制专门简化/proc文件的文本生成,seq_printf函数可以安全地将整数格式化为字符串,自动处理内存管理和数据拷贝,避免手动操作的失误。 - 使用简化的proc创建接口:用
proc_create_single替代proc_create,该接口针对只读的简单/proc文件做了封装,只需要实现一个负责格式化输出的回调函数,无需手动处理文件读写的偏移量、字节计数等细节,降低出错概率。
初始代码
// Includes #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/proc_fs.h> // License MODULE_LICENSE("GPL"); // Defines #define TEST_FILE "test_file" // Declarations & Variables static int start_module(void); static void exit_module(void); static void create_proc_fs_file(void); static void cleanup_proc_fs_file(void); static struct proc_dir_entry *res; static int my_number = 42; static ssize_t read_proc(struct file *file, char __user *buffer, size_t count, loff_t *pos); static struct proc_ops test_fops = { .proc_read = read_proc }; // Entry and Exit module_init(start_module); module_exit(exit_module); // Code static int start_module(void) { pr_info("\n\nSTARTING PROC ENTRY CREATION\n\n"); create_proc_fs_file(); return 0; } static void exit_module(void) { cleanup_proc_fs_file(); pr_info("\n\nExiting Module. Bye Bye!\n\n"); } static void create_proc_fs_file(void) { // Create /proc/test_file res = proc_create(TEST_FILE, 0666, NULL, &test_fops); if(!res){ pr_err("\nFailed to create /proc/test_file\n\n"); }else{ pr_info("\nSuccessfully create /proc/test_file\n\n"); } } static void cleanup_proc_fs_file(void) { pr_info("\nRemoving /proc/test_file subtree....\n\n"); remove_proc_subtree(TEST_FILE, NULL); } static ssize_t read_proc(struct file *file, char __user *buffer, size_t count, loff_t *pos) { size_t len = sizeof(my_number); pr_info("\nproc file read....\n\n"); if (*pos >= len) { return 0; // End of file } if (count > len - *pos) { count = len - *pos; } if(copy_to_user(buffer, &my_number + *pos, count)){ return -EFAULT; } *pos += count; return count; }
可行代码
// Includes #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> // License MODULE_LICENSE("GPL"); // Defines #define TEST_FILE "test_file" // Declarations & Variables static int start_module(void); static void exit_module(void); static void create_proc_fs_file(void); static void cleanup_proc_fs_file(void); static struct proc_dir_entry *res; static int my_number = 42; static int print_out(struct seq_file *m, void *v); // Entry and Exit module_init(start_module); module_exit(exit_module); // Code static int start_module(void) { pr_info("\n\nSTARTING PROC ENTRY CREATION\n\n"); create_proc_fs_file(); return 0; } static void exit_module(void) { cleanup_proc_fs_file(); pr_info("\n\nExiting Module. Bye Bye!\n\n"); } static void create_proc_fs_file(void) { // Create /proc/test_file res = proc_create_single(TEST_FILE, 0666, NULL, &print_out); if(!res){ pr_err("\nFailed to create /proc/test_file\n\n"); }else{ pr_info("\nSuccessfully create /proc/test_file\n\n"); } } static void cleanup_proc_fs_file(void) { pr_info("\nRemoving /proc/test_file subtree....\n\n"); remove_proc_subtree(TEST_FILE, NULL); } static int print_out(struct seq_file *m, void *v) { seq_printf(m, "Count of Packets: %d\n", my_number); return 0; }
内容的提问来源于stack exchange,提问作者Chris S
相关产品推荐
相关产品推荐

