github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/termios/sgtty_unix.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 // +build !plan9,!windows 6 7 package termios 8 9 import ( 10 "fmt" 11 "log" 12 "reflect" 13 "sort" 14 "strconv" 15 16 "golang.org/x/sys/unix" 17 ) 18 19 // GTTY returns the TTY struct for a given fd. It is like a New in 20 // many packages but the name GTTY is a tradition. 21 func GTTY(fd int) (*TTY, error) { 22 term, err := unix.IoctlGetTermios(fd, unix.TCGETS) 23 if err != nil { 24 return nil, err 25 } 26 w, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ) 27 if err != nil { 28 return nil, err 29 } 30 31 var t = TTY{Opts: make(map[string]bool), CC: make(map[string]uint8)} 32 for n, b := range boolFields { 33 val := uint32(reflect.ValueOf(term).Elem().Field(b.word).Uint()) & b.mask 34 t.Opts[n] = val != 0 35 } 36 37 for n, c := range cc { 38 t.CC[n] = term.Cc[c] 39 } 40 41 // back in the day, you could have different i and o speeds. 42 // since about 1975, this has not been a thing. It's still in POSIX 43 // evidently. WTF? 44 t.Ispeed = int(term.Ispeed) 45 t.Ospeed = int(term.Ospeed) 46 t.Row = int(w.Row) 47 t.Col = int(w.Col) 48 49 return &t, nil 50 } 51 52 // STTY uses a TTY * to set TTY settings on an fd. 53 // It returns a new TTY struct for the fd after the changes are made, 54 // and an error. It does not change the original TTY struct. 55 func (t *TTY) STTY(fd int) (*TTY, error) { 56 // Get a unix.Termios which we can partially fill in. 57 term, err := unix.IoctlGetTermios(fd, unix.TCGETS) 58 if err != nil { 59 return nil, err 60 } 61 62 for n, b := range boolFields { 63 set := t.Opts[n] 64 i := reflect.ValueOf(term).Elem().Field(b.word).Uint() 65 if set { 66 i |= uint64(b.mask) 67 } else { 68 i &= ^uint64(b.mask) 69 } 70 reflect.ValueOf(term).Elem().Field(b.word).SetUint(i) 71 } 72 73 for n, c := range cc { 74 term.Cc[c] = t.CC[n] 75 } 76 77 term.Ispeed = uint32(t.Ispeed) 78 term.Ospeed = uint32(t.Ospeed) 79 80 if err := unix.IoctlSetTermios(fd, unix.TCSETS, term); err != nil { 81 return nil, err 82 } 83 84 w := &unix.Winsize{Row: uint16(t.Row), Col: uint16(t.Col)} 85 if err := unix.IoctlSetWinsize(fd, unix.TIOCSWINSZ, w); err != nil { 86 return nil, err 87 } 88 89 return GTTY(fd) 90 } 91 92 // String will stringify a TTY, including printing out the options all in the same order. 93 func (t *TTY) String() string { 94 s := fmt.Sprintf("speed:%v ", t.Ispeed) 95 s += fmt.Sprintf("rows:%d cols:%d", t.Row, t.Col) 96 var opts []string 97 for n, c := range t.CC { 98 opts = append(opts, fmt.Sprintf("%v:%#02x", n, c)) 99 } 100 101 for n, set := range t.Opts { 102 if set { 103 opts = append(opts, fmt.Sprintf("%v:1", n)) 104 } else { 105 opts = append(opts, fmt.Sprintf("%v:0", n)) 106 } 107 } 108 sort.Strings(opts) 109 for _, v := range opts { 110 s += fmt.Sprintf(" %s", v) 111 } 112 return s 113 } 114 115 func intarg(s []string) int { 116 if len(s) < 2 { 117 log.Fatalf("%s requires an arg", s[0]) 118 } 119 i, err := strconv.Atoi(s[1]) 120 if err != nil { 121 log.Fatalf("%s is not a number", s) 122 } 123 return i 124 } 125 126 // SetOpts sets opts in a TTY given an array of key-value pairs and 127 // booleans. The arguments are a variety of key-value pairs and booleans. 128 // booleans are cleared if the first char is a -, set otherwise. 129 func (t *TTY) SetOpts(opts []string) error { 130 for i := 0; i < len(opts); i++ { 131 o := opts[i] 132 switch o { 133 case "row": 134 t.Row = intarg(opts[i:]) 135 i++ 136 continue 137 case "col": 138 t.Col = intarg(opts[i:]) 139 i++ 140 continue 141 case "speed": 142 t.Ispeed = intarg(opts[i:]) 143 i++ 144 continue 145 } 146 147 // see if it's one of the control char options. 148 if _, ok := cc[opts[i]]; ok { 149 t.CC[opts[i]] = uint8(intarg(opts[i:])) 150 i++ 151 continue 152 } 153 154 // At this point, it has to be one of the boolean ones 155 // or we're done here. 156 set := true 157 if o[0] == '~' { 158 set = false 159 o = o[1:] 160 } 161 if _, ok := boolFields[o]; !ok { 162 log.Fatalf("%s: unknown option", o) 163 } 164 165 t.Opts[o] = set 166 } 167 return nil 168 } 169 170 // Raw sets a TTY into raw more, returning a TTY struct 171 func Raw(fd int) (*TTY, error) { 172 t, err := GTTY(fd) 173 if err != nil { 174 return nil, err 175 } 176 177 t.SetOpts([]string{"~ignbrk", "~brkint", "~parmrk", "~istrip", "~inlcr", "~igncr", "~icrnl", "~ixon", "~opost", "~echo", "~echonl", "~icanon", "~isig", "~iexten", "~parenb" /*"cs8", */, "min", "1", "time", "0"}) 178 179 return t.STTY(fd) 180 }