如何将Ctrl-C控制字符或终端挂断消息发送到子进程?

时间:2022-07-05 21:05:44

I have a child process which runs in a pseudo terminal. The parent process does not run as root, but the child process does, through su or sudo. Because of this it is not possible to send a signal to the child process to force it to exit. I want to force it to exit by one of these means:

我有一个在伪终端中运行的子进程。父进程不以root身份运行,但子进程通过su或sudo运行。因此,无法向子进程发送信号以强制它退出。我想通过以下方法之一强制退出:

  • emulating a Ctrl-C.
  • 模拟Ctrl-C。

  • emulating a terminal hangup.
  • 模拟终端挂断。

How do I do either of these? I already have a pty master fd, and I've tried something like this:

我该怎么做?我已经有一个pty master fd,我尝试过这样的事情:

write(master, &termios.c_cc[VINTR], 1)

but it doesn't do anything.

但它没有做任何事情。

6 个解决方案

#1


4  

It seems to me that if you truly have a pty (unless you mean something else by pseudo terminal), that all you have to do is send a Control-C to that FD. As evidence of this, I submit the following code in Python (but fairly close to the C required to do it):

在我看来,如果你真的有一个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)

This forks a process under a pty, which runs an infinite loop printing the date. Then the parent waits 3 seconds and sends a control-C.

这会在pty下执行一个进程,它会运行一个打印日期的无限循环。然后父母等待3秒并发送一个control-C。

This results in the following output:

这导致以下输出:

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$

It ran just over 3 seconds, printed out the date 3 times, and exited.

它跑了3秒多,打印出日期3次,然后退出。

#2


2  

I eventually went with the following solution:

我最终选择了以下解决方案:

After forking, instead of exec'ing sudo immediately, I exec() a helper child process instead, which in turn forks and execs sudo and calls waitpid on it. So the process hierarchy looks like this:

在分叉之后,我不再立即执行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

By killing the helper process, the pty does not have a foreground process anymore. This will cause the OS to send SIGHUP to the entire foreground process group, regardless of the user, so sudo is SIGHUP'ed too.

通过杀死辅助进程,pty不再具有前台进程。这将导致操作系统将SIGHUP发送到整个前台进程组,无论用户如何,因此sudo也是SIGHUP。

#3


0  

There is two ways to achieve this:

有两种方法可以实现这一目标:

  • From the child process, trap the SIGCHLD signal and handle it, you could _exit(0) to end the child process
  • 从子进程捕获SIGCHLD信号并处理它,您可以_exit(0)结束子进程

  • There's a program called ptree. You could cheat this by doing it this way...in pseudocode:
  • 有一个名为ptree的程序。你可以通过这种方式来欺骗这个......在伪代码中:

obtain the parent's pid.
using _popen("ptree %d", parent_pid)
for each entry of child process
system ("kill -1 %d", child_process_pid)

There the two that comes to mind...sorry if its not of further help to you,

有两个想到的...抱歉,如果它不是对你的进一步帮助,

Hope this helps, Best regards, Tom.

希望这会有所帮助,最好的问候,汤姆。

#4


0  

Closing the master should signal a hangup to the controlling process group of the slave.

关闭主设备应该向从设备的控制进程组发出挂断信号。

#5


0  

I think you need to use ioctl to insert the interrupt character instead of write. Unfortunately the mechanism for this does not seem to be portable. For linux it looks this might work:

我认为你需要使用ioctl插入中断字符而不是写入。不幸的是,这种机制似乎并不便携。对于Linux,它看起来可能有用:

ioctl(master, TIOCSTI, &termios.c_cc[VINTR]);

#6


0  

The first thing I'd check is if you need to make it the controlling terminal on the slave side. It turns out this is more complex than I remember, with ptys possibly not becoming controlling by default. That link is for Linux, other systems should do one or the other depending on their SysV vs. BSD-ness, but it looks like the TIOCSCTTY is a good bet to try.

我要检查的第一件事是你是否需要将它作为从属端的控制终端。事实证明这比我记忆中的更复杂,ptys可能默认不会控制。这个链接适用于Linux,其他系统应该根据他们的SysV和BSD-ness做一个或另一个,但看起来TIOCSCTTY是一个不错的选择。

Secondly, I'd check if you're setting ISIG in your termios; if not, VINTR and VQUIT won't work.

其次,我会检查你是否在你的termios中设置了ISIG;如果没有,VINTR和VQUIT将无法正常工作。

Of course, if the other end is catching SIGINT and SIGQUIT, you will have other issues.

当然,如果另一端正在捕获SIGINT和SIGQUIT,那么您将遇到其他问题。

#1


4  

It seems to me that if you truly have a pty (unless you mean something else by pseudo terminal), that all you have to do is send a Control-C to that FD. As evidence of this, I submit the following code in Python (but fairly close to the C required to do it):

在我看来,如果你真的有一个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)

This forks a process under a pty, which runs an infinite loop printing the date. Then the parent waits 3 seconds and sends a control-C.

这会在pty下执行一个进程,它会运行一个打印日期的无限循环。然后父母等待3秒并发送一个control-C。

This results in the following output:

这导致以下输出:

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$

It ran just over 3 seconds, printed out the date 3 times, and exited.

它跑了3秒多,打印出日期3次,然后退出。

#2


2  

I eventually went with the following solution:

我最终选择了以下解决方案:

After forking, instead of exec'ing sudo immediately, I exec() a helper child process instead, which in turn forks and execs sudo and calls waitpid on it. So the process hierarchy looks like this:

在分叉之后,我不再立即执行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

By killing the helper process, the pty does not have a foreground process anymore. This will cause the OS to send SIGHUP to the entire foreground process group, regardless of the user, so sudo is SIGHUP'ed too.

通过杀死辅助进程,pty不再具有前台进程。这将导致操作系统将SIGHUP发送到整个前台进程组,无论用户如何,因此sudo也是SIGHUP。

#3


0  

There is two ways to achieve this:

有两种方法可以实现这一目标:

  • From the child process, trap the SIGCHLD signal and handle it, you could _exit(0) to end the child process
  • 从子进程捕获SIGCHLD信号并处理它,您可以_exit(0)结束子进程

  • There's a program called ptree. You could cheat this by doing it this way...in pseudocode:
  • 有一个名为ptree的程序。你可以通过这种方式来欺骗这个......在伪代码中:

obtain the parent's pid.
using _popen("ptree %d", parent_pid)
for each entry of child process
system ("kill -1 %d", child_process_pid)

There the two that comes to mind...sorry if its not of further help to you,

有两个想到的...抱歉,如果它不是对你的进一步帮助,

Hope this helps, Best regards, Tom.

希望这会有所帮助,最好的问候,汤姆。

#4


0  

Closing the master should signal a hangup to the controlling process group of the slave.

关闭主设备应该向从设备的控制进程组发出挂断信号。

#5


0  

I think you need to use ioctl to insert the interrupt character instead of write. Unfortunately the mechanism for this does not seem to be portable. For linux it looks this might work:

我认为你需要使用ioctl插入中断字符而不是写入。不幸的是,这种机制似乎并不便携。对于Linux,它看起来可能有用:

ioctl(master, TIOCSTI, &termios.c_cc[VINTR]);

#6


0  

The first thing I'd check is if you need to make it the controlling terminal on the slave side. It turns out this is more complex than I remember, with ptys possibly not becoming controlling by default. That link is for Linux, other systems should do one or the other depending on their SysV vs. BSD-ness, but it looks like the TIOCSCTTY is a good bet to try.

我要检查的第一件事是你是否需要将它作为从属端的控制终端。事实证明这比我记忆中的更复杂,ptys可能默认不会控制。这个链接适用于Linux,其他系统应该根据他们的SysV和BSD-ness做一个或另一个,但看起来TIOCSCTTY是一个不错的选择。

Secondly, I'd check if you're setting ISIG in your termios; if not, VINTR and VQUIT won't work.

其次,我会检查你是否在你的termios中设置了ISIG;如果没有,VINTR和VQUIT将无法正常工作。

Of course, if the other end is catching SIGINT and SIGQUIT, you will have other issues.

当然,如果另一端正在捕获SIGINT和SIGQUIT,那么您将遇到其他问题。