最可靠方式是尝试写临时文件并检查错误:errors.Is(err, syscall.EROFS)或错误信息含"read-only file system";Linux下可辅以syscall.Statfs查ST_RDONLY标志,跨平台应优先试写 fallback解析错误。

如何用 Go 判断挂载点是否只读
Go 标准库没有直接提供“判断挂载点是否只读”的函数,os.Stat 和 os.IsPermission 对只读文件系统无效——即使整个挂载点是 ro,只要用户对某个目录有执行权限,os.Stat 仍能成功返回。真正可靠的方式是尝试写一个临时文件并捕获错误。
关键不是“能不能读”,而是“能不能写”。只读挂载下,任何写操作(包括 open(O_CREAT|O_WRONLY)、os.Create、os.Mkdir)都会返回特定错误。
-
os.ErrPermission在部分系统(如 ext4 + ro mount)下可能不出现,实际常见的是<nil>错误返回但后续Write失败,或更典型的是read-only file system字符串出现在error.Error()中 - 不要依赖
syscall.EPERM或syscall.EACCES:它们表示权限不足,而非文件系统只读;只读挂载通常触发的是syscall.EROFS(Error Read-Only File System) - 最稳妥的做法:在目标路径下调用
os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0200),检查错误是否为syscall.EROFS或其字符串是否含"read-only file system"
用 syscall.Statfs 检查挂载标志(Linux 专用)
Linux 下可通过 syscall.Statfs 获取挂载选项,直接读取 Statfs_t.Flags 中的 ST_RDONLY 位。这比试写更快、更干净,且不产生副作用,但仅限 Linux,且需确保目标是挂载点根目录(非子路径)。
注意:syscall.Statfs 接收路径,但返回的是该路径所在文件系统的统计信息——如果传入的是挂载点内嵌套的子目录,依然能正确反映该文件系统是否只读;但如果路径跨了 bind mount 或 overlayfs,行为可能不符合预期。
立即学习“go语言免费学习笔记(深入)”;
- 必须 import
"syscall"(非golang.org/x/sys/unix,后者在部分老版本 Go 中未导出Statfs) - 调用后检查
statfsBuf.Flags & syscall.ST_RDONLY是否非零 - 若
syscall.Statfs返回 error(如路径不存在),应 fallback 到试写法 - 示例片段:
var sfs syscall.Statfs_t if err := syscall.Statfs(path, &sfs); err != nil { return false, err } return sfs.Flags&syscall.ST_RDONLY != 0, nil
跨平台兼容写法:封装可读/可写探测函数
生产环境往往要兼顾 Linux/macOS/Windows。Windows 没有“挂载点只读”概念(只有 ACL 或 FAT 只读属性),macOS 的 statfs 有 MNT_RDONLY 但字段名和位定义与 Linux 不同。因此统一策略是:优先试写,失败后解析错误文本;Linux 额外加 Statfs 快速路径。
- 避免在 /proc/mounts 或
mount命令输出中做字符串匹配——依赖 shell、解析脆弱、权限受限 - 试写路径应选目标挂载点下的可访问子路径(如
path + "/.rocheck-xxx"),写完立即os.Remove;若Remove也失败(比如只读又不可删),至少说明写已被拒,可判定为只读 - 错误判断逻辑建议:
errStr := err.Error() isRO := strings.Contains(errStr, "read-only file system") || strings.Contains(errStr, "EROFS") || errors.Is(err, syscall.EROFS) - 不要忽略
ENOSPC或EDQUOT:它们可能和只读混淆,需单独排除(例如先os.Stat确认路径存在且是 dir)
常见误判场景和绕过风险
只读检查常被用于“自动降级”或“拒绝启动”,但实际部署中容易踩坑。
- 容器环境里,
/proc、/sys是只读挂载,但应用不该去那里写;检查前应明确目标路径是否属于业务数据挂载点(如/data),而非任意os.Getwd() - bind mount 或 overlayfs 可能导致
Statfs返回底层 fs 标志,而非上层表现——比如 overlay lowerdir 是 ro,但 upperdir 是 rw,整体仍是可写的 - 某些 NFS 挂载在服务器端设为 ro,但客户端
mount时没加ro,此时Statfs可能不报ST_RDONLY,但实际写会卡住或超时;这时必须依赖试写 + 设置timeout(通过context.WithTimeout包裹 I/O) - root 用户在只读挂载下仍可能创建设备节点或修改扩展属性,所以单纯检查
os.Create不够,建议用os.WriteFile(path, []byte("x"), 0600)更贴近真实写行为
最麻烦的不是技术实现,而是确认你检查的路径确实代表你要保护的那个存储单元——挂载点边界、命名空间隔离、容器卷绑定方式,这些都比 EROFS 判断本身更易出错。


















