From 902d579a1fc0c0438a5738bf8d7aef036655936f Mon Sep 17 00:00:00 2001 From: Daniel J Walsh Date: Thu, 24 Jun 2021 10:49:20 -0400 Subject: [PATCH] Turn stdio back to blocking when command finishes Fixes: https://github.com/containers/buildah/issues/3152 Sometimes after running buildah run in a terminal, commands executed afterwards which try to read from stdin fail with EAGAIN. This is because it sets O_NONBLOCK on the FD: [NO TESTS NEEDED] Since I don't know how to test this. Signed-off-by: Daniel J Walsh --- run_linux.go | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/run_linux.go b/run_linux.go index 64ad8e2177..4a43525599 100644 --- a/run_linux.go +++ b/run_linux.go @@ -1182,16 +1182,21 @@ func runConfigureNetwork(isolation define.Isolation, options RunOptions, configu return teardown, nil } -func setNonblock(logger *logrus.Logger, fd int, description string, nonblocking bool) error { //nolint:interfacer - err := unix.SetNonblock(fd, nonblocking) +func setNonblock(logger *logrus.Logger, fd int, description string, nonblocking bool) (bool, error) { //nolint:interfacer + mask, err := unix.FcntlInt(uintptr(fd), unix.F_GETFL, 0) if err != nil { + return false, err + } + blocked := mask&unix.O_NONBLOCK == 0 + + if err := unix.SetNonblock(fd, nonblocking); err != nil { if nonblocking { logger.Errorf("error setting %s to nonblocking: %v", description, err) } else { logger.Errorf("error setting descriptor %s blocking: %v", description, err) } } - return err + return blocked, err } func runCopyStdio(logger *logrus.Logger, stdio *sync.WaitGroup, copyPipes bool, stdioPipe [][]int, copyConsole bool, consoleListener *net.UnixListener, finishCopy []int, finishedCopy chan struct{}, spec *specs.Spec) { @@ -1261,9 +1266,13 @@ func runCopyStdio(logger *logrus.Logger, stdio *sync.WaitGroup, copyPipes bool, } // Set our reading descriptors to non-blocking. for rfd, wfd := range relayMap { - if err := setNonblock(logger, rfd, readDesc[rfd], true); err != nil { + blocked, err := setNonblock(logger, rfd, readDesc[rfd], true) + if err != nil { return } + if blocked { + defer setNonblock(logger, rfd, readDesc[rfd], false) // nolint:errcheck + } setNonblock(logger, wfd, writeDesc[wfd], false) // nolint:errcheck }