44 "context"
55 "errors"
66 "fmt"
7- "io"
87 "os"
98 "os/exec"
109 "os/signal"
@@ -341,6 +340,9 @@ func tryPluginRun(ctx context.Context, dockerCli command.Cli, cmd *cobra.Command
341340 if force {
342341 _ = plugincmd .Process .Kill ()
343342 _ , _ = fmt .Fprint (dockerCli .Err (), "got 3 SIGTERM/SIGINTs, forcefully exiting\n " )
343+
344+ // Restore terminal in case it was in raw mode.
345+ restoreTerminal (dockerCli )
344346 os .Exit (1 )
345347 }
346348 }
@@ -388,7 +390,7 @@ func tryPluginRun(ctx context.Context, dockerCli command.Cli, cmd *cobra.Command
388390// to be caught and the context to be marked as done, then registers a new
389391// signal handler for subsequent signals. It forces the process to exit
390392// after 3 SIGTERM/SIGINT signals.
391- func forceExitAfter3TerminationSignals (ctx context.Context , w io. Writer ) {
393+ func forceExitAfter3TerminationSignals (ctx context.Context , streams command. Streams ) {
392394 // wait for the first signal to be caught and the context to be marked as done
393395 <- ctx .Done ()
394396 // register a new signal handler for subsequent signals
@@ -399,10 +401,22 @@ func forceExitAfter3TerminationSignals(ctx context.Context, w io.Writer) {
399401 for i := 0 ; i < 2 ; i ++ {
400402 <- sig
401403 }
402- _ , _ = fmt .Fprint (w , "\n got 3 SIGTERM/SIGINTs, forcefully exiting\n " )
404+ _ , _ = fmt .Fprint (streams .Err (), "\n got 3 SIGTERM/SIGINTs, forcefully exiting\n " )
405+
406+ // Restore terminal in case it was in raw mode.
407+ restoreTerminal (streams )
403408 os .Exit (1 )
404409}
405410
411+ // restoreTerminal restores the terminal if it was in raw mode; this prevents
412+ // local echo from being disabled for the current terminal after forceful
413+ // termination. It's a no-op if there's no prior state to restore.
414+ func restoreTerminal (streams command.Streams ) {
415+ streams .In ().RestoreTerminal ()
416+ streams .Out ().RestoreTerminal ()
417+ streams .Err ().RestoreTerminal ()
418+ }
419+
406420//nolint:gocyclo
407421func runDocker (ctx context.Context , dockerCli * command.DockerCli ) error {
408422 tcmd := newDockerCommand (dockerCli )
@@ -468,7 +482,7 @@ func runDocker(ctx context.Context, dockerCli *command.DockerCli) error {
468482
469483 // This is a fallback for the case where the command does not exit
470484 // based on context cancellation.
471- go forceExitAfter3TerminationSignals (ctx , dockerCli . Err () )
485+ go forceExitAfter3TerminationSignals (ctx , dockerCli )
472486
473487 // We've parsed global args already, so reset args to those
474488 // which remain.
0 commit comments