func (this *watcher) doDel() error { if res, errno := syscall.InotifyRmWatch(this.fd, uint32(this.wd)); res < 0 { return os.NewSyscallError("inotify_add_watch", errno) } return nil }
// Remove stops watching the named file or directory (non-recursively). func (w *Watcher) Remove(name string) error { name = filepath.Clean(name) // Fetch the watch. w.mu.Lock() defer w.mu.Unlock() watch, ok := w.watches[name] // Remove it from inotify. if !ok { return fmt.Errorf("can't remove non-existent inotify watch for: %s", name) } // inotify_rm_watch will return EINVAL if the file has been deleted; // the inotify will already have been removed. // That means we can safely delete it from our watches, whatever inotify_rm_watch does. delete(w.watches, name) success, errno := syscall.InotifyRmWatch(w.fd, watch.wd) if success == -1 { // TODO: Perhaps it's not helpful to return an error here in every case. // the only two possible errors are: // EBADF, which happens when w.fd is not a valid file descriptor of any kind. // EINVAL, which is when fd is not an inotify descriptor or wd is not a valid watch descriptor. // Watch descriptors are invalidated when they are removed explicitly or implicitly; // explicitly by inotify_rm_watch, implicitly when the file they are watching is deleted. return errno } return nil }
func (w *inotify) remove(id Id) error { watch, ok := w.watches[id] if !ok { return fmt.Errorf("can't remove non-existent inotify watch for: %x", id) } success, errno := syscall.InotifyRmWatch(w.watchfd, uint32(watch)) if success == -1 { return os.NewSyscallError("inotify_rm_watch", errno) } delete(w.watches, id) return nil }
// RemoveWatch removes path from the watched file set. func (w *Watcher) removeWatch(path string) error { watch, ok := w.watches[path] if !ok { return errors.New(fmt.Sprintf("can't remove non-existent inotify watch for: %s", path)) } success, errno := syscall.InotifyRmWatch(w.fd, watch.wd) if success == -1 { return os.NewSyscallError("inotify_rm_watch", errno) } delete(w.watches, path) return nil }
func inotify_rm_watch(name string) { wd, found := wd_by_name[name] if false == found { return } retval, _ /*err*/ := syscall.InotifyRmWatch(inotify_fd, uint32(wd)) if -1 == retval { //println("tabby: InotifyRmWatch failed, errno = ", err) return } delete(name_by_wd, wd) delete(wd_by_name, name) }
func (w *Watcher) rmWatch(path string) error { if found := w.wm.find(path); found != nil { success, errno := syscall.InotifyRmWatch(w.fd, uint32(found.(watch).wd)) if success == -1 { return os.NewSyscallError("inotify_rm_watch", errno) } w.wm.remove(path) fmt.Println("移除监控目录:", path) } else { fmt.Println("没有找到对应的监控", path) } return nil }
// Remove stops watching the the named file or directory (non-recursively). func (w *Watcher) Remove(name string) error { name = filepath.Clean(name) w.mu.Lock() defer w.mu.Unlock() watch, ok := w.watches[name] if !ok { return fmt.Errorf("can't remove non-existent inotify watch for: %s", name) } success, errno := syscall.InotifyRmWatch(w.fd, watch.wd) if success == -1 { return os.NewSyscallError("inotify_rm_watch", errno) } delete(w.watches, name) return nil }
func (w *Watcher) removeWatch(path string) error { watch, ok := w.watches[path] if !ok { return fmt.Errorf("can't remove non-existent inotify watch for: %s", path) } if len(w.watches) == 1 { atomic.CompareAndSwapInt32(w.state, 1, 0) } delete(w.watches, path) success, errno := syscall.InotifyRmWatch(w.fd, watch.wd) if success == -1 { return os.NewSyscallError("inotify_rm_watch", errno) } return nil }
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) } } }
// RemoveWatch removes path from the watched file set. func (w *Watcher) RemoveWatch(path string) error { watch, ok := w.watches[path] if !ok { return errors.New(fmt.Sprintf("can't remove non-existent inotify watch for: %s", path)) } success, errno := syscall.InotifyRmWatch(w.fd, watch.wd) if success == -1 { return os.NewSyscallError("inotify_rm_watch", errno) } delete(w.watches, path) // Locking here to protect the read from paths in readEvents. w.mu.Lock() delete(w.paths, int(watch.wd)) w.mu.Unlock() return nil }
// RemoveWatch removes path from the watched file set. func (w *Watcher) RemoveWatch(path string) error { if w.isClosed { return errors.New(fmt.Sprintf("can't remove non-existent inotify watch for: %s", path)) } w.mu.Lock() defer w.mu.Unlock() watch, ok := w.watches[path] if !ok { return errors.New(fmt.Sprintf("can't remove non-existent inotify watch for: %s", path)) } success, errno := syscall.InotifyRmWatch(w.fd, watch.wd) if success == -1 { return os.NewSyscallError("inotify_rm_watch", errno) } delete(w.watches, path) delete(w.paths, int(watch.wd)) return nil }
// Unwatch implements notify.watcher interface. It looks for watch descriptor // related to registered path and if found, calls inotify_rm_watch(2) function. // This method is allowed to return EINVAL error when concurrently requested to // delete identical path. func (i *inotify) Unwatch(path string) (err error) { iwd := int32(invalidDescriptor) i.RLock() for iwdkey, wd := range i.m { if wd.path == path { iwd = iwdkey break } } i.RUnlock() if iwd == invalidDescriptor { return errors.New("notify: path " + path + " is already watched") } fd := atomic.LoadInt32(&i.fd) if _, err = syscall.InotifyRmWatch(int(fd), uint32(iwd)); err != nil { return } i.Lock() delete(i.m, iwd) i.Unlock() return nil }
// Remove stops watching the the named file or directory (non-recursively). func (w *Watcher) Remove(name string) error { name = filepath.Clean(name) w.mu.Lock() defer w.mu.Unlock() watch, ok := w.watches[name] if !ok { return fmt.Errorf("can't remove non-existent inotify watch for: %s", name) } success, errno := syscall.InotifyRmWatch(w.fd, watch.wd) if success == -1 { return os.NewSyscallError("inotify_rm_watch", errno) } // not delete(w.watches, name) here, but in ignoreLinux() // use condv to sync with ignoreLinux() for ok { w.cv.Wait() _, ok = w.watches[name] } return nil }
// Remove stops watching the named file or directory (non-recursively). func (w *Watcher) Remove(name string) error { name = filepath.Clean(name) // Fetch the watch. w.mu.Lock() defer w.mu.Unlock() watch, ok := w.watches[name] // Remove it from inotify. if !ok { return fmt.Errorf("can't remove non-existent inotify watch for: %s", name) } // inotify_rm_watch will return EINVAL if the file has been deleted; // the inotify will already have been removed. // watches and pathes are deleted in ignoreLinux() implicitly and asynchronously // by calling inotify_rm_watch() below. e.g. readEvents() goroutine receives IN_IGNORE // so that EINVAL means that the wd is being rm_watch()ed or its file removed // by another thread and we have not received IN_IGNORE event. success, errno := syscall.InotifyRmWatch(w.fd, watch.wd) if success == -1 { // TODO: Perhaps it's not helpful to return an error here in every case. // the only two possible errors are: // EBADF, which happens when w.fd is not a valid file descriptor of any kind. // EINVAL, which is when fd is not an inotify descriptor or wd is not a valid watch descriptor. // Watch descriptors are invalidated when they are removed explicitly or implicitly; // explicitly by inotify_rm_watch, implicitly when the file they are watching is deleted. return errno } // wait until ignoreLinux() deleting maps exists := true for exists { w.cv.Wait() _, exists = w.watches[name] } return nil }
// Close implements notify.watcher interface. It removes all existing watch // descriptors and wakes up producer goroutine by sending data to the write end // of the pipe. The function waits for a signal from producer which means that // all operations on current monitoring instance are done. func (i *inotify) Close() (err error) { i.Lock() if fd := atomic.LoadInt32(&i.fd); fd == invalidDescriptor { i.Unlock() return nil } for iwd := range i.m { if _, e := syscall.InotifyRmWatch(int(i.fd), uint32(iwd)); e != nil && err == nil { err = e } delete(i.m, iwd) } switch _, errwrite := syscall.Write(i.pipefd[1], []byte{0x00}); { case errwrite != nil && err == nil: err = errwrite fallthrough case errwrite != nil: i.Unlock() default: i.Unlock() i.wg.Wait() } return }
// Close a pin func (pin *Pin) Close() { syscall.InotifyRmWatch(pin.Fd, syscall.IN_MODIFY) pin.CommandChannel <- Done fd, _ := openFh(pin.Unexport) fd.Close() }
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") }
// 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() }