// withSafeTTYAndInterrupts invokes the provided function after the terminal // state has been stored, and then on any error or termination attempts to // restore the terminal state to its prior behavior. It also eats signals // for the duration of the function. func withSafeTTYAndInterrupts(fn func() error) error { ch := make(chan os.Signal, 1) signal.Notify(ch, childSignals...) defer signal.Stop(ch) inFd := os.Stdin.Fd() if !term.IsTerminal(inFd) { if f, err := os.Open("/dev/tty"); err == nil { defer f.Close() inFd = f.Fd() } } if term.IsTerminal(inFd) { state, err := term.SaveState(inFd) if err != nil { return err } go func() { if _, ok := <-ch; !ok { return } term.RestoreTerminal(inFd, state) }() defer term.RestoreTerminal(inFd, state) return fn() } return fn() }
// Run executes a validated remote execution against a pod. func (p *AttachOptions) Run() error { pod, err := p.Client.Pods(p.Namespace).Get(p.PodName) if err != nil { return err } if pod.Status.Phase != api.PodRunning { return fmt.Errorf("pod %s is not running and cannot be attached to; current phase is %s", p.PodName, pod.Status.Phase) } // TODO: refactor with terminal helpers from the edit utility once that is merged var stdin io.Reader tty := p.TTY if p.Stdin { stdin = p.In if tty { if file, ok := stdin.(*os.File); ok { inFd := file.Fd() if term.IsTerminal(inFd) { oldState, err := term.SetRawTerminal(inFd) if err != nil { glog.Fatal(err) } // this handles a clean exit, where the command finished defer term.RestoreTerminal(inFd, oldState) // SIGINT is handled by term.SetRawTerminal (it runs a goroutine that listens // for SIGINT and restores the terminal before exiting) // this handles SIGTERM sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, syscall.SIGTERM) go func() { <-sigChan term.RestoreTerminal(inFd, oldState) os.Exit(0) }() } else { fmt.Fprintln(p.Err, "STDIN is not a terminal") } } else { tty = false fmt.Fprintln(p.Err, "Unable to use a TTY - input is not the right kind of file") } } } // TODO: consider abstracting into a client invocation or client helper req := p.Client.RESTClient.Post(). Resource("pods"). Name(pod.Name). Namespace(pod.Namespace). SubResource("attach"). Param("container", p.GetContainerName(pod)) return p.Attach.Attach("POST", req.URL(), p.Config, stdin, p.Out, p.Err, tty) }
func readPassword() string { var oldState *term.State var input string oldState, err := term.SetRawTerminal(os.Stdin.Fd()) if err != nil { authLogger.WithField("Error", err).Debug("Unable to Set Raw Terminal") } print("Password: "******"Error", err).Debug("Unable to read password") } if input == "" { authLogger.Println("Password required") os.Exit(1) } print("\n") return input }
// AttachTerminal connects us to container and gives us a terminal func (c *DockerClient) AttachTerminal(containerID string) error { c.logger.Println("Attaching to ", containerID) opts := docker.AttachToContainerOptions{ Container: containerID, Logs: true, Stdin: true, Stdout: true, Stderr: true, Stream: true, InputStream: os.Stdin, ErrorStream: os.Stderr, OutputStream: os.Stdout, RawTerminal: true, } var oldState *term.State oldState, err := term.SetRawTerminal(os.Stdin.Fd()) if err != nil { return err } defer term.RestoreTerminal(os.Stdin.Fd(), oldState) go func() { err := c.AttachToContainer(opts) if err != nil { c.logger.Panicln("attach panic", err) } }() _, err = c.WaitContainer(containerID) return err }
// PromptForPasswordString prompts for user input by disabling echo in terminal, useful for password prompt. func PromptForPasswordString(r io.Reader, w io.Writer, format string, a ...interface{}) string { if w == nil { w = os.Stdout } if file, ok := r.(*os.File); ok { inFd := file.Fd() if term.IsTerminal(inFd) { oldState, err := term.SaveState(inFd) if err != nil { glog.V(3).Infof("Unable to save terminal state") return PromptForString(r, w, format, a...) } fmt.Fprintf(w, format, a...) term.DisableEcho(inFd, oldState) input := readInput(r) defer term.RestoreTerminal(inFd, oldState) fmt.Fprintf(w, "\n") return input } glog.V(3).Infof("Stdin is not a terminal") return PromptForString(r, w, format, a...) } return PromptForString(r, w, format, a...) }
// Safe invokes the provided function and will attempt to ensure that when the // function returns (or a termination signal is sent) that the terminal state // is reset to the condition it was in prior to the function being invoked. If // t.Raw is true the terminal will be put into raw mode prior to calling the function. // If the input file descriptor is not a TTY and TryDev is true, the /dev/tty file // will be opened (if available). func (t TTY) Safe(fn SafeFunc) error { in := t.In var hasFd bool var inFd uintptr if desc, ok := in.(fd); ok && in != nil { inFd = desc.Fd() hasFd = true } if t.TryDev && (!hasFd || !term.IsTerminal(inFd)) { if f, err := os.Open("/dev/tty"); err == nil { defer f.Close() inFd = f.Fd() hasFd = true } } if !hasFd || !term.IsTerminal(inFd) { return fn() } var state *term.State var err error if t.Raw { state, err = term.MakeRaw(inFd) } else { state, err = term.SaveState(inFd) } if err != nil { return err } return interrupt.Chain(t.Parent, func() { term.RestoreTerminal(inFd, state) }).Run(fn) }
func (client *NativeClient) Shell(args ...string) error { var ( termWidth, termHeight int ) conn, err := ssh.Dial("tcp", net.JoinHostPort(client.Hostname, strconv.Itoa(client.Port)), &client.Config) if err != nil { return err } defer closeConn(conn) session, err := conn.NewSession() if err != nil { return err } defer session.Close() session.Stdout = os.Stdout session.Stderr = os.Stderr session.Stdin = os.Stdin modes := ssh.TerminalModes{ ssh.ECHO: 1, } fd := os.Stdin.Fd() if term.IsTerminal(fd) { oldState, err := term.MakeRaw(fd) if err != nil { return err } defer term.RestoreTerminal(fd, oldState) winsize, err := term.GetWinsize(fd) if err != nil { termWidth = 80 termHeight = 24 } else { termWidth = int(winsize.Width) termHeight = int(winsize.Height) } } if err := session.RequestPty("xterm", termHeight, termWidth, modes); err != nil { return err } if len(args) == 0 { if err := session.Shell(); err != nil { return err } session.Wait() } else { session.Run(strings.Join(args, " ")) } return nil }
// Safe invokes the provided function and will attempt to ensure that when the // function returns (or a termination signal is sent) that the terminal state // is reset to the condition it was in prior to the function being invoked. If // t.Raw is true the terminal will be put into raw mode prior to calling the function. // If the input file descriptor is not a TTY and TryDev is true, the /dev/tty file // will be opened (if available). func (t TTY) Safe(fn SafeFunc) error { inFd, isTerminal := term.GetFdInfo(t.In) if !isTerminal && t.TryDev { if f, err := os.Open("/dev/tty"); err == nil { defer f.Close() inFd = f.Fd() isTerminal = term.IsTerminal(inFd) } } if !isTerminal { return fn() } var state *term.State var err error if t.Raw { state, err = term.MakeRaw(inFd) } else { state, err = term.SaveState(inFd) } if err != nil { return err } return interrupt.Chain(t.Parent, func() { if t.sizeQueue != nil { t.sizeQueue.stop() } term.RestoreTerminal(inFd, state) }).Run(fn) }
func (cli *DockerCli) restoreTerminal(in io.Closer) error { if cli.inState != nil { term.RestoreTerminal(cli.inFd, cli.inState) } if cli.outState != nil { term.RestoreTerminal(cli.outFd, cli.outState) } // WARNING: DO NOT REMOVE THE OS CHECK !!! // For some reason this Close call blocks on darwin.. // As the client exists right after, simply discard the close // until we find a better solution. if in != nil && runtime.GOOS != "darwin" { return in.Close() } return nil }
func unsetRaw(t *testing.T, c *daemon.Container, state *term.State) { pty, err := c.GetPtyMaster() if err != nil { t.Fatal(err) } term.RestoreTerminal(pty.Fd(), state) }
// Run creates, start and attach to the container based on the image name, // the specified configuration. // It will always create a new container. func (c *Container) Run(ctx context.Context, configOverride *config.ServiceConfig) (int, error) { var ( errCh chan error out, stderr io.Writer in io.ReadCloser ) if configOverride.StdinOpen { in = os.Stdin } if configOverride.Tty { out = os.Stdout } if configOverride.Tty { stderr = os.Stderr } options := types.ContainerAttachOptions{ Stream: true, Stdin: configOverride.StdinOpen, Stdout: configOverride.Tty, Stderr: configOverride.Tty, } resp, err := c.client.ContainerAttach(ctx, c.container.ID, options) if err != nil { return -1, err } // set raw terminal inFd, _ := term.GetFdInfo(in) state, err := term.SetRawTerminal(inFd) if err != nil { return -1, err } // restore raw terminal defer term.RestoreTerminal(inFd, state) // holdHijackedConnection (in goroutine) errCh = promise.Go(func() error { return holdHijackedConnection(configOverride.Tty, in, out, stderr, resp) }) if err := c.client.ContainerStart(ctx, c.container.ID, types.ContainerStartOptions{}); err != nil { return -1, err } if err := <-errCh; err != nil { logrus.Debugf("Error hijack: %s", err) return -1, err } exitedContainer, err := c.client.ContainerInspect(ctx, c.container.ID) if err != nil { return -1, err } return exitedContainer.State.ExitCode, nil }
func (cli *DockerCli) configureAuth(flUser, flPassword, flEmail, serverAddress string) (types.AuthConfig, error) { authconfig, ok := cli.configFile.AuthConfigs[serverAddress] if !ok { authconfig = types.AuthConfig{} } if flUser == "" { cli.promptWithDefault("Username", authconfig.Username) flUser = readInput(cli.in, cli.out) flUser = strings.TrimSpace(flUser) if flUser == "" { flUser = authconfig.Username } } if flPassword == "" { oldState, err := term.SaveState(cli.inFd) if err != nil { return authconfig, err } fmt.Fprintf(cli.out, "Password: "******"\n") term.RestoreTerminal(cli.inFd, oldState) if flPassword == "" { return authconfig, fmt.Errorf("Error : Password Required") } } // Assume that a different username means they may not want to use // the email from the config file, so prompt it if flUser != authconfig.Username { if flEmail == "" { cli.promptWithDefault("Email", authconfig.Email) flEmail = readInput(cli.in, cli.out) if flEmail == "" { flEmail = authconfig.Email } } } else { // However, if they don't override the username use the // email from the cmd line if specified. IOW, allow // then to change/override them. And if not specified, just // use what's in the config file if flEmail == "" { flEmail = authconfig.Email } } authconfig.Username = flUser authconfig.Password = flPassword authconfig.Email = flEmail authconfig.ServerAddress = serverAddress cli.configFile.AuthConfigs[serverAddress] = authconfig return authconfig, nil }
func (cli *DockerCli) configureAuth(flUser, flPassword, serverAddress string, isDefaultRegistry bool) (types.AuthConfig, error) { authconfig, err := getCredentials(cli.configFile, serverAddress) if err != nil { return authconfig, err } // Some links documenting this: // - https://code.google.com/archive/p/mintty/issues/56 // - https://github.com/docker/docker/issues/15272 // - https://mintty.github.io/ (compatibility) // Linux will hit this if you attempt `cat | docker login`, and Windows // will hit this if you attempt docker login from mintty where stdin // is a pipe, not a character based console. if flPassword == "" && !cli.isTerminalIn { return authconfig, fmt.Errorf("Error: Cannot perform an interactive logon from a non TTY device") } authconfig.Username = strings.TrimSpace(authconfig.Username) if flUser = strings.TrimSpace(flUser); flUser == "" { if isDefaultRegistry { // if this is a defauly registry (docker hub), then display the following message. fmt.Fprintln(cli.out, "Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.") } cli.promptWithDefault("Username", authconfig.Username) flUser = readInput(cli.in, cli.out) flUser = strings.TrimSpace(flUser) if flUser == "" { flUser = authconfig.Username } } if flUser == "" { return authconfig, fmt.Errorf("Error: Non-null Username Required") } if flPassword == "" { oldState, err := term.SaveState(cli.inFd) if err != nil { return authconfig, err } fmt.Fprintf(cli.out, "Password: "******"\n") term.RestoreTerminal(cli.inFd, oldState) if flPassword == "" { return authconfig, fmt.Errorf("Error: Password Required") } } authconfig.Username = flUser authconfig.Password = flPassword authconfig.ServerAddress = serverAddress authconfig.IdentityToken = "" return authconfig, nil }
func (t *tty) Close() error { for _, c := range t.closers { c.Close() } if t.state != nil { term.RestoreTerminal(os.Stdin.Fd(), t.state) } return nil }
func (t *tty) Close() error { if t.console != nil { t.console.Close() } if t.state != nil { term.RestoreTerminal(os.Stdin.Fd(), t.state) } return nil }
func (cli *DockerCli) restoreTerminal(in io.Closer) error { if cli.state != nil { term.RestoreTerminal(cli.inFd, cli.state) } if in != nil { return in.Close() } return nil }
func (p *process) cleanup() { p.wire.Close() if p.pty != nil { p.pty.Close() } if p.termState != nil { term.RestoreTerminal(p.termState.fd, p.termState.state) } }
func (client NativeClient) Shell() error { var ( termWidth, termHeight int ) conn, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", client.Hostname, client.Port), &client.Config) if err != nil { return err } session, err := conn.NewSession() if err != nil { return err } defer session.Close() session.Stdout = os.Stdout session.Stderr = os.Stderr session.Stdin = os.Stdin modes := ssh.TerminalModes{ ssh.ECHO: 1, } fd := os.Stdin.Fd() if term.IsTerminal(fd) { oldState, err := term.MakeRaw(fd) if err != nil { return err } defer term.RestoreTerminal(fd, oldState) winsize, err := term.GetWinsize(fd) if err != nil { termWidth = 80 termHeight = 24 } else { termWidth = int(winsize.Width) termHeight = int(winsize.Height) } } if err := session.RequestPty("xterm", termHeight, termWidth, modes); err != nil { return err } if err := session.Shell(); err != nil { return err } session.Wait() return nil }
// Console opens a secure console to a code or database service. For code // services, a command is required. This command is executed as root in the // context of the application root directory. For database services, no command // is needed - instead, the appropriate command for the database type is run. // For example, for a postgres database, psql is run. func Console(serviceLabel string, command string, settings *models.Settings) { helpers.SignIn(settings) service := helpers.RetrieveServiceByLabel(serviceLabel, settings) if service == nil { fmt.Printf("Could not find a service with the label \"%s\"\n", serviceLabel) os.Exit(1) } fmt.Printf("Opening console to %s (%s)\n", serviceLabel, service.ID) task := helpers.RequestConsole(command, service.ID, settings) fmt.Print("Waiting for the console to be ready. This might take a minute.") ch := make(chan string, 1) go helpers.PollConsoleJob(task.ID, service.ID, ch, settings) jobID := <-ch defer helpers.DestroyConsole(jobID, service.ID, settings) creds := helpers.RetrieveConsoleTokens(jobID, service.ID, settings) creds.URL = strings.Replace(creds.URL, "http", "ws", 1) fmt.Println("Connecting...") // BEGIN websocket impl config, _ := websocket.NewConfig(creds.URL, "ws://localhost:9443/") config.TlsConfig = &tls.Config{ MinVersion: tls.VersionTLS12, } config.Header["X-Console-Token"] = []string{creds.Token} ws, err := websocket.DialConfig(config) if err != nil { panic(err) } defer ws.Close() fmt.Println("Connection opened") stdin, stdout, _ := term.StdStreams() fdIn, isTermIn := term.GetFdInfo(stdin) if !isTermIn { panic(errors.New("StdIn is not a terminal")) } oldState, err := term.SetRawTerminal(fdIn) if err != nil { panic(err) } done := make(chan bool) msgCh := make(chan []byte, 2) go webSocketDaemon(ws, &stdout, done, msgCh) signal.Notify(make(chan os.Signal, 1), os.Interrupt) defer term.RestoreTerminal(fdIn, oldState) go termDaemon(&stdin, ws) <-done }
// AttachInteractive starts an interactive session and runs cmd func (c *DockerClient) AttachInteractive(containerID string, cmd []string, initialStdin []string) error { exec, err := c.CreateExec(docker.CreateExecOptions{ AttachStdin: true, AttachStdout: true, AttachStderr: true, Tty: true, Cmd: cmd, Container: containerID, }) if err != nil { return err } // Dump any initial stdin then go into os.Stdin readers := []io.Reader{} for _, s := range initialStdin { if s != "" { readers = append(readers, strings.NewReader(s+"\n")) } } readers = append(readers, os.Stdin) stdin := io.MultiReader(readers...) // This causes our ctrl-c's to be passed to the stuff in the terminal var oldState *term.State oldState, err = term.SetRawTerminal(os.Stdin.Fd()) if err != nil { return err } defer term.RestoreTerminal(os.Stdin.Fd(), oldState) // Handle resizes sigchan := make(chan os.Signal, 1) signal.Notify(sigchan, dockersignal.SIGWINCH) go func() { for range sigchan { c.ResizeTTY(exec.ID) } }() err = c.StartExec(exec.ID, docker.StartExecOptions{ InputStream: stdin, OutputStream: os.Stdout, ErrorStream: os.Stderr, Tty: true, RawTerminal: true, }) return err }
func runIn(container *libcontainer.Config, state *libcontainer.State, args []string) (int, error) { var ( master *os.File console string err error stdin = os.Stdin stdout = os.Stdout stderr = os.Stderr sigc = make(chan os.Signal, 10) ) signal.Notify(sigc) if container.Tty { stdin = nil stdout = nil stderr = nil master, console, err = consolepkg.CreateMasterAndConsole() if err != nil { log.Fatal(err) } go io.Copy(master, os.Stdin) go io.Copy(os.Stdout, master) state, err := term.SetRawTerminal(os.Stdin.Fd()) if err != nil { log.Fatal(err) } defer term.RestoreTerminal(os.Stdin.Fd(), state) } startCallback := func(cmd *exec.Cmd) { go func() { resizeTty(master) for sig := range sigc { switch sig { case syscall.SIGWINCH: resizeTty(master) default: cmd.Process.Signal(sig) } } }() } return namespaces.RunIn(container, state, args, os.Args[0], stdin, stdout, stderr, console, startCallback) }
// the process for execing a new process inside an existing container is that we have to exec ourself // with the nsenter argument so that the C code can setns an the namespaces that we require. Then that // code path will drop us into the path that we can do the final setup of the namespace and exec the users // application. func startInExistingContainer(config *libcontainer.Config, state *libcontainer.State, action string, context *cli.Context) (int, error) { var ( master *os.File console string err error sigc = make(chan os.Signal, 10) stdin = os.Stdin stdout = os.Stdout stderr = os.Stderr ) signal.Notify(sigc) if config.Tty && action != "setup" { stdin = nil stdout = nil stderr = nil master, console, err = consolepkg.CreateMasterAndConsole() if err != nil { return -1, err } go io.Copy(master, os.Stdin) go io.Copy(os.Stdout, master) state, err := term.SetRawTerminal(os.Stdin.Fd()) if err != nil { return -1, err } defer term.RestoreTerminal(os.Stdin.Fd(), state) } startCallback := func(cmd *exec.Cmd) { go func() { resizeTty(master) for sig := range sigc { switch sig { case syscall.SIGWINCH: resizeTty(master) default: cmd.Process.Signal(sig) } } }() } return namespaces.ExecIn(config, state, context.Args(), os.Args[0], action, stdin, stdout, stderr, console, startCallback) }
func execInternal(where, params string, in io.Reader, out io.Writer) error { // if we can't connect to the server, lets bail out early conn, err := net.Dial("tcp4", config.ServerURI) if err != nil { return err } defer conn.Close() // get current term info stdInFD, isTerminal := term.GetFdInfo(in) stdOutFD, _ := term.GetFdInfo(out) // terminal.PrintNanoboxHeader(where) // begin watching for changes to the project go func() { if err := notifyutil.Watch(config.CWDir, NotifyServer); err != nil { fmt.Printf(err.Error()) } }() // if we are using a term, lets upgrade it to RawMode if isTerminal { // handle all incoming os signals and act accordingly; default behavior is to // forward all signals to nanobox server go monitorTerminal(stdOutFD) oldState, err := term.SetRawTerminal(stdInFD) // we only use raw mode if it is available. if err == nil { defer term.RestoreTerminal(stdInFD, oldState) } } // make a http request switch where { case "develop": if _, err := fmt.Fprintf(conn, "POST /develop?pid=%d&%v HTTP/1.1\r\n\r\n", os.Getpid(), params); err != nil { return err } default: if _, err := fmt.Fprintf(conn, "POST /exec?pid=%d&%v HTTP/1.1\r\n\r\n", os.Getpid(), params); err != nil { return err } } return pipeToConnection(conn, in, out) }
func cmdRun(c *cli.Context) { if c.Bool("detach") { cmdRunDetached(c) return } fd := os.Stdin.Fd() oldState, err := term.SetRawTerminal(fd) defer term.RestoreTerminal(fd, oldState) _, app, err := stdcli.DirApp(c, ".") if err != nil { stdcli.Error(err) return } if len(c.Args()) < 2 { stdcli.Usage(c, "run") return } ps := c.Args()[0] code, err := rackClient(c).RunProcessAttached(app, ps, strings.Join(c.Args()[1:], " "), os.Stdin, os.Stdout) if err != nil { stdcli.Error(err) return } term.RestoreTerminal(fd, oldState) os.Exit(code) }
func (cli *DockerCli) configureAuth(flUser, flPassword, serverAddress string, isDefaultRegistry bool) (types.AuthConfig, error) { authconfig, err := getCredentials(cli.configFile, serverAddress) if err != nil { return authconfig, err } authconfig.Username = strings.TrimSpace(authconfig.Username) if flUser = strings.TrimSpace(flUser); flUser == "" { if isDefaultRegistry { // if this is a defauly registry (docker hub), then display the following message. fmt.Fprintln(cli.out, "Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.") } cli.promptWithDefault("Username", authconfig.Username) flUser = readInput(cli.in, cli.out) flUser = strings.TrimSpace(flUser) if flUser == "" { flUser = authconfig.Username } } if flUser == "" { return authconfig, fmt.Errorf("Error: Non-null Username Required") } if flPassword == "" { oldState, err := term.SaveState(cli.inFd) if err != nil { return authconfig, err } fmt.Fprintf(cli.out, "Password: "******"\n") term.RestoreTerminal(cli.inFd, oldState) if flPassword == "" { return authconfig, fmt.Errorf("Error: Password Required") } } authconfig.Username = flUser authconfig.Password = flPassword authconfig.ServerAddress = serverAddress authconfig.IdentityToken = "" return authconfig, nil }
// Close closes all open fds for the tty and/or restores the orignal // stdin state to what it was prior to the container execution func (t *tty) Close() error { // ensure that our side of the fds are always closed for _, c := range t.postStart { c.Close() } // wait for the copy routines to finish before closing the fds t.wg.Wait() for _, c := range t.closers { c.Close() } if t.state != nil { term.RestoreTerminal(os.Stdin.Fd(), t.state) } return nil }
func (t *Task) runContainer(ctx *context.ExecuteContext) error { interactive := t.config.Interactive name := ContainerName(ctx, t.name.Resource()) container, err := ctx.Client.CreateContainer(t.createOptions(ctx, name)) if err != nil { return fmt.Errorf("failed creating container %q: %s", name, err) } chanSig := t.forwardSignals(ctx.Client, container.ID) defer signal.Stop(chanSig) defer RemoveContainer(t.logger(), ctx.Client, container.ID, true) _, err = ctx.Client.AttachToContainerNonBlocking(docker.AttachToContainerOptions{ Container: container.ID, OutputStream: t.output(), ErrorStream: os.Stderr, InputStream: ioutil.NopCloser(os.Stdin), Stream: true, Stdin: t.config.Interactive, RawTerminal: t.config.Interactive, Stdout: true, Stderr: true, }) if err != nil { return fmt.Errorf("failed attaching to container %q: %s", name, err) } if interactive { inFd, _ := term.GetFdInfo(os.Stdin) state, err := term.SetRawTerminal(inFd) if err != nil { return err } defer func() { if err := term.RestoreTerminal(inFd, state); err != nil { t.logger().Warnf("Failed to restore fd %v: %s", inFd, err) } }() } if err := ctx.Client.StartContainer(container.ID, nil); err != nil { return fmt.Errorf("failed starting container %q: %s", name, err) } return t.wait(ctx.Client, container.ID) }
// Connect func Connect(in io.Reader, out io.Writer) { stdInFD, isTerminal := term.GetFdInfo(in) stdOutFD, _ := term.GetFdInfo(out) // if we are using a term, lets upgrade it to RawMode if isTerminal { // handle all incoming os signals and act accordingly; default behavior is to // forward all signals to nanobox server go monitor(stdOutFD) oldState, err := term.SetRawTerminal(stdInFD) // we only use raw mode if it is available. if err == nil { defer term.RestoreTerminal(stdInFD, oldState) } } }
func getPassphrase(role string, confirm bool) ([]byte, error) { if pass := os.Getenv(fmt.Sprintf("TUF_%s_PASSPHRASE", strings.ToUpper(role))); pass != "" { return []byte(pass), nil } state, err := term.SaveState(0) if err != nil { return nil, err } term.DisableEcho(0, state) defer term.RestoreTerminal(0, state) stdin := bufio.NewReader(os.Stdin) fmt.Printf("Enter %s keys passphrase: ", role) passphrase, err := stdin.ReadBytes('\n') fmt.Println() if err != nil { return nil, err } passphrase = passphrase[0 : len(passphrase)-1] if !confirm { return passphrase, nil } fmt.Printf("Repeat %s keys passphrase: ", role) confirmation, err := stdin.ReadBytes('\n') fmt.Println() if err != nil { return nil, err } confirmation = confirmation[0 : len(confirmation)-1] if !bytes.Equal(passphrase, confirmation) { return nil, errors.New("The entered passphrases do not match") } return passphrase, nil }
func (ps passwordStore) Basic(u *url.URL) (string, string) { if ps.anonymous { return "", "" } stdin := bufio.NewReader(os.Stdin) fmt.Fprintf(os.Stdout, "Enter username: "******"error processing username input: %s", err) return "", "" } username := strings.TrimSpace(string(userIn)) if term.IsTerminal(0) { state, err := term.SaveState(0) if err != nil { logrus.Errorf("error saving terminal state, cannot retrieve password: %s", err) return "", "" } term.DisableEcho(0, state) defer term.RestoreTerminal(0, state) } fmt.Fprintf(os.Stdout, "Enter password: "******"error processing password input: %s", err) return "", "" } password := strings.TrimSpace(string(userIn)) return username, password }