package main import ( "bufio" "flag" "fmt" "log" "os" "os/exec" "strconv" "strings" "time" ) var ( MyPID string = strconv.Itoa(os.Getpid()) CPU string = "?" Mem string = "?" ARC string = "?" Swap string = "?" Flags string = "?" IOs string = "?" Net string = "?" N string = "?" ) 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 } } if err = scanner.Err(); err != nil { cmd.Process.Kill() cmd.Wait() return err } return nil } 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( strings.Join([]string{cols[1], cols[5], cols[7]}, " "), "%", "", ) case "Mem:": Mem = strings.ReplaceAll(strings.Join(cols[1:], " "), ",", "") case "ARC:": ARC = cols[1] case "Swap:": if cols[4] == "Used," { Swap = cols[3] + " Swap " } else { Swap = "" } } } } func iostat(devs ...string) { stats := make([]string, len(devs)*4) for i := 0; i < len(devs); i++ { stats[i*4+1] = "/" stats[i*4+3] = " " } stats = stats[:len(stats)-1] for cols := range bg("iostat", append([]string{"-d", "-w", N, "-x"}, devs...)...) { for i, dev := range devs { if cols[0] == dev { stats[i*4+0] = cols[1] stats[i*4+2] = cols[2] IOs = strings.Join(stats, "") } } } } func netstat() { stats := []string{"0", "0"} for cols := range bg("netstat", "-n", N) { if _, err := strconv.Atoi(cols[0]); err == nil { stats[0] = cols[0] stats[1] = cols[4] Net = strings.Join(stats, "/") } } } 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") iodevs := flag.String("iodevs", "ada0 ada1", "iostat devices") refresh := flag.Uint("refresh", 2, "Refresh interval") flag.Parse() N = strconv.Itoa(int(*refresh)) go func() { for { flagfiles() time.Sleep(20 * time.Second) } }() go top() go iostat(strings.Split(*iodevs, " ")...) go netstat() var now time.Time var status string var cmd *exec.Cmd for { now = time.Now() status = fmt.Sprintf( "[IO %s] [Net %s] [CPU %s] [%s%s %s ARC] [%s] %s", IOs, Net, CPU, Swap, Mem, ARC, Flags, now.Format("2006-01-02 15:04:05"), ) if *xsetroot { cmd = exec.Command("xsetroot", "-name", status) cmd.Run() } else { fmt.Println(status) } time.Sleep(time.Duration(*refresh) * time.Second) } }