Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to send Ctrl-C control character or terminal hangup message to child process?

Tags:

c

posix

pty

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:

  • emulating a 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:

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

but it doesn't do anything.

like image 288
Hongli Avatar asked Feb 03 '10 22:02

Hongli


2 Answers

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):

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.

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.

like image 86
Sean Reifschneider Avatar answered Nov 18 '22 13:11

Sean Reifschneider


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:

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.

like image 37
Hongli Avatar answered Nov 18 '22 14:11

Hongli