我有一个在伪终端中运行的子进程。父进程不以 root 身份运行,但子进程通过 su 或 sudo 运行。因此,不可能向子进程发送信号以强制其退出。我想通过以下方式之一强制它退出:
- 模拟 Ctrl-C。
- 模拟终端挂断。
我该怎么做?我已经有一个 pty master fd,我尝试过这样的事情:
write(master, &termios.c_cc[VINTR], 1)
但它什么也没做。
在我看来,如果你真的有一个 pty(除非你通过伪终端表示别的意思),那么你所要做的就是向该 FD 发送一个 Control-C。作为证据,我在 Python 中提交了以下代码(但与执行此操作所需的 C 相当接近):
import pty, os, sys, time
pid, fd = pty.fork()
if pid == 0:
os.execv('/bin/sh', ['/bin/sh', '-c',
'while true; do date; sleep 1; done'])
sys.exit(0)
time.sleep(3)
os.write(fd, '^C')
print 'results:', os.read(fd, 1024)
这在 pty 下创建了一个进程,该进程运行一个无限循环打印日期。然后父级等待 3 秒并发送一个 control-C。
这将产生以下输出:
guin:/tmp$ time python /tmp/foo
results: Fri Feb 5 08:28:09 MST 2010
Fri Feb 5 08:28:10 MST 2010
Fri Feb 5 08:28:11 MST 2010
python /tmp/foo 0.02s user 0.01s system 1% cpu 3.042 total
guin:/tmp$
它运行了 3 秒多一点,打印了 3 次日期,然后退出。
我最终采用了以下解决方案:
分叉后,我不是立即执行 sudo,而是 exec() 一个辅助子进程,该子进程又分叉并执行 sudo 并在其上调用 waitpid。因此流程层次结构如下所示:
original process <---- runs as user
|
+-- helper process <---- runs as user, session leader,
| has own pty, in pty's foreground process group
|
+--- sudo <---- runs as root
通过杀死辅助进程,pty 不再有前台进程。这将导致操作系统向整个前台进程组发送 SIGHUP,而不管用户如何,因此 sudo 也是 SIGHUP 的。
有两种方法可以实现这一点:
获取父进程的pid。 使用 _popen("ptree %d", parent_pid) 对于子进程的每个条目 系统(“kill -1 %d”,child_process_pid)
有两个浮现在脑海中......对不起,如果它对你没有进一步的帮助,
希望这会有所帮助,最好的问候,汤姆。
关闭主机应该向从机的控制进程组发出挂断信号。
我认为您需要使用ioctl
插入中断字符而不是write
. 不幸的是,这种机制似乎不是可移植的。对于 linux,看起来这可能有效:
ioctl(master, TIOCSTI, &termios.c_cc[VINTR]);
我要检查的第一件事是您是否需要将其设置为从属端的控制终端。事实证明,这比我记得的要复杂,因为 ptys 可能不会默认控制。该链接适用于 Linux,其他系统应该根据它们的 SysV 与 BSD-ness 做一个或另一个,但看起来 TIOCSCTTY 是一个不错的选择。
其次,我会检查您是否在 termios 中设置了 ISIG;如果没有,VINTR 和 VQUIT 将不起作用。
当然,如果另一端正在捕获 SIGINT 和 SIGQUIT,您将遇到其他问题。