🔍 内核日志过滤器

欢迎来到《QEMU-Friendly Linux内核驱动项目50例》的第二章!本章将带你创建一个有趣的字符设备驱动,它能够过滤用户写入的字符串,只将包含特定关键词的日志信息通过printk打印到内核日志中。让我们一起探索这个神奇的内核世界吧!

🎯 项目目标

本项目的目标是创建一个字符设备驱动,实现以下功能:

🏗️ 软件架构

用户空间 字符设备驱动 内核日志 写入数据 过滤后打印 关键词匹配

📋 核心实现步骤

  1. 创建字符设备,并实现必要的文件操作函数(openreleasewrite)。
  2. write函数中,检查用户数据是否包含预设的关键词。
  3. 如果匹配,使用printk打印字符串到内核日志。
  4. 注册设备到系统,并设置适当的权限。

🛠️ 代码实现

关键数据结构

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h>

#define DEVICE_NAME "log_filter"
#define KEYWORD "error"

static int major_num;
static char buffer[256];
static int buffer_size = 0;

文件操作函数

static ssize_t device_write(struct file *filp, const char __user *buf, size_t len, loff_t *off) {
    ssize_t retval = -ENOMEM;
    
    if (len > sizeof(buffer) - 1) {
        pr_err("Input too long\n");
        return -EINVAL;
    }
    
    if (copy_from_user(buffer, buf, len)) {
        return -EFAULT;
    }
    
    buffer[len] = '\0';
    buffer_size = len;
    
    if (strstr(buffer, KEYWORD) != NULL) {
        printk(KERN_INFO "Filtered log: %s\n", buffer);
    }
    
    return len;
}

static struct file_operations fops = {
    .owner = THIS_MODULE,
    .write = device_write,
};

模块初始化和退出

static int __init log_filter_init(void) {
    major_num = register_chrdev(0, DEVICE_NAME, &fops);
    if (major_num < 0) {
        pr_err("Failed to register device: %d\n", major_num);
        return major_num;
    }
    
    pr_info("Log filter device registered with major number %d\n", major_num);
    return 0;
}

static void __exit log_filter_exit(void) {
    unregister_chrdev(major_num, DEVICE_NAME);
    pr_info("Log filter device unregistered\n");
}

module_init(log_filter_init);
module_exit(log_filter_exit);

🧪 测试方法

编译并加载模块后,可以使用以下命令测试设备:

# 创建设备节点
mknod /dev/logfilter c 246 0

# 写入包含关键词的字符串
echo "This is an error message" > /dev/logfilter

# 写入不包含关键词的字符串
echo "This is a normal message" > /dev/logfilter

# 查看内核日志
dmesg | tail

📊 功能对比表

输入内容 是否包含关键词 内核日志输出
"System started normally" 无输出
"Network error: connection failed" "Filtered log: Network error: connection failed"
"Warning: disk space low" 否(除非关键词设置为"warning") 无输出
💡 扩展思考:尝试修改代码,支持多个关键词、正则表达式匹配,或者允许用户通过ioctl动态设置过滤关键词。

🎨 设计亮点