github.com/andrewsun2898/u-root@v6.0.1-0.20200616011413-4b2895c1b815+incompatible/cmds/exp/console/console.go (about)

     1  // Copyright 2015-2017 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // console implements a basic console. It establishes a pair of files
     6  // to read from, the default being a UART at 0x3f8, but an alternative
     7  // being just stdin and stdout. It will also set up a root file system
     8  // using util.Rootfs, although this can be disabled as well.
     9  // Console uses a Go version of fork_pty to start up a shell, default
    10  // sh. Console runs until the shell exits and then exits itself.
    11  package main
    12  
    13  import (
    14  	"flag"
    15  	"fmt"
    16  	"io"
    17  	"log"
    18  	"os"
    19  
    20  	"github.com/u-root/u-root/pkg/libinit"
    21  	"github.com/u-root/u-root/pkg/pty"
    22  )
    23  
    24  var (
    25  	serial    = flag.String("serial", "0x3f8", "which IO device: stdio, i8042, or serial port starting with 0")
    26  	setupRoot = flag.Bool("setuproot", false, "Set up a root file system")
    27  )
    28  
    29  func main() {
    30  	fmt.Printf("console -- starting")
    31  	flag.Parse()
    32  
    33  	a := flag.Args()
    34  	if len(a) == 0 {
    35  		a = []string{"/bin/sh"}
    36  	}
    37  
    38  	p, err := pty.New()
    39  	if err != nil {
    40  		log.Fatalf("Console exits: can't open pty: %v", err)
    41  	}
    42  	p.Command(a[0], a[1:]...)
    43  	// Make a good faith effort to set up root. This being
    44  	// a kind of init program, we do our best and keep going.
    45  	if *setupRoot {
    46  		libinit.SetEnv()
    47  		libinit.CreateRootfs()
    48  	}
    49  
    50  	in, out := io.Reader(os.Stdin), io.Writer(os.Stdout)
    51  
    52  	// This switch is kind of hokey, true, but it's also quite convenient for users.
    53  	switch {
    54  	// A raw IO port for serial console
    55  	case []byte(*serial)[0] == '0':
    56  		u, err := openUART(*serial)
    57  		if err != nil {
    58  			log.Fatalf("Console exits: sorry, can't get a uart: %v", err)
    59  		}
    60  		in, out = u, u
    61  	case *serial == "i8042":
    62  		u, err := openi8042()
    63  		if err != nil {
    64  			log.Fatalf("Console exits: sorry, can't get an i8042: %v", err)
    65  		}
    66  		in, out = u, os.Stdout
    67  	case *serial == "stdio":
    68  	default:
    69  		log.Fatalf("Console exits: console must be one of stdio, i8042, or an IO port with a leading 0 (e.g. 0x3f8)")
    70  	}
    71  
    72  	err = p.Start()
    73  	if err != nil {
    74  		log.Fatalf("Console exits: can't start %v: %v", a, err)
    75  	}
    76  	kid := p.C.Process.Pid
    77  
    78  	// You need the \r\n as we are now in raw mode!
    79  	fmt.Printf("Started %d\r\n", kid)
    80  
    81  	go io.Copy(out, p.Ptm)
    82  
    83  	go func() {
    84  		var data = make([]byte, 1)
    85  		for {
    86  			if _, err := in.Read(data); err != nil {
    87  				fmt.Printf("kid stdin: done\n")
    88  			}
    89  			if data[0] == '\r' {
    90  				if _, err := out.Write(data); err != nil {
    91  					log.Printf("error on echo %v: %v", data, err)
    92  				}
    93  				data[0] = '\n'
    94  			}
    95  			if _, err := p.Ptm.Write(data); err != nil {
    96  				log.Printf("Error writing input to ptm: %v: give up\n", err)
    97  				break
    98  			}
    99  		}
   100  	}()
   101  
   102  	if err := p.Wait(); err != nil {
   103  		log.Fatalf("Console exits: %v", err)
   104  	}
   105  	log.Printf("Console all done")
   106  	os.Exit(0)
   107  }