Bump console for windows tty handling

ref: https://github.com/containerd/console/pull/25

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
Michael Crosby 2018-06-05 10:14:41 -04:00
parent 0d7fd3f7ad
commit 0cfca1e633
3 changed files with 45 additions and 81 deletions

View File

@ -1,5 +1,5 @@
github.com/containerd/go-runc f271fa2021de855d4d918dbef83c5fe19db1bdd5 github.com/containerd/go-runc f271fa2021de855d4d918dbef83c5fe19db1bdd5
github.com/containerd/console cb7008ab3d8359b78c5f464cb7cf160107ad5925 github.com/containerd/console 9290d21dc56074581f619579c43d970b4514bc08
github.com/containerd/cgroups fe281dd265766145e943a034aa41086474ea6130 github.com/containerd/cgroups fe281dd265766145e943a034aa41086474ea6130
github.com/containerd/typeurl f6943554a7e7e88b3c14aad190bf05932da84788 github.com/containerd/typeurl f6943554a7e7e88b3c14aad190bf05932da84788
github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c

View File

@ -72,7 +72,7 @@ func NewEpoller() (*Epoller, error) {
}, nil }, nil
} }
// Add creates a epoll console based on the provided console. The console will // Add creates an epoll console based on the provided console. The console will
// be registered with EPOLLET (i.e. using edge-triggered notification) and its // be registered with EPOLLET (i.e. using edge-triggered notification) and its
// file descriptor will be set to non-blocking mode. After this, user should use // file descriptor will be set to non-blocking mode. After this, user should use
// the return console to perform I/O. // the return console to perform I/O.
@ -134,7 +134,7 @@ func (e *Epoller) Wait() error {
} }
} }
// Close unregister the console's file descriptor from epoll interface // CloseConsole unregisters the console's file descriptor from epoll interface
func (e *Epoller) CloseConsole(fd int) error { func (e *Epoller) CloseConsole(fd int) error {
e.mu.Lock() e.mu.Lock()
defer e.mu.Unlock() defer e.mu.Unlock()
@ -149,12 +149,12 @@ func (e *Epoller) getConsole(sysfd int) *EpollConsole {
return f return f
} }
// Close the epoll fd // Close closes the epoll fd
func (e *Epoller) Close() error { func (e *Epoller) Close() error {
return unix.Close(e.efd) return unix.Close(e.efd)
} }
// EpollConsole acts like a console but register its file descriptor with a // EpollConsole acts like a console but registers its file descriptor with an
// epoll fd and uses epoll API to perform I/O. // epoll fd and uses epoll API to perform I/O.
type EpollConsole struct { type EpollConsole struct {
Console Console
@ -167,7 +167,7 @@ type EpollConsole struct {
// Read reads up to len(p) bytes into p. It returns the number of bytes read // Read reads up to len(p) bytes into p. It returns the number of bytes read
// (0 <= n <= len(p)) and any error encountered. // (0 <= n <= len(p)) and any error encountered.
// //
// If the console's read returns EAGAIN or EIO, we assumes that its a // If the console's read returns EAGAIN or EIO, we assume that it's a
// temporary error because the other side went away and wait for the signal // temporary error because the other side went away and wait for the signal
// generated by epoll event to continue. // generated by epoll event to continue.
func (ec *EpollConsole) Read(p []byte) (n int, err error) { func (ec *EpollConsole) Read(p []byte) (n int, err error) {
@ -207,7 +207,7 @@ func (ec *EpollConsole) Read(p []byte) (n int, err error) {
// written from p (0 <= n <= len(p)) and any error encountered that caused // written from p (0 <= n <= len(p)) and any error encountered that caused
// the write to stop early. // the write to stop early.
// //
// If writes to the console returns EAGAIN or EIO, we assumes that its a // If writes to the console returns EAGAIN or EIO, we assume that it's a
// temporary error because the other side went away and wait for the signal // temporary error because the other side went away and wait for the signal
// generated by epoll event to continue. // generated by epoll event to continue.
func (ec *EpollConsole) Write(p []byte) (n int, err error) { func (ec *EpollConsole) Write(p []byte) (n int, err error) {
@ -224,7 +224,7 @@ func (ec *EpollConsole) Write(p []byte) (n int, err error) {
} else { } else {
hangup = (err == unix.EAGAIN || err == unix.EIO) hangup = (err == unix.EAGAIN || err == unix.EIO)
} }
// if the other end disappear, assume this is temporary and wait for the // if the other end disappears, assume this is temporary and wait for the
// signal to continue again. // signal to continue again.
if hangup { if hangup {
ec.writec.Wait() ec.writec.Wait()
@ -242,7 +242,7 @@ func (ec *EpollConsole) Write(p []byte) (n int, err error) {
return n, err return n, err
} }
// Close closed the file descriptor and signal call waiters for this fd. // Shutdown closes the file descriptor and signals call waiters for this fd.
// It accepts a callback which will be called with the console's fd. The // It accepts a callback which will be called with the console's fd. The
// callback typically will be used to do further cleanup such as unregister the // callback typically will be used to do further cleanup such as unregister the
// console's fd from the epoll interface. // console's fd from the epoll interface.

View File

@ -17,7 +17,6 @@
package console package console
import ( import (
"fmt"
"os" "os"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -29,90 +28,55 @@ var (
ErrNotImplemented = errors.New("not implemented") ErrNotImplemented = errors.New("not implemented")
) )
func (m *master) initStdios() { func (m *master) init() {
m.in = windows.Handle(os.Stdin.Fd()) m.h = windows.Handle(m.f.Fd())
if err := windows.GetConsoleMode(m.in, &m.inMode); err == nil { if err := windows.GetConsoleMode(m.h, &m.mode); err == nil {
// Validate that windows.ENABLE_VIRTUAL_TERMINAL_INPUT is supported, but do not set it. if m.f == os.Stdin {
if err = windows.SetConsoleMode(m.in, m.inMode|windows.ENABLE_VIRTUAL_TERMINAL_INPUT); err == nil { // Validate that windows.ENABLE_VIRTUAL_TERMINAL_INPUT is supported, but do not set it.
vtInputSupported = true if err = windows.SetConsoleMode(m.h, m.mode|windows.ENABLE_VIRTUAL_TERMINAL_INPUT); err == nil {
} vtInputSupported = true
// Unconditionally set the console mode back even on failure because SetConsoleMode }
// remembers invalid bits on input handles. // Unconditionally set the console mode back even on failure because SetConsoleMode
windows.SetConsoleMode(m.in, m.inMode) // remembers invalid bits on input handles.
} else { windows.SetConsoleMode(m.h, m.mode)
fmt.Printf("failed to get console mode for stdin: %v\n", err) } else if err := windows.SetConsoleMode(m.h, m.mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err == nil {
} m.mode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
m.out = windows.Handle(os.Stdout.Fd())
if err := windows.GetConsoleMode(m.out, &m.outMode); err == nil {
if err := windows.SetConsoleMode(m.out, m.outMode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err == nil {
m.outMode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
} else { } else {
windows.SetConsoleMode(m.out, m.outMode) windows.SetConsoleMode(m.h, m.mode)
} }
} else {
fmt.Printf("failed to get console mode for stdout: %v\n", err)
}
m.err = windows.Handle(os.Stderr.Fd())
if err := windows.GetConsoleMode(m.err, &m.errMode); err == nil {
if err := windows.SetConsoleMode(m.err, m.errMode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err == nil {
m.errMode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
} else {
windows.SetConsoleMode(m.err, m.errMode)
}
} else {
fmt.Printf("failed to get console mode for stderr: %v\n", err)
} }
} }
type master struct { type master struct {
in windows.Handle h windows.Handle
inMode uint32 mode uint32
f *os.File
out windows.Handle
outMode uint32
err windows.Handle
errMode uint32
} }
func (m *master) SetRaw() error { func (m *master) SetRaw() error {
if err := makeInputRaw(m.in, m.inMode); err != nil { if m.f == os.Stdin {
return err if err := makeInputRaw(m.h, m.mode); err != nil {
return err
}
} else {
// Set StdOut and StdErr to raw mode, we ignore failures since
// windows.DISABLE_NEWLINE_AUTO_RETURN might not be supported on this version of
// Windows.
windows.SetConsoleMode(m.h, m.mode|windows.DISABLE_NEWLINE_AUTO_RETURN)
} }
// Set StdOut and StdErr to raw mode, we ignore failures since
// windows.DISABLE_NEWLINE_AUTO_RETURN might not be supported on this version of
// Windows.
windows.SetConsoleMode(m.out, m.outMode|windows.DISABLE_NEWLINE_AUTO_RETURN)
windows.SetConsoleMode(m.err, m.errMode|windows.DISABLE_NEWLINE_AUTO_RETURN)
return nil return nil
} }
func (m *master) Reset() error { func (m *master) Reset() error {
for _, s := range []struct { if err := windows.SetConsoleMode(m.h, m.mode); err != nil {
fd windows.Handle return errors.Wrap(err, "unable to restore console mode")
mode uint32
}{
{m.in, m.inMode},
{m.out, m.outMode},
{m.err, m.errMode},
} {
if err := windows.SetConsoleMode(s.fd, s.mode); err != nil {
return errors.Wrap(err, "unable to restore console mode")
}
} }
return nil return nil
} }
func (m *master) Size() (WinSize, error) { func (m *master) Size() (WinSize, error) {
var info windows.ConsoleScreenBufferInfo var info windows.ConsoleScreenBufferInfo
err := windows.GetConsoleScreenBufferInfo(m.out, &info) err := windows.GetConsoleScreenBufferInfo(m.h, &info)
if err != nil { if err != nil {
return WinSize{}, errors.Wrap(err, "unable to get console info") return WinSize{}, errors.Wrap(err, "unable to get console info")
} }
@ -134,11 +98,11 @@ func (m *master) ResizeFrom(c Console) error {
} }
func (m *master) DisableEcho() error { func (m *master) DisableEcho() error {
mode := m.inMode &^ windows.ENABLE_ECHO_INPUT mode := m.mode &^ windows.ENABLE_ECHO_INPUT
mode |= windows.ENABLE_PROCESSED_INPUT mode |= windows.ENABLE_PROCESSED_INPUT
mode |= windows.ENABLE_LINE_INPUT mode |= windows.ENABLE_LINE_INPUT
if err := windows.SetConsoleMode(m.in, mode); err != nil { if err := windows.SetConsoleMode(m.h, mode); err != nil {
return errors.Wrap(err, "unable to set console to disable echo") return errors.Wrap(err, "unable to set console to disable echo")
} }
@ -150,15 +114,15 @@ func (m *master) Close() error {
} }
func (m *master) Read(b []byte) (int, error) { func (m *master) Read(b []byte) (int, error) {
panic("not implemented on windows") return m.f.Read(b)
} }
func (m *master) Write(b []byte) (int, error) { func (m *master) Write(b []byte) (int, error) {
panic("not implemented on windows") return m.f.Write(b)
} }
func (m *master) Fd() uintptr { func (m *master) Fd() uintptr {
return uintptr(m.in) return uintptr(m.h)
} }
// on windows, console can only be made from os.Std{in,out,err}, hence there // on windows, console can only be made from os.Std{in,out,err}, hence there
@ -210,7 +174,7 @@ func newMaster(f *os.File) (Console, error) {
if f != os.Stdin && f != os.Stdout && f != os.Stderr { if f != os.Stdin && f != os.Stdout && f != os.Stderr {
return nil, errors.New("creating a console from a file is not supported on windows") return nil, errors.New("creating a console from a file is not supported on windows")
} }
m := &master{} m := &master{f: f}
m.initStdios() m.init()
return m, nil return m, nil
} }