From fff4226b17debe07f4e6af1165b13addc286b181 Mon Sep 17 00:00:00 2001 From: Chris Kuehl Date: Mon, 10 Oct 2016 11:10:08 -0700 Subject: [PATCH 1/2] Hand controlling TTY to child, if we have one --- dumb-init.c | 18 ++++++++++++++++ tests/tty_test.py | 53 ++++++++++++++++++++++++++++++++++------------- 2 files changed, 57 insertions(+), 14 deletions(-) diff --git a/dumb-init.c b/dumb-init.c index cb0cbec..8993d84 100644 --- a/dumb-init.c +++ b/dumb-init.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -250,6 +251,15 @@ int main(int argc, char *argv[]) { for (i = 1; i <= MAXSIG; i++) signal(i, dummy); + /* detach dumb-init from controlling tty */ + if (use_setsid && ioctl(0, TIOCNOTTY, NULL) == -1) { + DEBUG( + "Unable to detach from controlling tty (errno=%d %s).\n", + errno, + strerror(errno) + ); + } + child_pid = fork(); if (child_pid < 0) { PRINTERR("Unable to fork. Exiting.\n"); @@ -266,6 +276,14 @@ int main(int argc, char *argv[]) { ); exit(1); } + + if (ioctl(0, TIOCSCTTY, NULL) == -1) { + DEBUG( + "Unable to attach to controlling tty (errno=%d %s).\n", + errno, + strerror(errno) + ); + } DEBUG("setsid complete.\n"); } execvp(cmd[0], &cmd[0]); diff --git a/tests/tty_test.py b/tests/tty_test.py index 23f6a5c..9e2dac4 100644 --- a/tests/tty_test.py +++ b/tests/tty_test.py @@ -1,5 +1,6 @@ import os import pty +import re import termios import pytest @@ -35,24 +36,48 @@ def readall(fd): result += chunk -def _test(fd): - """write to tac via the pty and verify its output""" - ttyflags(fd) - assert os.write(fd, b'1\n2\n3\n') == 6 - assert os.write(fd, EOF * 2) == 2 - output = readall(fd) - assert output == b'3\n2\n1\n', repr(output) - print('PASS') - - # disable debug output so it doesn't break our assertion @pytest.mark.usefixtures('debug_disabled') def test_tty(): - """ - Ensure processes wrapped by dumb-init can write successfully, given a tty - """ + """Ensure processes under dumb-init can write successfully, given a tty.""" pid, fd = pty.fork() if pid == 0: os.execvp('dumb-init', ('dumb-init', 'tac')) else: - _test(fd) + # write to tac via the pty and verify its output + ttyflags(fd) + assert os.write(fd, b'1\n2\n3\n') == 6 + assert os.write(fd, EOF * 2) == 2 + output = readall(fd) + assert os.waitpid(pid, 0) == (pid, 0) + + assert output == b'3\n2\n1\n', repr(output) + + +@pytest.mark.usefixtures('both_debug_modes') +@pytest.mark.usefixtures('both_setsid_modes') +def test_child_gets_controlling_tty_if_we_had_one(): + """If dumb-init has a controlling TTY, it should give it to the child. + + To test this, we make a new TTY then exec "dumb-init bash" and ensure that + the shell has working job control. + """ + pid, sfd = pty.fork() + if pid == 0: + os.execvpe('./dumb-init', ('dumb-init', 'bash', '-m'), {}) + else: + ttyflags(sfd) + + # We might get lots of extra output from the shell, so print something + # we can match on easily. + assert os.write(sfd, b'echo "flags are: [[$-]]"\n') == 25 + assert os.write(sfd, b'exit 0\n') == 7 + output = readall(sfd) + assert os.waitpid(pid, 0) == (pid, 0), output + + m = re.search(b'flags are: \[\[([a-zA-Z]+)\]\]\n', output) + assert m, output + + # "m" is job control + flags = m.group(1) + assert b'm' in flags From e4e2dd0503fdc07973e193414335725570f4238a Mon Sep 17 00:00:00 2001 From: Chris Kuehl Date: Mon, 10 Oct 2016 12:23:19 -0700 Subject: [PATCH 2/2] Fix ioctl arguments --- dumb-init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dumb-init.c b/dumb-init.c index 8993d84..65e69ef 100644 --- a/dumb-init.c +++ b/dumb-init.c @@ -252,7 +252,7 @@ int main(int argc, char *argv[]) { signal(i, dummy); /* detach dumb-init from controlling tty */ - if (use_setsid && ioctl(0, TIOCNOTTY, NULL) == -1) { + if (use_setsid && ioctl(STDIN_FILENO, TIOCNOTTY) == -1) { DEBUG( "Unable to detach from controlling tty (errno=%d %s).\n", errno, @@ -277,7 +277,7 @@ int main(int argc, char *argv[]) { exit(1); } - if (ioctl(0, TIOCSCTTY, NULL) == -1) { + if (ioctl(STDIN_FILENO, TIOCSCTTY, 0) == -1) { DEBUG( "Unable to attach to controlling tty (errno=%d %s).\n", errno,