github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/pkg/domain/infra/abi/terminal/terminal_linux.go (about) 1 // +build ABISupport 2 3 package terminal 4 5 import ( 6 "bufio" 7 "context" 8 "fmt" 9 "os" 10 11 "github.com/containers/libpod/libpod" 12 "github.com/containers/libpod/libpod/define" 13 "github.com/pkg/errors" 14 "github.com/sirupsen/logrus" 15 "golang.org/x/crypto/ssh/terminal" 16 "k8s.io/client-go/tools/remotecommand" 17 ) 18 19 // ExecAttachCtr execs and attaches to a container 20 func ExecAttachCtr(ctx context.Context, ctr *libpod.Container, tty, privileged bool, env map[string]string, cmd []string, user, workDir string, streams *define.AttachStreams, preserveFDs uint, detachKeys string) (int, error) { 21 resize := make(chan remotecommand.TerminalSize) 22 haveTerminal := terminal.IsTerminal(int(os.Stdin.Fd())) 23 24 // Check if we are attached to a terminal. If we are, generate resize 25 // events, and set the terminal to raw mode 26 if haveTerminal && tty { 27 cancel, oldTermState, err := handleTerminalAttach(ctx, resize) 28 if err != nil { 29 return -1, err 30 } 31 defer cancel() 32 defer func() { 33 if err := restoreTerminal(oldTermState); err != nil { 34 logrus.Errorf("unable to restore terminal: %q", err) 35 } 36 }() 37 } 38 39 execConfig := new(libpod.ExecConfig) 40 execConfig.Command = cmd 41 execConfig.Terminal = tty 42 execConfig.Privileged = privileged 43 execConfig.Environment = env 44 execConfig.User = user 45 execConfig.WorkDir = workDir 46 execConfig.DetachKeys = &detachKeys 47 execConfig.PreserveFDs = preserveFDs 48 49 return ctr.Exec(execConfig, streams, resize) 50 } 51 52 // StartAttachCtr starts and (if required) attaches to a container 53 // if you change the signature of this function from os.File to io.Writer, it will trigger a downstream 54 // error. we may need to just lint disable this one. 55 func StartAttachCtr(ctx context.Context, ctr *libpod.Container, stdout, stderr, stdin *os.File, detachKeys string, sigProxy bool, startContainer bool, recursive bool) error { //nolint-interfacer 56 resize := make(chan remotecommand.TerminalSize) 57 58 haveTerminal := terminal.IsTerminal(int(os.Stdin.Fd())) 59 60 // Check if we are attached to a terminal. If we are, generate resize 61 // events, and set the terminal to raw mode 62 if haveTerminal && ctr.Spec().Process.Terminal { 63 cancel, oldTermState, err := handleTerminalAttach(ctx, resize) 64 if err != nil { 65 return err 66 } 67 defer func() { 68 if err := restoreTerminal(oldTermState); err != nil { 69 logrus.Errorf("unable to restore terminal: %q", err) 70 } 71 }() 72 defer cancel() 73 } 74 75 streams := new(define.AttachStreams) 76 streams.OutputStream = stdout 77 streams.ErrorStream = stderr 78 streams.InputStream = bufio.NewReader(stdin) 79 streams.AttachOutput = true 80 streams.AttachError = true 81 streams.AttachInput = true 82 83 if stdout == nil { 84 logrus.Debugf("Not attaching to stdout") 85 streams.AttachOutput = false 86 } 87 if stderr == nil { 88 logrus.Debugf("Not attaching to stderr") 89 streams.AttachError = false 90 } 91 if stdin == nil { 92 logrus.Debugf("Not attaching to stdin") 93 streams.AttachInput = false 94 } 95 96 if !startContainer { 97 if sigProxy { 98 ProxySignals(ctr) 99 } 100 101 return ctr.Attach(streams, detachKeys, resize) 102 } 103 104 attachChan, err := ctr.StartAndAttach(ctx, streams, detachKeys, resize, recursive) 105 if err != nil { 106 return err 107 } 108 109 if sigProxy { 110 ProxySignals(ctr) 111 } 112 113 if stdout == nil && stderr == nil { 114 fmt.Printf("%s\n", ctr.ID()) 115 } 116 117 err = <-attachChan 118 if err != nil { 119 return errors.Wrapf(err, "error attaching to container %s", ctr.ID()) 120 } 121 122 return nil 123 }