func main() { flag.Parse() args = flag.Args() if len(args) <= 0 { fmt.Fprintf(os.Stderr, "Must specify at least one argument to run:\n") fmt.Fprintf(os.Stderr, "\t%s <options> <command> <arguments>...\n", os.Args[0]) flag.PrintDefaults() return } startCommand(false) usr1c := make(chan os.Signal) signal.Notify(usr1c, syscall.SIGUSR1) go func() { for { <-usr1c if canExecute() { startCommand(true) } } }() for { inotifyFd, err := syscall.InotifyInit() if err != nil { log.Fatalf("Inotify init failed: %v", err) } recdepth := 0 if *recurse { recdepth = *depth } registerDirectory(inotifyFd, ".", recdepth) inotifyBuf := make([]byte, 1024*syscall.SizeofInotifyEvent+16) for { n, err := syscall.Read(inotifyFd, inotifyBuf[0:]) if err == io.EOF { break } if err != nil { log.Printf("Can not read inotify: %v", err) break } if n > syscall.SizeofInotifyEvent { if canExecute() { startCommand(true) } } } syscall.Close(inotifyFd) } }
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) } } } }
// lazyinit sets up all required file descriptors and starts 1+consumersCount // goroutines. The producer goroutine blocks until file-system notifications // occur. Then, all events are read from system buffer and sent to consumer // goroutines which construct valid notify events. This method uses // Double-Checked Locking optimization. func (i *inotify) lazyinit() error { if atomic.LoadInt32(&i.fd) == invalidDescriptor { i.Lock() defer i.Unlock() if atomic.LoadInt32(&i.fd) == invalidDescriptor { fd, err := syscall.InotifyInit() if err != nil { return err } i.fd = int32(fd) if err = i.epollinit(); err != nil { _, _ = i.epollclose(), syscall.Close(int(fd)) // Ignore errors. i.fd = invalidDescriptor return err } esch := make(chan []*event) go i.loop(esch) i.wg.Add(consumersCount) for n := 0; n < consumersCount; n++ { go i.send(esch) } } } return nil }
// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. func NewWatcher() (*Watcher, error) { // Create inotify fd fd, errno := syscall.InotifyInit() if fd == -1 { return nil, errno } // Create epoll poller, err := newFdPoller(fd) if err != nil { syscall.Close(fd) return nil, err } w := &Watcher{ fd: fd, poller: poller, watches: make(map[string]*watch), paths: make(map[int]string), Events: make(chan Event), Errors: make(chan error), done: make(chan struct{}), doneResp: make(chan struct{}), } go w.readEvents() return w, nil }
func main() { log.SetFlags(log.LstdFlags | log.Lshortfile) inotify_fd, err := syscall.InotifyInit() if err != nil { log.Fatal(err) } paths := make(map[int]string) add_watch_r(inotify_fd, "/home/feng/workspace/rssminer", paths) log.Print("watcher added") for { var ( buf [syscall.SizeofInotifyEvent * 4096]byte ) n, _ := syscall.Read(inotify_fd, buf[0:]) offset := 0 for offset <= n-syscall.SizeofInotifyEvent { raw := (*syscall.InotifyEvent)(unsafe.Pointer(&buf[offset])) wd := int(raw.Wd) file := paths[wd] mask := raw.Mask printEvent(file, mask) offset += syscall.SizeofInotifyEvent + int(raw.Len) } } }
func newinotify() (*inotify, error) { fd, err := syscall.InotifyInit() if fd == -1 { return nil, os.NewSyscallError("inotify_init", err) } return &inotify{ fd: fd, }, nil }
func NewWatcher() (IFSEventsWatcher, error) { if fd, errno := syscall.InotifyInit(); errno != nil { return nil, os.NewSyscallError("inotify_init", errno) } else { w := &watcher{ fd: fd, } return w, nil } }
// 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 NewInotify(ctrler Controller) (Watcher, error) { watchfd, errno := syscall.InotifyInit() if watchfd == -1 { return nil, os.NewSyscallError("inotify_init", errno) } w := &inotify{ watchfd: watchfd, watches: make(map[Id]int32), ids: make(map[int32]Id), done: make(chan bool, 1), ctrler: ctrler, } go w.readEvents() return w, 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) } } }
// NewWatcher creates and returns a new inotify instance using inotify_init(2) func NewWatcher() (*Watcher, error) { fd, errno := syscall.InotifyInit() if fd == -1 { return nil, os.NewSyscallError("inotify_init", errno) } w := &Watcher{ fd: fd, watches: make(map[string]*watch), paths: make(map[int]string), Event: make(chan *Event), Error: make(chan error), state: new(int32), } return w, nil }
// NewWatcher creates and returns a new inotify instance using inotify_init(2) func NewWatcher() (*Watcher, error) { fd, errno := syscall.InotifyInit() if fd == -1 { return nil, os.NewSyscallError("inotify_init", errno) } w := &Watcher{ fd: fd, watches: make(map[string]*watch), paths: make(map[int]string), Event: make(chan *Event), Error: make(chan error), done: make(chan bool, 1), } go w.readEvents() return w, nil }
//starts inotify tracking func runInotify() { fd, err := syscall.InotifyInit() if err != nil { log.Fatal("error initializing Inotify: ", err) return } addFilesToInotify(fd, path) var buffer []byte = make([]byte, 1024*EVENT_SIZE) for { n, err := syscall.Read(fd, buffer) if err != nil { log.Fatal("Read failed: ", err) return } processBuffer(n, buffer) } }
// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. func NewWatcher() (*Watcher, error) { fd, errno := syscall.InotifyInit() if fd == -1 { return nil, os.NewSyscallError("inotify_init", errno) } w := &Watcher{ fd: fd, watches: make(map[string]*watch), paths: make(map[int]string), Events: make(chan Event), Errors: make(chan error), done: make(chan bool), closed: make(chan bool), } w.cv = sync.NewCond(&w.mu) rp, wp, err := os.Pipe() // for done if err != nil { return nil, err } epfd, err := syscall.EpollCreate1(0) if err != nil { return nil, os.NewSyscallError("epoll_create1", err) } event := &syscall.EpollEvent{syscall.EPOLLIN, int32(w.fd), 0} if err = syscall.EpollCtl(epfd, syscall.EPOLL_CTL_ADD, w.fd, event); err != nil { return nil, os.NewSyscallError("epoll_ctl", err) } event = &syscall.EpollEvent{syscall.EPOLLIN, int32(rp.Fd()), 0} if err = syscall.EpollCtl(epfd, syscall.EPOLL_CTL_ADD, int(rp.Fd()), event); err != nil { return nil, os.NewSyscallError("epoll_ctl", err) } go func() { <-w.done wp.Close() // make rp readable }() go w.epollEvents(epfd, rp) return w, nil }
// NewWatcher creates and returns a new inotify instance using inotify_init(2) func NewWatcher() (*Watcher, error) { fd, errno := syscall.InotifyInit() if fd == -1 { return nil, os.NewSyscallError("inotify_init", errno) } mf := &filter{ memo: make(map[string]time.Time), interval: time.Minute, } w := &Watcher{ fd: fd, watches: make(map[string]*watch), paths: make(map[int]string), Event: make(chan *Event), Error: make(chan error), done: make(chan bool, 1), mfilter: mf, } go w.readEvents() return w, nil }
func init_inotify() { var err error name_by_wd = make(map[int32]string) wd_by_name = make(map[string]int32) var event syscall.InotifyEvent event_size = int(unsafe.Sizeof(event)) inotify_fd, _ = syscall.InotifyInit() if -1 == inotify_fd { bump_message("InotifyInit failed, file changes outside of tabby " + "will remain unnoticed") return } epoll_fd, err = syscall.EpollCreate(1) if -1 == epoll_fd { tabby_log("init_inotify: " + err.Error()) } var epoll_event syscall.EpollEvent epoll_event.Events = syscall.EPOLLIN syscall.EpollCtl(epoll_fd, syscall.EPOLL_CTL_ADD, inotify_fd, &epoll_event) go inotify_observe() }
func NewWatcher() (w *Watcher, err error) { fd, err := syscall.InotifyInit() if fd == -1 { log.Fatal("Watcher Init Error", err) } watcher := &Watcher{ wm: newWatchMap(), fd: fd, acceptEvent: make(chan *FileEvent), handleEvent: make(chan *FileEvent), Error: make(chan error), done: make(chan bool), skipDir: make(map[string]int), skipExt: make(map[string]int), isClose: false, } go watcher.readEvent() //读取事件,把事件发送到acceptEvent通道中 go watcher.purgeEvents() //处理时间,把处理的结果发送到handleEvent通道中 return watcher, nil }
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() }