Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 2 commits into from
Nov 3, 2016
Merged

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

merged 2 commits into from
Nov 3, 2016

Conversation

cyphar
Copy link
Member

@cyphar cyphar commented Oct 24, 2016

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.

Fixes #1145.

Signed-off-by: Aleksa Sarai [email protected]

@cyphar
Copy link
Member Author

cyphar commented Oct 24, 2016

/cc @hqhq Does this patchset help with the bats situation?

@hqhq
Copy link
Contributor

hqhq commented Oct 24, 2016

My local experimental change looks like:

diff --git a/Godeps/_workspace/src/github.com/docker/docker/pkg/term/tc_linux_cgo.go b/Godeps/_workspace/src/github.com/docker/docker/pkg/term/tc_linux_cgo.go
index d47cf59..2804089 100644
--- a/Godeps/_workspace/src/github.com/docker/docker/pkg/term/tc_linux_cgo.go
+++ b/Godeps/_workspace/src/github.com/docker/docker/pkg/term/tc_linux_cgo.go
@@ -25,6 +25,8 @@ func MakeRaw(fd uintptr) (*State, error) {

        C.cfmakeraw((*C.struct_termios)(unsafe.Pointer(&newState)))
        newState.Oflag = newState.Oflag | C.OPOST
+       newState.Oflag = newState.Oflag ^ C.ONLCR
+
        if err := tcset(fd, &newState); err != 0 {
                return nil, err
        }
diff --git a/tty.go b/tty.go
index 5a76ebe..415d2e2 100644
--- a/tty.go
+++ b/tty.go
@@ -66,7 +66,8 @@ func createTty(p *libcontainer.Process, rootuid, rootgid int, consolePath string
        go io.Copy(console, os.Stdin)
        go io.Copy(os.Stdout, console)

-       state, err := term.SetRawTerminal(os.Stdin.Fd())
+       //state, err := term.SetRawTerminal(os.Stdin.Fd())
+       state, err := term.SetRawTerminal(console.Fd())
        if err != nil {
                return nil, fmt.Errorf("failed to set the terminal from the stdin: %v", err)
        }

I'm not sure if we should set stdin as raw mode.
BTW this default +onlcr is really suspicious.

@hqhq
Copy link
Contributor

hqhq commented Oct 24, 2016

$ stty -a
speed 38400 baud; rows 52; columns 211; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke

Looks like linux default tty setting enables onlcr? Do we still miss something?

@cyphar
Copy link
Member Author

cyphar commented Oct 24, 2016

We shouldn't set stdin in raw mode. The default +ONCLR is a kernel default (you can take a look at drivers/pty/n_tty.c if you want to hate yourself). The reason you don't notice it normally is that a pty is only created by your terminal emulator for your shell. You never see the weird stuff because all subprocess output is done with non-magical pipes.

So this isn't weird, it's just that we need to make it appear as though the output came from a pipe. We can work on this later (adding more settings), but this is enough to fix the immediate issue.

@cyphar
Copy link
Member Author

cyphar commented Oct 25, 2016

Do we still miss something?

I don't think so. And if we end up missing something we can always update SaneTerminal to make the change.

// 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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you put this function in utils and not with the other terminal handling code in console_linux.go?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm actually not sure (I think I wanted to make it so other people could use it but I'm not sure why that's necessary). Fixed.

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 <[email protected]>
@mrunalp
Copy link
Contributor

mrunalp commented Nov 1, 2016

LGTM

Approved with PullApprove

@crosbymichael
Copy link
Member

I'm guessing this fixes moby/moby#22450 right?

@mrunalp
Copy link
Contributor

mrunalp commented Nov 3, 2016

Looks like it should.

On Nov 3, 2016, at 10:46 AM, Michael Crosby [email protected] wrote:

I'm guessing this fixes moby/moby#22450 right?


You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.

@crosbymichael
Copy link
Member

crosbymichael commented Nov 3, 2016

LGTM

Approved with PullApprove

@crosbymichael crosbymichael merged commit 5f24c9a into opencontainers:master Nov 3, 2016
@cyphar cyphar deleted the io-set-termios-onlcr branch November 3, 2016 20:36
@hqhq hqhq mentioned this pull request Nov 22, 2016
9 tasks
@datawolf datawolf mentioned this pull request Jan 12, 2017
hqhq added a commit to hqhq/runc that referenced this pull request Jan 17, 2017
This reverts opencontainers#1146
it doesn't work well with docker, and we don't need
this fix for now, so revert it.

Signed-off-by: Qiang Huang <[email protected]>
romainreignier added a commit to romainreignier/rosmon that referenced this pull request Jul 28, 2021
Linux creates a new unix98 pty with the `ONLCR` flag set, see:
[pty.c:941](https://elixir.bootlin.com/linux/v5.13.5/source/drivers/tty/pty.c#L941)
and [tty_io.c:125](https://elixir.bootlin.com/linux/v5.13.5/source/drivers/tty/tty_io.c#L125).

The flag [ONLCR](https://www.gnu.org/software/libc/manual/html_node/Output-Modes.html#index-ONLCR) replaces `\n` with `\r\n` as done in [n_tty.c:444](https://elixir.bootlin.com/linux/v5.13.5/source/drivers/tty/n_tty.c#L444).

This can be an issue while using rosmon in a Docker container with the journald log driver.

Docker removes the trailing `\n` in log lines [here](https://github.com/moby/moby/blob/1f42dd5e91a643d8d4e3ef009fc8ba6e78c391d1/daemon/logger/copier.go#L104-L111).
This might not be obvious, but it is tested [here](https://github.com/moby/moby/blob/1f42dd5e91a643d8d4e3ef009fc8ba6e78c391d1/daemon/logger/copier_test.go#L52-L121).
And discussed [here](moby/moby#15722 (comment)).

And systemd-journald treats a log line with a non printable character, including
a trailing `\r`, as a binary blob and does not displays it with `journalctl`
as discussed [here](systemd/systemd#3416)
and [here](moby/moby#22450).

To fix the issue, the `\r` should be removed. And from [this PR](opencontainers/runc#1146),
I have learned its origin and how to get rid of it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

io: container output becomes windows-ised
5 participants