github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/pkg/domain/infra/abi/terminal/terminal.go (about) 1 package terminal 2 3 import ( 4 "context" 5 "os" 6 "os/signal" 7 8 "github.com/hanks177/podman/v4/libpod/define" 9 lsignal "github.com/hanks177/podman/v4/pkg/signal" 10 "github.com/moby/term" 11 "github.com/pkg/errors" 12 "github.com/sirupsen/logrus" 13 ) 14 15 // RawTtyFormatter ... 16 type RawTtyFormatter struct { 17 } 18 19 // getResize returns a TerminalSize command matching stdin's current 20 // size on success, and nil on errors. 21 func getResize() *define.TerminalSize { 22 winsize, err := term.GetWinsize(os.Stdin.Fd()) 23 if err != nil { 24 logrus.Warnf("Could not get terminal size %v", err) 25 return nil 26 } 27 return &define.TerminalSize{ 28 Width: winsize.Width, 29 Height: winsize.Height, 30 } 31 } 32 33 // Helper for prepareAttach - set up a goroutine to generate terminal resize events 34 func resizeTty(ctx context.Context, resize chan define.TerminalSize) { 35 sigchan := make(chan os.Signal, 1) 36 signal.Notify(sigchan, lsignal.SIGWINCH) 37 go func() { 38 defer close(resize) 39 // Update the terminal size immediately without waiting 40 // for a SIGWINCH to get the correct initial size. 41 resizeEvent := getResize() 42 for { 43 if resizeEvent == nil { 44 select { 45 case <-ctx.Done(): 46 return 47 case <-sigchan: 48 resizeEvent = getResize() 49 } 50 } else { 51 select { 52 case <-ctx.Done(): 53 return 54 case <-sigchan: 55 resizeEvent = getResize() 56 case resize <- *resizeEvent: 57 resizeEvent = nil 58 } 59 } 60 } 61 }() 62 } 63 64 func restoreTerminal(state *term.State) error { 65 logrus.SetFormatter(&logrus.TextFormatter{}) 66 return term.RestoreTerminal(os.Stdin.Fd(), state) 67 } 68 69 // Format ... 70 func (f *RawTtyFormatter) Format(entry *logrus.Entry) ([]byte, error) { 71 textFormatter := logrus.TextFormatter{} 72 bytes, err := textFormatter.Format(entry) 73 74 if err == nil { 75 bytes = append(bytes, '\r') 76 } 77 78 return bytes, err 79 } 80 81 func handleTerminalAttach(ctx context.Context, resize chan define.TerminalSize) (context.CancelFunc, *term.State, error) { 82 logrus.Debugf("Handling terminal attach") 83 84 subCtx, cancel := context.WithCancel(ctx) 85 86 resizeTty(subCtx, resize) 87 88 oldTermState, err := term.SaveState(os.Stdin.Fd()) 89 if err != nil { 90 // allow caller to not have to do any cleaning up if we error here 91 cancel() 92 return nil, nil, errors.Wrapf(err, "unable to save terminal state") 93 } 94 95 logrus.SetFormatter(&RawTtyFormatter{}) 96 if _, err := term.SetRawTerminal(os.Stdin.Fd()); err != nil { 97 return cancel, nil, err 98 } 99 100 return cancel, oldTermState, nil 101 }