libcontainer: io: stop screwing with \n in console output

The default terminal setting for a new pty on Linux (unix98) has +ONLCR,
resulting in '\n' writes by a container process to be converted to
'\r\n' reads by the managing process. This is quite unexpected, and
causes multiple issues with things like bats testing. To fix it, make
the terminal sane after opening it by setting -ONLCR.

This patch might need to be rewritten after the console rewrite patchset
is merged.

Signed-off-by: Aleksa Sarai <asarai@suse.de>
This commit is contained in:
Aleksa Sarai 2016-10-24 22:09:01 +11:00
parent 4c8007f34a
commit eea28f480d
No known key found for this signature in database
GPG Key ID: 9E18AA267DDB8DB4
1 changed files with 26 additions and 0 deletions

View File

@ -17,6 +17,9 @@ func NewConsole(uid, gid int) (Console, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := saneTerminal(master); err != nil {
return nil, err
}
console, err := ptsname(master) console, err := ptsname(master)
if err != nil { if err != nil {
return nil, err return nil, err
@ -143,3 +146,26 @@ func ptsname(f *os.File) (string, error) {
} }
return fmt.Sprintf("/dev/pts/%d", n), nil return fmt.Sprintf("/dev/pts/%d", n), nil
} }
// saneTerminal sets the necessary tty_ioctl(4)s to ensure that a pty pair
// created by us acts normally. In particular, a not-very-well-known default of
// Linux unix98 ptys is that they have +onlcr by default. While this isn't a
// problem for terminal emulators, because we relay data from the terminal we
// also relay that funky line discipline.
func saneTerminal(terminal *os.File) error {
// Go doesn't have a wrapper for any of the termios ioctls.
var termios syscall.Termios
if err := ioctl(terminal.Fd(), syscall.TCGETS, uintptr(unsafe.Pointer(&termios))); err != nil {
return fmt.Errorf("ioctl(tty, tcgets): %s", err.Error())
}
// Set -onlcr so we don't have to deal with \r.
termios.Oflag &^= syscall.ONLCR
if err := ioctl(terminal.Fd(), syscall.TCSETS, uintptr(unsafe.Pointer(&termios))); err != nil {
return fmt.Errorf("ioctl(tty, tcsets): %s", err.Error())
}
return nil
}