github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/runc/tty.go (about)

     1  // +build linux
     2  
     3  package main
     4  
     5  import (
     6  	"fmt"
     7  	"io"
     8  	"os"
     9  	"sync"
    10  
    11  	"github.com/docker/docker/pkg/term"
    12  	"github.com/opencontainers/runc/libcontainer"
    13  )
    14  
    15  // setup standard pipes so that the TTY of the calling runc process
    16  // is not inherited by the container.
    17  func createStdioPipes(p *libcontainer.Process, rootuid, rootgid int) (*tty, error) {
    18  	i, err := p.InitializeIO(rootuid, rootgid)
    19  	if err != nil {
    20  		return nil, err
    21  	}
    22  	t := &tty{
    23  		closers: []io.Closer{
    24  			i.Stdin,
    25  			i.Stdout,
    26  			i.Stderr,
    27  		},
    28  	}
    29  	// add the process's io to the post start closers if they support close
    30  	for _, cc := range []interface{}{
    31  		p.Stdin,
    32  		p.Stdout,
    33  		p.Stderr,
    34  	} {
    35  		if c, ok := cc.(io.Closer); ok {
    36  			t.postStart = append(t.postStart, c)
    37  		}
    38  	}
    39  	go func() {
    40  		io.Copy(i.Stdin, os.Stdin)
    41  		i.Stdin.Close()
    42  	}()
    43  	t.wg.Add(2)
    44  	go t.copyIO(os.Stdout, i.Stdout)
    45  	go t.copyIO(os.Stderr, i.Stderr)
    46  	return t, nil
    47  }
    48  
    49  func (t *tty) copyIO(w io.Writer, r io.ReadCloser) {
    50  	defer t.wg.Done()
    51  	io.Copy(w, r)
    52  	r.Close()
    53  }
    54  
    55  func createTty(p *libcontainer.Process, rootuid, rootgid int, consolePath string) (*tty, error) {
    56  	if consolePath != "" {
    57  		if err := p.ConsoleFromPath(consolePath); err != nil {
    58  			return nil, err
    59  		}
    60  		return &tty{}, nil
    61  	}
    62  	console, err := p.NewConsole(rootuid, rootgid)
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  	go io.Copy(console, os.Stdin)
    67  	go io.Copy(os.Stdout, console)
    68  
    69  	state, err := term.SetRawTerminal(os.Stdin.Fd())
    70  	if err != nil {
    71  		return nil, fmt.Errorf("failed to set the terminal from the stdin: %v", err)
    72  	}
    73  	return &tty{
    74  		console: console,
    75  		state:   state,
    76  		closers: []io.Closer{
    77  			console,
    78  		},
    79  	}, nil
    80  }
    81  
    82  type tty struct {
    83  	console   libcontainer.Console
    84  	state     *term.State
    85  	closers   []io.Closer
    86  	postStart []io.Closer
    87  	wg        sync.WaitGroup
    88  }
    89  
    90  // ClosePostStart closes any fds that are provided to the container and dup2'd
    91  // so that we no longer have copy in our process.
    92  func (t *tty) ClosePostStart() error {
    93  	for _, c := range t.postStart {
    94  		c.Close()
    95  	}
    96  	return nil
    97  }
    98  
    99  // Close closes all open fds for the tty and/or restores the orignal
   100  // stdin state to what it was prior to the container execution
   101  func (t *tty) Close() error {
   102  	// ensure that our side of the fds are always closed
   103  	for _, c := range t.postStart {
   104  		c.Close()
   105  	}
   106  	// wait for the copy routines to finish before closing the fds
   107  	t.wg.Wait()
   108  	for _, c := range t.closers {
   109  		c.Close()
   110  	}
   111  	if t.state != nil {
   112  		term.RestoreTerminal(os.Stdin.Fd(), t.state)
   113  	}
   114  	return nil
   115  }
   116  
   117  func (t *tty) resize() error {
   118  	if t.console == nil {
   119  		return nil
   120  	}
   121  	ws, err := term.GetWinsize(os.Stdin.Fd())
   122  	if err != nil {
   123  		return err
   124  	}
   125  	return term.SetWinsize(t.console.Fd(), ws)
   126  }