package main import ( "bufio" "flag" "fmt" "log" "os" "os/exec" "strconv" "strings" "sync" "time" "github.com/dustin/go-humanize" ) var ( MyPID string = strconv.Itoa(os.Getpid()) CPU string = "?" Freq string = "?" Mem string = "?" ARC string = "?" Swap string = "" Flags string = "?" IOs string = "?" Net = map[string]string{} NetM sync.RWMutex ) func piper(c chan []string, name string, args ...string) error { cmd := exec.Command(name, args...) r, err := cmd.StdoutPipe() if err != nil { return err } err = cmd.Start() if err != nil { return err } scanner := bufio.NewScanner(r) for scanner.Scan() { cols := strings.Fields(scanner.Text()) if len(cols) > 0 { c <- cols } } cmd.Process.Kill() cmd.Wait() return scanner.Err() } func bg(cmd string, args ...string) chan []string { c := make(chan []string) go func() { for { err := piper(c, cmd, args...) if err != nil { log.Println("error:", cmd, ":", err) } time.Sleep(time.Second) } }() return c } func top() { for cols := range bg("top", "-b", "-d", "infinity", "-p", MyPID, "-s", "5", "infinity") { switch cols[0] { case "CPU:": CPU = strings.ReplaceAll(fmt.Sprintf( "%s sys:%s int:%s n:%s", cols[1], cols[5], cols[7], cols[3], ), "%", "") case "Mem:": Mem = strings.ReplaceAll(strings.Join(cols[1:], " "), ",", "") case "ARC:": ARC = cols[1] case "Swap:": if len(cols) >= 5 && cols[4] == "Used," { Swap = cols[3] + " Swap " } } } } func iostat() { var stats []string for cols := range bg("iostat", "-d", "-w", "1", "-x") { if cols[0] == "device" { IOs = strings.Join(stats, " ") stats = nil continue } if len(cols) < 4 || (cols[1] == "0" && cols[2] == "0") { continue } stats = append(stats, fmt.Sprintf("%s:%s/%s", cols[0], cols[1], cols[2])) } } func netstat(iface, short string) { for cols := range bg("netstat", "-I", iface, "-n", "1") { if _, err := strconv.Atoi(cols[0]); err != nil { continue } ibps, err := strconv.Atoi(cols[3]) if err != nil { continue } obps, err := strconv.Atoi(cols[6]) if err != nil { continue } _ = cols[0] // pkts rx _ = cols[4] // pkts tx NetM.Lock() Net[short] = fmt.Sprintf( "%s:%s/%s", short, humanize.IBytes(uint64(ibps)), humanize.IBytes(uint64(obps)), ) NetM.Unlock() } } func freq() { for cols := range bg("sysctl", "-n", "dev.cpu.0.freq") { if strings.HasSuffix(cols[0], "01") { Freq = "TB" } else { raw, err := strconv.Atoi(cols[0]) if err != nil { continue } Freq = fmt.Sprintf("%.1fG", float64(raw)/1000) } } } func flagfiles() { ents, err := os.ReadDir("/tmp/stargrave-flags") if err != nil { log.Println(err) return } fs := make([]string, 0, len(ents)) for _, ent := range ents { fs = append(fs, ent.Name()) } Flags = strings.Join(fs, " ") } func main() { xsetroot := flag.Bool("xsetroot", false, "Call xsetroot") flag.Parse() go func() { for { flagfiles() time.Sleep(20 * time.Second) } }() go top() go freq() go iostat() go netstat("bridge0", "br") go netstat("ix0", "ix") var now time.Time var status string var cmd *exec.Cmd for { now = time.Now() NetM.RLock() status = fmt.Sprintf( "[%s] [%s %s] [%s %s] [%s%s %s ARC] [%s] %s", IOs, Net["br"], Net["ix"], CPU, Freq, Swap, Mem, ARC, Flags, now.Format("2006-01-02 15:04:05"), ) NetM.RUnlock() if *xsetroot { cmd = exec.Command("xsetroot", "-name", status) cmd.Run() } else { fmt.Println(status) } time.Sleep(time.Second) } }