func main() { fd, err := syscall.InotifyInit() if err != nil { log.Fatal(err) } defer syscall.Close(fd) wd, err := syscall.InotifyAddWatch(fd, "test1.log", syscall.IN_ALL_EVENTS) _, err = syscall.InotifyAddWatch(fd, "../test2.log", syscall.IN_ALL_EVENTS) //_, err = syscall.InotifyAddWatch(fd, ".", syscall.IN_ALL_EVENTS) if err != nil { log.Fatal(err) } defer syscall.InotifyRmWatch(fd, uint32(wd)) fmt.Printf("WD is %d\n", wd) for { // Room for at least 128 events buffer := make([]byte, syscall.SizeofInotifyEvent*128) bytesRead, err := syscall.Read(fd, buffer) if err != nil { log.Fatal(err) } if bytesRead < syscall.SizeofInotifyEvent { // No point trying if we don't have at least one event continue } fmt.Printf("Size of InotifyEvent is %s\n", syscall.SizeofInotifyEvent) fmt.Printf("Bytes read: %d\n", bytesRead) offset := 0 for offset < bytesRead-syscall.SizeofInotifyEvent { event := (*syscall.InotifyEvent)(unsafe.Pointer(&buffer[offset])) fmt.Printf("%+v\n", event) if (event.Mask & syscall.IN_ACCESS) > 0 { fmt.Printf("Saw IN_ACCESS for %+v\n", event) } // We need to account for the length of the name offset += syscall.SizeofInotifyEvent + int(event.Len) } } }
// watch adds a new watcher to the set of watched objects or modifies the existing // one. If called for the first time, this function initializes inotify filesystem // monitor and starts producer-consumers goroutines. func (i *inotify) watch(path string, e Event) (err error) { if e&^(All|Event(syscall.IN_ALL_EVENTS)) != 0 { return errors.New("notify: unknown event") } if err = i.lazyinit(); err != nil { return } iwd, err := syscall.InotifyAddWatch(int(i.fd), path, encode(e)) if err != nil { return } i.RLock() wd := i.m[int32(iwd)] i.RUnlock() if wd == nil { i.Lock() if i.m[int32(iwd)] == nil { i.m[int32(iwd)] = &watched{path: path, mask: uint32(e)} } i.Unlock() } else { i.Lock() wd.mask = uint32(e) i.Unlock() } return nil }
// Add starts watching the named file or directory (non-recursively). func (w *Watcher) Add(name string) error { name = filepath.Clean(name) if w.isClosed() { return errors.New("inotify instance already closed") } const agnosticEvents = syscall.IN_MOVED_TO | syscall.IN_MOVED_FROM | syscall.IN_CREATE | syscall.IN_ATTRIB | syscall.IN_MODIFY | syscall.IN_MOVE_SELF | syscall.IN_DELETE | syscall.IN_DELETE_SELF var flags uint32 = agnosticEvents w.mu.Lock() watchEntry, found := w.watches[name] w.mu.Unlock() if found { watchEntry.flags |= flags flags |= syscall.IN_MASK_ADD } wd, errno := syscall.InotifyAddWatch(w.fd, name, flags) if wd == -1 { return errno } w.mu.Lock() w.watches[name] = &watch{wd: uint32(wd), flags: flags} w.paths[wd] = name w.mu.Unlock() return nil }
func monitor(root string, action chan uint32) { fd, err := syscall.InotifyInit() if fd == -1 || err != nil { end <- true return } flags := syscall.IN_MODIFY | syscall.IN_CREATE | syscall.IN_DELETE // 2/128/512 wd, _ := syscall.InotifyAddWatch(fd, root, uint32(flags)) if wd == -1 { end <- true return } var ( buf [syscall.SizeofInotifyEvent * 10]byte n int ) for { n, _ = syscall.Read(fd, buf[0:]) if n > syscall.SizeofInotifyEvent { var offset = 0 for offset < n { raw := (*syscall.InotifyEvent)(unsafe.Pointer(&buf[offset])) mask := uint32(raw.Mask) offset = offset + int(raw.Len) + syscall.SizeofInotifyEvent action <- mask log.Println("action:", mask) } } } }
func add_watch_r(inotify_fd int, f string, paths map[int]string) { fi, err := os.Open(f) if err != nil { log.Fatal(err) } defer fi.Close() n, err := syscall.InotifyAddWatch(inotify_fd, f, syscall.IN_ALL_EVENTS) paths[n] = f if err != nil { log.Fatal(err) } s, _ := fi.Stat() if s.IsDir() { files, _ := ioutil.ReadDir(f) for _, file := range files { if file.IsDir() { f := path.Join(f, file.Name()) add_watch_r(inotify_fd, f, paths) // log.Print(path.Join(f, file.Name())) } } } }
// AddWatch adds path to the watched file set. // The flags are interpreted as described in inotify_add_watch(2). func (w *Watcher) AddWatch(path string, flags uint32) error { if w.isClosed { return errors.New("inotify instance already closed") } watchEntry, found := w.watches[path] if found { watchEntry.flags |= flags flags |= syscall.IN_MASK_ADD } w.mu.Lock() // synchronize with readEvents goroutine wd, err := syscall.InotifyAddWatch(w.fd, path, flags) if err != nil { w.mu.Unlock() return &os.PathError{ Op: "inotify_add_watch", Path: path, Err: err, } } if !found { w.watches[path] = &watch{wd: uint32(wd), flags: flags} w.paths[wd] = path } w.mu.Unlock() return nil }
//Add directories recursively to the tracking list func addFilesToInotify(fd int, dirPath string) { dir, err := os.Stat(dirPath) if err != nil { log.Fatal("error getting info on dir: ", err) return } if dir.IsDir() && dir.Name() != ".git" { log.Print("adding: ", dirPath) _, err = syscall.InotifyAddWatch(fd, dirPath, syscall.IN_CLOSE_WRITE|syscall.IN_DELETE) if err != nil { log.Fatal("error adding watch: ", err) return } fileList, err := ioutil.ReadDir(dirPath) if err != nil { log.Fatal("error reading dir: ", err) return } for _, file := range fileList { newPath := dirPath + "/" + file.Name() if file.IsDir() && file.Name() != ".git" { addFilesToInotify(fd, newPath) } } } }
func (w *inotify) add(id Id, path string, flags uint32) error { wd, err := syscall.InotifyAddWatch(w.watchfd, path, flags) if err != nil { return err } watch := int32(wd) w.watches[id] = watch w.ids[watch] = id return nil }
func inotify_add_watch(name string) { wd, err := syscall.InotifyAddWatch(inotify_fd, name, syscall.IN_MODIFY|syscall.IN_DELETE_SELF|syscall.IN_MOVE_SELF) if -1 == wd { if err == syscall.ENOENT { // Dirty hack. return } tabby_log("InotifyAddWatch failed, changes of file " + name + " outside of tabby will remain unnoticed, errno = " + err.Error()) return } name_by_wd[int32(wd)] = name wd_by_name[name] = int32(wd) }
// eventProcessor processes events from the file system func (pin *Pin) eventProcessor() error { fd, err := syscall.InotifyInit() pin.Fd = fd if err != nil { return err } _, err = syscall.InotifyAddWatch(fd, pin.ValuePath, syscall.IN_MODIFY) if err != nil { return err } go pin.watcher() return nil }
func (this *watcher) doAdd(path string, flags uint32) error { //Check that file exists if _, err := os.Lstat(path); err != nil { return err } if wd, errno := syscall.InotifyAddWatch(this.fd, path, flags); wd < 0 { return os.NewSyscallError("inotify_add_watch", errno) } else { this.wd = wd this.root = path } return nil }
// AddWatch adds path to the watched file set. // The flags are interpreted as described in inotify_add_watch(2). func (w *Watcher) AddWatch(path string, flags uint32) error { if w.isClosed { return errors.New("inotify instance already closed") } watchEntry, found := w.watches[path] if found { watchEntry.flags |= flags flags |= syscall.IN_MASK_ADD } wd, err := syscall.InotifyAddWatch(w.fd, path, flags) if err != nil { return &os.PathError{"inotify_add_watch", path, err} } if !found { w.watches[path] = &watch{wd: uint32(wd), flags: flags} w.paths[wd] = path } return nil }
func (w *Watcher) AddWatch(path string, flags uint32) error { if w.isClose { log.Fatal("监控已经关闭") } //判断是否已经监控了 if found := w.wm.find(path); found != nil { f := found.(watch) f.flags |= flags flags |= syscall.IN_MASK_ADD } wd, err := syscall.InotifyAddWatch(w.fd, path, flags) fmt.Println("开始监控目录:", path, wd) if wd == -1 { return err } w.wm.add(path, wd, flags) return nil }
// AddWatch adds path to the watched file set. // The flags are interpreted as described in inotify_add_watch(2). func (w *Watcher) AddWatch(path string, flags uint32) os.Error { if w.isClosed { return os.NewError("inotify instance already closed") } watchEntry, found := w.watches[path] if found { watchEntry.flags |= flags flags |= syscall.IN_MASK_ADD } wd, errno := syscall.InotifyAddWatch(w.fd, path, flags) if wd == -1 { return os.NewSyscallError("inotify_add_watch", errno) } if !found { w.watches[path] = &watch{wd: uint32(wd), flags: flags} w.paths[wd] = path } return nil }
// AddWatch adds path to the watched file set. // The flags are interpreted as described in inotify_add_watch(2). func (w *Watcher) addWatch(path string, flags uint32) error { if w.isClosed { return errors.New("inotify instance already closed") } watchEntry, found := w.watches[path] if found { watchEntry.flags |= flags flags |= syscall.IN_MASK_ADD } wd, errno := syscall.InotifyAddWatch(w.fd, path, flags) if wd == -1 { return errno } w.mu.Lock() w.watches[path] = &watch{wd: uint32(wd), flags: flags} w.paths[wd] = path w.mu.Unlock() return nil }
func registerDirectory(inotifyFd int, dirname string, recurse int) { _, err := syscall.InotifyAddWatch(inotifyFd, dirname, syscall.IN_CREATE|syscall.IN_DELETE|syscall.IN_CLOSE_WRITE) if err != nil { log.Fatalf("Can not add %s to inotify: %v", dirname, err) } if recurse <= 0 { return } dir, err := LsDir(dirname) if err != nil { log.Fatalf("Can not read directory %s: %v", dirname, err) } for _, cur := range dir { if cur.Mode().IsDir() { if cur.Name()[0] == '.' { continue } // skip hidden directories registerDirectory(inotifyFd, dirname+"/"+cur.Name(), recurse-1) } } }
// Returns errors (if any) triggered by the inotify subsystem or when reading // the file. Errors when writing to the writer are ignored. func streamFile(writer io.Writer, path string, maxIdleTime uint32) error { handle, err := os.Open(path) if err != nil { return err } _, err = handle.Seek(0, os.SEEK_END) if err != nil { handle.Close() return err } reader := bufio.NewReader(handle) readBuffer := make([]byte, 4096) inotifyFd, err := syscall.InotifyInit() if err != nil { handle.Close() return err } watchDesc, err := syscall.InotifyAddWatch(inotifyFd, path, syscall.IN_MODIFY) if err != nil { syscall.Close(inotifyFd) handle.Close() return err } eventsBuffer := make([]byte, syscall.SizeofInotifyEvent*4096) selectMaxIdleTime := syscall.Timeval{} selectMaxIdleTime.Sec = int64(maxIdleTime) inotifyFdSet := syscall.FdSet{} lastWriteTime := time.Now() canScan := true for canScan && !timeout(lastWriteTime, maxIdleTime) { clearAll(&inotifyFdSet) set(&inotifyFdSet, inotifyFd) _, err := syscall.Select(inotifyFd+1, &inotifyFdSet, nil, nil, &selectMaxIdleTime) if err != nil { break } if !isSet(&inotifyFdSet, inotifyFd) { continue } numEventsBytes, err := syscall.Read(inotifyFd, eventsBuffer[0:]) if numEventsBytes < syscall.SizeofInotifyEvent { if numEventsBytes < 0 { err = errors.New("inotify: read failed.") } else { err = errors.New("inotify: short read.") } break } var offset uint32 = 0 for offset <= uint32(numEventsBytes-syscall.SizeofInotifyEvent) { event := (*syscall.InotifyEvent)(unsafe. Pointer(&eventsBuffer[offset])) n, err := reader.Read(readBuffer) if err != nil { // Ignore the EOF error and continue polling // the file until timeout. if err == io.EOF { err = nil } break } buffer := make([]byte, n) for index := 0; index < n; index++ { buffer[index] = readBuffer[index] } _, err = writer.Write(buffer) if err != nil { // Stop scanning for updates to the file. canScan = false // Ignore the write error. err = nil break } lastWriteTime = time.Now() // Move to the next event. offset += syscall.SizeofInotifyEvent + event.Len } } // The inotify watch gets automatically removed by the inotify system // when the file is removed. If the above loop times out, but the file // is removed only just before the if block below is executed, then the // removal of the watch below will throw an error as the watch // descriptor is obsolete. We ignore this error because it is harmless. syscall.InotifyRmWatch(inotifyFd, uint32(watchDesc)) // Though we return the first error that occured, we still need to // attempt to close all the file descriptors. inotifyCloseErr := syscall.Close(inotifyFd) handleCloseErr := handle.Close() if err != nil { return err } else if inotifyCloseErr != nil { return inotifyCloseErr } return handleCloseErr }
// Data file number monitor depends on mongodb disk file layout, the layout is // united in all of current supported versions, 1.8, 2.0 and 2.2. // // For example: // // Say base dir path is '/tmp/mongodb' and database name is 'db', then the disk // file layout would be, /tmp/mongodb/db.ns, /tmp/mongodb/db.0, /tmp/mongodb/db.1, // and /tmp/mongodb/db.2 ... func (filter *ProxyFilterImpl) MonitorQuotaFiles() { var fd, wd, nread int var err error buffer := make([]byte, 256) dbfiles := make(map[string]int) asyncops := NewAsyncOps() dbname := filter.mongo.DBNAME base_dir := filter.config.BASE_DIR quota_files := filter.config.QUOTA_FILES filter.lock.Lock() filter.running++ filter.lock.Unlock() filecount := 0 filecount = iterateDatafile(dbname, base_dir, dbfiles) if filecount < 0 { logger.Errorf("Failed to iterate data files under %s.", base_dir) goto Error } logger.Infof("At the begining time we have disk files: [%d].", filecount) if filecount > int(quota_files) { logger.Error("Disk files exceeds quota.") atomic.StoreUint32(&filter.mfblocked, BLOCKED) } // Golang does not recommend to invoke system call directly, but // it does not contain any 'inotify' wrapper function fd, err = syscall.InotifyInit() if err != nil { logger.Errorf("Failed to call InotifyInit: [%s].", err) goto Error } wd, err = syscall.InotifyAddWatch(fd, base_dir, syscall.IN_CREATE|syscall.IN_MOVED_TO|syscall.IN_DELETE) if err != nil { logger.Errorf("Failed to call InotifyAddWatch: [%s].", err) syscall.Close(fd) goto Error } defer func() { syscall.InotifyRmWatch(fd, uint32(wd)) syscall.Close(fd) }() for { select { case event := <-filter.file_count_channel: if event == STOP_EVENT { goto Error } default: } nread, err = asyncops.AsyncRead(syscall.Read, fd, buffer, time.Second) if err != nil { if err == ErrTimeout { continue } logger.Errorf("Failed to read inotify event: [%s].", err) break } else { err = parseInotifyEvent(dbname, buffer[0:nread], &filecount, dbfiles) if err != nil { logger.Errorf("Failed to parse inotify event.") atomic.StoreUint32(&filter.mfblocked, BLOCKED) } else { logger.Debugf("Current db disk file number: [%d].", filecount) if filecount > int(quota_files) { logger.Error("Disk files exceeds quota.") atomic.StoreUint32(&filter.mfblocked, BLOCKED) } else { atomic.StoreUint32(&filter.mfblocked, UNBLOCKED) } } } } Error: atomic.StoreUint32(&filter.mfblocked, BLOCKED) filter.lock.Lock() filter.running-- if filter.running == 0 { filter.wait <- STOP_EVENT } filter.lock.Unlock() }
func (i *inotify) add(path string, flags uint32) (int, error) { return syscall.InotifyAddWatch(i.fd, path, flags) }
func TestParseInotifyEvent(t *testing.T) { logger = setupStdoutLogger() setupDatafile() defer cleanDatafile() dbfiles := make(map[string]int) filecount := iterateDatafile(dbname, dbdir, dbfiles) if filecount < 0 { t.Error("Failed to parse inotify event.\n") } fd, err := syscall.InotifyInit() if err != nil { t.Error("Failed to call InotifyInit: [%s].\n", err) return } wd, err := syscall.InotifyAddWatch(fd, dbdir, syscall.IN_CREATE|syscall.IN_OPEN| syscall.IN_MOVED_TO|syscall.IN_DELETE) if err != nil { t.Error("Failed to call InotifyAddWatch: [%s].\n", err) syscall.Close(fd) return } go fileCreator() buffer := make([]byte, 256) for { nread, err := syscall.Read(fd, buffer) if nread < 0 { t.Error("Failed to read inotify event: [%s].\n", err) } else { err = parseInotifyEvent(dbname, buffer[0:nread], &filecount, dbfiles) if err != nil { t.Error("Failed to parse inotify event.\n") } else { fmt.Printf("Current dbfiles are, %v.\n", dbfiles) if _, ok := dbfiles["db.10"]; ok { break } } } } syscall.InotifyRmWatch(fd, uint32(wd)) syscall.Close(fd) if filecount < 3 { t.Error("Failed to parse inotify event.\n") } if _, ok := dbfiles["db.0"]; !ok { t.Error("Failed to get db.0 file.\n") } if _, ok := dbfiles["db.1"]; !ok { t.Error("Failed to get db.1 file.\n") } fmt.Printf("Succeed to parse all inotify events.\n") }