# 代理指南：深度ROFS错误监视器

本指南帮助AI代理理解并有效地使用深度只读文件系统错误监视器代码库。

## 项目概览

这是一个多语言项目，使用Linux Generic Netlink机制监控深度系统`/usr`目录的只读文件系统错误消息以与内核模块通信。该项目提供三种客户端实现：

1. **C客户端** (`src/cli/`) - 轻量级命令行工具
2. **C++系统插件** (`src/sys-plugin/`) - deepin-service-manager系统级插件，具有D-Bus接口
3. **C++用户插件** (`src/user-plugin/`) - deepin-service-manager用户级插件
4. **Go客户端** (`go-rofs-err-watcher/`) - 现代Go实现（可选组件，默认构建deb包时不包含）

C、C++客户端和插件的实现都使用共享的`netlink_client`库进行内核通信，需要CAP_NET_ADMIN 权限或 root 权限才能运行。

## 基本命令

### 构建系统

**构建默认组件（CMake管理的组件）：**
```bash
make                # 构建CMake管理的组件（C客户端、C++插件），不包含Go客户端
```

**基于CMake的构建（C/C++组件）：**
```bash
make cmake-build    # 构建C客户端和C++插件
cd build && cmake .. && make  # 手动CMake构建
cd build && cmake -DCMAKE_BUILD_TYPE=Debug .. && make  # 调试构建
```

**Go客户端构建（可选）：**
```bash
make go-client      # 构建Go客户端（可选组件，默认不包含在deb包中）
cd go-rofs-err-watcher && make build  # 手动Go构建
cd go-rofs-err-watcher && make deps   # 更新依赖项
```

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

**单个组件构建：**
```bash
make install-c-client     # 仅构建和安装C客户端
make install-go-client    # 仅构建和安装Go客户端  
make install-plugin-client # 仅构建和安装C++插件
make install-user-plugin  # 仅构建和安装用户级插件
```
注：一般无须执行install。

### 测试

**Go客户端测试（netlink操作需要root权限）：**
```bash
cd go-rofs-err-watcher
make test           # 运行测试（没有root可能失败）
make test-root      # 使用sudo运行测试（推荐）
```

注：一般无须执行测试。

**测试要求：**
- netlink操作需要root权限
- 测试触发实际系统调用以验证通知
- 一般使用`/usr/share/man/man1/dash.1.gz`作为测试文件

### 安装

```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
sudo make install-user-plugin PREFIX=/usr

# 将Go客户端安装到/usr/local/bin（备选方案）
cd go-rofs-err-watcher && make install
```

注：一般不这样安装，通过打包为deb包后安装deb包。

### 运行客户端

```bash
# 运行C客户端（需要root权限）
sudo ./build/src/cli/deepin-immutable-eventd-cli

# 运行Go客户端（如已编译，需要root权限）
sudo ./go-rofs-err-watcher/go-rofs-err-watcher

# 运行带详细输出的Go客户端
sudo ./go-rofs-err-watcher/go-rofs-err-watcher --verbose
```

注：一般无须执行，通常是人类手动执行。

### 清理

```bash
make clean          # 清理所有构建工件
```

## 代码组织

### 目录结构

```
deepn-rofs-err-watcher/
├── src/                    # 原生C/C++代码
│   ├── lib/               # 共享Netlink库
│   │   ├── netlink_client.c
│   │   └── netlink_client.h
│   ├── cli/               # C客户端
│   │   └── main.c
│   ├── sys-plugin/        # C++系统级插件
│   │   ├── CMakeLists.txt
│   │   ├── plugin.c
│   │   ├── service.c
│   │   ├── service.h
│   │   └── cleanup.h
│   └── user-plugin/       # C++用户级插件
├── go-rofs-err-watcher/   # Go实现
│   ├── cmd/go-rofs-err-watcher/
│   │   └── main.go
│   ├── pkg/client/
│   │   ├── client.go
│   │   └── client_test.go
│   ├── Makefile
│   ├── go.mod
│   └── go.sum
├── debian/                # Debian打包文件
├── misc/                  # 配置文件（D-Bus、服务管理器）
├── build/                 # CMake构建输出目录
├── CMakeLists.txt         # 主CMake配置
├── Makefile              # 主构建编排
└── .clang-format         # Linux内核代码风格配置
```

### 共享库模式

- `src/lib/netlink_client`提供统一的Netlink通信接口
- 由C客户端和C++插件使用
- 通过CMake构建的静态库（`libnetlink_client.a`）
- 启用位置独立代码（PIC）以支持共享库兼容性

### Python脚本

- `scripts/export_log_client.py` - 用于测试系统级插件的日志导出功能的D-Bus客户端
- 使用GObject introspection进行D-Bus通信
- 为系统插件的ExportLog方法提供Python接口

## 代码约定

### C/C++代码风格

- **格式化：** 使用Linux内核`.clang-format`配置
- **缩进：** 一个Tab字符
- **行长：** 最多80个字符
- **SPDX头：** 所有文件包含SPDX许可证头
- **函数命名：** 函数使用`snake_case`，常量使用`SCREAMING_SNAKE_CASE`

### Go代码风格

- **格式化：** 标准`gofmt`约定
- **错误处理：** 使用`if err != nil`进行显式错误检查
- **测试：** 使用testify框架进行断言
- **包结构：** `pkg/client`用于核心功能，`cmd/`用于可执行文件

### 构建配置

- **CMakeLists.txt：** 使用现代CMake（3.16+）
- **依赖项：** 需要libnl-3.0和libnl-genl-3.0、libsystemd
- **Go模块：** 使用Go 1.22.3与显式依赖项管理
- **构建输出：** 
  - `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`（C++用户级插件）
  - `build/src/lib/libnetlink_client.a`（共享库）
  - `go-rofs-err-watcher/go-rofs-err-watcher`（Go客户端，可选）

## 测试方法

### Go客户端测试

- 涵盖所有系统调用的综合测试套件
- netlink操作需要root权限
- 测试实际的内核通知功能
- 使用基于超时的方法进行异步消息接收
- 使用testify框架进行断言

**关键测试模式：**
- 基于上下文的消息接收和超时
- inode验证（消除误报）
- 多个文件操作测试（打开、创建链接、创建目录等）
- 错误注入和验证

### 测试文件和路径

测试在`/usr`目录中使用特定路径：
- `/usr/share/man/man1/dash.1.gz` - 主测试文件
- `/usr/share/man/man1/` - 测试目录
- 用于创建操作的不存在路径

测试二进制编译为`test-client`用于手动测试。

### 测试命令

```bash
# 运行Go测试（需要root）
cd go-rofs-err-watcher
make test-root

# 使用编译的测试客户端进行手动测试
sudo ./test-client -test.v
```

注：一般无须执行测试，通常是人类手动执行。

## 安全考虑

### 权限要求

- **Root权限：** 所有客户端需要root或CAP_NET_ADMIN能力
- **内核通信：** 使用Generic Netlink进行内核用户空间通信
- **Inode验证：** 通过验证inode号消除误报
- **D-Bus访问：** 用于插件功能的系统总线访问
- **文件系统访问：** 对`/proc`的读访问以获取进程信息

### 安全模式

- **Inode验证：** 所有接收的消息验证文件inode是否与预期匹配
- **父目录验证：** 支持来自父目录的inode
- **多文件支持：** 处理每个通知的多个文件名、inode
- **速率限制：** 系统插件实现速率限制（5秒窗口，最多20个事件）

## 开发工作流

### 进行更改

1. **C/C++更改：** 修改`src/`中的文件，然后运行`make cmake-build`
2. **Go更改：** 修改`go-rofs-err-watcher/`中的文件，然后运行`make go-client`
3. **共享库更改：** 修改`src/lib/`，影响C客户端和插件
4. **Python更改：** 修改`src/user-plugin/`中的文件，无需构建
5. **配置更改：** 更新`misc/`中的文件并测试安装

### 测试更改

1. 构建特定组件
2. 使用适当权限运行测试
3. 使用实际系统调用验证功能
4. 如果修改系统插件则测试系统级D-Bus接口
5. 如果修改日志导出功能则验证Python脚本 `scripts/export_log_client.py`
6. 如果修改用户级插件则测试用户级DBus接口

### 调试模式

- **详细输出：** 使用`--verbose`标志获取详细日志
- **CMake调试：** 使用`-DCMAKE_BUILD_TYPE=Debug`进行调试构建
- **Go调试：** 使用标准Go调试工具
- **clangd支持：** 存在`.clangd`配置文件用于LSP支持

## 常见陷阱

### 构建问题

- **缺少依赖项：** 确保安装了libnl-3.0、libnl-genl-3.0和libsystemd
- **权限错误：** 构建系统可能需要对系统目录的写入权限
- **Go模块问题：** 如果依赖项失败，在Go目录中运行`go mod tidy`
- **CMake版本：** 需要CMake 3.16+（使用`cmake --version`检查）
- **多架构支持：** 用于交叉编译的DEB_HOST_MULTIARCH环境变量

### 运行时问题

- **权限被拒绝：** 所有 netlink 客户端需要root权限才能运行
- **内核模块缺失：** "Object not found"错误表示缺少内核支持
- **无通知：** 确保`/usr`挂载为只读且测试操作触发错误
- **Netlink族：** 在内核日志中查找"DEEPIN_ENOTIFY"族注册
- **D-Bus服务：** 系统插件需要D-Bus系统总线访问

### 测试问题

- **Root要求：** 没有root权限测试会失败
- **超时问题：** 如果内核响应超出频率限制，某些测试可能超时
- **文件存在：** 测试假设特定文件存在于`/usr`目录中
- **测试二进制：** Go测试编译为`test-client`二进制用于手动测试
- **内核响应：** 如果内核模块未加载，测试必然失败

### 开发问题

- **代码格式化：** 对C/C++使用Linux内核风格（8个空格，80字符行）
- **SPDX头：** 所有文件必须包含SPDX许可证头
- **clang-format：** `.clang-format`中的配置（Linux内核风格）
- **clangd支持：** `.clangd`中的LSP配置用于IDE集成

## 集成点

### D-Bus集成

- 系统插件提供D-Bus系统服务（`org.deepin.immutable.ReadOnlyAuditor1`）
- `misc/usr/share/dbus-1/`中的配置文件
- 在`scripts/export_log_client.py`中实现了调用它导出日志。

### 服务管理器集成

通过JSON配置让系统插件和用户级插件与deepin-service-manager集成：

- `misc/usr/share/deepin-service-manager/system/plugin-immutable-read-only-auditor.json`中的系统级插件配置，插件文件名：`plugin-immutable-read-only-auditor.so`
- `misc/usr/share/deepin-service-manager/user/plugin-immutable-err-notifier.json`中的用户级插件配置，插件文件名：`libplugin-immutable-err-notifier.so`

### 包构建

- `debian/`目录中的Debian打包文件
- 通过DEB_HOST_MULTIARCH支持多架构
- Lintian覆盖用于包验证
- 自动生成和打包调试符号
- 包含服务管理器集成文件

## 文档

- **README.md：** 中文的全面项目文档
- **代码注释：** 头文件中大量的Doxygen风格注释
- **测试文档：** 含有说明的良好文档测试用例
- **draw.md：** 项目设计文档

## 其他资源

### 配置文件

- **`.clang-format`:** Linux内核代码风格配置
- **`.clangd`:** C/C++开发的LSP配置
- **`misc/`:** D-Bus服务定义和服务管理器配置
- **`debian/`:** Debian打包配置和元数据

### 内核模块要求

- 需要具有Generic Netlink族"DEEPIN_ENOTIFY"的内核模块
- 必须注册多播组"err_events"
- 命令和属性必须与内核模块定义匹配
- 有关协议定义，请参阅`src/lib/netlink_client.h`

### 协议常数

所有实现共享这些常数（在`netlink_client.h`中定义）：
- **族名称：** `DEEPIN_ENOTIFY`
- **多播组：** `err_events`
- **命令：** `DEEPIN_ERR_NOTIFY_CMD_*`（1-4）
- **属性：** `DEEPIN_ERR_NOTIFY_ATTR_*`（1-9）

当对构建系统、测试方法或代码约定进行重大更改时，应更新此AGENTS.md文件。
