// Catch signals func catchNotifications() { state, err := terminal.GetState(int(os.Stdin.Fd())) checkErr(err) // Deal with SIGINT sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, os.Interrupt) var timer time.Time go func() { for sig := range sigChan { // Prevent exiting on accidental signal send if time.Now().Sub(timer) < time.Second*signalTimeout { terminal.Restore(int(os.Stdin.Fd()), state) os.Exit(0) } fmt.Fprintln(os.Stderr, "") fmt.Fprintln(os.Stderr, "") fmt.Fprintln(os.Stderr, "") fmt.Fprintln(os.Stderr, sig, "signal caught!") fmt.Fprintf(os.Stderr, "Send signal again within %v seconds to exit\n", signalTimeout) fmt.Fprintln(os.Stderr, "") fmt.Fprintln(os.Stderr, "") fmt.Fprintln(os.Stderr, "") timer = time.Now() } }() }
func getPassword() (string, error) { stdin := int(syscall.Stdin) initialTermState, err := terminal.GetState(stdin) if err != nil { return "", err } c := make(chan os.Signal) signal.Notify(c, os.Interrupt, os.Kill) go func() { s := <-c terminal.Restore(stdin, initialTermState) switch sig := s.(type) { case syscall.Signal: if int(sig) == 2 { fmt.Println("^C") } } os.Exit(1) }() passBytes, err := terminal.ReadPassword(stdin) if err != nil { return "", err } signal.Stop(c) fmt.Print("\n") return string(passBytes), nil }
func getPassword() ([]byte, error) { signals := make(chan os.Signal, 1) passwords := make(chan password) signal.Notify(signals, os.Interrupt, os.Kill) defer signal.Stop(signals) state, err := terminal.GetState(2) if err != nil { return nil, err } defer terminal.Restore(2, state) go func() { fmt.Fprintf(os.Stderr, "Password: "******"\n") p, err := terminal.ReadPassword(2) passwords <- password{ Password: p, Err: err, } close(passwords) }() select { case <-signals: return nil, fmt.Errorf("Password entry cancelled") case password := <-passwords: return password.Password, password.Err } }
func runAttached(c *cli.Context, app, ps, args, release string) (int, error) { fd := os.Stdin.Fd() var w, h int if terminal.IsTerminal(int(fd)) { stdinState, err := terminal.GetState(int(fd)) if err != nil { return -1, err } defer terminal.Restore(int(fd), stdinState) w, h, err = terminal.GetSize(int(fd)) if err != nil { return -1, err } } code, err := rackClient(c).RunProcessAttached(app, ps, args, release, h, w, os.Stdin, os.Stdout) if err != nil { return -1, err } return code, nil }
func GetState(fd int) (*State, error) { state, err := terminal.GetState(fd) if err != nil { return nil, err } currentState := State(*state) return ¤tState, nil }
func init() { if runtime.GOOS != "windows" { terminalState, _ := terminal.GetState(0) sigint := make(chan os.Signal, 1) signal.Notify(sigint, os.Interrupt) go func() { <-sigint terminal.Restore(0, terminalState) fmt.Println("") os.Exit(1) }() } }
func Signals() { prev, err := terminal.GetState(int(os.Stdin.Fd())) if err != nil { prev = nil } s := make(chan os.Signal, 1) signal.Notify(s, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT) for _ = range s { terminal.Restore(int(os.Stdin.Fd()), prev) os.Exit(1) } }
/* Read non-empty password from terminal */ func GetPass(prompt string) (pass string, err error) { var resp []byte fd, err := getTerminalFd() if err != nil { return } /* Store current terminal state in case the call gets interrupted by signal */ oldState, err := terminal.GetState(fd) if err != nil { err = errors.Errorf("failed to get terminal state: %s\n", err) return } /* * Install signal handler * Unlike the ReadLine function, using a raw terminal state here does not help. * If the prompt gets killed by a signal, the terminal state is not restored. * Hence restore it in a signal handler */ c := make(chan os.Signal, 1) signal.Notify(c, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGINT) go func() { <-c terminal.Restore(fd, oldState) fmt.Fprintln(os.Stderr, "aborting") os.Exit(1) }() for i := 0; len(resp) == 0; i++ { if i > 0 { fmt.Printf("\rInvalid response - try again") time.Sleep(500 * time.Millisecond) } /* Clear line - see https://en.wikipedia.org/wiki/ANSI_escape_code */ fmt.Printf("\r\033[2K%s: ", prompt) /* This function internally takes care of restoring terminal state. */ resp, err = terminal.ReadPassword(fd) if err != nil { return } resp = bytes.TrimSpace(resp) } /* Restore signal handling */ signal.Stop(c) signal.Reset(syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGINT) return string(resp), nil }
// restoreTerminal installs a cleanup handler that restores the previous // terminal state on exit. func restoreTerminal() { if !stdoutIsTerminal() { return } fd := int(os.Stdout.Fd()) state, err := terminal.GetState(fd) if err != nil { fmt.Fprintf(os.Stderr, "unable to get terminal state: %v\n", err) return } AddCleanupHandler(func() error { err := checkErrno(terminal.Restore(fd, state)) if err != nil { fmt.Fprintf(os.Stderr, "unable to get restore terminal state: %#+v\n", err) } return err }) }
func (r *LightRenderer) Init() { delay := 100 delayEnv := os.Getenv("ESCDELAY") if len(delayEnv) > 0 { num, err := strconv.Atoi(delayEnv) if err == nil && num >= 0 { delay = num } } r.escDelay = delay fd := r.fd() origState, err := terminal.GetState(fd) if err != nil { errorExit(err.Error()) } r.origState = origState terminal.MakeRaw(fd) r.updateTerminalSize() initTheme(r.theme, r.defaultTheme(), r.forceBlack) _, x := r.findOffset() if x > 0 { r.upOneLine = true r.stderr("\n") } for i := 1; i < r.MaxY(); i++ { r.stderr("\n") r.csi("G") } if r.mouse { r.csi("?1000h") } r.csi(fmt.Sprintf("%dA", r.MaxY()-1)) r.csi("G") // r.csi("s") if r.mouse { r.yoffset, _ = r.findOffset() } }
func sshWithRestore(c *cli.Context, id, cmd string) (int, error) { fd := os.Stdin.Fd() isTerm := terminal.IsTerminal(int(fd)) var h, w int if isTerm { stdinState, err := terminal.GetState(int(fd)) if err != nil { return -1, err } h, w, err = terminal.GetSize(int(fd)) if err != nil { return -1, err } defer terminal.Restore(int(fd), stdinState) } return rackClient(c).SSHInstance(id, cmd, h, w, isTerm, os.Stdin, os.Stdout) }
func readPass(fd int) ([]byte, error) { // make sure an interrupt won't break the terminal sigint := make(chan os.Signal) state, err := terminal.GetState(fd) if err != nil { return nil, err } go func() { for _ = range sigint { terminal.Restore(fd, state) fmt.Println("^C") os.Exit(1) } }() signal.Notify(sigint, os.Interrupt) defer func() { signal.Stop(sigint) close(sigint) }() return terminal.ReadPassword(fd) }
// Catch signals func catchNotifications() { ignoreStdin := false state, err := terminal.GetState(int(os.Stdin.Fd())) if err != nil { // Stdin may be redirected, then just exit ignoreStdin = true } // Deal with SIGINT sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, os.Interrupt) var timer time.Time go func() { for sig := range sigChan { if ignoreStdin { fmt.Fprintln(os.Stderr, sig, "signal caught!") fmt.Fprintln(os.Stderr, "Exiting") os.Exit(0) } else { // Prevent exiting on accidental signal send if time.Now().Sub(timer) < time.Second*signalTimeout { terminal.Restore(int(os.Stdin.Fd()), state) os.Exit(0) } fmt.Fprintln(os.Stderr, "") fmt.Fprintln(os.Stderr, "") fmt.Fprintln(os.Stderr, "") fmt.Fprintln(os.Stderr, sig, "signal caught!") fmt.Fprintf(os.Stderr, "Send signal again within %v seconds to exit\n", signalTimeout) fmt.Fprintln(os.Stderr, "") fmt.Fprintln(os.Stderr, "") fmt.Fprintln(os.Stderr, "") timer = time.Now() } } }() }
func startTerminal(c *config) { fmt.Printf("Starting terminal mode.\n") fmt.Printf("Enter h for [h]elp.\n") fmt.Printf("Enter q for [q]uit.\n") done := make(chan bool) initState, err := terminal.GetState(0) protected := false if err != nil { fmt.Printf("error getting terminal state: %v\n", err.Error()) return } go func() { terminal.MakeRaw(int(os.Stdin.Fd())) n := terminal.NewTerminal(os.Stdin, "> ") for { var ln string var err error if !protected { ln, err = n.ReadLine() if err != nil { done <- true } } else { ln, err = n.ReadPassword(">*") if err != nil { done <- true } } execute(done, &protected, c, ln) } }() select { case <-done: fmt.Printf("exiting...\n") terminal.Restore(0, initState) close(done) } }
func getpass(prompt string) (pass string, err error) { tstate, err := terminal.GetState(0) if err != nil { return } sig := make(chan os.Signal, 1) signal.Notify(sig, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT) go func() { quit := false for _ = range sig { quit = true break } terminal.Restore(0, tstate) if quit { fmt.Println() os.Exit(2) } }() defer func() { signal.Stop(sig) close(sig) }() f := bufio.NewWriter(os.Stdout) f.Write([]byte(prompt)) f.Flush() passbytes, err := terminal.ReadPassword(0) pass = string(passbytes) f.Write([]byte("\n")) f.Flush() return }
func cmdExec(c *cli.Context) error { fd := os.Stdin.Fd() var h, w int if terminal.IsTerminal(int(fd)) { stdinState, err := terminal.GetState(int(fd)) if err != nil { return stdcli.Error(err) } defer terminal.Restore(int(fd), stdinState) w, h, err = terminal.GetSize(int(fd)) if err != nil { return stdcli.Error(err) } } _, app, err := stdcli.DirApp(c, ".") if err != nil { return stdcli.Error(err) } if len(c.Args()) < 2 { stdcli.Usage(c, "exec") return nil } ps := c.Args()[0] code, err := rackClient(c).ExecProcessAttached(app, ps, strings.Join(c.Args()[1:], " "), os.Stdin, os.Stdout, h, w) if err != nil { return stdcli.Error(err) } return stdcli.Errorf("", code) }
func cmdExec(c *cli.Context) { fd := os.Stdin.Fd() stdinState, err := terminal.GetState(int(fd)) defer terminal.Restore(int(fd), stdinState) _, app, err := stdcli.DirApp(c, ".") if err != nil { stdcli.Error(err) return } if len(c.Args()) < 2 { stdcli.Usage(c, "exec") return } w, h, err := terminal.GetSize(int(fd)) if err != nil { stdcli.Error(err) return } ps := c.Args()[0] code, err := rackClient(c).ExecProcessAttached(app, ps, strings.Join(c.Args()[1:], " "), os.Stdin, os.Stdout, h, w) terminal.Restore(int(fd), stdinState) if err != nil { stdcli.Error(err) return } os.Exit(code) }