@@ -5,14 +5,20 @@ import (
55 "fmt"
66 "io"
77 "os"
8+ "os/signal"
89 "strings"
910 "sync"
1011
12+ "github.com/moby/term"
13+ terminal "golang.org/x/term"
14+
1115 "github.com/containers/common/pkg/config"
16+ "github.com/containers/common/pkg/resize"
1217 "github.com/containers/podman/v5/libpod/define"
1318 "github.com/containers/podman/v5/pkg/bindings"
1419 "github.com/containers/podman/v5/pkg/bindings/containers"
1520 "github.com/containers/podman/v5/pkg/bindings/images"
21+ lsignal "github.com/containers/podman/v5/pkg/signal"
1622 "github.com/containers/podman/v5/pkg/specgen"
1723 log "github.com/sirupsen/logrus"
1824
@@ -485,6 +491,21 @@ func HandlePodmanRuntime(
485491 return
486492 }
487493
494+ if terminal .IsTerminal (int (os .Stdin .Fd ())) {
495+ resize := make (chan resize.TerminalSize )
496+
497+ cancel , oldTermState , err := podmanTerminalAttach (connCtx , resize )
498+ if err != nil {
499+ return
500+ }
501+ defer func () {
502+ if err := podmanTerminalRestore (oldTermState ); err != nil {
503+ log .Errorf ("podmanTerminalRestore - %v" , err )
504+ }
505+ }()
506+ defer cancel ()
507+ }
508+
488509 r , w := io .Pipe ()
489510 go io .Copy (w , os .Stdin )
490511
@@ -512,6 +533,87 @@ func HandlePodmanRuntime(
512533 logger .Trace ("Debugger exited..." )
513534}
514535
536+ func podmanTerminalAttach (ctx context.Context , resize chan resize.TerminalSize ) (context.CancelFunc , * term.State , error ) {
537+ log .Debug ("podmanTerminalAttach" )
538+
539+ subCtx , cancel := context .WithCancel (ctx )
540+
541+ resizeTty (subCtx , resize )
542+
543+ oldTermState , err := term .SaveState (os .Stdin .Fd ())
544+ if err != nil {
545+ // allow caller to not have to do any cleaning up if we error here
546+ cancel ()
547+ return nil , nil , fmt .Errorf ("unable to save terminal state: %w" , err )
548+ }
549+
550+ log .SetFormatter (& rawFormatter {})
551+ if _ , err := term .SetRawTerminal (os .Stdin .Fd ()); err != nil {
552+ return cancel , nil , err
553+ }
554+
555+ return cancel , oldTermState , nil
556+ }
557+
558+ func podmanTerminalRestore (state * term.State ) error {
559+ log .SetFormatter (& log.TextFormatter {})
560+ return term .RestoreTerminal (os .Stdin .Fd (), state )
561+ }
562+
563+ type rawFormatter struct {
564+ log.TextFormatter
565+ }
566+
567+ func (f * rawFormatter ) Format (entry * log.Entry ) ([]byte , error ) {
568+ bytes , err := f .TextFormatter .Format (entry )
569+ if err != nil {
570+ return bytes , err
571+ }
572+ return append (bytes , '\r' ), nil
573+ }
574+
575+ func getResize () * resize.TerminalSize {
576+ winsize , err := term .GetWinsize (os .Stdin .Fd ())
577+ if err != nil {
578+ log .Warnf ("Could not get terminal size %v" , err )
579+ return nil
580+ }
581+ return & resize.TerminalSize {
582+ Width : winsize .Width ,
583+ Height : winsize .Height ,
584+ }
585+ }
586+
587+ func resizeTty (ctx context.Context , resize chan resize.TerminalSize ) {
588+ sigchan := make (chan os.Signal , 1 )
589+ signal .Notify (sigchan , lsignal .SIGWINCH )
590+ go func () {
591+ defer close (resize )
592+ // Update the terminal size immediately without waiting
593+ // for a SIGWINCH to get the correct initial size.
594+ resizeEvent := getResize ()
595+ for {
596+ if resizeEvent == nil {
597+ select {
598+ case <- ctx .Done ():
599+ return
600+ case <- sigchan :
601+ resizeEvent = getResize ()
602+ }
603+ } else {
604+ select {
605+ case <- ctx .Done ():
606+ return
607+ case <- sigchan :
608+ resizeEvent = getResize ()
609+ case resize <- * resizeEvent :
610+ resizeEvent = nil
611+ }
612+ }
613+ }
614+ }()
615+ }
616+
515617func podmanEnsureImage (logger * log.Entry , connCtx context.Context , image string ) error {
516618 if image == "" {
517619 return nil
@@ -628,6 +730,23 @@ func listPodmanDebugContainersWithConfig(
628730 return listPodmanDebugContainers (connCtx , targetContainer , onlyActive )
629731}
630732
733+ // https://github.com/containers/podman/blob/main/libpod/define/containerstate.go#L42
734+ // PCS - Podman Container State
735+ const (
736+ PCSUnknown = "unknown"
737+ PCSConfigured = "created"
738+ PCSCreated = "initialized"
739+ PCSRunning = "running"
740+ PCSStopped = "stopped"
741+ PCSPaused = "paused"
742+ PCSExited = "exited"
743+ PCSRemoving = "removing"
744+ PCSStopping = "stopping"
745+ //also referenced in the APIs/docs:
746+ PCSRestarting = "restarting"
747+ PCSDead = "dead"
748+ )
749+
631750func listPodmanDebugContainers (
632751 connCtx context.Context ,
633752 targetContainer string ,
@@ -668,11 +787,11 @@ func listPodmanDebugContainers(
668787 }
669788
670789 switch container .State {
671- case "created" , "paused" , "restarting" : //"restarting" - confirm
790+ case PCSConfigured , PCSCreated , PCSPaused , PCSRestarting :
672791 info .State = CSWaiting
673- case "running" :
792+ case PCSRunning :
674793 info .State = CSRunning
675- case "exited" , "dead" , "removing" : //"removing" - confirm
794+ case PCSExited , PCSRemoving , PCSStopping , PCSStopped , PCSDead :
676795 info .State = CSTerminated
677796 default :
678797 info .State = CSOther
0 commit comments