proc-connector 0.1.0

A safe, modern Rust wrapper for the Linux Process Event Connector (netlink PROC_EVENT_*)
Documentation
# PROGRESS — proc-connector crate 开发计划

> **动机**:fsmon 项目中 `proc_cache.rs` 包含 10 处无法消除的 `unsafe`,均来自 Linux Netlink Proc Connector 的 FFI 调用。市面上缺少一个完整、现代化、覆盖所有 proc 事件类型的 safe Rust 封装。本 crate 填补这个空白,对标 `fanotify-fid` 的设计哲学。

## 目标

- 完整覆盖 Proc Connector **所有 10+ 种事件类型**(而非仅限 `EXEC`- 完全 safe 的 API(内部 unsafe 集中在协议解析层,向调用者呈现纯 safe 接口)
- 零开销抽象(解析仅在成功 recv 后执行)
- 可组合(暴露 `as_raw_fd()` 支持 tokio/mio 等 async runtime)
- 不越界(不做缓存、查 /proc、线程管理、业务策略)

## `fanotify-fid` 对标的哲学

| 维度 | `fanotify-fid` | 本 crate |
|------|---------------|----------|
| 系统调用封装 | `fanotify_init/mark` safe 函数 | socket/bind/send(订阅)/recv safe 函数 |
| 类型安全常量 | `FAN_CREATE``u64` 常量 | `CN_IDX_PROC``PROC_EVENT_EXEC`|
| 事件枚举 | `FidEvent { mask, pid, path, ... }` | `ProcEvent::Exec { pid, tgid, ... }` |
| 全协议覆盖 | 2 种报告模式 + FID/DFID_NAME 路径解析 | 全 10+ 种处理器事件 |
| 不做什么 | 不管理线程、不缓存路径 | 不查 /proc、不缓存、不管理线程 |
| async 支持 | `AsRawFd` 暴露 raw fd | 同样暴露 `as_raw_fd()` |
| 编程风格 | 现代化常量命名、文档完整 | 对标 |

## 模块设计

```
proc-connector
├── Cargo.toml
└── src/
    ├── lib.rs        // re-export, prelude
    ├── socket.rs     // ProcConnector 核心类型 + 系统调用封装
    ├── event.rs      // ProcEvent 枚举 + 协议解析器
    ├── consts.rs     // 内核常量(全覆盖)
    └── error.rs      // 错误类型
```

## API 设计

### `socket.rs` — 核心类型

```rust
pub struct ProcConnector {
    fd: OwnedFd,  // safe: RAII close on drop
}

impl ProcConnector {
    /// 创建 netlink socket + bind + 订阅,一步到位
    pub fn new() -> Result<Self, Error>

    /// 重新订阅(断开后重连时使用)
    pub fn subscribe(&mut self) -> Result<(), Error>

    /// 退订
    pub fn unsubscribe(&mut self) -> Result<(), Error>

    /// 接收并解析一个 proc 事件。
    /// buf 由调用者提供以控制分配策略。
    pub fn recv(&self, buf: &mut [u8]) -> Result<ProcEvent, Error>

    /// 带超时的接收
    pub fn recv_timeout(&self, buf: &mut [u8], timeout: Duration)
        -> Result<Option<ProcEvent>, Error>

    /// 暴露 raw fd 供 tokio::AsyncFd / mio 集成
    pub fn as_raw_fd(&self) -> RawFd
}
```

### `event.rs` — 事件枚举(全 10+ 种覆盖)

```rust
#[derive(Debug, Clone)]
pub enum ProcEvent {
    /// 进程执行 (exec)
    Exec   { pid: u32, tgid: u32 },
    /// 进程派生 (fork)
    Fork   {
        child_pid: u32, child_tgid: u32,
        parent_pid: u32, parent_tgid: u32,
    },
    /// 进程退出 (exit)
    Exit   { pid: u32, tgid: u32, exit_code: u32, exit_signal: u32 },
    /// UID 变化
    UidChange  { pid: u32, tgid: u32, ruid: u32, euid: u32 },
    /// GID 变化
    GidChange  { pid: u32, tgid: u32, rgid: u32, egid: u32 },
    /// Session ID 变化
    SidChange  { pid: u32, tgid: u32 },
    /// ptrace 附加/分离
    Ptrace { pid: u32, tgid: u32, tracer_pid: u32, tracer_tgid: u32 },
    /// 进程名变更
    CommChange { pid: u32, tgid: u32, comm: [u8; 16] },
    /// 核心转储
    Coredump { pid: u32, tgid: u32 },
    /// 内核新增但本 crate 未显式覆盖的事件(未来兼容)
    Unknown { what: u32, raw_data: Vec<u8> },
}
```

### `error.rs` — 错误类型

```rust
#[derive(Debug)]
pub enum Error {
    /// 系统调用失败(socket/bind/send/recv)
    Os(std::io::Error),
    /// 报文长度短于最小协议头
    Truncated,
    /// 缓冲区太小,需要至少 N 字节
    BufferTooSmall { needed: usize },
    /// recv 被信号中断,应重试
    Interrupted,
    /// socket 关闭(recv 返回 0)
    ConnectionClosed,
}
```

## 不合规的 msg_type 处理

netlink 报文可能包含 `NLMSG_DONE`、`NLMSG_ERROR`、`NLMSG_NOOP` 等控制消息,或者 `NLMSG_OVERRUN`(当订阅者消费不够快时)。处理策略:

| 消息类型 | 处理方式 |
|---------|---------|
| `NLMSG_DONE` | 忽略,继续 recv |
| `NLMSG_ERROR` | 返回 `Err(Error::Os(...))` |
| `NLMSG_NOOP` | 忽略,继续 recv |
| `NLMSG_OVERRUN` | 返回 `Err(Error::Overrun)` — 告知调用者可能丢事件 |
| `NLMSG_DATA` + proc_event | 正常解析 |

## 实施步骤

### Step 1 — 项目骨架 ✅
- [x] `cargo init --lib` + 配置 `Cargo.toml`(依赖:`libc`- [x] 错误类型 `error.rs`
- [x] 内核常量 `consts.rs`(全事件类型掩码 + cn_msg 偏移量常量)

### Step 2 — 核心 socket 操作 ✅
- [x] `socket.rs``ProcConnector::new()`(socket + bind)
- [x] subscribe / unsubscribe
- [x] recv_raw / recv_raw_timeout

### Step 3 — 协议解析器 ✅
- [x] `event.rs`:解析 `nlmsghdr → cn_msg → proc_event` 三层嵌套
- [x] 所有事件变体的解析(Exec, Fork, Exit, Uid, Gid, Sid, Ptrace, Comm, Coredump)
- [x] 带 `Unknown` 兜底的未来兼容
- [x] 22 个单元测试全部通过

### Step 4 — 进阶功能 ✅
- [x] `recv_timeout``recv_raw_timeout` + `recv_timeout`- [x] 集成测试(`tests/integration_test.rs`,标记 `#[ignore]`,需 root 运行)
- [x] 文档和示例(`examples/proc_watch.rs` + `examples/async_integration.rs`
### Step 5 — 替换 fsmon 中的 proc_cache.rs
- [ ] 在 fsmon 中引入 `proc-connector` 依赖
- [ ] 替换 `proc_cache.rs` 中的全部 unsafe 为 safe 调用
- [ ] 确认所有测试通过

## 边界规则(绝不放进 crate)

```
❌ 查 /proc/{pid}/comm           → 调用者的事
❌ 查 /proc/{pid}/status 拿 UID   → 调用者的事
❌ UID 转用户名                    → 调用者的事
❌ PID → cmd/user 的 DashMap 缓存  → 调用者的事
❌ 线程管理 (std::thread::spawn)   → 调用者的事
❌ tokio::spawn / async 封装       → 调用者通过 as_raw_fd() 自己集成
❌ AtomicBool 就绪信号量           → 调用者的事
```