Files
MeowOS-For-R3P2/patch_v2/meow_svcd/meow_svcd.md
T

175 lines
8.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# meow_svcd — MeowOS 服务管理器守护进程
类 systemd/systemctl 的角色:由 supervisor(meow_bootmenu/launcher)托管
`fork/exec` 启动的一个**独立**进程;每个服务又是 svcd 的独立子进程。svcd 极简:
无 `dlopen`、无外部依赖(仅 POSIX + Linux 基础接口),交叉编译为 **mipsel 静态**
打进固件(不入卡——拔卡 svcd 本体不消失)。
二进制入口:`patch_v2/meow_svcd/meow_svcd`(mipsel 静态,~98KB,<200KB 固件阈值)。
宿主编译:`patch_v2/meow_svcd/meow_svcd_host`。
> 本阶段(M2.54)范围:守护 + 双源 services.d + 宿主测试。**接入系统启动链**已定:
> 固件预置 `etc/init.d/S89meow_svcd`(开机自启,`myow_svcd -f` 前台 + shell 重挂在 rcS 早期,
> 先于 S90meow_bootmenu——因 S90 exec 引导选单后阻塞 rcS,故须排在 S90 之前)。
> 直接由 bootmenu/launcher `fork+exec` + `waitpid` 托管的方案仍成立(改固件有风险),
> 作为备选——用 `-f` 前台即可被 waitpid。
---
## 1. 路径契约
| 用途 | 默认值 | 覆盖方式 |
|---|---|---|
| TF 卡挂载点 | `/usr/data/mnt/sd_0`(SPEC §1.2) | `--card` / `MEOW_SVCD_CARD` |
| 板载服务目录 | `/usr/data/meow/services.d`(首启预置/Data 区) | `--board` / `MEOW_SVCD_BOARD` |
| TF 服务目录 | `<card>/MeowOS/services.d/` | 随 `--card` |
| 控制 socket | `/tmp/meow_svcd.sock` | `--sock` / `MEOW_SVCD_SOCK` |
| 状态文件 | `/tmp/meow_svcd.status` | `--status` / `MEOW_SVCD_STATUS` |
| pid 文件 | `/tmp/meow_svcd.pid` | `--pidfile` |
| svcd 自身日志 | stderr(supervisor 捕获) | 追加 `--log` / `MEOW_SVCD_LOG` |
> 状态文件写板载 `/tmp`(tmpfs,存活期)或可配置;svcd 日志走 stderr 便于
> supervisor 捕获(`-f` 前台时子进程 stdout/stderr 也落到同一 sink)。
## 2. services.d 目录式配置(**双源**:板载 + TF,板载优先)
服务配置**两处都读**,一个服务一个 `<name>.conf`:
- **板载** `/usr/data/meow/services.d/<name>.conf`:Data 区,恒定存在、权威优先;
首启由固件 `S89meow_svcd` 预置(如 `mdnsd.conf`)。拔卡不丢。
- **TF** `<card>/MeowOS/services.d/<name>.conf`:随卡存在/消失。
**同名遮蔽规则**:先扫板载(权威),再扫 TF;若 TF 出现与板载同名服务 → **跳过 +
WARN**「<name> 板载与 TF 都存在,采用板载」。无双源冲突时行为不变。
极简 `key = value`,`#`/`;` 注释,空行忽略;**未知键忽略**(前向兼容)。行内注释可用 `\#` 转义。
| 字段 | 必填 | 类型 | 说明 | 默认 |
|---|---|---|---|---|
| `exec` | ✅ | 路径 | 服务二进制绝对路径(可卡上或固件) | 无(缺省 → 跳过该服务) |
| `args` | 否 | 串 | 空格切分,支持单/双引号与 `\` 转义 | 无 |
| `name` | 否 | 串 | 仅备忘;**实际名以文件名 `<name>.conf` 为准** | =文件名 |
| `env` | 否 | `K=V` | 可多条;子进程 exec 前 `setenv` | 无 |
| `enabled` | 否 | 1/0 | 0=永不自动启动 | 0 |
| `restart` | 否 | 枚举 | `always`/`on-fail`/`never` | `on-fail` |
| `backoff_ms` | 否 | int | 崩溃后重启退避毫秒(固定退避) | 1000 |
| `max_restart` | 否 | int | 连续重启次数上限,超限 → `failed` 停止;`-1`=无限 | 5 |
| `cap` | 否 | 串 | 能力串如 `cap_net_bind_service,cap_net_raw`;**本阶段仅解析保留,不实装**(属后续) | 无 |
| `trigger` | 否 | 枚举 | `boot`/`card-mount`/`wifi-up` | `card-mount` |
`restart` 语义:
- `always`:无论退出码都重启(受 `max_restart` 约束)。
- `on-fail`:仅非零退出/被信号杀(崩溃)重启;`exit 0` 不重启。
- `never`:崩溃不重启(记为 `failed`)。
`cap`/`wifi-up` 均属**扩展点**:本阶段解析并保留字符串 / 实现一个 `/sys/class/net/<iface>/operstate`
的最小判定(本平台无 WiFi 接口时恒 `0`),真机能力绑定(`capset`)留待后续。
示例:
```ini
# 网络栈辅助服务(固件二进制,卡上有配置)
exec = /usr/bin/meow_netd
args = --foreground -v
env = MEOW_LOG_LEVEL=INFO
enabled = 1
restart = on-fail
backoff_ms = 2000
max_restart = 5
trigger = card-mount
# 可选 setcap(本阶段不实装)
# cap = cap_net_bind_service,cap_net_raw
```
**板载 mDNS 应答器示例**(固件预置 `/usr/data/meow/services.d/mdnsd.conf`,首启建):
```ini
# 自研 IPv4-only mDNS 应答器(固件 /usr/bin/meow_mdns;板载服务,拔卡不丢)
exec = /usr/bin/meow_mdns
args =
enabled = 1
restart = on-fail
backoff_ms = 2000
max_restart = 5
trigger = boot # 板载服务:boot 触发不依赖卡(恒定存在);cap 空=root 绑 5353/组播
cap =
```
> `trigger` 为单值枚举(`boot|card-mount|wifi-up`)。板载服务用 `boot`(恒存在即启动);
> `wifi-up` 属扩展点(`/sys/class/net/<iface>/operstate`),当前平台无无线接口恒 0。
## 3. 状态机
```
DISABLED enabled=0,永不自动启动
STOPPED 未运行(触发不满足 / 被停 / 等待退避)
RUNNING 子进程存活
STOPPING 已发 SIGTERM,等退出(SVCD_STOP_GRACE_MS=2500 后 SIGKILL 兜底)
FAILED 崩溃且不再重启(超 max_restart / restart=never)
```
转换(主循环事件驱动 + 周期 tick):
- **子进程死亡**(`waitpid` 匹配):若无 `stop_requested`/`restart_pending` → 按
`restart` 策略决定重建(先进 `backoff_ms` 退避)或落 `FAILED`/`STOPPED`;
连续稳定运行 `SVCD_STABLE_MS=30s` 后清零 `restart_count`。
- **`stop` 命令**:`STOPPING → STOPPED`(置 `user_stopped`,抑制触发自动拉起)。
- **`restart` 命令**:`STOPPING →` 收尸后原地 `respawn`(无视崩溃策略,清零计数)。
- **触发/禁用**:`tick` 中 `enabled && trigger 满足 && STOPPED && !user_stopped` → 启动;
运行中但 `!enabled || !trigger` → 停。
## 4. 崩溃隔离
- **独立进程**:每个服务 `fork()+execv()`,svcd 只通过 `waitpid`/`SIGCHLD` 感知死亡;
无中间层内存共享、无 `dlopen`。
- **信号健壮**:`SIGPIPE` 置 `SIG_IGN`(服务关管道不杀 svcd);`SIGTERM`/`SIGCHLD`
处理器仅写自管道字节(async-signal-safe);`poll` 因信号中断 `EINTR` 续跑。
- **不读服务输出**:子进程继承 svcd stdio(stdout/stderr 落同一 sink),svcd **不
设管道读服务体**——服务写多少都不进 svcd 内存,天然规避「输出撑爆 → svcd 崩」。
- **后退避**:重启间隔受 `backoff_ms` 约束,防崩溃-重启热循环拖垮系统。
- 服务崩**绝不**连带 supervisor:svcd 是 supervisor 的子进程且自身不死;服务是
svcd 的子进程,服务死只影响 svcd 内部一张表。
## 5. 事件触发(低成本轮询)
每 `SVCD_SCAN_MS=1000ms` 一轮:
- **卡挂载**:`card_present()`=目录存在 +(`services.d` 在 | 真实挂载点(子目录
`st_dev` 不同)| `MEOW_SVCD_CARD_PRESENT=0/1` 测试覆盖)。拔卡 → `on_card_out()`
优雅停所有服务**并保留 `restart_count`/`last_exit` 状态**;插卡 → `scan_and_reconcile()`
重建并按触发拉起。
- **`wifi-up`**:读 `/sys/class/net/<iface>/operstate`,无无线接口恒 `0`(扩展点)。
- `boot`:TF 配置在卡 → 随卡存在即启动(拔卡即停);**板载配置**(`src=board`)→ 恒定存在即启动(不依赖卡,拔卡保留,供 mdnsd 等常驻服务)。
## 6. CLI / 控制协议
守护进程默认后台常驻(无子命令即启动);`-f` 前台(supervisor 托管用)。控制走
AF_UNIX 单行文本:
```
meow_svcd status # 列出(daemon 未运行则打印状态文件)
meow_svcd reload # 重读卡配置
meow_svcd start <name|all>
meow_svcd stop <name|all>
meow_svcd restart <name|all>
meow_svcd pid
```
应答:`OK` / `ERR no-such-service` / 多行 `svc=... state=... pid=... restart=... exit=...`。
## 7. 编译
```bash
./build_svcd.sh # mipsel 静态 → meow_svcd(0 warning)
./build_svcd.sh host # 宿主编译 → meow_svcd_host(集成测试)
```
## 后续(不在本阶段)
- ~~接入 supervisor 启动链~~(已改由 `etc/init.d/S89meow_svcd` 开机自启;bootmenu/launcher
`fork+exec` + `waitpid` 托管仍为备选)。
- `cap` 真机实装(平台是否支持 capset/pthread caps 待确认;需先探测)。
- `wifi-up` 事件细节(是否用 `/proc/net/wireless` / 重试文件,接口判定收紧)。
- svcd/服务日志落位到卡 `MeowOS/logs/` 的行为(当前 svcd 日志 stderr + 可选 `--log`)。