Created
January 17, 2020 23:42
-
-
Save bored-engineer/ff428f9e41a8ff4743435e8ba30bc7fb to your computer and use it in GitHub Desktop.
Revisions
-
bored-engineer created this gist
Jan 17, 2020 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,87 @@ package main import ( "bufio" "bytes" "io/ioutil" "log" "os" "path/filepath" "strconv" "strings" "syscall" "time" ) // Entry point func main() { // Read in /etc/passwd so we know which uid is which (os/user cannot x-compile easily) passwdBytes, err := ioutil.ReadFile("/etc/passwd") if err != nil { log.Fatalf("failed to read /etc/passwd: %v", err) } scanner := bufio.NewScanner(bytes.NewReader(passwdBytes)) users := make(map[uint32]string) for scanner.Scan() { parts := strings.SplitN(scanner.Text(), ":", 4) if uid, err := strconv.Atoi(parts[2]); err == nil { users[uint32(uid)] = parts[0] } } if err := scanner.Err(); err != nil { log.Fatalf("scanner failed: %v", err) } // Determine the max PID that can occur maxPIDBytes, err := ioutil.ReadFile("/proc/sys/kernel/pid_max") if err != nil { log.Fatalf("failed to determine max PID: %v", err) } maxPID, err := strconv.Atoi(strings.TrimSpace(string(maxPIDBytes))) if err != nil { log.Fatalf("failed to parse max PID: %v", err) } // Slices are _fast_ compared to map[int]time.Time processes := make([]time.Time, maxPID) // Using time.Tick will skip ticks if we're still processing the last tick for tick := range time.Tick(time.Millisecond * 100) { // List out /proc to get a list of every running process files, err := ioutil.ReadDir("/proc") if err != nil { log.Fatalf("failed to list proc: %v", err) } for _, file := range files { // Skip anything that's not a PID/number id, err := strconv.Atoi(file.Name()) if err != nil { continue } // If this is the first time we've seen the process, emit it if processes[id].IsZero() { cmdline, err := ioutil.ReadFile(filepath.Join("/proc", strconv.Itoa(id), "cmdline")) if err != nil { if os.IsNotExist(err) { log.Printf("Process %d went away while we were reading it", id) continue } log.Fatalf("failed to read PID: %v", err) } args := strings.Split(strings.TrimSpace(string(cmdline)), "\000") username := "unknown" if stat, ok := file.Sys().(*syscall.Stat_t); ok { if name, ok := users[stat.Uid]; ok { username = name } } log.Printf("Process %d spawned by %s with arguments %v", id, username, args) } processes[id] = tick } // Expire any process we haven't seen in a second for id, lastSeen := range processes { if !lastSeen.IsZero() && lastSeen.Before(tick) { log.Printf("Process %d seems to have stopped", id) processes[id] = time.Time{} } } } }