func startTerminal(c *config) { var clear, protected bool fmt.Println("Starting terminal mode.") fmt.Println("Enter h for [h]elp.") fmt.Println("Enter l for [l]ist of commands.") fmt.Println("Enter q for [q]uit.") termState, err := terminal.MakeRaw(int(os.Stdin.Fd())) if err != nil { fmt.Fprintf(os.Stderr, "Failed to set raw mode on STDIN: %v\n", err) return } n := terminal.NewTerminal(os.Stdin, "> ") n.SetSize(int(^uint(0)>>1), 0) var ln string for { if !protected { ln, err = n.ReadLine() } else { ln, err = n.ReadPassword(">*") } terminal.Restore(int(os.Stdin.Fd()), termState) if err != nil { break } quit := execute(&protected, c, ln, &clear) if quit { break } if clear { fmt.Println("Clearing history...") termState, err = terminal.MakeRaw(int(os.Stdin.Fd())) if err != nil { fmt.Fprintf(os.Stderr, "Failed to set raw "+ "mode on STDIN: %v\n", err) break } n = terminal.NewTerminal(os.Stdin, "> ") n.SetSize(int(^uint(0)>>1), 0) clear = false } else { termState, err = terminal.MakeRaw(int(os.Stdin.Fd())) if err != nil { fmt.Fprintf(os.Stderr, "Failed to set raw "+ "mode on STDIN: %v\n", err) break } } } fmt.Println("exiting...") }
func askConfig() (cfg, error) { stdinState, err := terminal.MakeRaw(syscall.Stdin) if err != nil { return cfg{}, err } defer terminal.Restore(syscall.Stdin, stdinState) stdoutState, err := terminal.MakeRaw(syscall.Stdout) if err != nil { return cfg{}, err } defer terminal.Restore(syscall.Stdout, stdoutState) t := struct { io.Reader io.Writer }{os.Stdin, os.Stdout} term := terminal.NewTerminal(t, "") msg := "Configure git-erickson for first time use.\nErickson server URL: " if _, err := term.Write([]byte(msg)); err != nil { return cfg{}, err } url, err := term.ReadLine() if err != nil { return cfg{}, err } cmd := exec.Command("git", "config", "--global", "erickson.url", string(url)) if err := cmd.Run(); err != nil { return cfg{}, err } if _, err := term.Write([]byte("Erickson username: "******"git", "config", "--global", "erickson.username", string(username)) if err := cmd.Run(); err != nil { return cfg{}, err } return cfg{url: url, username: username}, nil }
// NewCLI creates a new cliUI instance func NewCLI(version string) UI { oldState, err := terminal.MakeRaw(0) if err != nil { panic(err.Error()) } term := terminal.NewTerminal(os.Stdin, "") updateTerminalSize(term) term.SetBracketedPasteMode(true) resizeChan := make(chan os.Signal) go func() { for _ = range resizeChan { updateTerminalSize(term) } }() signal.Notify(resizeChan, syscall.SIGWINCH) return &cliUI{ term: term, oldState: oldState, terminate: make(chan bool), input: &input{ term: term, uidComplete: new(priorityList), }, RosterEditor: RosterEditor{ PendingRosterChan: make(chan *RosterEdit), }, events: make(chan interface{}), commands: make(chan interface{}, 5), } }
func copyWithExit(w io.Writer, r io.Reader, ch chan int) { buf := make([]byte, 1024) isTerminalRaw := false for { n, err := r.Read(buf) if err == io.EOF { ch <- 1 return } if err != nil { break } if !isTerminalRaw { terminal.MakeRaw(int(os.Stdin.Fd())) isTerminalRaw = true } if s := string(buf[0:n]); strings.HasPrefix(s, "F1E49A85-0AD7-4AEF-A618-C249C6E6568D:") { code, _ := strconv.Atoi(s[37:]) ch <- code return } _, err = w.Write(buf[0:n]) if err != nil { break } } }
func makeRaw(fd uintptr) (*terminalState, error) { state, err := terminal.MakeRaw(int(fd)) return &terminalState{ state: state, }, err }
// promptForPassword prompts the user for a password twice, returning // the read bytes if they match, or an error. // It turns out getting non-echo stdin is tricky and not portable at all. // terminal seems a decent solution, although it does not work on windows. func promptForPassword() ([]byte, error) { // Use a raw terminal. oldState, err := terminal.MakeRaw(0) if err != nil { return nil, err } defer func() { _ = terminal.Restore(0, oldState) }() fmt.Print("Enter password: "******"\nConfirm password: "******"\n") if !bytes.Equal(one, two) { return nil, util.Errorf("password mismatch") } return []byte(one), nil }
// promptConfirm prompts a user to confirm (or deny) something. // // True is returned iff the prompt is confirmed. // Errors are reported to the log, and return false. // // Valid confirmations: // y, yes, true, t, aye-aye // // Valid denials: // n, no, f, false // // Any other prompt response will return false, and issue a warning to the // user. func promptConfirm(msg string) bool { oldState, err := terminal.MakeRaw(0) if err != nil { log.Err("Could not get terminal: %s", err) return false } defer terminal.Restore(0, oldState) f := readerWriter(log.Stdin, log.Stdout) t := terminal.NewTerminal(f, msg+" (y/N) ") res, err := t.ReadLine() if err != nil { log.Err("Could not read line: %s", err) return false } res = strings.ToLower(res) switch res { case "yes", "y", "true", "t", "aye-aye": return true case "no", "n", "false", "f": return false } log.Warn("Did not understand answer %q, assuming No", res) return false }
func rawConnectionFromSerial() (net.Conn, error) { log.Info("opening ttyS0 for backchannel") f, err := os.OpenFile(pathPrefix+"/ttyS0", os.O_RDWR|os.O_SYNC|syscall.O_NOCTTY, backchannelMode) if err != nil { detail := fmt.Errorf("failed to open serial port for backchannel: %s", err) log.Error(detail) return nil, detail } // set the provided FDs to raw if it's a termial // 0 is the uninitialized value for Fd if f.Fd() != 0 && terminal.IsTerminal(int(f.Fd())) { log.Debug("setting terminal to raw mode") s, err := terminal.MakeRaw(int(f.Fd())) if err != nil { return nil, err } log.Infof("s = %#v", s) } var conn net.Conn log.Infof("creating raw connection from ttyS0 (fd=%d)", f.Fd()) conn, err = serial.NewFileConn(f) return conn, err }
func (r *LightRenderer) Resume() bool { terminal.MakeRaw(r.fd()) r.csi("?1049l") r.flush() // Should redraw return true }
func copyWithExit(w io.Writer, r io.Reader, ch chan int) { buf := make([]byte, 1024) isTerminalRaw := false for { n, err := r.Read(buf) if err == io.EOF { ch <- 1 return } if err != nil { break } if !isTerminalRaw { terminal.MakeRaw(int(os.Stdin.Fd())) isTerminalRaw = true } if s := string(buf[0:n]); strings.HasPrefix(s, StatusCodePrefix) { code, _ := strconv.Atoi(strings.TrimSpace(s[37:])) ch <- code return } _, err = w.Write(buf[0:n]) if err != nil { break } } }
func client(user, passwd, ip string) { config := &ssh.ClientConfig{ User: user, Auth: []ssh.AuthMethod{ ssh.Password(passwd), }, } client, err := ssh.Dial("tcp", ip, config) if err != nil { fmt.Println("建立连接: ", err) return } defer client.Close() session, err := client.NewSession() if err != nil { fmt.Println("创建Session出错: ", err) return } defer session.Close() fd := int(os.Stdin.Fd()) oldState, err := terminal.MakeRaw(fd) if err != nil { fmt.Println("创建文件描述符: ", err) return } session.Stdout = os.Stdout session.Stderr = os.Stderr session.Stdin = os.Stdin termWidth, termHeight, err := terminal.GetSize(fd) if err != nil { fmt.Println("获取窗口宽高: ", err) return } defer terminal.Restore(fd, oldState) modes := ssh.TerminalModes{ ssh.ECHO: 1, ssh.TTY_OP_ISPEED: 14400, ssh.TTY_OP_OSPEED: 14400, } if err := session.RequestPty("xterm-256color", termHeight, termWidth, modes); err != nil { fmt.Println("创建终端出错: ", err) return } err = session.Shell() if err != nil { fmt.Println("执行Shell出错: ", err) return } err = session.Wait() if err != nil { fmt.Println("执行Wait出错: ", err) return } }
func handleConnection(c net.Conn) { defer c.Close() // Start the command cmd := exec.Command(flagCommand) // Create PTY pty, tty, err := pty.Open() if err != nil { log.Printf("error: could not open PTY: %s", err) return } defer tty.Close() defer pty.Close() // Put the TTY into raw mode _, err = terminal.MakeRaw(int(tty.Fd())) if err != nil { log.Printf("warn: could not make TTY raw: %s", err) } // Hook everything up cmd.Stdout = tty cmd.Stdin = tty cmd.Stderr = tty if cmd.SysProcAttr == nil { cmd.SysProcAttr = &syscall.SysProcAttr{} } cmd.SysProcAttr.Setctty = true cmd.SysProcAttr.Setsid = true // Start command err = cmd.Start() if err != nil { log.Printf("error: could not start command: %s", err) return } errs := make(chan error, 3) go func() { _, err := io.Copy(c, pty) errs <- err }() go func() { _, err := io.Copy(pty, c) errs <- err }() go func() { errs <- cmd.Wait() }() // Wait for a single error, then shut everything down. Since returning from // this function closes the connection, we just read a single error and // then continue. <-errs log.Printf("info: connection from %s finished", c.RemoteAddr()) }
func connect(ip string, creds server.Credentials) error { config := &ssh.ClientConfig{ User: creds.Username, Auth: []ssh.AuthMethod{ ssh.Password(creds.Password), }, } conn, err := ssh.Dial("tcp", fmt.Sprintf("%s:22", ip), config) if err != nil { return err } defer conn.Close() // Create a session session, err := conn.NewSession() defer session.Close() if err != nil { return err } fd := int(os.Stdin.Fd()) oldState, err := terminal.MakeRaw(fd) if err != nil { return err } termWidth, termHeight, err := terminal.GetSize(fd) defer terminal.Restore(fd, oldState) if err != nil { return err } session.Stdout = os.Stdout session.Stderr = os.Stderr session.Stdin = os.Stdin modes := ssh.TerminalModes{ ssh.ECHO: 1, // disable echoing ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud } // Request pseudo terminal if err := session.RequestPty("xterm-256color", termHeight, termWidth, modes); err != nil { return err } // Start remote shell if err := session.Shell(); err != nil { return err } if err := session.Wait(); err != nil { if reflect.TypeOf(err) == reflect.TypeOf(&ssh.ExitError{}) { return nil } else { return err } } return nil }
func (c *execCmd) run(config *lxd.Config, args []string) error { if len(args) < 2 { return errArgs } remote, name := config.ParseRemoteAndContainer(args[0]) d, err := lxd.NewClient(config, remote) if err != nil { return err } env := map[string]string{"HOME": "/root", "USER": "******"} myEnv := os.Environ() for _, ent := range myEnv { if strings.HasPrefix(ent, "TERM=") { env["TERM"] = ent[len("TERM="):] } } for _, arg := range envArgs { pieces := strings.SplitN(arg, "=", 2) value := "" if len(pieces) > 1 { value = pieces[1] } env[pieces[0]] = value } cfd := syscall.Stdout var oldttystate *terminal.State if terminal.IsTerminal(cfd) { oldttystate, err = terminal.MakeRaw(cfd) if err != nil { return err } defer terminal.Restore(cfd, oldttystate) } ret, err := d.Exec(name, args[1:], env, os.Stdin, os.Stdout, os.Stderr) if err != nil { return err } if oldttystate != nil { /* A bit of a special case here: we want to exit with the same code as * the process inside the container, so we explicitly exit here * instead of returning an error. * * Additionally, since os.Exit() exits without running deferred * functions, we restore the terminal explicitly. */ terminal.Restore(cfd, oldttystate) } /* we get the result of waitpid() here so we need to transform it */ os.Exit(ret >> 8) return fmt.Errorf(gettext.Gettext("unreachable return reached")) }
func main() { flag.Parse() slides, err := readSlidesDat() if err != nil { log.Fatal(err) } if *stats { fmt.Println(len(slides), "slides") return } if len(slides) == 0 { slides = []string{"No slides\n"} } oldState, err := terminal.MakeRaw(0) if err != nil { panic(err) } defer terminal.Restore(0, oldState) clear, err := exec.Command("clear").Output() if err != nil { log.Fatal(err) } keyBuf := make([]byte, 10) n := 0 for { os.Stdout.Write(clear) io.WriteString(os.Stdout, "\n ") io.WriteString(os.Stdout, strings.TrimSuffix(strings.Replace(slides[n], "\n", "\n ", -1), " ")) got, err := os.Stdin.Read(keyBuf) if err != nil { log.Printf("Read key: %v", err) return } key := string(keyBuf[:got]) switch key { case ctrlC, ctrlZ, keyq: return case up, left, keyp: n-- case down, right, keyn: n++ case keyP: n = 0 case keyN: n = len(slides) - 1 } if n < 0 { n = 0 } if n >= len(slides) { n = len(slides) - 1 } } }
func MakeRaw(fd int) (*State, error) { state, err := terminal.MakeRaw(fd) if err != nil { return nil, err } oldState := State(*state) return &oldState, nil }
func newTerm(prompt string) *Term { term := new(Term) var err error term.s, err = terminal.MakeRaw(0) if err != nil { panic(err) } term.t = terminal.NewTerminal(os.Stdin, prompt) return term }
func (i *Interactive) terminalInit() { var err error i.oldTermState, err = terminal.MakeRaw(syscall.Stdin) if err != nil { i.fatalf("Failed to get raw terminal: %v", err) } i.term = terminal.NewTerminal(os.Stdin, i.Prompt) i.term.AutoCompleteCallback = i.defaultAutoComplete }
// Read a password from stdin without echoing input to stdout. func ReadPassword(prompt string) (string, error) { oldState, err := terminal.MakeRaw(0) if err != nil { return "", err } defer terminal.Restore(0, oldState) term := terminal.NewTerminal(os.Stdin, "") pass, err := term.ReadPassword(prompt) return pass, err }
func terminalInit() { var err error oldTermState, err = terminal.MakeRaw(syscall.Stdin) if err != nil { fatalf("Failed to get raw terminal: %v", err) } term = terminal.NewTerminal(os.Stdin, prompt) term.AutoCompleteCallback = autoComplete }
func askCredentials(username string) (password string, err error) { stdinState, err := terminal.MakeRaw(syscall.Stdin) if err != nil { return } defer terminal.Restore(syscall.Stdin, stdinState) stdoutState, err := terminal.MakeRaw(syscall.Stdout) if err != nil { return } defer terminal.Restore(syscall.Stdout, stdoutState) t := struct { io.Reader io.Writer }{os.Stdin, os.Stdout} term := terminal.NewTerminal(t, "") msg := fmt.Sprintf("Password for %s: ", username) password, err = term.ReadPassword(msg) return }
// Read credentials from standard input func readCredentials() (username string, password string, err error) { state, err := terminal.MakeRaw(0) if err == nil { t := terminal.NewTerminal(os.Stdin, "Username: "******"Password: ") } terminal.Restore(0, state) } return username, password, nil }
func getch() byte { if oldState, err := terminal.MakeRaw(0); err != nil { panic(err) } else { defer terminal.Restore(0, oldState) } var buf [1]byte if n, err := syscall.Read(0, buf[:]); n == 0 || err != nil { panic(err) } return buf[0] }
func read(f *os.File) (string, error) { fd := int(f.Fd()) if !terminal.IsTerminal(fd) { return "", fmt.Errorf("File descriptor %d is not a terminal", fd) } oldState, err := terminal.MakeRaw(fd) if err != nil { return "", err } defer terminal.Restore(fd, oldState) return readline(f) }
// makeSession initializes a gossh.Session connected to the invoking process's stdout/stderr/stdout. // If the invoking session is a terminal, a TTY will be requested for the SSH session. // It returns a gossh.Session, a finalizing function used to clean up after the session terminates, // and any error encountered in setting up the session. func makeSession(client *SSHForwardingClient) (session *gossh.Session, finalize func(), err error) { session, err = client.NewSession() if err != nil { return } if err = client.ForwardAgentAuthentication(session); err != nil { return } session.Stdout = os.Stdout session.Stderr = os.Stderr session.Stdin = os.Stdin modes := gossh.TerminalModes{ gossh.ECHO: 1, // enable echoing gossh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud gossh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud } fd := int(os.Stdin.Fd()) if terminal.IsTerminal(fd) { var termWidth, termHeight int var oldState *terminal.State oldState, err = terminal.MakeRaw(fd) if err != nil { return } finalize = func() { session.Close() terminal.Restore(fd, oldState) } termWidth, termHeight, err = terminal.GetSize(fd) if err != nil { return } err = session.RequestPty("xterm-256color", termHeight, termWidth, modes) } else { finalize = func() { session.Close() } } return }
func terminalMode(c *serflash.Conn) { timeout := time.Duration(*idleFlag) * time.Second idleTimer := time.NewTimer(timeout) // FIXME still in line mode, so only complete lines will be shown go func() { for line := range c.Lines { idleTimer.Reset(timeout) fmt.Println(line) } }() // put stdin in raw mode oldState, err := terminal.MakeRaw(0) Check(err) defer terminal.Restore(0, oldState) // cleanup when program is terminated via a signal sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, os.Interrupt, syscall.SIGHUP, syscall.SIGTERM) go func() { sigMsg := <-sigChan terminal.Restore(0, oldState) log.Fatal(sigMsg) }() // cleanup when idle timer fires, and exit cleanly if *idleFlag > 0 { go func() { <-idleTimer.C terminal.Restore(0, oldState) fmt.Println("\nidle timeout") os.Exit(0) }() } // copy key presses to the serial port for { var b [1]byte n, _ := os.Stdin.Read(b[:]) idleTimer.Reset(timeout) if n < 1 || b[0] == 0x1B { // ESC break } c.Write(b[:n]) } }
func runTerm(cmd *cobra.Command, args []string) { if len(args) != 0 { cmd.Usage() return } db := makeSQLClient() readWriter := struct { io.Reader io.Writer }{ Reader: os.Stdin, Writer: os.Stdout, } // We need to switch to raw mode. Unfortunately, this masks // signals-from-keyboard, meaning that ctrl-C cannot be caught. oldState, err := terminal.MakeRaw(0) if err != nil { panic(err) } defer func() { _ = terminal.Restore(0, oldState) }() term := terminal.NewTerminal(readWriter, "> ") for { line, err := term.ReadLine() if err != nil { if err != io.EOF { fmt.Fprintf(os.Stderr, "Input error: %s\n", err) } break } if len(line) == 0 { continue } shouldExit, err := processOneLine(db, line, term) if err != nil { fmt.Fprintf(term, "Error: %s\n", err) } if shouldExit { break } } }
func getch() (byte, error) { if oldState, err := terminal.MakeRaw(0); err != nil { return 0, err } else { defer terminal.Restore(0, oldState) } var buf [1]byte if n, err := syscall.Read(0, buf[:]); n == 0 || err != nil { if err != nil { return 0, err } return 0, io.EOF } return buf[0], nil }
// getPasswd returns the input read from terminal. // If masked is true, typing will be matched by asterisks on the screen. // Otherwise, typing will echo nothing. func getPasswd(masked bool) ([]byte, error) { var err error var pass, bs, mask []byte if masked { bs = []byte("\b \b") mask = []byte("*") } if terminal.IsTerminal(int(os.Stdin.Fd())) { if oldState, err := terminal.MakeRaw(int(os.Stdin.Fd())); err != nil { return pass, err } else { defer terminal.Restore(int(os.Stdin.Fd()), oldState) } } // Track total bytes read, not just bytes in the password. This ensures any // errors that might flood the console with nil or -1 bytes infinitely are // capped. var counter int for counter = 0; counter <= maxLength; counter++ { if v, e := getch(); e != nil { err = e break } else if v == 127 || v == 8 { if l := len(pass); l > 0 { pass = pass[:l-1] fmt.Print(string(bs)) } } else if v == 13 || v == 10 { break } else if v == 3 { err = ErrInterrupted break } else if v != 0 { pass = append(pass, v) fmt.Print(string(mask)) } } if counter > maxLength { err = ErrMaxLengthExceeded } fmt.Println() return pass, err }
// rawRead reads file with raw mode (without prompting to terminal). func (i *UI) rawRead(f *os.File) (string, error) { // MakeRaw put the terminal connected to the given file descriptor // into raw mode fd := int(f.Fd()) if !terminal.IsTerminal(fd) { return "", fmt.Errorf("file descriptor %d is not a terminal", fd) } oldState, err := terminal.MakeRaw(fd) if err != nil { return "", err } defer terminal.Restore(fd, oldState) return i.rawReadline(f) }