go syscall: SysProcAttr.Noctty仅在子进程的标准输入控制终端时有效,

vatpfxk5  于 4个月前  发布在  Go
关注(0)|答案(5)|浏览(60)

SysProcAttr.Noctty 通过在执行前调用 RawSyscall(SYS_IOCTL, 0, uintptr(TIOCNOTTY), 0) 来实现。TIOCNOTTY ioctl 仅在控制终端的文件描述符上实现,这并不一定与子进程的 FD 0 相连。这意味着 SysProcAttr.Noctty 仅在 cmd.Stdin 是会话终端时有效,而且不可能同时运行一个既没有终端又具有功能性 stdin 的子进程。

这个问题出现是因为我正在为一个使用 /dev/tty 与用户交互并分别获取输入的应用程序编写测试。我想测试当 /dev/tty 不可用时会发生什么,所以我用 SysProcAttr.Noctty 启动子进程,并为其提供一个 stdin 管道。结果是在管道上发出了 TIOCNOTTY,导致 operation not supported by device

下面是一个简短的例子:

package main

import (
"os"
"os/exec"
"syscall"
)

func main() {
if len(os.Args) > 1 && os.Args[1] == "child" {
_, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
if err != nil {
println(err.Error()) // expect: "device not configured"
}
return
}

cmd := exec.Command(os.Args[0], "child")
// Uncomment this block to have Noccty work correctly,
// but making stdin in the child unusable.
// f, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
// if err != nil {
// 	panic(err)
// }
// cmd.Stdin = f
cmd.Stderr = os.Stderr // to see the output
cmd.SysProcAttr = &syscall.SysProcAttr{}
cmd.SysProcAttr.Noctty = true
if err := cmd.Run(); err != nil {
	panic(err)
}

}

zfciruhq

zfciruhq1#

另外,由于SetcttyNoctty之后应用,我们也无法测试stdin是一个终端但没有控制终端的情况(如果操作顺序颠倒,这种情况是可能的)。

dzhpxtsq

dzhpxtsq2#

Well, Noctty 正在按照文档进行操作。对于这里需要添加的内容有什么建议吗?

i7uaboj4

i7uaboj43#

对我来说,最直接的解决方案似乎是在 /dev/tty 上打开并发行 TIOCNOTTY,但也许我没有看到一些理由认为它会是不理想的。如果出于某种原因 /dev/tty 不可用,它仍然可以尝试 FD 0 作为后备。任何当前工作的应用的行为都不会改变。

vu8f3i0k

vu8f3i0k4#

听起来有道理。看看是否会出现任何问题会很有趣。

wa7juj8i

wa7juj8i5#

有人打算提出更详细的修复方案(例如一个CL)吗?还是我应该去别的地方找人来处理?(我标记它需要决策,因为我认为测试修复基本上给了我们决策。还有可能是里程碑1.20吗?)

相关问题