package cmd import ( "log" "time" "github.com/dominicbreuker/pspy/internal/inotify" "github.com/dominicbreuker/pspy/internal/process" "github.com/dominicbreuker/pspy/internal/walker" ) const MaxInt = int(^uint(0) >> 1) func Monitor() { watch([]string{"/tmp"}, nil) } func watch(rdirs, dirs []string) { maxWatchers, err := inotify.WatcherLimit() if err != nil { log.Printf("Can't get inotify watcher limit...: %v\n", err) } log.Printf("Inotify watcher limit: %d (/proc/sys/fs/inotify/max_user_watches)\n", maxWatchers) ping := make(chan struct{}) in, err := inotify.NewInotify(ping) if err != nil { log.Fatalf("Can't init inotify: %v", err) } defer in.Close() for _, dir := range rdirs { addWatchers(dir, MaxInt, in, maxWatchers) } for _, dir := range dirs { addWatchers(dir, 0, in, maxWatchers) } log.Printf("Inotify watchers set up: %s\n", in) procList := process.NewProcList() ticker := time.NewTicker(100 * time.Millisecond) for { select { case <-ticker.C: refresh(in, procList) case <-ping: refresh(in, procList) } } } func addWatchers(dir string, depth int, in *inotify.Inotify, maxWatchers int) { dirCh, errCh, doneCh := walker.Walk(dir, depth) loop: for { if in.NumWatchers() >= maxWatchers { close(doneCh) break loop } select { case dir, ok := <-dirCh: if !ok { break loop } if err := in.Watch(dir); err != nil { log.Printf("Can't create watcher: %v", err) } case err := <-errCh: log.Printf("Error walking filesystem: %v", err) } } } func refresh(in *inotify.Inotify, pl *process.ProcList) { in.Pause() if err := pl.Refresh(); err != nil { log.Printf("ERROR refreshing process list: %v", err) } time.Sleep(5 * time.Millisecond) in.UnPause() }