func ext۰os۰Pipe(fr *frame, args []value) value { // This is an inlining of linux's os.Pipe. // func os.Pipe() (r *File, w *File, err error) var p [2]int if err := syscall.Pipe2(p[:], syscall.O_CLOEXEC); err != nil { // TODO(adonovan): fix: return an *os.SyscallError. return tuple{nil, nil, wrapError(err)} } NewFile := fr.i.prog.ImportedPackage("os").Func("NewFile") r := call(fr.i, fr, 0, NewFile, []value{uintptr(p[0]), "|0"}) w := call(fr.i, fr, 0, NewFile, []value{uintptr(p[1]), "|1"}) return tuple{r, w, wrapError(nil)} }
// Create a new inotify poller. // This creates an inotify handler, and an epoll handler. func newFdPoller(fd int) (*fdPoller, error) { var errno error poller := emptyPoller(fd) defer func() { if errno != nil { poller.close() } }() poller.fd = fd // Create epoll fd poller.epfd, errno = syscall.EpollCreate1(0) if poller.epfd == -1 { return nil, errno } // Create pipe; pipe[0] is the read end, pipe[1] the write end. errno = syscall.Pipe2(poller.pipe[:], syscall.O_NONBLOCK) if errno != nil { return nil, errno } // Register inotify fd with epoll event := syscall.EpollEvent{ Fd: int32(poller.fd), Events: syscall.EPOLLIN, } errno = syscall.EpollCtl(poller.epfd, syscall.EPOLL_CTL_ADD, poller.fd, &event) if errno != nil { return nil, errno } // Register pipe fd with epoll event = syscall.EpollEvent{ Fd: int32(poller.pipe[0]), Events: syscall.EPOLLIN, } errno = syscall.EpollCtl(poller.epfd, syscall.EPOLL_CTL_ADD, poller.pipe[0], &event) if errno != nil { return nil, errno } return poller, nil }
// Pipe returns a connected pair of Files; reads from r return bytes written to w. // It returns the files and an error, if any. func Pipe() (r *File, w *File, err error) { var p [2]int e := syscall.Pipe2(p[0:], syscall.O_CLOEXEC) // pipe2 was added in 2.6.27 and our minimum requirement is 2.6.23, so it // might not be implemented. if e == syscall.ENOSYS { // See ../syscall/exec.go for description of lock. syscall.ForkLock.RLock() e = syscall.Pipe(p[0:]) if e != nil { syscall.ForkLock.RUnlock() return nil, nil, NewSyscallError("pipe", e) } syscall.CloseOnExec(p[0]) syscall.CloseOnExec(p[1]) syscall.ForkLock.RUnlock() } else if e != nil { return nil, nil, NewSyscallError("pipe2", e) } return NewFile(uintptr(p[0]), "|0"), NewFile(uintptr(p[1]), "|1"), nil }
func main() { runtime.GOMAXPROCS(8) dec := json.NewDecoder(os.Stdin) var plan plan if err := dec.Decode(&plan); err != nil { panic(fmt.Sprintf("failed to parse plan: %s", err)) } //fmt.Fprintf(os.Stderr, "plan: %+v\n", plan) runtime.LockOSThread() if err := syscall.Setresuid(0, 0, 0); err != nil { poePanic(err, "setuid failed") } if err := InitializeSystemdBus(); err != nil { poePanic(err, "failed to connect to systemd") } runtime.UnlockOSThread() rootdir, errx := PlaygroundCreate(plan.Base, plan.Compiler.Overlay) if errx != nil { poePanic(errx, "playground_create failed") } progfile, errx := PlaygroundCopy(rootdir, plan.Source) if errx != nil { poePanic(errx, "playground_copy failed") } var stdin_fd, stdout_fd, stderr_fd [2]int if err := syscall.Pipe2(stdin_fd[:], 0); err != nil { poePanic(err, "pipe2 failed") } if err := syscall.Pipe2(stdout_fd[:], syscall.O_DIRECT); err != nil { poePanic(err, "pipe2 failed") } if err := syscall.Pipe2(stderr_fd[:], syscall.O_DIRECT); err != nil { poePanic(err, "pipe2 failed") } pid_, _, err := syscall.Syscall(syscall.SYS_CLONE, uintptr(syscall.SIGCHLD|syscall.CLONE_NEWIPC|syscall.CLONE_NEWNS|syscall.CLONE_NEWPID|syscall.CLONE_NEWUTS|syscall.CLONE_NEWNET), 0, 0) pid := int(pid_) if err != 0 { poePanic(error(err), "clone failed") } else if pid == 0 { runtime.LockOSThread() if err, msg := doChild(rootdir, progfile, plan, stdin_fd, stdout_fd, stderr_fd); err != nil { fmt.Fprintf(os.Stderr, "%s (%s)", msg, err.Error()) os.Exit(127) } // unreachable } else { res := doParent(pid, stdin_fd, stdout_fd, stderr_fd) cleanup() var buf bytes.Buffer binary.Write(&buf, binary.LittleEndian, int32(res.result)) binary.Write(&buf, binary.LittleEndian, int32(res.status)) if _, err := os.Stderr.Write(buf.Bytes()); err != nil { poePanic(err, "stderr write failed") } if _, err := os.Stderr.Write([]byte(res.msg)); err != nil { poePanic(err, "stderr write failed") } os.Exit(0) // unreachable } }