I'm learning about container technologies of Linux and wrote a minimal container implementation on my own. I'm currently confused about consoles / terminals for container processes, as I'm "reusing" the controlling terminal as /dev/console
(instead of c 5 1
) in the container.
I determine the current terminal from /proc/self/fd/0
and /proc/self/fd/2
, read its device node (major and minor), and mknod(2)
using the discovered device nodes to create /dev/console
node in the container.
This appears fine when running a regular application like /bin/sh
as PID 1 (in PID namespace), but not when through an init system (I used BusyBox for this).
Here's my /etc/inittab
for the BusyBox rootfs:
::sysinit:/bin/true
::respawn:-/bin/sh
However, the shell spawned by init always complains can't access tty; job control turned off
. I also tried using the same host TTY node for /dev/tty
(instead of c 5 0
) but this problem still persists.
I looked into the source code of systemd-nspawn
and found that it creates a "forwarded pty", where the container runs on a new PTY that's "forwarded" to the host side. The code is too complex for my educational project so it's not viable for me.
How can I use the host terminal for the container?
Details: My container program clone(2)
only one child with flags = CLONE_NEWGROUP | CLONE_NEWNET | CLONE_NEWPID | CLONE_NEWIPC | CLONE_NEWUTS | SIGCHLD
, and the child sets up capabilities (blacklisting) and seccomp (whitelisting, syscall list taken from Docker), before pivot_root(2)
to the container rootfs and execve(2)
into the target application.
I'm currently experimenting on Linux 5.3 (Ubuntu 18.04 HWE), but I don't expect this to be different on any recent Linux versions.
::respawn:-/bin/sh
, use::respawn:/bin/cttyhack /bin/sh
. This is a well known problem, well explained in the//config
comments from the cttyhack source codescript /dev/null
(which will create a pseudo-tty owned by you) also works in cases like this.