name: root-owned-path-disposition description: Android/Termux 双 uid 环境下「路径属主 root」的判读与两向处置——同一个 root 属主文件,「要读它」⇒ su -c + 解释器全路径;「要覆写它」⇒ rm 后重跑(家目录写权足够)。含实测签名(root:644 产物静默挡住 gen 重跑、root:600 探针、root:600 SKILL.md 只能走影子副本、jobs.json 被 root 重写致 termux tick 恒 Permission denied)。触发词:Errno 13、Permission denied、root root 600、root root 644、覆写失败、属主、chown 不生效、python3 inaccessible or not found、su -c。 version: 1.0
category: android
root 属主路径的判读与两向处置
适用:本机(Pixel / Android 16 + Termux;termux 用户 u0_a329,su 可拿 root)任何一份
属主是 root 的文件出现在 termux 家目录树下(~、~/tmp、~/.hermes、$TMPDIR)时的判读与处置。
典型来源:某轮用 su -c 跑出的产物与状态戳、root 侧进程重写的共享状态文件、
随包/手工分发的 root:600 运维脚本与 SKILL.md。
一、判据:先 ls -la 看属主,再决定方向
ls -la <path> # 只看第 3/4 列(owner/group)与 mode
| 你要对它做什么 | 属主 root 的形态 | 正确动作 |
|---|---|---|
| 读它 / 跑它(探针脚本、SKILL.md、日志) | root:600 |
su -c "<解释器全路径> <脚本绝对路径> <args>" —— su 环境没有 Termux PATH ⇒ 裸 python3 回 inaccessible or not found |
| 覆写它(重跑 gen / 重新生成产物 / 覆盖状态文件) | root:644 |
rm -f 后重跑 —— 家目录属 u0_a329,目录写权足以 unlink,不必 su、不必 chown |
只想读、不想每次 su |
root:600 |
找影子副本(§三.3),或请上游把它 chown 回 u0_a329 |
通则一句话:同一份 root 属主文件,要读它 ⇒ su;要覆写它 ⇒ rm。别一律 su。
二、为什么「覆写」既不能 su 也不能 chmod/chown
- u0_a329 侧
open(...,"w")需要文件写权 ⇒ 截断失败[Errno 13] Permission denied; 脚本一般不会先替你删旧档 ⇒ 整步必失败,而退出码还可能被| tail之类包装层洗成 0 (看着像「跑了、没输出」)。 chmod/chown需要su,且 root 侧下次再写又变回 root(属主翻转会复发,见 §三.4)⇒ 是「修了这次、下次还踩」的假修。rm只要求目录写权(家目录属 u0_a329)⇒ 无副作用、不需 root,是正解。改属主不是判据,能删能写才是。
三、实测案例(本机)
- root:644 产物静默挡住 gen 重跑(2026-10-07 01:00 轮):
~/daily_digest_tgo_all_2026-10-06.md=root root 6448621B(前一日 10:37 某个su路径留下的半日残件)⇒ 重跑前rm -f(exit 0) ⇒gen_agg_digest.py随即 exit 0、产物 20779B。 ⚠️ 症状静默:只看「文件在不在」会以为「已有产物、不用跑」,从而整天不补(当轮已在案才算发现)。 ⇒ 补跑/重跑类动作的前置:ls -la目标产物,属主 root 就先删。 - root:600 探针 ⇒
su -c+ 解释器全路径:~/tmp/digest_gap_for_date.py为root root 600:python3 ~/tmp/digest_gap_for_date.py …→can't open file '…': [Errno 13] Permission denied(是权限,不是文件不存在 ⇒ 别去查路径拼写、别以为被清理了)su -c "python3 …"→/system/bin/sh: python3: inaccessible or not found(su 环境无 Termux PATH)su -c "/data/data/com.termux/files/usr/bin/python3 /data/data/com.termux/files/home/tmp/digest_gap_for_date.py tgo 2026-10-06"✅
- root:600 SKILL.md ⇒ 只能走影子副本:
~/.hermes/skills/cron/cron-scheduler/SKILL.md是root root 600⇒skill_view恒报 not found、Job prompt 每轮打Skill(s) not found and skipped: cron-scheduler; 实务读$TMPDIR/_sched_read_*.md(历轮拷出的全文副本,28981B)。 新鲜度核对 =su -c "stat -c '%U %G %a %s %y' <SKILL.md>"与副本比字节数 + mtime。 - 被 root 侧进程重写的共享状态文件 ⇒ termux 侧恒
Permission denied:两个 gateway(root +u0_a329)并跑时, root 侧原子替换重写~/.hermes/cron/jobs.json⇒ 属主变root:600⇒ termux 侧每 tick 一条Failed to read cron database: [Errno 13] Permission denied。 ⚠️ 这类别在无人值守轮内自发kill/chown(可能是本会话的父进程、且 chown 不持久) ⇒ 升级给用户拍板,轮内只留痕。
四、同轮附带:两个「读数假象」(canonical 家在 scheduler-round-authority-caliber,该 skill 只读)
- 审计器 ① 报
自报=无≠ 该轮 FAILED / 空档(2026-10-07 01:00 实测):cross-round-handoff-ledger/scripts/handoff_round_audit.sh <DATE>把某份 output md 打成自报=无, 而该 md 首行 =# Cron Job: 调度器(无(FAILED))、正文确有自报行 —— 只因写成**[HH:MM] scheduler: daily=…**(加粗),审计器的锚定 grep 不认**前缀。 ⇒ 5 秒复核:看 md 首行有无(FAILED)+search_files(pattern='scheduler: daily=')是否命中; 别据自报=无补记、别判空档。想让审计器下次认得出 ⇒ 汇总行别加粗(账本条目里外层字段名加粗无妨, 被审的是 output md)。 executions.db不能用order by id排序:id是 UUID hex ⇒order by id desc排的是字典序, 读到的「最近几行」实为乱序(实测13:01 / 02:00 / 23:00 / 10-05混排)⇒ 误判「本轮没注册 / 有双派发」。 ⇒ 一律order by started_at;判「每整点恰 1 轮 / 无双派发」用where started_at like '<今天>%'+order by started_at。 实测正确读数:cd69c503fbb7 | running | 2026-10-07T01:00:34(当日首行)。
五、落点说明(为什么这份 skill 存在)
本机 cron/ meta/ wechat/ android/ 四族的带判据 skill 全部 created_by=None(手工维护)
⇒ skill_manage 的 patch / write_file 一律 Refusing … it is not agent-created(零写入,不是半成功)。
2026-10-07 实测:连自称「唯一可写落点」的两个 skill(cron/scheduler-round-authority-caliber、
cron/daily-digest-gen-window-ops)也被拒。
⇒ 纪律:试 1 个被拒即停(别逐个试完),新实测落 agent-owned 落点(create 是本机唯一还通的写路径,本条即一处)。
⚠️ 这些手工 skill 正文里的「本 skill = 可写落点」自述已被实测推翻,别再按它选落点。