在Linux内核模块中,如何让/proc文件返回整数而不是字符

7vhp5slm  于 2023-10-16  发布在  Linux
关注(0)|答案(1)|浏览(126)

C和内核编程新手-所以想知道你是否可以建议我需要改变什么才能得到正确的输出。
我有一个内核模块,它将创建/proc/test_file
当我在/proc/test_file上使用cat命令时-我希望它返回存储在变量“my_number”中的整数值。但是现在它返回的是asynchronous字符 的asynchronous decimal是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”是一个char,它正在转换它或其他东西:
静态ssize_t read_proc(结构文件 * 文件,*char __user * 缓冲区 *,size_t计数,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;
    
}
lf5gs5x2

lf5gs5x21#

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机制描述如下:在kernel documentation中。该文档仅描述了该机制对“标准”文件的应用,即file_operations。该机制对procfs文件的适应由include/linux/proc_fs.h头文件中的几个函数表示。

相关问题