func Listen(path string) (*Listener, error) { rname := ".ftrig-" + randomName() tmpfifo := filepath.Join(path, rname) err := syscall.Mkfifo(tmpfifo, syscall.S_IRUSR|syscall.S_IWUSR|syscall.S_IWGRP|syscall.S_IWOTH) if err != nil { return nil, err } fd, fdw, name := C.int(0), C.int(0), filepath.Join(path, rname[1:]) fd, err = C.open_read(C.CString(tmpfifo)) if fd == -1 { goto err1 } fdw, err = C.open_write(C.CString(tmpfifo)) if fd == -1 { C.fd_close(fd) goto err1 } err = os.Rename(tmpfifo, name) if err != nil { C.fd_close(fdw) C.fd_close(fd) goto err1 } err = syscall.SetNonblock(int(fd), false) if err != nil { goto err1 } return subscribe(name, uintptr(fd), uintptr(fdw)) err1: os.Remove(tmpfifo) if errno, ok := err.(syscall.Errno); ok { return nil, errno } return nil, fmt.Errorf("unknown error opening fifo at %q", tmpfifo) }
func notifyNosig(path, s string) (int, error) { files, err := ioutil.ReadDir(path) if err != nil { return 0, err } success := 0 for i := range files { if files[i].Mode()&os.ModeNamedPipe == 0 { continue } p := filepath.Join(path, files[i].Name()) fd, ferr := C.open_write(C.CString(p)) if fd == -1 { if errno, ok := ferr.(syscall.Errno); ok && errno == syscall.ENXIO { err = errno os.Remove(p) } } else { r, ferr := C.fd_write(fd, C.CString(s), C.uint(len(s))) if (r < 0) || uint(r) < uint(len(s)) { if errno, ok := ferr.(syscall.Errno); ok && errno == syscall.EPIPE { err = errno os.Remove(p) } // what to do if EGAIN ? full fifo -> fix the reader ! // There's a race condition in extreme cases though ; // but it's still better to be nonblocking - the writer // shouldn't get in trouble because of a bad reader. C.fd_close(fd) } else { C.fd_close(fd) success++ } } } return success, err }
func Clean(path string) error { files, err := ioutil.ReadDir(path) if err != nil { return nil // yes, we don't care if the dir failed to scan } for i := range files { if files[i].Mode()&os.ModeNamedPipe == 0 { continue } p := filepath.Join(path, files[i].Name()) fd, ferr := C.open_write(C.CString(p)) if fd >= 0 { C.fd_close(fd) } else if errno, ok := ferr.(syscall.Errno); ok && errno == syscall.ENXIO { err = os.Remove(p) } } return err }
func (x *Listener) close() { os.Remove(x.path) C.fd_close(C.int(x.fdw)) x.f.Close() }