45 lines
1.2 KiB
Go
45 lines
1.2 KiB
Go
// Copyright (c) 2026 Storm Dragon
|
|
// Authors: Storm Dragon, Angus Kola
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package remoteinput
|
|
|
|
import (
|
|
"os"
|
|
"syscall"
|
|
)
|
|
|
|
// AdoptPipe transfers an inherited pipe to an owned nonblocking duplicate so
|
|
// Go's poller can interrupt blocked I/O on Close. Terminals/regular files and
|
|
// wrong-direction descriptors are rejected; a helper must have private control
|
|
// pipes. Failure leaves the original file owned by its caller.
|
|
func AdoptPipe(file *os.File, write bool) (*os.File, error) {
|
|
if file == nil {
|
|
return nil, ErrProtocol
|
|
}
|
|
info, err := file.Stat()
|
|
if err != nil || info.Mode()&os.ModeNamedPipe == 0 {
|
|
return nil, ErrProtocol
|
|
}
|
|
flags, _, failure := syscall.Syscall(syscall.SYS_FCNTL, file.Fd(), syscall.F_GETFL, 0)
|
|
want := syscall.O_RDONLY
|
|
if write {
|
|
want = syscall.O_WRONLY
|
|
}
|
|
if failure != 0 || int(flags)&syscall.O_ACCMODE != want {
|
|
return nil, ErrProtocol
|
|
}
|
|
fd, err := syscall.Dup(int(file.Fd()))
|
|
if err != nil {
|
|
return nil, ErrProtocol
|
|
}
|
|
syscall.CloseOnExec(fd)
|
|
if err := syscall.SetNonblock(fd, true); err != nil {
|
|
syscall.Close(fd)
|
|
return nil, ErrProtocol
|
|
}
|
|
owned := os.NewFile(uintptr(fd), "remote-input-pipe")
|
|
file.Close()
|
|
return owned, nil
|
|
}
|