C 和内核编程新手 - 所以想知道您是否可以建议我需要更改哪些内容才能获得正确的输出。
我有一个内核模块,它将创建/proc/test_file
当我在 /proc/test_file 上使用 cat 命令时 - 我希望它返回存储在变量“my_number”中的整数值。但现在它返回 ascii 字符 *(* 的 ascii 十进制为 42),而不是我存储在“my_number”中的整数。我假设我错误地调用了该函数,或者以某种方式错误地传递了变量。我还没有真正得到C。
// 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;
}
预期输出:
chris@dev:~$cat /proc/test_file
42
实际产量:
chris@dev:~$cat /proc/test_file
*
我猜问题就在这里,我告诉它“42”是一个字符,它正在转换它或其他东西:
静态 ssize_t read_proc(struct file *file, char __user *buffer, size_t count, loff_t *pos)
编辑:
只是回来根据下面@Tsyvarev 的答案添加工作代码。好处之一是它通过 proc_ops 绕过了对 file_operations 的需求 - 因此它现在可以在较旧的内核版本上工作(如果这是您需要的......)
// 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;
}
seq_file
提供了一种方便的机制,可以轻松创建文件,将某些信息表示为字符串。对于 procfs,此机制可用,例如通过 proc_create_single
功能:
// Pointer to the created file, so it can be deleted in the exit function.
static struct proc_dir_entry *res;
// Number which will be represented by the file.
static int my_number = 42;
// Generates the content of the file
static int my_show(struct seq_file *m, void *v)
{
// Just "print" the value of the integer variable.
// Tail '\n' is useful for pretty output when use 'cat' utility.
seq_printf(m, "%d\n", my_number);
return 0;
}
static int start_module(void)
{
pr_info("\n\nSTARTING PROC ENTRY CREATION\n\n");
// Create a file
res = proc_create_single(TEST_FILE, 0666, NULL, &my_show);
// ... check for errors
return 0;
}
使用这种方法,您只需提供
show
函数(在上面的示例中,它被命名为 my_show
),每当读取文件时都会调用该函数。该函数的目的是生成内容,该内容将返回给用户。
在此类函数中有多个用于生成内容的助手,
seq_printf
就是其中之一。正如你可以从它的名字中猜到的那样,这个助手与 printf
函数非常相似,但使用 seq_file 进行操作。
然后将
show
函数作为参数传递给 proc_create_single
。
描述了
seq_file
机制,例如在内核文档中。该文档仅描述了该机制对“标准”文件的应用,带有 file_operations
。该机制对 procfs 文件的适应由 include/linux/proc_fs.h 标头中的几个函数表示。