github.com/ratrocket/u-root@v0.0.0-20180201221235-1cf9f48ee2cf/cmds/stty/termios.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 package main 6 7 import ( 8 "fmt" 9 "io" 10 "log" 11 "reflect" 12 "strconv" 13 14 "golang.org/x/sys/unix" 15 ) 16 17 type ( 18 // tty is an os-independent version of the combined info in termios and window size structs. 19 // It is used to get/set info to the termios functions as well as marshal/unmarshal data 20 // in JSON formwt for dump and loading. 21 tty struct { 22 Ispeed int 23 Ospeed int 24 Row int 25 Col int 26 27 CC map[string]uint8 28 29 Opts map[string]bool 30 } 31 ) 32 33 func gtty(fd int) (*tty, error) { 34 term, err := unix.IoctlGetTermios(fd, unix.TCGETS) 35 if err != nil { 36 return nil, err 37 } 38 w, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ) 39 if err != nil { 40 return nil, err 41 } 42 43 var t = tty{Opts: make(map[string]bool), CC: make(map[string]uint8)} 44 for n, b := range boolFields { 45 val := uint32(reflect.ValueOf(term).Elem().Field(b.word).Uint()) & b.mask 46 t.Opts[n] = val != 0 47 } 48 49 for n, c := range cc { 50 t.CC[n] = term.Cc[c] 51 } 52 53 // back in the day, you could have different i and o speeds. 54 // since about 1975, this has not been a thing. It's still in POSIX 55 // evidently. WTF? 56 t.Ispeed = int(term.Ispeed) 57 t.Ospeed = int(term.Ospeed) 58 t.Row = int(w.Row) 59 t.Col = int(w.Col) 60 61 return &t, nil 62 } 63 64 func stty(fd int, t *tty) (*tty, error) { 65 // Get a unix.Termios which we can partially fill in. 66 term, err := unix.IoctlGetTermios(fd, unix.TCGETS) 67 if err != nil { 68 return nil, err 69 } 70 71 for n, b := range boolFields { 72 set := t.Opts[n] 73 i := reflect.ValueOf(term).Elem().Field(b.word).Uint() 74 if set { 75 i |= uint64(b.mask) 76 } else { 77 i &= ^uint64(b.mask) 78 } 79 reflect.ValueOf(term).Elem().Field(b.word).SetUint(i) 80 } 81 82 for n, c := range cc { 83 term.Cc[c] = t.CC[n] 84 } 85 86 term.Ispeed = uint32(t.Ispeed) 87 term.Ospeed = uint32(t.Ospeed) 88 89 if err := unix.IoctlSetTermios(fd, unix.TCSETS, term); err != nil { 90 return nil, err 91 } 92 93 w := &unix.Winsize{Row: uint16(t.Row), Col: uint16(t.Col)} 94 if err := unix.IoctlSetWinsize(fd, unix.TIOCSWINSZ, w); err != nil { 95 return nil, err 96 } 97 98 return gtty(fd) 99 } 100 101 func pretty(w io.Writer, t *tty) { 102 fmt.Printf("speed: %v ", t.Ispeed) 103 for n, c := range t.CC { 104 fmt.Printf("%v: %#q, ", n, c) 105 } 106 fmt.Fprintf(w, "%d rows, %d cols\n", t.Row, t.Col) 107 108 for n, set := range t.Opts { 109 if set { 110 fmt.Fprintf(w, "%v ", n) 111 } else { 112 fmt.Fprintf(w, "~%v ", n) 113 } 114 } 115 fmt.Fprintln(w) 116 } 117 118 func intarg(s []string) int { 119 if len(s) < 2 { 120 log.Fatalf("%s requires an arg", s[0]) 121 } 122 i, err := strconv.Atoi(s[1]) 123 if err != nil { 124 log.Fatalf("%s is not a number", s) 125 } 126 return i 127 } 128 129 // the arguments are a variety of key-value pairs and booleans. 130 // booleans are cleared if the first char is a -, set otherwise. 131 func setOpts(t *tty, opts []string) error { 132 for i := 0; i < len(opts); i++ { 133 o := opts[i] 134 switch o { 135 case "row": 136 t.Row = intarg(opts[i:]) 137 i++ 138 continue 139 case "col": 140 t.Col = intarg(opts[i:]) 141 i++ 142 continue 143 case "speed": 144 t.Ispeed = intarg(opts[i:]) 145 i++ 146 continue 147 } 148 149 // see if it's one of the control char options. 150 if _, ok := cc[opts[i]]; ok { 151 t.CC[opts[i]] = uint8(intarg(opts[i:])) 152 i++ 153 continue 154 } 155 156 // At this point, it has to be one of the boolean ones 157 // or we're done here. 158 set := true 159 if o[0] == '~' { 160 set = false 161 o = o[1:] 162 } 163 if _, ok := boolFields[o]; !ok { 164 log.Fatalf("%s: unknown option", o) 165 } 166 167 t.Opts[o] = set 168 } 169 return nil 170 } 171 172 func setRaw(fd int) (*tty, error) { 173 t, err := gtty(fd) 174 if err != nil { 175 return nil, err 176 } 177 178 setOpts(t, []string{"~ignbrk", "~brkint", "~parmrk", "~istrip", "~inlcr", "~igncr", "~icrnl", "~ixon", "~opost", "~echo", "~echonl", "~icanon", "~isig", "~iexten", "~parenb" /*"cs8", */, "min", "1", "time", "0"}) 179 180 return stty(fd, t) 181 }