# Deepin read-only filesystem error watcher

这是一个用于监控 Deepin 系统 /usr 等不可变目录下只读文件系统错误消息的工具，使用 Linux Generic Netlink 机制与内核模块通信。

项目提供了**三种客户端实现**,可根据使用场景选择:

1. **C 客户端** (`src/cli/`) - 轻量级命令行工具,基于共享库 `netlink_client` 构建
2. **C++ 系统插件** (`src/sys-plugin/`) - deepin-service-manager 插件,生成 `libplugin-immutable-read-only-auditor.so`
3. **Go 客户端** (`go-rofs-err-watcher/`) - Go语言实现 (可选,默认构建 deb 包时不包含)

所有原生代码组件共享 `src/lib/netlink_client` 库，提供统一的 Netlink 通信接口。

## 项目结构

```
deepin-immutable-eventd
├── Makefile                    # 主 Makefile
├── CMakeLists.txt              # CMake 构建配置
├── README.md                   # 说明文档
├── src/                        # 源代码目录
│   ├── lib/                    # 共享库
│   │   ├── netlink_client.c    # Netlink 客户端实现
│   │   ├── netlink_client.h    # Netlink 客户端头文件
│   │   └── utils.c             # 工具函数实现
│   ├── cli/                    # C 客户端
│   │   ├── CMakeLists.txt      # C 客户端构建配置
│   │   └── main.c              # C 客户端主程序
│   ├── sys-plugin/             # 系统插件
│   │   ├── CMakeLists.txt      # 插件构建配置
│   │   ├── plugin.c            # 插件主程序
│   │   ├── service.c           # D-Bus 服务实现
│   │   ├── service.h           # D-Bus 服务头文件
│   │   ├── dconfig.c           # 配置管理实现
│   │   ├── dconfig.h           # 配置管理头文件
│   │   ├── log.c               # 日志功能实现
│   │   ├── log.h               # 日志功能头文件
│   │   ├── cleanup.h           # 清理宏定义
│   │   ├── polkit_auth.c       # Polkit 权限认证实现
│   │   └── polkit_auth.h       # Polkit 权限认证头文件
│   └── user-plugin/            # 用户插件
│       ├── CMakeLists.txt      # 用户插件构建配置
│       ├── plugin.cpp          # 用户插件主程序
│       ├── err_notifier_service.cpp  # 错误通知服务实现
│       └── err_notifier_service.h    # 错误通知服务头文件
├── misc/                       # 配置文件目录
│   └── usr/share/
│       ├── deepin-service-manager/   # deepin-service-manager 配置
│       │   ├── system/         # 系统插件配置
│       │   └── user/           # 用户插件配置
│       └── dsg/configs/
│           └── org.deepin.immutable.eventd/  # 程序 DSG 配置
└── go-rofs-err-watcher/        # Go 客户端
    ├── cmd/
    │   └── go-rofs-err-watcher/
    │       └── main.go         # Go 客户端主程序
    ├── pkg/
    │   └── client/
    │       ├── client.go       # Go 客户端库
    │       └── client_test.go  # 测试文件
    └── Makefile                # Go 客户端 Makefile
```

## 功能特性

- 自动查找Generic Netlink family ID
- 接收并显示内核响应
- **安全限制**：只有 root 用户（或具有 CAP_NET_ADMIN 权限的进程）才能连接并接收广播消息

## 编译步骤

### 编译默认组件

```bash
make
```

这将构建 CMake 管理的组件(默认构建 deb 包时包含):
- C 客户端:`build/src/cli/deepin-immutable-eventd-cli`
- C++ 系统插件:`build/src/sys-plugin/libplugin-immutable-read-only-auditor.so`
- C++ 用户插件:`build/src/user-plugin/libplugin-immutable-err-notifier.so`
- 共享库:`build/src/lib/libnetlink_client.a`

### 编译可选组件

```bash
make go-client       # 编译 Go 客户端(可选,开发者自行选择)
```

这将构建:
- Go 客户端:`go-rofs-err-watcher/go-rofs-err-watcher`

> **注意:** Go 客户端是可选组件,默认构建 deb 包时不包含。开发者可根据需要自行编译和安装。

## 使用方法

> **注意：** 所有客户端都需要 **root 权限**才能运行，因为内核限制了只有具有 CAP_NET_ADMIN 权限的进程才能加入 netlink 多播组。

### 基本用法

**C 客户端:**
```bash
sudo ./deepin-immutable-eventd-cli
```

**Go 客户端(如已编译):**
```bash
sudo ./go-rofs-err-watcher
```

### 命令行选项

```bash
./deepin-immutable-eventd-cli [OPTIONS]
```

**可用选项：**

- `-h, --help`    显示帮助信息并退出

### 使用示例

```bash
# 开始监控错误消息(需要 root 权限)
sudo ./deepin-immutable-eventd-cli

# 显示帮助信息
./deepin-immutable-eventd-cli --help
./deepin-immutable-eventd-cli -h
```

## 示例输出

### 运行程序
```bash
$ sudo ./deepin-immutable-eventd-cli
Found family 'DEEPIN_ENOTIFY' with ID: 28
Starting notification monitor...
=== Error Notification ===
PID: 20317
PPID: 20316
Comm: chmod
Cmdline: chmod +x /usr/share/man/man1/dash.1.gz
Cgroup: /user.slice/user-1000.slice/session-32.scope
UID: 0
GID: 0
Inode Count: 1
Files:
  [0] Filename: /usr/share/man/man1/dash.1.gz
      Inode: 306758
      Is Parent: false
==========================
```

## 代码说明

### 架构设计

项目采用模块化设计,核心功能位于 `src/lib/netlink_client` 共享库中:

- **共享库** (`src/lib/`): 提供统一的 Netlink 通信接口,被所有原生客户端复用
- **C 客户端** (`src/cli/`): 使用共享库的简单命令行工具
- **C++ 系统插件** (`src/sys-plugin/`): 集成到 deepin-service-manager 的系统服务
- **C++ 用户插件** (`src/user-plugin/`): 集成到 deepin-service-manager 的用户服务
- **Go 客户端** (`go-rofs-err-watcher/`): 独立的 Go 语言实现(可选组件)

### 程序关键功能

1. **Socket创建**: 创建Generic Netlink socket
2. **Family查找**: 通过名称查找family ID
3. **消息接收**: 与内核通信，解析netlink消息
4. **Inode验证**: 验证文件路径与 inode 匹配，防止路径伪造

## 安装

```bash
# 安装所有客户端
sudo make install PREFIX=/usr

# 仅安装特定客户端
sudo make install-c-client PREFIX=/usr
sudo make install-go-client PREFIX=/usr
sudo make install-plugin-client PREFIX=/usr
```

## 清理

```bash
# 清理所有编译文件
make clean

## 故障排除

### 常见问题

#### 1. "failed to resolve family 'DEEPIN_ENOTIFY': Object not found"

**原因：** 内核未添加这部分功能，考虑更换内核。

#### 2. "failed to join multicast group: Operation not permitted" 或 "Permission denied"

**原因：** 程序没有足够的权限加入 netlink 多播组。内核要求进程具有 CAP_NET_ADMIN 权限。

**解决方法：**
```bash
# 使用 sudo 以 root 权限运行
sudo ./deepin-immutable-eventd-cli

# 或者为程序设置 CAP_NET_ADMIN 能力
sudo setcap cap_net_admin+ep ./deepin-immutable-eventd-cli
./deepin-immutable-eventd-cli
```

#### 3. "failed to resolve multicast group"

**原因：** 内核代码的组播组配置不正确。

**解决方法：**
- 确保内核代码正确注册了组播组
- 检查内核代码的组名是否与用户程序匹配

#### 4. 程序无响应或无输出

**原因：** 可能是因为没有触发相关的文件系统错误事件。

**解决方法：**
- 确保使用 root 权限运行（`sudo`）
- 尝试在 /usr 目录下进行写操作来触发事件
- 查看系统日志获取更多信息：`dmesg | grep err_notify`

## 参考资料

- [Netlink Protocol Library Documentation](https://www.infradead.org/~tgr/libnl/doc/core.html)
