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  }