github.com/shaardie/u-root@v4.0.1-0.20190127173353-f24a1c26aa2e+incompatible/xcmds/ash/ash.go (about) 1 // Copyright 2012-2018 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 package main 6 7 import ( 8 "bufio" 9 "bytes" 10 "flag" 11 "io" 12 "log" 13 "os" 14 "os/exec" 15 "strings" 16 17 "github.com/u-root/u-root/pkg/complete" 18 "github.com/u-root/u-root/pkg/termios" 19 ) 20 21 var ( 22 debug = flag.Bool("d", false, "enable debug prints") 23 userush = flag.Bool("R", false, "Use the rush interpreter for commands") 24 v = func(string, ...interface{}) {} 25 ) 26 27 func verbose(f string, a ...interface{}) { 28 v(f+"\r\n", a...) 29 } 30 31 func output(s chan string, w io.Writer) { 32 for l := range s { 33 if _, err := w.Write([]byte("\r")); err != nil { 34 log.Printf("output write: %v", err) 35 } 36 for _, b := range l { 37 var o string 38 switch b { 39 default: 40 o = string(b) 41 case '\b', 127: 42 o = "\b \b" 43 case '\r', '\n': 44 o = "\r\n" 45 } 46 if _, err := w.Write([]byte(o)); err != nil { 47 log.Printf("output write: %v", err) 48 } 49 } 50 } 51 } 52 53 func main() { 54 tty() 55 flag.Parse() 56 if *debug { 57 v = log.Printf 58 complete.Debug = verbose 59 } 60 t, err := termios.New() 61 if err != nil { 62 log.Fatal(err) 63 } 64 r, err := t.Raw() 65 if err != nil { 66 log.Printf("non-fatal cannot get tty: %v", err) 67 } 68 defer t.Set(r) 69 _, cw, err := os.Pipe() 70 if err != nil { 71 log.Fatal(err) 72 } 73 p, err := complete.NewPathCompleter() 74 if err != nil { 75 log.Fatal(err) 76 } 77 f := complete.NewFileCompleter("/") 78 bin := complete.NewMultiCompleter(complete.NewStringCompleter([]string{"exit"}), p) 79 rest := f 80 l := complete.NewLineReader(bin, t, cw) 81 lines := make(chan string) 82 go output(lines, os.Stdout) 83 var lineComplete bool 84 for !l.EOF { 85 lineComplete = false 86 l.C = bin 87 if l.Fields > 1 { 88 l.C = rest 89 } 90 // Read one byte, run it through the completer, then print the string 91 // as we have it. 92 v("start with %v", l) 93 var b [1]byte 94 n, err := l.R.Read(b[:]) 95 if err != nil { 96 break 97 } 98 v("ReadLine: got %s, %v, %v", b, n, err) 99 100 if err := l.ReadChar(b[0]); err != nil { 101 v("ERR -> %v (%v)", l, err) 102 if err == io.EOF || err != complete.ErrEOL { 103 v("%v", err) 104 lines <- l.Line 105 continue 106 } 107 v("set linecomplete") 108 lineComplete = true 109 } 110 111 v("back from ReadChar, l is %v", l) 112 if l.Line == "exit" { 113 break 114 } 115 if lineComplete && l.Line != "" { 116 v("ash: Done reading args: line %q", l.Line) 117 // here we go. 118 lines <- "\n" 119 t.Set(r) 120 if !*userush { 121 f := strings.Fields(l.Line) 122 var args []string 123 if l.Exact != "" { 124 args = append(args, l.Exact) 125 } 126 args = append(args, l.Candidates...) 127 if len(f) > 1 && len(args) > 1 { 128 f = append(f[:len(f)-1], args...) 129 } 130 131 cmd := exec.Command(f[0], f[1:]...) 132 cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr 133 134 if err := cmd.Run(); err != nil { 135 log.Print(err) 136 } 137 138 } else { 139 b := bufio.NewReader(bytes.NewBufferString(l.Line)) 140 if err := rush(b); err != nil { 141 log.Print(err) 142 } 143 } 144 foreground() 145 t.Raw() 146 147 l.Line = "" 148 l.Candidates = []string{} 149 l.C = bin 150 l.Fields = 0 151 l.Exact = "" 152 continue 153 } 154 if l.Exact != "" { 155 lines <- "\n" + l.Exact 156 } 157 if len(l.Candidates) > 0 { 158 for _, ln := range l.Candidates { 159 lines <- "\n" + ln 160 } 161 lines <- "\n" 162 } 163 lines <- l.Line 164 } 165 }