diff --git a/vendor.conf b/vendor.conf index b6fc34a..aa69c40 100644 --- a/vendor.conf +++ b/vendor.conf @@ -1,5 +1,7 @@ # go-runc client for runc; master as of 01/20/2017 -github.com/crosbymichael/go-runc f36917a18b3d962aee066063cba0bcff44e338ca +github.com/crosbymichael/go-runc d300412371ca6865a40bd4559599bb370889e2aa +# console pkg; +github.com/crosbymichael/console 4bf9d88357031b516b3794a2594b6d060a29c59c # go-metrics client to prometheus; master as of 12/16/2016 github.com/docker/go-metrics 0f35294225552d968a13f9c5bc71a3fa44b2eb87 # prometheus client; latest release as of 12/16/2016 diff --git a/vendor/github.com/crosbymichael/console/LICENSE b/vendor/github.com/crosbymichael/console/LICENSE new file mode 100644 index 0000000..109b6bd --- /dev/null +++ b/vendor/github.com/crosbymichael/console/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2017-infinity Michael Crosby. crosbymichael@gmail.com + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH +THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/crosbymichael/console/console.go b/vendor/github.com/crosbymichael/console/console.go new file mode 100644 index 0000000..5513a1e --- /dev/null +++ b/vendor/github.com/crosbymichael/console/console.go @@ -0,0 +1,54 @@ +package console + +import ( + "errors" + "io" + "os" +) + +var ErrNotAConsole = errors.New("provided file is not a console") + +type Console interface { + io.Reader + io.Writer + io.Closer + + // Resize resizes the console to the provided window size + Resize(WinSize) error + // ResizeFrom resizes the calling console to the size of the + // provided console + ResizeFrom(Console) error + // SetRaw sets the console in raw mode + SetRaw() error + // Reset restores the console to its orignal state + Reset() error + // Size returns the window size of the console + Size() (WinSize, error) +} + +// WinSize specifies the window size of the console +type WinSize struct { + // Width of the console + Width uint16 + // Height of the console + Height uint16 + x uint16 + y uint16 +} + +// Current returns the current processes console +func Current() Console { + return &master{ + f: os.Stdin, + } +} + +// ConsoleFromFile returns a console using the provided file +func ConsoleFromFile(f *os.File) (Console, error) { + if err := checkConsole(f); err != nil { + return nil, err + } + return &master{ + f: f, + }, nil +} diff --git a/vendor/github.com/crosbymichael/console/console_linux.go b/vendor/github.com/crosbymichael/console/console_linux.go new file mode 100644 index 0000000..7c2c681 --- /dev/null +++ b/vendor/github.com/crosbymichael/console/console_linux.go @@ -0,0 +1,105 @@ +package console + +// #include +import "C" + +import ( + "os" + "syscall" + "unsafe" +) + +// 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", syscall.O_RDWR|syscall.O_NOCTTY|syscall.O_CLOEXEC, 0) + if err != nil { + return nil, "", err + } + if err := saneTerminal(f); err != nil { + return nil, "", err + } + slave, err := ptsname(f) + if err != nil { + return nil, "", err + } + if err := unlockpt(f); err != nil { + return nil, "", err + } + return &master{ + f: f, + }, slave, nil +} + +type master struct { + f *os.File + termios *syscall.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 ioctl( + m.f.Fd(), + uintptr(syscall.TIOCSWINSZ), + uintptr(unsafe.Pointer(&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.termios == nil { + return nil + } + return tcset(m.f.Fd(), m.termios) +} + +func (m *master) SetRaw() error { + m.termios = &syscall.Termios{} + if err := tcget(m.f.Fd(), m.termios); err != nil { + return err + } + rawState := *m.termios + C.cfmakeraw((*C.struct_termios)(unsafe.Pointer(&rawState))) + rawState.Oflag = rawState.Oflag | C.OPOST + return tcset(m.f.Fd(), &rawState) +} + +func (m *master) Size() (WinSize, error) { + var ws WinSize + if err := ioctl( + m.f.Fd(), + uintptr(syscall.TIOCGWINSZ), + uintptr(unsafe.Pointer(&ws)), + ); err != nil { + return ws, err + } + return ws, nil +} + +// checkConsole checks if the provided file is a console +func checkConsole(f *os.File) error { + var termios syscall.Termios + if tcget(f.Fd(), &termios) != nil { + return ErrNotAConsole + } + return nil +} diff --git a/vendor/github.com/crosbymichael/console/tc.go b/vendor/github.com/crosbymichael/console/tc.go new file mode 100644 index 0000000..c17b75f --- /dev/null +++ b/vendor/github.com/crosbymichael/console/tc.go @@ -0,0 +1,52 @@ +// +build linux + +package console + +import ( + "fmt" + "os" + "syscall" + "unsafe" +) + +func tcget(fd uintptr, p *syscall.Termios) error { + return ioctl(fd, syscall.TCGETS, uintptr(unsafe.Pointer(p))) +} + +func tcset(fd uintptr, p *syscall.Termios) error { + return ioctl(fd, syscall.TCSETS, uintptr(unsafe.Pointer(p))) +} + +func ioctl(fd, flag, data uintptr) error { + if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, flag, data); err != 0 { + return err + } + return nil +} + +// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f. +// unlockpt should be called before opening the slave side of a pty. +func unlockpt(f *os.File) error { + var u int32 + return ioctl(f.Fd(), syscall.TIOCSPTLCK, uintptr(unsafe.Pointer(&u))) +} + +// ptsname retrieves the name of the first available pts for the given master. +func ptsname(f *os.File) (string, error) { + var n int32 + if err := ioctl(f.Fd(), syscall.TIOCGPTN, uintptr(unsafe.Pointer(&n))); err != nil { + return "", err + } + return fmt.Sprintf("/dev/pts/%d", n), nil +} + +func saneTerminal(f *os.File) error { + // Go doesn't have a wrapper for any of the termios ioctls. + var termios syscall.Termios + if err := tcget(f.Fd(), &termios); err != nil { + return err + } + // Set -onlcr so we don't have to deal with \r. + termios.Oflag &^= syscall.ONLCR + return tcset(f.Fd(), &termios) +} diff --git a/vendor/github.com/crosbymichael/go-runc/console.go b/vendor/github.com/crosbymichael/go-runc/console.go index 63a7771..da288c0 100644 --- a/vendor/github.com/crosbymichael/go-runc/console.go +++ b/vendor/github.com/crosbymichael/go-runc/console.go @@ -3,22 +3,26 @@ package runc import ( "fmt" "net" - "os" + "path/filepath" - "github.com/docker/docker/pkg/term" + "github.com/crosbymichael/console" "github.com/opencontainers/runc/libcontainer/utils" ) // NewConsoleSocket creates a new unix socket at the provided path to accept a // pty master created by runc for use by the container func NewConsoleSocket(path string) (*ConsoleSocket, error) { - l, err := net.Listen("unix", path) + abs, err := filepath.Abs(path) + if err != nil { + return nil, err + } + l, err := net.Listen("unix", abs) if err != nil { return nil, err } return &ConsoleSocket{ l: l, - path: path, + path: abs, }, nil } @@ -34,7 +38,7 @@ func (c *ConsoleSocket) Path() string { } // ReceiveMaster blocks until the socket receives the pty master -func (c *ConsoleSocket) ReceiveMaster() (*Console, error) { +func (c *ConsoleSocket) ReceiveMaster() (console.Console, error) { conn, err := c.l.Accept() if err != nil { return nil, err @@ -52,9 +56,7 @@ func (c *ConsoleSocket) ReceiveMaster() (*Console, error) { if err != nil { return nil, err } - return &Console{ - master: f, - }, nil + return console.ConsoleFromFile(f) } // Close closes the unix socket @@ -69,31 +71,3 @@ type WinSize struct { // Height of the console Height uint16 } - -// Console is a pty master -type Console struct { - master *os.File -} - -// Read from the console -func (c *Console) Read(b []byte) (int, error) { - return c.master.Read(b) -} - -// Write writes to the console -func (c *Console) Write(b []byte) (int, error) { - return c.master.Write(b) -} - -// Resize the console -func (c *Console) Resize(ws WinSize) error { - return term.SetWinsize(c.master.Fd(), &term.Winsize{ - Width: ws.Width, - Height: ws.Height, - }) -} - -// Close the console -func (c *Console) Close() error { - return c.master.Close() -} diff --git a/vendor/github.com/crosbymichael/go-runc/runc.go b/vendor/github.com/crosbymichael/go-runc/runc.go index cb48f99..3cb57a3 100644 --- a/vendor/github.com/crosbymichael/go-runc/runc.go +++ b/vendor/github.com/crosbymichael/go-runc/runc.go @@ -8,6 +8,7 @@ import ( "io/ioutil" "os" "os/exec" + "path/filepath" "strconv" "syscall" "time" @@ -73,9 +74,13 @@ type CreateOpts struct { NoNewKeyring bool } -func (o *CreateOpts) args() (out []string) { +func (o *CreateOpts) args() (out []string, err error) { if o.PidFile != "" { - out = append(out, "--pid-file", o.PidFile) + abs, err := filepath.Abs(o.PidFile) + if err != nil { + return nil, err + } + out = append(out, "--pid-file", abs) } if o.ConsoleSocket != nil { out = append(out, "--console-socket", o.ConsoleSocket.Path()) @@ -89,17 +94,21 @@ func (o *CreateOpts) args() (out []string) { if o.Detach { out = append(out, "--detach") } - return out + return out, nil } // Create creates a new container and returns its pid if it was created successfully func (r *Runc) Create(context context.Context, id, bundle string, opts *CreateOpts) error { args := []string{"create", "--bundle", bundle} if opts != nil { - args = append(args, opts.args()...) + oargs, err := opts.args() + if err != nil { + return err + } + args = append(args, oargs...) } cmd := r.command(context, append(args, id)...) - if opts != nil { + if opts != nil && opts.IO != nil { opts.Set(cmd) } if cmd.Stdout == nil && cmd.Stderr == nil { @@ -138,7 +147,7 @@ type ExecOpts struct { Detach bool } -func (o *ExecOpts) args() (out []string) { +func (o *ExecOpts) args() (out []string, err error) { out = append(out, "--user", fmt.Sprintf("%d:%d", o.Uid, o.Gid)) if o.Tty { out = append(out, "--tty") @@ -153,9 +162,13 @@ func (o *ExecOpts) args() (out []string) { out = append(out, "--detach") } if o.PidFile != "" { - out = append(out, "--pid-file", o.PidFile) + abs, err := filepath.Abs(o.PidFile) + if err != nil { + return nil, err + } + out = append(out, "--pid-file", abs) } - return out + return out, nil } // Exec executres and additional process inside the container based on a full @@ -173,7 +186,11 @@ func (r *Runc) Exec(context context.Context, id string, spec specs.Process, opts } args := []string{"exec", "--process", f.Name()} if opts != nil { - args = append(args, opts.args()...) + oargs, err := opts.args() + if err != nil { + return err + } + args = append(args, oargs...) } cmd := r.command(context, append(args, id)...) if opts != nil { @@ -187,7 +204,11 @@ func (r *Runc) Exec(context context.Context, id string, spec specs.Process, opts func (r *Runc) Run(context context.Context, id, bundle string, opts *CreateOpts) (int, error) { args := []string{"run", "--bundle", bundle} if opts != nil { - args = append(args, opts.args()...) + oargs, err := opts.args() + if err != nil { + return -1, err + } + args = append(args, oargs...) } cmd := r.command(context, append(args, id)...) if opts != nil {