func addWatchToClosestPath(watcher *inotify.Watcher, path string) { err := watcher.AddWatch(path, InotifyFlags) for err != nil && err.(*os.PathError).Err == syscall.ENOENT && path != "/" { path = filepath.Dir(path) if path != "/" { err = watcher.AddWatch(path, InotifyDirFlags) } } }
func addWatch(from string, rec bool, hidden bool, watcher *inotify.Watcher) error { mask := inotify.IN_MODIFY | inotify.IN_CLOSE_WRITE | inotify.IN_MOVE | inotify.IN_CREATE walkFn := func(path string, _ os.FileInfo, err error) error { if !hidden && path != "." && strings.HasPrefix(path, ".") { return nil } return watcher.AddWatch(path, mask) } if rec { return filepath.Walk(from, walkFn) } return watcher.AddWatch(from, mask) }
func watch(watcher *inotify.Watcher, paths []string, flag uint32, recursive, must bool) { log.Debugln("Watching: ", paths) for _, p := range paths { fi, err := os.Stat(p) if err != nil { if must { log.Fatal(err) } return } if err := watcher.AddWatch(p, flag); err != nil { if must { log.Fatal(err) } return } if !recursive || !fi.IsDir() { return } entries, err := ioutil.ReadDir(p) if err != nil { if must { log.Fatal(err) } return } var ps []string for _, en := range entries { if en.IsDir() { ps = append(ps, path.Join(p, en.Name())) } } if len(ps) == 0 { return } watch(watcher, ps, flag, true, false) } }
// TODO: Resolve some corner cases like watches not set after create, delete, create, move func runWatcher(watcher *inotify.Watcher) { LogWriter.Info("Starting paxrat watcher") for { select { case ev := <-watcher.Event: if ev.Mask == inotify.IN_CREATE { if _, ok := (*Conf).Settings[ev.Name]; ok { watcher.AddWatch(ev.Name, InotifyFlags) msg := fmt.Sprintf("File created: %s\n", ev.Name) LogWriter.Info(msg) } // Catch directory creation events for non-existent directories in executable path } else if ev.Mask == (inotify.IN_CREATE | inotify.IN_ISDIR) { for path, _ := range (*Conf).Settings { if strings.HasPrefix(path, ev.Name) { addWatchToClosestPath(watcher, path) } } } else if ev.Mask == inotify.IN_DELETE_SELF || ev.Mask == inotify.IN_MOVE_SELF { if _, ok := (*Conf).Settings[ev.Name]; ok { msg := fmt.Sprintf("File deleted: %s\n", ev.Name) LogWriter.Info(msg) parent := filepath.Dir(ev.Name) watcher.AddWatch(parent, InotifyDirFlags) continue } } else if ev.Mask == inotify.IN_ATTRIB { if _, ok := (*Conf).Settings[ev.Name]; ok { exists := pathExists(ev.Name) if !exists { msg := fmt.Sprintf("File deleted: %s\n", ev.Name) LogWriter.Info(msg) parent := filepath.Dir(ev.Name) watcher.AddWatch(parent, InotifyDirFlags) continue } else { msg := fmt.Sprintf("File attributes changed: %s", ev.Name) LogWriter.Info(msg) } } } if settings, ok := (*Conf).Settings[ev.Name]; ok { if ev.Mask != inotify.IN_IGNORED { err := setFlagsWatchMode(watcher, ev.Name, settings.Flags, settings.Nonroot) if err != nil { msg := fmt.Sprintf("watch mode setFlags error: %s", err) LogWriter.Err(msg) } } } case err := <-watcher.Error: msg := fmt.Sprintf("watch mode watcher error: %s", err) LogWriter.Err(msg) } } return }
func setWatch(watch *inotify.Watcher, path string) { if err := watch.AddWatch(path, inotify.IN_MODIFY); err != nil { log.Println(fmt.Sprintf("Error %s setting a watcher on the config file. Changes will need a restart to become effective", err)) } }