package collect import ( "encoding/json" "os/exec" "strings" "time" ) // ShareServices is the read-only view of the file-sharing daemons. type ShareServices struct { SMBInstalled bool `json:"smb_installed"` NFSInstalled bool `json:"nfs_installed"` SMBActive bool `json:"smb_active"` NFSActive bool `json:"nfs_active"` SMBSessions int `json:"smb_sessions"` } // ReadShareServices checks which sharing daemons exist and run. func ReadShareServices() ShareServices { var s ShareServices if _, err := exec.LookPath("smbd"); err == nil { s.SMBInstalled = true s.SMBActive = unitActive("smbd") if s.SMBActive { s.SMBSessions = smbSessions() } } if _, err := exec.LookPath("exportfs"); err == nil { s.NFSInstalled = true s.NFSActive = unitActive("nfs-server") } return s } func unitActive(unit string) bool { out, _ := run(5*time.Second, "systemctl", "is-active", unit) return strings.TrimSpace(string(out)) == "active" } // smbSessions counts connected SMB sessions via smbstatus --json (Samba ≥ 4.17). func smbSessions() int { out, err := run(10*time.Second, "smbstatus", "--json", "-b") if err != nil && len(out) == 0 { return 0 } return parseSmbSessions(out) } func parseSmbSessions(b []byte) int { var j struct { Sessions map[string]json.RawMessage `json:"sessions"` } if json.Unmarshal(b, &j) != nil { return 0 } return len(j.Sessions) }