- svcd: 审计确认现网已子进程化(fork+execv+setpgid+waitpid+SIGCHLD+set_cloexec,无system()); 增量 prctl(PR_SET_CHILD_SUBREAPER) 代收孤儿孙进程 → fb2d608b - meow_sysui(新增): 系统进程总监, 仿svcd成熟模式(信号自管道/poll/双探测kill/waitpid/subreaper/状态机), 监护自己fork+exec进程, 按sysui.d/<name>.conf逐条拉起, 无级联/有限次兜底/主循环绝不exit/空配置空转 → 173013cc - 启动链 S70meow_sysui → S89meow_svcd → S90meow_bootmenu; svcd拉起权判归(sysui在→交监管,不在→回退现网重挂循环) - 宿主集成测试过(常崩/稳定隔离/无级联/subreaper收尸/端到端); meow_ui.a未动 - 需加到固件打包(build_fw_apps_m267.sh): sysui→/usr/bin/meow_sysui, svcd覆盖(fb2d608b), S70+S89; 校验 svcd 762e84d0→fb2d608b, 新增 sysui 173013cc
11 KiB
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/launcherfork+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「 板载与 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)留待后续。
示例:
# 网络栈辅助服务(固件二进制,卡上有配置)
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,首启建):
# 自研 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约束,防崩溃-重启热循环拖垮系统。 - 孤儿/僵死隔离:
start_daemon()设PR_SET_CHILD_SUBREAPER——服务若派生孙进程, 在服务(直接子进程)退出后由 svcd 收尸而非 reparent 到 init,避免游离/僵死进程;失败仅记日志继续。 - 服务崩绝不连带 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 [name|all] # 列出各服务+全局(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 / 多列对齐表格。每服务一行:服务名/状态/pid/
重启次数+max_restart/backoff_ms/trigger/来源(board|tf)/最近退出码/退出时间/exec 路径;
TTY 时带 ANSI 配色(服务名=加粗青、RUNNING=绿、FAILED=红、STOPPED·STOPPING=黄、DISABLED=灰、
数字=黄、表头/分隔线=dim),stdout 非 TTY(重定向/SSH 管道)自动去色。
6.1 systemctl 式 CLI 用法(SSH 终端示例)
守护已由固件 etc/init.d/S89meow_svcd 开机自启,SSH 登录设备后直接敲命令即可,无需先知道 socket:
meow_svcd status # 列出所有服务 + 全局状态(TTY 带色;管道/重定向自动去色)
# meow_svcd status
# card_present=1 wifi_up=0 services=3
# NAME STATE PID RESTART BACKOFF TRIGGER SRC EXIT EXIT_TIME EXEC
# ------------------------------------------------------------------------------
# mdnsd running 1234 0/5 2000ms boot board - - /usr/bin/meow_mdns
# meow_netd stopped 0 0/5 1000ms card-mount tf - - /usr/bin/meow_netd
# ntpc disabled 0 0/inf 1000ms card-mount tf - - /usr/bin/ntpc
meow_svcd status mdnsd # 只显示单个服务(其余列同;`status all` 等效于无参)
meow_svcd restart mdnsd # 重启单个服务(如板载 mDNS 应答器)
meow_svcd start meow_netd # 启动单个服务
meow_svcd stop all # 停止全部服务
meow_svcd reload # 重读板载 + TF 双源 services.d 配置
meow_svcd pid # 打印守护进程 pid
- socket:控制走 AF_UNIX 单行文本,默认
/tmp/meow_svcd.sock(--sock/MEOW_SVCD_SOCK可改)。 守护未运行时命令回退打印状态文件/tmp/meow_svcd.status(或card_present=0 services=0)并以退出码 1 返回。 - 守护前台:
-f/--foreground—— 守护自身跑前台,供 supervisorfork/exec+waitpid托管; 默认(无子命令)则为后台常驻。 - 应答:成功
OK(pid→pid 数字);服务不存在ERR no-such-service;status返回对齐表格, 行内含state/pid/restart(重启计数)/exit(上次退出码)/trigger/来源/backoff_ms/exec。
7. 编译
./build_svcd.sh # mipsel 静态 → meow_svcd(0 warning)
./build_svcd.sh host # 宿主编译 → meow_svcd_host(集成测试)
后续(不在本阶段)
接入 supervisor 启动链(已改由etc/init.d/S89meow_svcd开机自启;bootmenu/launcherfork+exec+waitpid托管仍为备选)。cap真机实装(平台是否支持 capset/pthread caps 待确认;需先探测)。wifi-up事件细节(是否用/proc/net/wireless/ 重试文件,接口判定收紧)。- svcd/服务日志落位到卡
MeowOS/logs/的行为(当前 svcd 日志 stderr + 可选--log)。