github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/pkg/adapter/terminal_linux.go (about)

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