diff --git a/display.go b/display.go index fc84b8d..6833128 100644 --- a/display.go +++ b/display.go @@ -1,161 +1,158 @@ package main import ( - "fmt" - "github.com/shirou/gopsutil/disk" - "github.com/shirou/gopsutil/load" - "github.com/shirou/gopsutil/mem" - "net" - "os" - "os/exec" - "os/user" - "runtime" - "strings" - "time" + "fmt" + "github.com/shirou/gopsutil/disk" + "github.com/shirou/gopsutil/load" + "github.com/shirou/gopsutil/mem" + "os" + "os/exec" + "os/user" + "runtime" + "strings" + "time" ) -func displaySystemInfoInInterval(interval time.Duration) { - for { - clearScreen() - displaySystemInfo() - time.Sleep(interval) - } +// displaySystemInfoAtInterval displays system information at specified intervals. +func displaySystemInfoAtInterval(interval time.Duration) { + for { + clearScreen() + displaySystemInfo() + time.Sleep(interval) + } } +// displaySystemInfo collects and displays system information. func displaySystemInfo() { - currentUser, err := user.Current() - if err != nil { - fmt.Printf("Failed to get current user: %s\n", err) - return - } - userName := currentUser.Username - - currentPTS, err := getCurrentPTS() - if err != nil { - fmt.Printf("Failed to get current PTS: %s\n", err) - return - } - - activeUsers, err := getActiveUsers() - if err != nil { - fmt.Printf("Error getting active users: %s\n", err) - return - } - - hostName, err := os.Hostname() - if err != nil { - fmt.Printf("Failed to get hostname: %s\n", err) - return - } - - conn, err := net.Dial("udp", "8.8.8.8:80") - if err != nil { - fmt.Printf("Failed to dial: %s\n", err) - return - } - localAddr := conn.LocalAddr().(*net.UDPAddr) - ip := localAddr.IP.String() - conn.Close() - - uptime, err := getUptime() - if err != nil { - fmt.Printf("Failed to get uptime: %s\n", err) - return - } - upDays := uptime / (24 * time.Hour) - upHours := (uptime % (24 * time.Hour)) / time.Hour - upMins := (uptime % time.Hour) / time.Minute - upSecs := (uptime % time.Minute) / time.Second - - vmStat, err := mem.VirtualMemory() - if err != nil { - fmt.Printf("Failed to get virtual memory info: %s\n", err) - return - } - memoryUsed := vmStat.Used / 1024 / 1024 - memoryTotal := vmStat.Total / 1024 / 1024 - memoryAvailable := vmStat.Available / 1024 / 1024 - usedMemoryPercent := (float64(memoryUsed) / float64(memoryTotal)) * 100 - freeMemoryPercent := 100 - usedMemoryPercent - - cpuInfo, err := getCPUInfo() - if err != nil { - fmt.Printf("Failed to get CPU info: %s\n", err) - return - } - - cpuCores, err := getCPUCores() - if err != nil { - fmt.Printf("Failed to get CPU cores: %s\n", err) - return - } - - loadAvg, err := load.Avg() - if err != nil { - fmt.Printf("Failed to get load average: %s\n", err) - return - } - - diskStat, err := disk.Usage("/") - if err != nil { - fmt.Printf("Failed to get disk usage: %s\n", err) - return - } - - memoryUsedGB := float64(memoryUsed) / 1024 - memoryTotalGB := float64(memoryTotal) / 1024 - memoryAvailableGB := float64(memoryAvailable) / 1024 - - diskFree := float64(diskStat.Free) / 1024 / 1024 / 1024 - diskTotal := float64(diskStat.Total) / 1024 / 1024 / 1024 - diskUsed := diskTotal - diskFree - freeDiskPercent := (diskFree / diskTotal) * 100 - - const ( - resetColor = "\033[0m" - bold = "\033[1m" - cyan = "\033[36m" - ) - fmt.Println(cyan + "======================================OSMON======================================" + resetColor) - fmt.Printf("%s%s - CPU.................:%s %s (%d cores)%s\n", bold, cyan, resetColor, cpuInfo, cpuCores, resetColor) - fmt.Printf("%s%s - Load................:%s %.2f %.2f %.2f%s\n", bold, cyan, resetColor, loadAvg.Load1, loadAvg.Load5, loadAvg.Load15, resetColor) - fmt.Printf("%s%s - Memory..............:%s %.2f GB / %.2f GB (%.2f GB remaining, %.2f%% free)%s\n", - bold, cyan, resetColor, memoryUsedGB, memoryTotalGB, memoryAvailableGB, freeMemoryPercent, resetColor) - fmt.Printf("%s%s - Disk space /........:%s %.2f GB / %.2f GB (%.2f GB remaining, %.2f%% free)%s\n", bold, cyan, resetColor, diskUsed, diskTotal, diskFree, freeDiskPercent, resetColor) - fmt.Printf("%s%s - Processes...........:%s %d running%s\n", bold, cyan, resetColor, getProcessCount(), resetColor) - fmt.Printf("%s%s - System uptime.......:%s %d days %d hours %d minutes %d seconds%s\n", bold, cyan, resetColor, upDays, upHours, upMins, upSecs, resetColor) - fmt.Printf("%s%s - Hostname / IP.......:%s %s / %s%s\n", bold, cyan, resetColor, hostName, ip, resetColor) - fmt.Printf("%s%s - Release.............:%s %s%s\n", bold, cyan, resetColor, getOSRelease(), resetColor) - fmt.Printf("%s%s - Current user........:%s [%s: %s]%s\n", bold, cyan, resetColor, currentPTS, userName, resetColor) - if runtime.GOOS == "linux" { - fmt.Printf("%s%s - Active users........:%s ", bold, cyan, resetColor) - for terminal, users := range activeUsers { - fmt.Printf("[%s: %s] ", terminal, strings.Join(users, ", ")) - } - fmt.Println() - } - fmt.Println(cyan + "=================================================================================" + resetColor) + currentUser, err := user.Current() + if err != nil { + fmt.Printf("Failed to get current user: %s\n", err) + return + } + userName := currentUser.Username + + currentPTS, err := getCurrentPTS() + if err != nil { + fmt.Printf("Failed to get current PTS: %s\n", err) + currentPTS = "Unknown" + } + + activeUsers, err := getActiveUsers() + if err != nil { + fmt.Printf("Error getting active users: %s\n", err) + activeUsers = make(map[string][]string) + } + + hostName, err := os.Hostname() + if err != nil { + fmt.Printf("Failed to get hostname: %s\n", err) + hostName = "Unknown" + } + + ip, err := getLocalIP() + if err != nil { + fmt.Println("No network access") + ip = "No connection" + } + + uptime, err := getUptime() + if err != nil { + fmt.Printf("Failed to get uptime: %s\n", err) + uptime = 0 + } + upDays := uptime / (24 * time.Hour) + upHours := (uptime % (24 * time.Hour)) / time.Hour + upMins := (uptime % time.Hour) / time.Minute + upSecs := (uptime % time.Minute) / time.Second + + vmStat, err := mem.VirtualMemory() + if err != nil { + fmt.Printf("Failed to get virtual memory info: %s\n", err) + vmStat = &mem.VirtualMemoryStat{} + } + memoryUsedGB := float64(vmStat.Used) / 1024 / 1024 / 1024 + memoryTotalGB := float64(vmStat.Total) / 1024 / 1024 / 1024 + memoryAvailableGB := float64(vmStat.Available) / 1024 / 1024 / 1024 + usedMemoryPercent := (float64(vmStat.Used) / float64(vmStat.Total)) * 100 + freeMemoryPercent := 100 - usedMemoryPercent + + cpuInfo, err := getCPUInfo() + if err != nil { + fmt.Printf("Failed to get CPU info: %s\n", err) + cpuInfo = "Unknown" + } + + cpuCores, err := getCPUCores() + if err != nil { + fmt.Printf("Failed to get CPU cores: %s\n", err) + cpuCores = 0 + } + + loadAvg, err := load.Avg() + if err != nil { + fmt.Printf("Failed to get load average: %s\n", err) + loadAvg = &load.AvgStat{} + } + + diskStat, err := disk.Usage("/") + if err != nil { + fmt.Printf("Failed to get disk usage: %s\n", err) + diskStat = &disk.UsageStat{} + } + diskFreeGB := float64(diskStat.Free) / 1024 / 1024 / 1024 + diskTotalGB := float64(diskStat.Total) / 1024 / 1024 / 1024 + diskUsedGB := diskTotalGB - diskFreeGB + freeDiskPercent := (diskFreeGB / diskTotalGB) * 100 + + const ( + resetColor = "\033[0m" + bold = "\033[1m" + cyan = "\033[36m" + ) + + fmt.Println(cyan + "======================================OSMON======================================" + resetColor) + fmt.Printf("%s%s - CPU.................:%s %s (%d cores)%s\n", bold, cyan, resetColor, cpuInfo, cpuCores, resetColor) + fmt.Printf("%s%s - Load................:%s %.2f %.2f %.2f%s\n", bold, cyan, resetColor, loadAvg.Load1, loadAvg.Load5, loadAvg.Load15, resetColor) + fmt.Printf("%s%s - Memory..............:%s %.2f GB / %.2f GB (%.2f GB remaining, %.2f%% free)%s\n", + bold, cyan, resetColor, memoryUsedGB, memoryTotalGB, memoryAvailableGB, freeMemoryPercent, resetColor) + fmt.Printf("%s%s - Disk space /........:%s %.2f GB / %.2f GB (%.2f GB remaining, %.2f%% free)%s\n", + bold, cyan, resetColor, diskUsedGB, diskTotalGB, diskFreeGB, freeDiskPercent, resetColor) + fmt.Printf("%s%s - Processes...........:%s %d running%s\n", bold, cyan, resetColor, getProcessCount(), resetColor) + fmt.Printf("%s%s - System uptime.......:%s %d days %d hours %d minutes %d seconds%s\n", bold, cyan, resetColor, upDays, upHours, upMins, upSecs, resetColor) + fmt.Printf("%s%s - Hostname / IP.......:%s %s / %s%s\n", bold, cyan, resetColor, hostName, ip, resetColor) + fmt.Printf("%s%s - Release.............:%s %s%s\n", bold, cyan, resetColor, getOSRelease(), resetColor) + fmt.Printf("%s%s - Current user........:%s [%s: %s]%s\n", bold, cyan, resetColor, currentPTS, userName, resetColor) + if runtime.GOOS == "linux" { + fmt.Printf("%s%s - Active users........:%s ", bold, cyan, resetColor) + for terminal, users := range activeUsers { + fmt.Printf("[%s: %s] ", terminal, strings.Join(users, ", ")) + } + fmt.Println() + } + fmt.Println(cyan + "=================================================================================" + resetColor) } +// clearScreen clears the terminal screen. func clearScreen() { - if runtime.GOOS == "windows" { - cmd := exec.Command("cmd", "/c", "cls") - cmd.Stdout = os.Stdout - cmd.Run() - } else { - fmt.Print("\033[H\033[2J") - } + if runtime.GOOS == "windows" { + cmd := exec.Command("cmd", "/c", "cls") + cmd.Stdout = os.Stdout + cmd.Run() + } else { + fmt.Print("\033[H\033[2J") + } } +// displayHelp displays the help information. func displayHelp() { - fmt.Println("OSInfo - Display system information with refresh interval") - fmt.Println("\nUsage:") - fmt.Println(" ./osmon Display system information once") - fmt.Println(" ./osmon -i Refresh system information every seconds") - fmt.Println(" ./osmon -h/--help Display this help information") - fmt.Println(" ./osmon -v/--version Display the version of the application") - fmt.Println("\nFlags:") - fmt.Println(" -i, --interval Set interval for refreshing the display in seconds") - fmt.Println(" -h, --help Display help information") - fmt.Println(" -v, --version Display the version of the application") + fmt.Println("OSMON - Display system information with refresh interval") + fmt.Println("\nUsage:") + fmt.Println(" ./osmon Display system information once") + fmt.Println(" ./osmon -i Refresh system information every seconds") + fmt.Println(" ./osmon -h/--help Display this help information") + fmt.Println(" ./osmon -v/--version Display the version of the application") + fmt.Println("\nFlags:") + fmt.Println(" -i, --interval Set interval for refreshing the display in seconds") + fmt.Println(" -h, --help Display help information") + fmt.Println(" -v, --version Display the version of the application") } diff --git a/flags.go b/flags.go index 16042fb..ce835a6 100644 --- a/flags.go +++ b/flags.go @@ -1,45 +1,45 @@ package main import ( - "flag" - "fmt" - "strconv" - "time" + "flag" + "fmt" + "strconv" + "time" ) type intervalFlag struct { - set bool - value time.Duration + set bool + value time.Duration } -// Set is a method called by the flag package when the flag is set. +// Set is called by the flag package when the flag is set. func (f *intervalFlag) Set(s string) error { - f.set = true - var seconds int - var err error - seconds, err = strconv.Atoi(s) - if err != nil { - return fmt.Errorf("invalid format for interval: %v", err) - } - f.value = time.Duration(seconds) * time.Second - return nil + f.set = true + var seconds int + var err error + seconds, err = strconv.Atoi(s) + if err != nil { + return fmt.Errorf("invalid format for interval: %v", err) + } + f.value = time.Duration(seconds) * time.Second + return nil } -// String returns the string representation of the flag +// String returns the string representation of the flag. func (f *intervalFlag) String() string { - if !f.set { - return "not set" - } - return fmt.Sprintf("%d", f.value) + if !f.set { + return "not set" + } + return fmt.Sprintf("%d", f.value) } func DefineFlags() (intervalFlag, *bool, *bool) { - var interval intervalFlag - var helpFlag = flag.Bool("h", false, "Display help information (shorthand)") - var versionFlag = flag.Bool("v", false, "Display the version of the application (shorthand)") + var interval intervalFlag + var helpFlag = flag.Bool("h", false, "Display help information (shorthand)") + var versionFlag = flag.Bool("v", false, "Display the version of the application (shorthand)") - flag.Var(&interval, "i", "Set interval for refreshing the display in seconds (shorthand)") - flag.Var(&interval, "interval", "Set interval for refreshing the display in seconds") + flag.Var(&interval, "i", "Set interval for refreshing the display in seconds (shorthand)") + flag.Var(&interval, "interval", "Set interval for refreshing the display in seconds") - return interval, helpFlag, versionFlag + return interval, helpFlag, versionFlag } diff --git a/go.mod b/go.mod index f2e73d8..ed33c05 100644 --- a/go.mod +++ b/go.mod @@ -1,11 +1,11 @@ -module github.com/debek/osmon +module osmon -go 1.16 +go 1.17 require github.com/shirou/gopsutil v3.21.11+incompatible require ( - github.com/stretchr/testify v1.8.4 // indirect - github.com/tklauser/go-sysconf v0.3.13 // indirect - github.com/yusufpapurcu/wmi v1.2.3 // indirect + github.com/tklauser/go-sysconf v0.3.14 // indirect + github.com/tklauser/numcpus v0.8.0 // indirect + golang.org/x/sys v0.26.0 // indirect ) diff --git a/go.sum b/go.sum index d0f8733..76fc5ca 100644 --- a/go.sum +++ b/go.sum @@ -16,13 +16,19 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4= github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0= +github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU= +github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY= github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4= github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY= +github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY= +github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/main.go b/main.go index 051c9b4..a652054 100644 --- a/main.go +++ b/main.go @@ -6,44 +6,44 @@ package main import ( - "flag" - "fmt" - "os" + "flag" + "fmt" + "os" ) func main() { - var interval intervalFlag - var helpFlag bool - var versionFlag bool + var interval intervalFlag + var helpFlag bool + var versionFlag bool - flag.Usage = displayHelp - flag.Var(&interval, "i", "Set interval for refreshing the display in seconds (shorthand)") - flag.Var(&interval, "interval", "Set interval for refreshing the display in seconds") - flag.BoolVar(&helpFlag, "h", false, "Display help information (shorthand)") - flag.BoolVar(&helpFlag, "help", false, "Display help information") - flag.BoolVar(&versionFlag, "v", false, "Display the version of the application (shorthand)") - flag.BoolVar(&versionFlag, "version", false, "Display the version of the application") - flag.Parse() + flag.Usage = displayHelp + flag.Var(&interval, "i", "Set interval for refreshing the display in seconds (shorthand)") + flag.Var(&interval, "interval", "Set interval for refreshing the display in seconds") + flag.BoolVar(&helpFlag, "h", false, "Display help information (shorthand)") + flag.BoolVar(&helpFlag, "help", false, "Display help information") + flag.BoolVar(&versionFlag, "v", false, "Display the version of the application (shorthand)") + flag.BoolVar(&versionFlag, "version", false, "Display the version of the application") + flag.Parse() - if versionFlag { - appVersion := os.Getenv("APP_VERSION") - if appVersion == "" { - appVersion = "development" - } - fmt.Printf("Osmon version %s\n", appVersion) - os.Exit(0) - } + if versionFlag { + appVersion := os.Getenv("APP_VERSION") + if appVersion == "" { + appVersion = "development" + } + fmt.Printf("Osmon version %s\n", appVersion) + os.Exit(0) + } - if helpFlag { - displayHelp() - os.Exit(0) - } + if helpFlag { + displayHelp() + os.Exit(0) + } - if interval.set { - // Display system information in interval - displaySystemInfoInInterval(interval.value) - } else { - // Display system information once - displaySystemInfo() - } + if interval.set { + // Display system information at intervals + displaySystemInfoAtInterval(interval.value) + } else { + // Display system information once + displaySystemInfo() + } } diff --git a/network_info.go b/network_info.go new file mode 100644 index 0000000..47d70e9 --- /dev/null +++ b/network_info.go @@ -0,0 +1,38 @@ +package main + +import ( + "fmt" + "net" +) + +// getLocalIP retrieves the local IP address without connecting to an external server. +func getLocalIP() (string, error) { + interfaces, err := net.Interfaces() + if err != nil { + return "", err + } + for _, iface := range interfaces { + if iface.Flags&net.FlagUp != 0 && iface.Flags&net.FlagLoopback == 0 { + addrs, err := iface.Addrs() + if err != nil { + continue + } + for _, addr := range addrs { + var ip net.IP + switch v := addr.(type) { + case *net.IPNet: + ip = v.IP + case *net.IPAddr: + ip = v.IP + } + if ip == nil || ip.IsLoopback() { + continue + } + if ip.To4() != nil { + return ip.String(), nil + } + } + } + } + return "", fmt.Errorf("No network connection available") +} diff --git a/system_info.go b/system_info.go index 4923b28..c13641a 100644 --- a/system_info.go +++ b/system_info.go @@ -1,120 +1,125 @@ package main import ( - "bufio" - "fmt" - "os" - "os/exec" - "runtime" - "strconv" - "strings" - "time" + "bufio" + "fmt" + "os" + "os/exec" + "runtime" + "strconv" + "strings" + "time" ) +// getOSRelease retrieves the operating system release information. func getOSRelease() string { - if runtime.GOOS == "darwin" { - out, err := exec.Command("sw_vers", "-productVersion").Output() - if err != nil { - return "Unknown" - } - return "macOS " + strings.TrimSpace(string(out)) - } - if runtime.GOOS == "linux" { - file, err := os.Open("/etc/os-release") - if err != nil { - return "Unknown" - } - defer file.Close() + if runtime.GOOS == "darwin" { + out, err := exec.Command("sw_vers", "-productVersion").Output() + if err != nil { + return "Unknown" + } + return "macOS " + strings.TrimSpace(string(out)) + } + if runtime.GOOS == "linux" { + file, err := os.Open("/etc/os-release") + if err != nil { + return "Unknown" + } + defer file.Close() - scanner := bufio.NewScanner(file) - for scanner.Scan() { - line := scanner.Text() - if strings.HasPrefix(line, "PRETTY_NAME=") { - return strings.Trim(line[13:], "\"") - } - } - } - return "Unknown" + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := scanner.Text() + if strings.HasPrefix(line, "PRETTY_NAME=") { + return strings.Trim(line[13:], "\"") + } + } + } + return "Unknown" } +// getCPUInfo retrieves information about the CPU. func getCPUInfo() (string, error) { - if runtime.GOOS == "darwin" { - out, err := exec.Command("sysctl", "-n", "machdep.cpu.brand_string").Output() - if err != nil { - return "", err - } - return strings.TrimSpace(string(out)), nil - } - if runtime.GOOS == "linux" { - out, err := exec.Command("cat", "/proc/cpuinfo").Output() - if err != nil { - return "", err - } - return parseLinuxCPUInfo(string(out)), nil - } - return "", fmt.Errorf("unsupported platform") + if runtime.GOOS == "darwin" { + out, err := exec.Command("sysctl", "-n", "machdep.cpu.brand_string").Output() + if err != nil { + return "", err + } + return strings.TrimSpace(string(out)), nil + } + if runtime.GOOS == "linux" { + out, err := exec.Command("cat", "/proc/cpuinfo").Output() + if err != nil { + return "", err + } + return parseLinuxCPUInfo(string(out)), nil + } + return "", fmt.Errorf("unsupported platform") } +// parseLinuxCPUInfo parses CPU information from /proc/cpuinfo on Linux. func parseLinuxCPUInfo(info string) string { - lines := strings.Split(info, "\n") - for _, line := range lines { - if strings.HasPrefix(line, "model name") { - return strings.TrimSpace(strings.Split(line, ":")[1]) - } - } - return "Unknown" + lines := strings.Split(info, "\n") + for _, line := range lines { + if strings.HasPrefix(line, "model name") { + return strings.TrimSpace(strings.Split(line, ":")[1]) + } + } + return "Unknown" } +// getCPUCores retrieves the number of CPU cores. func getCPUCores() (int, error) { - if runtime.GOOS == "darwin" { - out, err := exec.Command("sysctl", "-n", "hw.ncpu").Output() - if err != nil { - return 0, err - } - cores, err := strconv.Atoi(strings.TrimSpace(string(out))) - if err != nil { - return 0, err - } - return cores, nil - } - if runtime.GOOS == "linux" { - out, err := exec.Command("grep", "-c", "processor", "/proc/cpuinfo").Output() - if err != nil { - return 0, err - } - cores, err := strconv.Atoi(strings.TrimSpace(string(out))) - if err != nil { - return 0, err - } - return cores, nil - } - return 0, fmt.Errorf("unsupported platform") + if runtime.GOOS == "darwin" { + out, err := exec.Command("sysctl", "-n", "hw.ncpu").Output() + if err != nil { + return 0, err + } + cores, err := strconv.Atoi(strings.TrimSpace(string(out))) + if err != nil { + return 0, err + } + return cores, nil + } + if runtime.GOOS == "linux" { + out, err := exec.Command("grep", "-c", "processor", "/proc/cpuinfo").Output() + if err != nil { + return 0, err + } + cores, err := strconv.Atoi(strings.TrimSpace(string(out))) + if err != nil { + return 0, err + } + return cores, nil + } + return 0, fmt.Errorf("unsupported platform") } +// getUptime retrieves the system uptime. func getUptime() (time.Duration, error) { - if runtime.GOOS == "darwin" { - out, err := exec.Command("sysctl", "-n", "kern.boottime").Output() - if err != nil { - return 0, err - } - uptimeString := strings.Split(strings.Split(string(out), "=")[1], ",")[0] - uptimeSec, err := strconv.ParseInt(strings.TrimSpace(uptimeString), 10, 64) - if err != nil { - return 0, err - } - return time.Since(time.Unix(uptimeSec, 0)), nil - } - if runtime.GOOS == "linux" { - out, err := exec.Command("cat", "/proc/uptime").Output() - if err != nil { - return 0, err - } - uptimeString := strings.Fields(string(out))[0] - uptimeSec, err := strconv.ParseFloat(uptimeString, 64) - if err != nil { - return 0, err - } - return time.Duration(uptimeSec) * time.Second, nil - } - return 0, fmt.Errorf("unsupported platform") + if runtime.GOOS == "darwin" { + out, err := exec.Command("sysctl", "-n", "kern.boottime").Output() + if err != nil { + return 0, err + } + uptimeString := strings.Split(strings.Split(string(out), "=")[1], ",")[0] + uptimeSec, err := strconv.ParseInt(strings.TrimSpace(uptimeString), 10, 64) + if err != nil { + return 0, err + } + return time.Since(time.Unix(uptimeSec, 0)), nil + } + if runtime.GOOS == "linux" { + out, err := exec.Command("cat", "/proc/uptime").Output() + if err != nil { + return 0, err + } + uptimeString := strings.Fields(string(out))[0] + uptimeSec, err := strconv.ParseFloat(uptimeString, 64) + if err != nil { + return 0, err + } + return time.Duration(uptimeSec) * time.Second, nil + } + return 0, fmt.Errorf("unsupported platform") } diff --git a/user_info.go b/user_info.go index bad3f2d..693b3d1 100644 --- a/user_info.go +++ b/user_info.go @@ -1,91 +1,94 @@ package main import ( - "bufio" - "fmt" - "os" - "os/exec" - "regexp" - "runtime" - "strings" + "bufio" + "fmt" + "os" + "os/exec" + "regexp" + "runtime" + "strings" ) +// getActiveUsers retrieves a map of active users and their terminals. func getActiveUsers() (map[string][]string, error) { - out, err := exec.Command("ps", "aux").Output() - if err != nil { - return nil, err - } + out, err := exec.Command("ps", "aux").Output() + if err != nil { + return nil, err + } - activeUsers := make(map[string][]string) - lines := strings.Split(string(out), "\n") - for _, line := range lines { - fields := strings.Fields(line) - if len(fields) > 1 { - user := fields[0] - tty := fields[6] - if strings.HasPrefix(tty, "pts") { // Dodano sprawdzenie czy tty zaczyna siÄ™ od "pts" - if _, found := activeUsers[tty]; !found { - activeUsers[tty] = []string{} - } - fullUserName, err := getFullUserName(user) - if err == nil { - user = fullUserName - } - if !contains(activeUsers[tty], user) { - activeUsers[tty] = append(activeUsers[tty], user) - } - } - } - } - return activeUsers, nil + activeUsers := make(map[string][]string) + lines := strings.Split(string(out), "\n") + for _, line := range lines { + fields := strings.Fields(line) + if len(fields) > 1 { + user := fields[0] + tty := fields[6] + if strings.HasPrefix(tty, "pts") { + if _, found := activeUsers[tty]; !found { + activeUsers[tty] = []string{} + } + fullUserName, err := getFullUserName(user) + if err == nil { + user = fullUserName + } + if !contains(activeUsers[tty], user) { + activeUsers[tty] = append(activeUsers[tty], user) + } + } + } + } + return activeUsers, nil } +// getFullUserName retrieves the full username from /etc/passwd. func getFullUserName(shortName string) (string, error) { - file, err := os.Open("/etc/passwd") - if err != nil { - return shortName, err - } - defer file.Close() + file, err := os.Open("/etc/passwd") + if err != nil { + return shortName, err + } + defer file.Close() - trimmedShortName := strings.TrimSuffix(shortName, "+") + trimmedShortName := strings.TrimSuffix(shortName, "+") - scanner := bufio.NewScanner(file) - for scanner.Scan() { - line := scanner.Text() - parts := strings.Split(line, ":") - if len(parts) > 0 { - userName := parts[0] - if strings.HasPrefix(userName, trimmedShortName) { - return userName, nil - } - } - } - if err := scanner.Err(); err != nil { - return shortName, err - } - return shortName, nil + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := scanner.Text() + parts := strings.Split(line, ":") + if len(parts) > 0 { + userName := parts[0] + if strings.HasPrefix(userName, trimmedShortName) { + return userName, nil + } + } + } + if err := scanner.Err(); err != nil { + return shortName, err + } + return shortName, nil } +// getCurrentPTS retrieves the current terminal (PTS). func getCurrentPTS() (string, error) { - if runtime.GOOS == "linux" { - tty, err := os.Readlink("/proc/self/fd/0") - if err != nil { - return "", err - } - re := regexp.MustCompile(`(pts/\d+|ttyS?\d*)`) - pts := re.FindString(tty) - if pts == "" { - return "", fmt.Errorf("could not parse PTS") - } - return pts, nil - } else if runtime.GOOS == "darwin" { - ttyNumber := os.Getenv("_P9K_SSH_TTY") - re := regexp.MustCompile(`(ttys?\d*)`) - pts := re.FindString(ttyNumber) - if ttyNumber == "" { - return "not available", nil - } - return pts, nil - } - return "", fmt.Errorf("unsupported platform") + if runtime.GOOS == "linux" { + tty, err := os.Readlink("/proc/self/fd/0") + if err != nil { + return "", err + } + re := regexp.MustCompile(`(pts/\d+|ttyS?\d*)`) + pts := re.FindString(tty) + if pts == "" { + return "", fmt.Errorf("could not parse PTS") + } + return pts, nil + } else if runtime.GOOS == "darwin" { + ttyNumber := os.Getenv("_P9K_SSH_TTY") + re := regexp.MustCompile(`(ttys?\d*)`) + pts := re.FindString(ttyNumber) + if ttyNumber == "" { + return "not available", nil + } + return pts, nil + } + return "", fmt.Errorf("unsupported platform") } diff --git a/utility.go b/utility.go index bc3dec5..2a43d87 100644 --- a/utility.go +++ b/utility.go @@ -2,19 +2,21 @@ package main import "github.com/shirou/gopsutil/process" +// contains checks if a slice contains a specific string. func contains(slice []string, item string) bool { - for _, s := range slice { - if s == item { - return true - } - } - return false + for _, s := range slice { + if s == item { + return true + } + } + return false } +// getProcessCount retrieves the total number of running processes. func getProcessCount() int { - pids, err := process.Pids() - if err != nil { - return 0 - } - return len(pids) + pids, err := process.Pids() + if err != nil { + return 0 + } + return len(pids) }