package storage import ( "context" "os/exec" "syscall" "github.com/darroyo/nasctl/internal/db" "github.com/darroyo/nasctl/internal/system" ) type Capabilities struct { Rsync bool `json:"rsync"` MergerfsBin bool `json:"mergerfs"` MergerfsMounted bool `json:"mergerfs_mounted"` SnapraidBin bool `json:"snapraid"` } func Probe(ctx context.Context) (Capabilities, error) { _, rsyncErr := exec.LookPath("rsync") _, snapraidErr := exec.LookPath("snapraid") _, mergerfsErr := exec.LookPath("mergerfs") _, _, mergerfsMountedErr := system.Run(ctx, "grep", "-q", "fuse.mergerfs", "/proc/mounts") return Capabilities{ Rsync: rsyncErr == nil, MergerfsBin: mergerfsErr == nil, MergerfsMounted: mergerfsMountedErr == nil, SnapraidBin: snapraidErr == nil, }, nil } type PathStat struct { Path string `json:"path"` Available bool `json:"available"` TotalBytes uint64 `json:"total_bytes"` UsedBytes uint64 `json:"used_bytes"` FreeBytes uint64 `json:"free_bytes"` UsedPercent float64 `json:"used_percent"` Error string `json:"error,omitempty"` } func StatPath(p string) PathStat { out := PathStat{Path: p, Available: false} if p == "" { out.Error = "path no configurado" return out } var st syscall.Statfs_t if err := syscall.Statfs(p, &st); err != nil { out.Error = err.Error() return out } out.Available = true out.TotalBytes = st.Blocks * uint64(st.Bsize) out.FreeBytes = st.Bavail * uint64(st.Bsize) out.UsedBytes = out.TotalBytes - out.FreeBytes if out.TotalBytes > 0 { out.UsedPercent = float64(out.UsedBytes) / float64(out.TotalBytes) * 100 } return out } func ValidatePaths(cfg db.StorageConfig) error { return nil }