Linux strace -f 如何定位子进程继承的文件访问:follow-forks、文件过滤与证据核对
来源:17golang原创
时间:2026-08-30 05:08:12 282浏览 收藏
排查 Linux 服务“明明没有读这个文件”时,先别只盯着主进程的一行日志:程序可能已经 fork 出子进程,真正的 openat、read 或 stat 发生在另一个 PID 里。最小可用的定位命令是 strace -f -e trace=%file -p PID,其中 -f 扩大跟踪范围,-e trace=%file 把输出收窄到文件相关调用。
先用
-f保证子进程不会从视野里消失,再用%file过滤调用,最后同时核对 PID、路径和返回值;只看到一条“访问失败”并不能证明访问者是主进程。
strace -f会跟踪 fork、vfork、clone 产生的进程,输出中的 PID 是判断调用归属的第一证据。-e trace=%file适合从大量系统调用中筛出 openat、stat、readlink 等文件路径相关调用。- 用
-o保存原始记录,再结合返回值和子进程退出时间核对,避免把“路径不存在”和“权限拒绝”混成一个结论。
接口目标:把“谁访问了文件”还原出来
strace 记录的是进程发起的系统调用,不是应用日志。对一个会派生 worker 的服务来说,目标不是收集越多越好,而是回答三个问题:哪个 PID 发起了调用、调用针对什么路径、内核返回了什么结果。
下面用一个假设的服务 worker 说明命令形状。PID 请替换为现场通过 pgrep -n worker 找到的真实值;不要直接复制示例数字。
sudo strace -f -e trace=%file -p 2418 -o /tmp/worker-file.trace
这里的 2418 只是示例主 PID。跟踪开始后,再触发一次可复现的文件读取动作,随后按 Ctrl+C 结束。生产环境先确认权限、输出文件所在磁盘空间和业务窗口,避免把长期跟踪当成常驻日志。
调用方需求:为什么必须保留 fork 后的子进程
没有 -f 时,strace 只观察附着的那个进程。若主进程随后调用 fork 或 clone,文件访问可能出现在子进程,主进程的记录就会在最关键的位置断开。
带 -f 后,输出通常会把不同 PID 写在每行开头。下面这段是核对格式的示意,路径和返回值来自本文的验证思路,不代表某台机器的固定结果:
[pid 2418] clone(...) = 2427
[pid 2427] openat(AT_FDCWD, "/srv/worker/config.json", O_RDONLY) = 3
[pid 2427] read(3, "{...}", 4096) = 128
[pid 2427] close(3) = 0
第一行说明主进程创建了子进程,后面三行的 2427 说明实际文件调用属于子进程。这里的连线关系是 2418 产生 2427,再由 2427 发起 openat;不要用主进程 PID 替代调用行前的 PID。

参数设计:用 trace=%file 缩小文件访问范围
完整跟踪会混入信号、内存映射、线程同步等调用。只关心路径和文件描述符时,可以先用系统调用集合过滤:
sudo strace -f -e trace=%file -p 2418 -o /tmp/worker-file.trace
%file 是 strace 提供的系统调用类选择器,实际展开集合由 strace 版本和平台定义决定。它不是“只匹配某个文件名”的过滤器,所以仍要在输出里搜索目标路径:
rg -n 'config\.json|No such file|Permission denied' /tmp/worker-file.trace
这一步的证据链是 trace=%file 先减少噪声,config.json 再筛目标,最后看调用返回值。若路径包含空格或正则元字符,调整 rg 模式,不要误把搜索表达式当成 strace 的系统调用过滤规则。

错误处理:路径出现了,不等于文件读取成功
判断结果要看返回值。= 3 表示 openat 返回了文件描述符,= -1 ENOENT 表示目标不存在,= -1 EACCES 则更接近权限或访问控制问题。它们都可能出现在同一个路径旁边,但修复动作完全不同。
| 记录片段 | 先得出的结论 | 下一步 |
|---|---|---|
openat(...) = 3 | 打开成功 | 继续核对 read 和 close |
= -1 ENOENT | 路径在该时刻不存在 | 核对工作目录、挂载点和创建时序 |
= -1 EACCES | 访问被拒绝 | 核对 UID、目录执行权限和安全策略日志 |
如果输出中同时出现主进程和多个子进程,先按 PID 分组,再按时间顺序阅读。不要只截取包含文件名的一行,因为前一行可能是子进程创建,后一行可能是关闭或错误回退。
兼容策略:附着、启动跟踪和输出文件怎么选
已运行服务适合用 -p PID 附着;如果问题只在启动阶段出现,应该让 strace 启动目标程序:
strace -f -e trace=%file -o /tmp/worker-start.trace -- ./worker --config /srv/worker/config.json
附着模式能减少重启影响,但可能错过启动期的文件访问;启动模式能覆盖最早的调用,却会改变启动时序。两种方式都用 -o 保存原始记录,便于把 PID、路径和返回值交给同事复核。
最小核验示例:从一行输出走到可复查结论
拿到 /tmp/worker-file.trace 后,按下面顺序核验:
- 先看每行的 PID,确认调用者是 2418 还是由它产生的 2427。
- 再看
openat的路径是否确实是/srv/worker/config.json,不要只凭文件名判断。 - 最后看返回值,再决定是检查文件存在性、权限,还是继续追踪后续
read。
这套顺序把“进程归属”“路径匹配”“内核结果”拆开了。即便最终没有找到目标路径,也能保留一份可复查的负证据:在本次触发和筛选条件下,哪个进程没有发起预期调用。
常见问题
为什么 strace 里看不到子进程的文件访问?
最常见原因是附着时没有使用 -f,或者子进程在跟踪开始前已经创建。启动期问题优先用启动跟踪,运行期问题再用带 -f 的附着方式复测。
-e trace=%file 会不会只显示某一个文件?
不会。它选择的是文件相关系统调用集合,目标路径仍需要在输出文件中搜索;要确认是否成功,还必须阅读返回值。
看到 ENOENT 就能确定文件不存在吗?
只能说明该调用当时解析到的路径没有对应对象。还要核对进程的工作目录、挂载命名空间、符号链接和调用发生的时刻。
总结
定位 Linux 子进程文件访问时,strace -f 解决的是跟踪范围,-e trace=%file 解决的是输出噪声,-o 解决的是证据保存。真正的结论来自三项同时成立:调用行的 PID、完整路径和系统调用返回值。
-
426 收藏
-
387 收藏
-
242 收藏
-
436 收藏
-
238 收藏
-
165 收藏
-
399 收藏
-
361 收藏
-
262 收藏
-
501 收藏
-
183 收藏
-
192 收藏
-
448 收藏
-
235 收藏
-
363 收藏
-
397 收藏
-
277 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习