Files
felhom-controller/controller/internal/system/mountdead_linux.go
T

57 lines
1.7 KiB
Go

//go:build linux
package system
import (
"os"
"path/filepath"
"strings"
)
// MountIsShutdown reports whether the TOP mount at path is a dead filesystem — ext4's `shutdown` super option, set when
// the device under it went away (a pulled drive). It reads /proc/self/mountinfo only: NO disk I/O, so it never hangs on
// the dead device (gates.md: health checks issue no block I/O). A timed `stat` is NOT a substitute: it answered „ok" on
// a dead drive from the cache (measured 2026-10-14, `15` §10 K4). Pinned by TestMountIsShutdown_*.
func MountIsShutdown(path string) bool {
data, err := os.ReadFile(mountinfoPath)
if err != nil {
return false
}
return mountinfoShutdown(string(data), path)
}
var mountinfoPath = "/proc/self/mountinfo"
// mountinfoShutdown: the LAST mountinfo line whose mount point is path (the top of a stack) carries `shutdown` in its
// super options (the third field after " - ").
func mountinfoShutdown(mountinfo, path string) bool {
path = filepath.Clean(path)
dead := false
found := false
for _, line := range strings.Split(mountinfo, "\n") {
f := strings.Fields(line)
if len(f) < 5 || unescapeMountinfo(f[4]) != path {
continue
}
found = true
dead = false
if i := strings.Index(line, " - "); i >= 0 {
tail := strings.Fields(line[i+3:])
if len(tail) >= 3 {
for _, o := range strings.Split(tail[2], ",") {
if o == "shutdown" {
dead = true
}
}
}
}
}
return found && dead
}
// unescapeMountinfo undoes mountinfo's octal escapes for space, tab, newline and backslash.
func unescapeMountinfo(s string) string {
r := strings.NewReplacer(`\040`, " ", `\011`, "\t", `\012`, "\n", `\134`, `\`)
return r.Replace(s)
}