Exemple #1
0
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
}
Exemple #2
0
// 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
}
Exemple #3
0
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
}
Exemple #5
0
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)
}
Exemple #6
0
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

}
Exemple #7
0
// 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
}
Exemple #8
0
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
}
Exemple #9
0
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
}
Exemple #11
0
// 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
}
Exemple #13
0
// 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
}
Exemple #14
0
// 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
}
Exemple #16
0
// 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")
}
Exemple #18
0
// 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()
}