应通过 disk.partitions(false) 获取挂载项并检查 opts 是否含 "ro" 字符串来判断只读状态,而非依赖 disk.usage()、os.stat() 或写入试探;需先解析符号链接并注意 bind mount 独立性。

如何用 disk.Usage() 判断挂载点是否只读
直接调用 disk.Usage() 无法得知只读状态——它只返回容量和使用量,不暴露挂载选项。真正可靠的方式是先获取挂载信息,再检查 Opts 字段是否含 "ro"。Linux 下需依赖 disk.Partitions(false)(第二个参数设为 false,避免过滤掉只读挂载),然后遍历结果:
-
disk.Partitions(false)返回所有块设备挂载项,包括/proc、tmpfs等虚拟文件系统,也包含ro挂载点 - 对每个
disk.PartitionStat,检查Opts字符串是否包含"ro"(注意:不是"rw"缺失,而是显式含"ro";某些内核会同时写"rw,relatime,ro",所以必须用子串匹配) - 只读判断不能仅靠
os.Stat()或os.OpenFile(..., os.O_WRONLY, 0)试探——前者不报错,后者可能因权限/父目录执行位缺失而误判
os.IsPermission() 不等于只读,但能帮你快速失败
当你尝试写入某个路径却失败时,os.IsPermission(err) 只说明“当前用户无权写”,不区分是文件权限不足、父目录缺 x 位,还是整个文件系统被 mount -o ro。但它仍是第一道轻量拦截:
- 写日志前先
os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0644),捕获os.IsPermission错误并记录原始err.Error() - 若错误含
"read-only file system"字样(Linux 错误字符串固定),可直接判定为只读挂载,无需再查Partitions - Windows 下该字符串不存在,但
os.IsPermission仍有效——此时只读由 NTFS ACL 或卷属性控制,disk.Partitions不适用
符号链接和 bind mount 会让路径解析失效
你传给 disk.Partitions() 的路径必须是真实挂载点,否则查到的 Opts 和实际路径无关。常见陷阱:
-
filepath.EvalSymlinks("/data")必须在调用前做,否则软链指向的路径可能挂载在另一设备上,且选项不同 - bind mount(如
mount --bind /src /dst)会生成独立挂载项,disk.Partitions()能列出/dst,但它的Opts和源路径无关 - overlayfs、btrfs subvolume 等高级文件系统,
Opts可能不含"ro",但实际行为只读——这时得结合os.OpenFile试探 + 错误字符串判断
开机自启服务里日志写入失败,优先查挂载选项而非权限
用 github.com/kardianos/service 启动的服务,启动时机早于某些挂载完成(如 NFS、加密卷),/var/log 可能尚未挂载或以 ro 挂载。此时:
- 不要硬编码日志路径为
/var/log/myapp.log,先用disk.Usage("/var/log")确认挂载点存在且可访问 - 若
disk.Usage()返回ErrNotFound或ErrPermission,立即 fallback 到/tmp或内存 buffer,并发告警 - 真正要修复的不是代码,而是 systemd service 文件里的
After=依赖项,比如加After=remote-fs.target或具体挂载单元名
os.OpenFile(..., os.O_WRONLY) 都会失败,但只有检查 disk.Partitions().Opts 才能定位到最外层原因。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











