Pty is a Go package for using unix pseudo-terminals.

Overview

pty

Pty is a Go package for using unix pseudo-terminals.

Install

go get github.com/creack/pty

Examples

Note that those examples are for demonstration purpose only, to showcase how to use the library. They are not meant to be used in any kind of production environment.

Command

package main

import (
	"io"
	"os"
	"os/exec"

	"github.com/creack/pty"
)

func main() {
	c := exec.Command("grep", "--color=auto", "bar")
	f, err := pty.Start(c)
	if err != nil {
		panic(err)
	}

	go func() {
		f.Write([]byte("foo\n"))
		f.Write([]byte("bar\n"))
		f.Write([]byte("baz\n"))
		f.Write([]byte{4}) // EOT
	}()
	io.Copy(os.Stdout, f)
}

Shell

package main

import (
        "io"
        "log"
        "os"
        "os/exec"
        "os/signal"
        "syscall"

        "github.com/creack/pty"
        "golang.org/x/term"
)

func test() error {
        // Create arbitrary command.
        c := exec.Command("bash")

        // Start the command with a pty.
        ptmx, err := pty.Start(c)
        if err != nil {
                return err
        }
        // Make sure to close the pty at the end.
        defer func() { _ = ptmx.Close() }() // Best effort.

        // Handle pty size.
        ch := make(chan os.Signal, 1)
        signal.Notify(ch, syscall.SIGWINCH)
        go func() {
                for range ch {
                        if err := pty.InheritSize(os.Stdin, ptmx); err != nil {
                                log.Printf("error resizing pty: %s", err)
                        }
                }
        }()
        ch <- syscall.SIGWINCH // Initial resize.
        defer func() { signal.Stop(ch); close(ch) }() // Cleanup signals when done.

        // Set stdin in raw mode.
        oldState, err := term.MakeRaw(int(os.Stdin.Fd()))
        if err != nil {
                panic(err)
        }
        defer func() { _ = term.Restore(int(os.Stdin.Fd()), oldState) }() // Best effort.

        // Copy stdin to the pty and the pty to stdout.
        // NOTE: The goroutine will keep reading until the next keystroke before returning.
        go func() { _, _ = io.Copy(ptmx, os.Stdin) }()
        _, _ = io.Copy(os.Stdout, ptmx)

        return nil
}

func main() {
        if err := test(); err != nil {
                log.Fatal(err)
        }
}
Comments
  • Portable ioctl calls

    Portable ioctl calls

    Add _IOC macros (<sys/ioccom.h>, <asm-generic/ioctl.h>) for linux and bsd's, unify ioctl() calls. FreeBSD: use modern pts(4) interface instead of the old pty(4) one. Use cgo -godefs generated ztypes_GOOS_GOARCH.go approach as in the syscall package to handle native C types.

    opened by paulzhol 15
  • FreeBSD: use modern pts(4) interface instead of the old pty(4) one

    FreeBSD: use modern pts(4) interface instead of the old pty(4) one

    Using the old pty(4) drivers requires kldload of the pty.ko driver (a kernel module which cannot be unloaded without a restart) while the pts(4) works out of the box on FreeBSD-10.

    opened by paulzhol 15
  • How to access the pseudo terminal's stderr?

    How to access the pseudo terminal's stderr?

    Great library, thanks! I'm confused as to how to handle stderr. The returned *os.File is used for stdout and stdin, so where is stderr? Am I misunderstanding something?

    opened by tliron 11
  • A little confuse about pty.StartWithSize

    A little confuse about pty.StartWithSize

    image the high light code defer tty.Close() I wonder why close slave after c.Start() without waiting it finishs I have tried to close slave after cmd finished(the cmd is /bin/zsh), the origin shell can't come back image

    could you tell me the reason?

    opened by Sherlock-Holo 9
  • Set Ctty in SysProcAttr

    Set Ctty in SysProcAttr

    Without this change, the controlling TTY is not set, so processes like less cannot have their stdin redirected. This was partially fixed many years ago, but it seemed the last piece of the puzzle was never put in.

    opened by ddevault 9
  • Reading from PTY in OSX makes the CPU go to 100%

    Reading from PTY in OSX makes the CPU go to 100%

    The following go code running on OSX (version 10.12.6, MacBook Pro (Retina, 15-inch, Mid 2014)) will cause the CPU to go to 100% within 10 seconds, and stay there. It is due to the io.Copy(stdout, t) line. It doesn't happen on Ubuntu 16.04 (nor Android 5.1.1).

    Anyone have any ideas as to why?

    package main
    
    import (
    	"io"
    	"log"
    	"os"
    	"os/exec"
    
    	"golang.org/x/crypto/ssh/terminal"
    
    	"github.com/kr/pty"
    )
    
    func main() {
    	stdin := os.Stdin
    	stdout := os.Stdout
    
    	os.Stdin = nil
    	os.Stdout = nil
    	// os.Stderr = nil
    
    	bash := exec.Command("/bin/bash")
    
    	// Allocate a terminal for this channel
    	t, err := pty.Start(bash)
    	if err != nil {
    		log.Fatalf("Could not start pty (%s)\n", err)
    	}
    
    	_, err = terminal.MakeRaw(int(stdin.Fd()))
    	if err != nil {
    		log.Fatalln(err)
    	}
    
    	go func() {
    		if _, err := io.Copy(stdout, t); err != nil {
    			log.Fatalln(err)
    		}
    	}()
    
    	if _, err := io.Copy(t, stdin); err != nil {
    		log.Fatalln(err)
    	}
    }
    
    opened by kristoiv 9
  • Unexpected behaviour when used with GDB --tty on Mac OS X 10.10.3

    Unexpected behaviour when used with GDB --tty on Mac OS X 10.10.3

    First of all I want to apologise if the following is not an issue with this project, but I really don't know where to start.

    Issue

    As the title says, I tried to use the terminals returned by pty.Open() to interact with the target program with GDB. I try to provide a minimal working example that reproduce this issue.

    Here's a dummy C program (hello.c):

    #include <stdio.h>
    
    int main()
    {
        printf("Hello!\n");
        return 0;
    }
    

    Here's the Go program (issue.go):

    package main
    
    import (
        "github.com/kr/pty"
        "io"
        "os"
        "os/exec"
    )
    
    func main() {
        ptm, pts, err := pty.Open()
        if err != nil {
            panic(err)
        }
        println(ptm.Name())
        println(pts.Name())
    
        ttyName := pts.Name()
        // ttyName := "/dev/ttys000" // taken from $ tty
    
        gdb := exec.Command("gdb", "--tty", ttyName)
    
        stdin, err := gdb.StdinPipe()
        if err != nil {
            panic(err)
        }
    
        if err := gdb.Start(); err != nil {
            panic(err)
        }
    
        go func() {
            _, err := io.Copy(os.Stdout, ptm)
            if err != nil {
                panic(err)
            }
        }()
    
        if _, err := stdin.Write([]byte("file ./a.out\n")); err != nil {
            panic(err)
        }
    
        if _, err := stdin.Write([]byte("run\n")); err != nil {
            panic(err)
        }
    
        // this is not received by GDB when ttyName := pts.Name()
        if _, err := stdin.Write([]byte("run\n")); err != nil {
            panic(err)
        }
    
        if _, err := stdin.Write([]byte("quit\n")); err != nil {
            panic(err)
        }
    
        if err := gdb.Wait(); err != nil {
            panic(err)
        }
    }
    

    Now with:

    gcc hello.c
    go run issue.go
    

    what I get is:

    /dev/ptmx
    /dev/ttys001
    Hello!
    

    then the program is stuck. While if I use a TTY of another terminal as ttyName in issue.go everything seems to work as expected:

    $ tty
    /dev/ttys000
    $ tail -f /dev/null
    warning: GDB: Failed to set controlling terminal: Operation not permitted
    Hello!
    warning: GDB: Failed to set controlling terminal: Operation not permitted
    Hello!
    

    And the program exits successfully.

    Also, commenting out the second stdin.Write([]byte("run\n")) the program works even with a TTY coming from pty.Open().

    System details

    $ uname -a
    Darwin pacinotti-wifi-219-203.unipi.it 14.3.0 Darwin Kernel Version 14.3.0: Mon Mar 23 11:59:05 PDT 2015; root:xnu-2782.20.48~5/RELEASE_X86_64 x86_64
    $ go version
    go version go1.4.2 darwin/amd64
    $ gdb --version
    GNU gdb (GDB) 7.9
    

    If more are needed please do ask.

    opened by cyrus-and 9
  • Add support for Power (ppc64, ppc64le) and System z (s390x)

    Add support for Power (ppc64, ppc64le) and System z (s390x)

    This PR add support for Power systems (ppc64, ppc64le) and System z (s390x).

    We are working on porting Docker to Power and System z, and pty is an essential component for it.

    Signed-off-by: Yohei Ueda [email protected]

    opened by yoheiueda 9
  • Add setsize for darwin

    Add setsize for darwin

    Uses TIOCSWINSZ to set the rows/cols of a pseudo terminal. Should work on both mac/linux, but only confirmed on a mac.

    I'm new to Go, feedback/criticism is welcome.

    opened by markjlorenz 9
  • Panic on OpenBSD

    Panic on OpenBSD

    Hi, I'm one of the developers of aerc and we received a report from a user with a crash caused by pty.

    The report is here and if questions come up, please feel free to ask in this thread. Maybe the Stack Trace will be enough to find and fix the issue though.

    aerc-crash-20220405-134420.log

    opened by mpldr 8
  • Add StartWithAttrs to allow bypassing setsid/setctty

    Add StartWithAttrs to allow bypassing setsid/setctty

    Revert #75 but don't change the "old" behavior of pty.Start and pty.StartWithSize.

    Introduce pty.StartWithAttr to explicitly set process attributes, which allow for pty to be created without setsid/setctty, fixing the issue faced by aerc.

    Fixes error with the new go1.15 behavior introduced in https://go-review.googlesource.com/c/go/+/231638/ ( golang/go#29458 ).

    Fixes #96

    cc @kr @ddevault @myitcv

    opened by creack 8
  • Data race on ioctl

    Data race on ioctl

    I'm seeing data races when calling pty.Setsize , c.f. https://github.com/coder/coder/issues/3236

    I think what's going on here is that calling Fd() on an os.File is inherently racy if multiple goroutines have reference to the file. While Read() and Write() go through the fdmutex, Fd() does not.

    I believe the correct fix is to wrap calls like ioctl in SyscallConn.

    In testing this out locally, I noticed that it breaks riscv builds, which are apparently still on Go 1.6. I saw #149 mention that it should be possible to get riscv builds natively, so hopefully this isn't a blocker.

    Does that sound right to you and would you be interested in a PR?

    opened by spikecurtis 0
  • Another attempt of support pty on windows with ConPTY api

    Another attempt of support pty on windows with ConPTY api

    This is an another attempt to support pseudo-terminal on windows using ConPty API (should resolve issue https://github.com/creack/pty/issues/95)

    This pull request does introduce major api change for Start method (*os.File -> Pty),

    I have tested this code with remote terminal application that I wrote. It would be great to get some additional testing with other use cases.

    opened by photostorm 18
  • Use pty with no command?

    Use pty with no command?

    Thanks @creack for the great library and community support!

    I have a question that I hope makes sense.

    I am using a websocket api that sends stdin messages and receives stdout and stderr output from the command as well as exit codes.

    For example, this API is used in a web UI, with the following string of messages sent and received 2022-06-25_09-35-14

    This web UI uses xterm.js to provide a terminal-like input ui and to interpret the responses, including ansi escape sequences, into terminal output.

    I am building a terminal application that would like to leverage this same API, so a "terminal-in-a-terminal" like thing, where stdin is sent to the API and responses received are rendered in my application.

    I would like to use creack/pty as the response interpreter, handling ansi escape sequences and the like, and holding a view of the terminal session that I can read into a string and render to the screen of my application.

    So the flow is roughly like:

    • stdin sent to websocket connection
    • response received
    • write response to pty
    • read entire pty to string
    • render string to screen
    • repeat

    If I use creack/pty this way, I don't actually have a command to start - it's just a nice box that interprets ansi escape sequences for me and allows me to retrieve the current "string view" of the terminal.

    Here is my attempt to get a command-less pty, write to it, and read from it:

    package main
    
    import (
    	"bytes"
    	"fmt"
    	"github.com/creack/pty"
    	"io"
    	"os"
    )
    
    func getPtyWithoutCommand() (*os.File, error) {
    	// this function just pty.StartWithAttrs with command-specific stuff commented out
    	pty, tty, err := pty.Open()
    	if err != nil {
    		return nil, err
    	}
    	defer func() { _ = tty.Close() }() // Best effort.
    
    	// if sz != nil {
    	// 	if err := Setsize(pty, sz); err != nil {
    	// 		_ = pty.Close() // Best effort.
    	// 		return nil, err
    	// 	}
    	// }
    	// if c.Stdout == nil {
    	// 	c.Stdout = tty
    	// }
    	// if c.Stderr == nil {
    	// 	c.Stderr = tty
    	// }
    	// if c.Stdin == nil {
    	// 	c.Stdin = tty
    	// }
    	//
    	// c.SysProcAttr = attrs
    	//
    	// if err := c.Start(); err != nil {
    	// 	_ = pty.Close() // Best effort.
    	// 	return nil, err
    	// }
    	return pty, err
    }
    
    func main() {
    	myPty, err := getPtyWithoutCommand()
    	if err != nil {
    		panic(err)
    	}
    
    	_, err = myPty.Write([]byte("test\n"))
    	if err != nil {
    		panic(err)
    	}
    	_, err = myPty.Write([]byte{4}) // EOT
    	if err != nil {
    		panic(err)
    	}
    
    	buf := new(bytes.Buffer)
    	_, err = io.Copy(buf, myPty)
    	if err != nil {
    		panic(err)
    	}
    	fmt.Println(buf.String())
    }
    

    I get the following error

    ❯ go run test.go
    panic: write /dev/ptmx: input/output error
    
    goroutine 1 [running]:
    main.main()
            test.go:52 +0x19c
    exit status 2
    

    Is what I'm trying to do sane at all? Is there a better way to achieve my goal here?

    Thank you! Leo

    opened by robinovitch61 3
  • README examples fix

    README examples fix

    In the README shell example, there is a line: ptmx, err := pty.Start(c) but maybe ptm is better than ptmx to be used as the variable name. Because ptmx means "pseudoterminal multiplexor", which is used to create a pseudoterminal master and slave pair.(https://man7.org/linux/man-pages/man4/pts.4.html) Here, we just get a pseudoterminal master by calling pty.Start(c). So, maybe ptm is better.

    opened by Anthony6075 0
Releases(v1.1.18)
Owner
Guillaume J. Charmes
@golang @docker @gofinance @while42-org
Guillaume J. Charmes
The slightly more awesome standard unix password manager for teams

gopass Introduction gopass is a password manager for the command line written in Go. It supports all major operating systems (Linux, MacOS, BSD) as we

Gopass 4.9k Dec 4, 2022
A modern UNIX ed (line editor) clone written in Go

ed (the awesome UNIX line editor) ed is a clone of the UNIX command-line tool by the same name ed a line editor that was nortorious for being and most

James Mills 45 May 29, 2021
A go library for easy configure and run command chains. Such like pipelining in unix shells.

go-command-chain A go library for easy configure and run command chains. Such like pipelining in unix shells. Example cat log_file.txt | grep error |

null 36 Nov 18, 2022
Pack a Go workflow/function as a Unix-style pipeline command

tpack Pack a Go workflow/function as a Unix-style pipeline command. Wiki In Unix-like computer operating systems, a pipeline is a mechanism for inter-

Eugene R. 55 Nov 9, 2022
A command line tool for quickly converting Unix timestamps to human readable form.

stamp A command line tool to quickly format a Unix timestamp in a human-readable form. Installation Go is required to build this software. To just bui

Ricco Førgaard 1 Oct 30, 2021
PickleShell - best shell for unix-like os

?? PickleShell shell for super users Compilation Windows go build -o PickleShell.exe

null 1 Nov 8, 2021
NYAGOS - The hybrid Commandline Shell between UNIX & DOS

The Nihongo Yet Another GOing Shell English / Japanese NYAGOS is the commandline-shell written with the Programming Language GO and Lua. There are som

nyaos.org 303 Nov 26, 2022
A command line utility that automagically replaces UNIX timestamps with human interpretable timestamps.

Unfy unfy is a command line utility that automagically identifies and translated UNIX timestamps (since epoch) to human readable timestamps. Example B

Jens Rantil 41 Oct 22, 2022
A simple command line tool using which you can skip phone number based SMS verification by using a temporary phone number that acts like a proxy.

Fake-SMS A simple command line tool using which you can skip phone number based SMS verification by using a temporary phone number that acts like a pr

Narasimha Prasanna HN 745 Nov 29, 2022
GC2 is a Command and Control application that allows an attacker to execute commands on the target machine using Google Sheet and exfiltrate data using Google Drive.

GC2 GC2 (Google Command and Control) is a Command and Control application that allows an attacker to execute commands on the target machine using Goog

Lorenzo Grazian 186 Nov 18, 2022
CLI - A package for building command line app with go

Command line interface Screenshot Key features Lightweight and easy to use. Defines flag by tag, e.g. flag name(short or/and long), description, defau

王仕晋 676 Dec 1, 2022
The standard library flag package with its missing features

cmd Package cmd is a minimalistic library that enables easy sub commands with the standard flag library. This library extends the standard library fla

Eyal Posener 35 Oct 4, 2022
Idiomatic Go input parsing with subcommands, positional values, and flags at any position. No required project or package layout and no external dependencies.

Sensible and fast command-line flag parsing with excellent support for subcommands and positional values. Flags can be at any position. Flaggy has no

Eric Greer 814 Nov 15, 2022
A collection of CLI argument types for the Go `flag` package.

flagvar A collection of CLI argument types for the flag package. import "github.com/sgreben/flagvar" Or just copy & paste what you need. It's public d

Sergey Grebenshchikov 41 Sep 26, 2022
Drop-in replacement for Go's flag package, implementing POSIX/GNU-style --flags.

Description pflag is a drop-in replacement for Go's flag package, implementing POSIX/GNU-style --flags. pflag is compatible with the GNU extensions to

Steve Francia 2k Dec 7, 2022
Package for creating interpreters

sand sand is for creating interpreters, like the Python interpreter and Haskell interpreter. It can also be used for creating text based games and CLI

null 19 Sep 26, 2022
A simple, fast, and fun package for building command line apps in Go

cli cli is a simple, fast, and fun package for building command line apps in Go. The goal is to enable developers to write fast and distributable comm

null 19.4k Dec 8, 2022
Color package for Go (golang)

color Color lets you use colorized outputs in terms of ANSI Escape Codes in Go (Golang). It has support for Windows too! The API can be used in severa

Fatih Arslan 5.8k Dec 2, 2022
Go package to make lightweight ASCII line graph ╭┈╯ in command line apps with no other dependencies.

asciigraph Go package to make lightweight ASCII line graphs ╭┈╯. Installation go get github.com/guptarohit/asciigraph Usage Basic graph package main

Rohit Gupta 2.1k Dec 7, 2022