Jiri Simsa | d7616c9 | 2015-03-24 23:44:30 -0700 | [diff] [blame] | 1 | // Copyright 2015 The Vanadium 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 | |
Todd Wang | affd04d | 2015-04-08 10:25:35 -0700 | [diff] [blame] | 5 | // Package internal defines common types and functions used by both tunnel |
| 6 | // clients and servers. |
| 7 | package internal |
Jiri Simsa | d5aae83 | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 8 | |
| 9 | import ( |
| 10 | "errors" |
| 11 | "os/exec" |
| 12 | "strings" |
| 13 | "syscall" |
| 14 | "unsafe" |
| 15 | |
Cosmos Nicolaou | e6fbf98 | 2015-06-18 16:37:19 -0700 | [diff] [blame] | 16 | "v.io/x/ref/internal/logger" |
Jiri Simsa | d5aae83 | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 17 | ) |
| 18 | |
Todd Wang | affd04d | 2015-04-08 10:25:35 -0700 | [diff] [blame] | 19 | // Winsize defines the window size used by ioctl TIOCGWINSZ and TIOCSWINSZ. |
Jiri Simsa | d5aae83 | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 20 | type Winsize struct { |
| 21 | Row uint16 |
| 22 | Col uint16 |
| 23 | Xpixel uint16 |
Jiri Simsa | d5aae83 | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 24 | } |
| 25 | |
| 26 | // SetWindowSize sets the terminal's window size. |
| 27 | func SetWindowSize(fd uintptr, ws Winsize) error { |
Cosmos Nicolaou | e6fbf98 | 2015-06-18 16:37:19 -0700 | [diff] [blame] | 28 | logger.Global().Infof("Setting window size: %v", ws) |
Jiri Simsa | d5aae83 | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 29 | ret, _, _ := syscall.Syscall( |
| 30 | syscall.SYS_IOCTL, |
| 31 | fd, |
| 32 | uintptr(syscall.TIOCSWINSZ), |
| 33 | uintptr(unsafe.Pointer(&ws))) |
| 34 | if int(ret) == -1 { |
| 35 | return errors.New("ioctl(TIOCSWINSZ) failed") |
| 36 | } |
| 37 | return nil |
| 38 | } |
| 39 | |
| 40 | // GetWindowSize gets the terminal's window size. |
| 41 | func GetWindowSize() (*Winsize, error) { |
| 42 | ws := &Winsize{} |
| 43 | ret, _, _ := syscall.Syscall( |
| 44 | syscall.SYS_IOCTL, |
| 45 | uintptr(syscall.Stdin), |
| 46 | uintptr(syscall.TIOCGWINSZ), |
| 47 | uintptr(unsafe.Pointer(ws))) |
| 48 | if int(ret) == -1 { |
| 49 | return nil, errors.New("ioctl(TIOCGWINSZ) failed") |
| 50 | } |
| 51 | return ws, nil |
| 52 | } |
| 53 | |
Todd Wang | affd04d | 2015-04-08 10:25:35 -0700 | [diff] [blame] | 54 | // EnterRawTerminalMode uses stty to enter the terminal into raw mode; stdin is |
| 55 | // unbuffered, local echo of input characters is disabled, and special signal |
| 56 | // characters are disabled. Returns a string which may be passed to |
| 57 | // RestoreTerminalSettings to restore to the original terminal settings. |
Jiri Simsa | d5aae83 | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 58 | func EnterRawTerminalMode() string { |
| 59 | var savedBytes []byte |
| 60 | var err error |
| 61 | if savedBytes, err = exec.Command("stty", "-F", "/dev/tty", "-g").Output(); err != nil { |
Cosmos Nicolaou | e6fbf98 | 2015-06-18 16:37:19 -0700 | [diff] [blame] | 62 | logger.Global().Infof("Failed to save terminal settings: %q (%v)", savedBytes, err) |
Jiri Simsa | d5aae83 | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 63 | } |
| 64 | saved := strings.TrimSpace(string(savedBytes)) |
| 65 | |
| 66 | args := []string{ |
| 67 | "-F", "/dev/tty", |
| 68 | // Don't buffer stdin. Read characters as they are typed. |
| 69 | "-icanon", "min", "1", "time", "0", |
| 70 | // Turn off local echo of input characters. |
| 71 | "-echo", "-echoe", "-echok", "-echonl", |
| 72 | // Disable interrupt, quit, and suspend special characters. |
| 73 | "-isig", |
| 74 | // Ignore characters with parity errors. |
| 75 | "ignpar", |
| 76 | // Disable translate newline to carriage return. |
| 77 | "-inlcr", |
| 78 | // Disable ignore carriage return. |
| 79 | "-igncr", |
| 80 | // Disable translate carriage return to newline. |
| 81 | "-icrnl", |
| 82 | // Disable flow control. |
| 83 | "-ixon", "-ixany", "-ixoff", |
| 84 | // Disable non-POSIX special characters. |
| 85 | "-iexten", |
| 86 | } |
| 87 | if out, err := exec.Command("stty", args...).CombinedOutput(); err != nil { |
Cosmos Nicolaou | e6fbf98 | 2015-06-18 16:37:19 -0700 | [diff] [blame] | 88 | logger.Global().Infof("stty failed (%v) (%q)", err, out) |
Jiri Simsa | d5aae83 | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 89 | } |
| 90 | |
| 91 | return string(saved) |
| 92 | } |
| 93 | |
Todd Wang | affd04d | 2015-04-08 10:25:35 -0700 | [diff] [blame] | 94 | // RestoreTerminalSettings uses stty to restore the terminal to the original |
| 95 | // settings, taking the saved settings returned by EnterRawTerminalMode. |
Jiri Simsa | d5aae83 | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 96 | func RestoreTerminalSettings(saved string) { |
| 97 | args := []string{ |
| 98 | "-F", "/dev/tty", |
| 99 | saved, |
| 100 | } |
| 101 | if out, err := exec.Command("stty", args...).CombinedOutput(); err != nil { |
Cosmos Nicolaou | e6fbf98 | 2015-06-18 16:37:19 -0700 | [diff] [blame] | 102 | logger.Global().Infof("stty failed (%v) (%q)", err, out) |
Jiri Simsa | d5aae83 | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 103 | } |
| 104 | } |