123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- // +build darwin freebsd linux solaris
- package console
- import (
- "os"
- "golang.org/x/sys/unix"
- )
- // NewPty creates a new pty pair
- // The master is returned as the first console and a string
- // with the path to the pty slave is returned as the second
- func NewPty() (Console, string, error) {
- f, err := os.OpenFile("/dev/ptmx", unix.O_RDWR|unix.O_NOCTTY|unix.O_CLOEXEC, 0)
- if err != nil {
- return nil, "", err
- }
- slave, err := ptsname(f)
- if err != nil {
- return nil, "", err
- }
- if err := unlockpt(f); err != nil {
- return nil, "", err
- }
- m, err := newMaster(f)
- if err != nil {
- return nil, "", err
- }
- return m, slave, nil
- }
- type master struct {
- f *os.File
- original *unix.Termios
- }
- func (m *master) Read(b []byte) (int, error) {
- return m.f.Read(b)
- }
- func (m *master) Write(b []byte) (int, error) {
- return m.f.Write(b)
- }
- func (m *master) Close() error {
- return m.f.Close()
- }
- func (m *master) Resize(ws WinSize) error {
- return tcswinsz(m.f.Fd(), ws)
- }
- func (m *master) ResizeFrom(c Console) error {
- ws, err := c.Size()
- if err != nil {
- return err
- }
- return m.Resize(ws)
- }
- func (m *master) Reset() error {
- if m.original == nil {
- return nil
- }
- return tcset(m.f.Fd(), m.original)
- }
- func (m *master) getCurrent() (unix.Termios, error) {
- var termios unix.Termios
- if err := tcget(m.f.Fd(), &termios); err != nil {
- return unix.Termios{}, err
- }
- return termios, nil
- }
- func (m *master) SetRaw() error {
- rawState, err := m.getCurrent()
- if err != nil {
- return err
- }
- rawState = cfmakeraw(rawState)
- rawState.Oflag = rawState.Oflag | unix.OPOST
- return tcset(m.f.Fd(), &rawState)
- }
- func (m *master) DisableEcho() error {
- rawState, err := m.getCurrent()
- if err != nil {
- return err
- }
- rawState.Lflag = rawState.Lflag &^ unix.ECHO
- return tcset(m.f.Fd(), &rawState)
- }
- func (m *master) Size() (WinSize, error) {
- return tcgwinsz(m.f.Fd())
- }
- func (m *master) Fd() uintptr {
- return m.f.Fd()
- }
- func (m *master) Name() string {
- return m.f.Name()
- }
- // checkConsole checks if the provided file is a console
- func checkConsole(f *os.File) error {
- var termios unix.Termios
- if tcget(f.Fd(), &termios) != nil {
- return ErrNotAConsole
- }
- return nil
- }
- func newMaster(f *os.File) (Console, error) {
- m := &master{
- f: f,
- }
- t, err := m.getCurrent()
- if err != nil {
- return nil, err
- }
- m.original = &t
- return m, nil
- }
- // ClearONLCR sets the necessary tty_ioctl(4)s to ensure that a pty pair
- // created by us acts normally. In particular, a not-very-well-known default of
- // Linux unix98 ptys is that they have +onlcr by default. While this isn't a
- // problem for terminal emulators, because we relay data from the terminal we
- // also relay that funky line discipline.
- func ClearONLCR(fd uintptr) error {
- return setONLCR(fd, false)
- }
- // SetONLCR sets the necessary tty_ioctl(4)s to ensure that a pty pair
- // created by us acts as intended for a terminal emulator.
- func SetONLCR(fd uintptr) error {
- return setONLCR(fd, true)
- }
|