@@ -31,6 +31,7 @@ import (
3131 "os"
3232 "os/exec"
3333 "os/user"
34+ "path"
3435 "path/filepath"
3536 "strconv"
3637 "strings"
@@ -237,12 +238,19 @@ func (h *HyperKit) checkLegacyConsole() error {
237238}
238239
239240func (h * HyperKit ) checkSerials () error {
240- for _ , serial := range h .Serials {
241+ stdioConsole := - 1
242+ for i , serial := range h .Serials {
241243 if serial .LogToRingBuffer && h .StateDir == "" {
242244 return fmt .Errorf ("If VM is to log to a ring buffer, StateDir must be specified" )
243245 }
244- if serial .InteractiveConsole == StdioInteractiveConsole && ! isTerminal (os .Stdout ) {
245- return fmt .Errorf ("If StdioInteractiveConsole is set, stdio must be a TTY" )
246+ if serial .InteractiveConsole == StdioInteractiveConsole {
247+ if isTerminal (os .Stdout ) {
248+ return fmt .Errorf ("If StdioInteractiveConsole is set, stdio must be a TTY" )
249+ }
250+ if stdioConsole != - 1 {
251+ return fmt .Errorf ("Only one serial port can be nominated as the stdio interactive console" )
252+ }
253+ stdioConsole = i
246254 }
247255 if serial .InteractiveConsole == TTYInteractiveConsole && h .StateDir == "" {
248256 return fmt .Errorf ("If TTYInteractiveConsole is set, StateDir must be specified " )
@@ -442,10 +450,12 @@ func (h *HyperKit) serialArgs() []string {
442450 for i , serial := range h .Serials {
443451 cfg := fmt .Sprintf ("com%d" , i + 1 )
444452 switch serial .InteractiveConsole {
453+ case NoInteractiveConsole :
454+ cfg += ",null"
445455 case StdioInteractiveConsole :
446456 cfg += fmt .Sprintf (",stdio" )
447457 case TTYInteractiveConsole :
448- cfg += fmt .Sprintf (",autopty=%s/tty" , h .StateDir )
458+ cfg += fmt .Sprintf (",autopty=%s/tty%d " , h .StateDir , i + 1 )
449459 }
450460 if serial .LogToASL {
451461 cfg += fmt .Sprintf (",asl" )
@@ -543,8 +553,8 @@ func (h *HyperKit) buildArgs(cmdline string) {
543553}
544554
545555// openTTY opens the tty files for reading, and returns it.
546- func (h * HyperKit ) openTTY () * os.File {
547- path := fmt . Sprintf ( "%s/tty" , h .StateDir )
556+ func (h * HyperKit ) openTTY (filename string ) * os.File {
557+ path := path . Join ( h .StateDir , filename )
548558 for {
549559 if res , err := os .OpenFile (path , os .O_RDONLY , 0 ); err != nil {
550560 log .Infof ("hyperkit: openTTY: %v, retrying" , err )
@@ -558,6 +568,21 @@ func (h *HyperKit) openTTY() *os.File {
558568 }
559569}
560570
571+ func (h * HyperKit ) findStdioTTY () string {
572+ if h .Serials != nil {
573+ for i , serial := range h .Serials {
574+ if serial .InteractiveConsole == StdioInteractiveConsole {
575+ return fmt .Sprintf ("tty%d" , i )
576+ }
577+ }
578+ return ""
579+ }
580+ if h .Console == ConsoleStdio {
581+ return "tty"
582+ }
583+ return ""
584+ }
585+
561586// execute forges the command to run hyperkit, runs and returns it.
562587// It also plumbs stdin/stdout/stderr.
563588func (h * HyperKit ) execute () (* exec.Cmd , error ) {
@@ -580,19 +605,21 @@ func (h *HyperKit) execute() (*exec.Cmd, error) {
580605 //
581606 // If a logger is specified, use it for stdout/stderr
582607 // logging. Otherwise use the default /dev/null.
583- if h .Console == ConsoleStdio {
608+ filename := h .findStdioTTY ()
609+ if filename != "" {
584610 if isTerminal (os .Stdout ) {
585611 cmd .Stdin = os .Stdin
586612 cmd .Stdout = os .Stdout
587613 cmd .Stderr = os .Stderr
588614 } else {
589615 go func () {
590- tty := h .openTTY ()
616+ tty := h .openTTY (filename )
591617 defer tty .Close ()
592618 io .Copy (os .Stdout , tty )
593619 }()
594620 }
595- } else if log != nil {
621+ }
622+ if log != nil {
596623 log .Debugf ("hyperkit: Redirecting stdout/stderr to logger" )
597624 stdout , err := cmd .StdoutPipe ()
598625 if err != nil {
0 commit comments