Merge pull request #861 from justincormack/go-runc-port
Portability fixes for containerd shim
This commit is contained in:
commit
47718b0930
@ -6,7 +6,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
@ -17,9 +16,7 @@ import (
|
|||||||
shimapi "github.com/containerd/containerd/api/services/shim"
|
shimapi "github.com/containerd/containerd/api/services/shim"
|
||||||
"github.com/containerd/containerd/linux/shim"
|
"github.com/containerd/containerd/linux/shim"
|
||||||
"github.com/containerd/containerd/reaper"
|
"github.com/containerd/containerd/reaper"
|
||||||
"github.com/containerd/containerd/sys"
|
|
||||||
"github.com/containerd/containerd/version"
|
"github.com/containerd/containerd/version"
|
||||||
runc "github.com/containerd/go-runc"
|
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -81,21 +78,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// setupSignals creates a new signal handler for all signals and sets the shim as a
|
|
||||||
// sub-reaper so that the container processes are reparented
|
|
||||||
func setupSignals() (chan os.Signal, error) {
|
|
||||||
signals := make(chan os.Signal, 2048)
|
|
||||||
signal.Notify(signals)
|
|
||||||
// make sure runc is setup to use the monitor
|
|
||||||
// for waiting on processes
|
|
||||||
runc.Monitor = reaper.Default
|
|
||||||
// set the shim as the subreaper for all orphaned processes created by the container
|
|
||||||
if err := sys.SetSubreaper(1); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return signals, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// serve serves the grpc API over a unix socket at the provided path
|
// serve serves the grpc API over a unix socket at the provided path
|
||||||
// this function does not block
|
// this function does not block
|
||||||
func serve(server *grpc.Server, path string) error {
|
func serve(server *grpc.Server, path string) error {
|
||||||
@ -131,8 +113,3 @@ func handleSignals(signals chan os.Signal, server *grpc.Server) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// setupRoot sets up the root as the shim is started in its own mount namespace
|
|
||||||
func setupRoot() error {
|
|
||||||
return unix.Mount("", "/", "", unix.MS_SLAVE|unix.MS_REC, "")
|
|
||||||
}
|
|
||||||
|
32
cmd/containerd-shim/shim_linux.go
Normal file
32
cmd/containerd-shim/shim_linux.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/reaper"
|
||||||
|
"github.com/containerd/containerd/sys"
|
||||||
|
runc "github.com/containerd/go-runc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// setupSignals creates a new signal handler for all signals and sets the shim as a
|
||||||
|
// sub-reaper so that the container processes are reparented
|
||||||
|
func setupSignals() (chan os.Signal, error) {
|
||||||
|
signals := make(chan os.Signal, 2048)
|
||||||
|
signal.Notify(signals)
|
||||||
|
// make sure runc is setup to use the monitor
|
||||||
|
// for waiting on processes
|
||||||
|
runc.Monitor = reaper.Default
|
||||||
|
// set the shim as the subreaper for all orphaned processes created by the container
|
||||||
|
if err := sys.SetSubreaper(1); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return signals, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// setupRoot sets up the root as the shim is started in its own mount namespace
|
||||||
|
func setupRoot() error {
|
||||||
|
return unix.Mount("", "/", "", unix.MS_SLAVE|unix.MS_REC, "")
|
||||||
|
}
|
27
cmd/containerd-shim/shim_unix.go
Normal file
27
cmd/containerd-shim/shim_unix.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// +build !linux
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/reaper"
|
||||||
|
runc "github.com/containerd/go-runc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// setupSignals creates a new signal handler for all signals and sets the shim as a
|
||||||
|
// sub-reaper so that the container processes are reparented
|
||||||
|
func setupSignals() (chan os.Signal, error) {
|
||||||
|
signals := make(chan os.Signal, 2048)
|
||||||
|
signal.Notify(signals)
|
||||||
|
// make sure runc is setup to use the monitor
|
||||||
|
// for waiting on processes
|
||||||
|
runc.Monitor = reaper.Default
|
||||||
|
return signals, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// setupRoot is a no op except on Linux
|
||||||
|
func setupRoot() error {
|
||||||
|
return nil
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
// +build linux
|
// +build !windows
|
||||||
|
|
||||||
package shim
|
package shim
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// +build linux
|
// +build !windows
|
||||||
|
|
||||||
package shim
|
package shim
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// +build linux
|
// +build !windows
|
||||||
|
|
||||||
package shim
|
package shim
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// +build linux
|
// +build !windows
|
||||||
|
|
||||||
package shim
|
package shim
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// +build linux
|
// +build !windows
|
||||||
|
|
||||||
package shim
|
package shim
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
github.com/coreos/go-systemd 48702e0da86bd25e76cfef347e2adeb434a0d0a6
|
github.com/coreos/go-systemd 48702e0da86bd25e76cfef347e2adeb434a0d0a6
|
||||||
github.com/containerd/go-runc 5fe4d8cb7fdc0fae5f5a7f4f1d65a565032401b2
|
github.com/containerd/go-runc 66d084de463f26efe84e6a5669e573fa6202e814
|
||||||
github.com/containerd/console a3863895279f5104533fd999c1babf80faffd98c
|
github.com/containerd/console a3863895279f5104533fd999c1babf80faffd98c
|
||||||
github.com/containerd/cgroups 7b2d1a0f50963678d5799e29d17a4d611f5a5dee
|
github.com/containerd/cgroups 7b2d1a0f50963678d5799e29d17a4d611f5a5dee
|
||||||
github.com/docker/go-metrics 8fd5772bf1584597834c6f7961a530f06cbfbb87
|
github.com/docker/go-metrics 8fd5772bf1584597834c6f7961a530f06cbfbb87
|
||||||
|
21
vendor/github.com/containerd/go-runc/command_linux.go
generated
vendored
Normal file
21
vendor/github.com/containerd/go-runc/command_linux.go
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package runc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os/exec"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r *Runc) command(context context.Context, args ...string) *exec.Cmd {
|
||||||
|
command := r.Command
|
||||||
|
if command == "" {
|
||||||
|
command = DefaultCommand
|
||||||
|
}
|
||||||
|
cmd := exec.CommandContext(context, command, append(r.args(), args...)...)
|
||||||
|
if r.PdeathSignal != 0 {
|
||||||
|
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||||
|
Pdeathsig: r.PdeathSignal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cmd
|
||||||
|
}
|
16
vendor/github.com/containerd/go-runc/command_other.go
generated
vendored
Normal file
16
vendor/github.com/containerd/go-runc/command_other.go
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// +build !linux
|
||||||
|
|
||||||
|
package runc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r *Runc) command(context context.Context, args ...string) *exec.Cmd {
|
||||||
|
command := r.Command
|
||||||
|
if command == "" {
|
||||||
|
command = DefaultCommand
|
||||||
|
}
|
||||||
|
return exec.CommandContext(context, command, append(r.args(), args...)...)
|
||||||
|
}
|
75
vendor/github.com/containerd/go-runc/console.go
generated
vendored
75
vendor/github.com/containerd/go-runc/console.go
generated
vendored
@ -10,7 +10,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/containerd/console"
|
"github.com/containerd/console"
|
||||||
"github.com/opencontainers/runc/libcontainer/utils"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewConsoleSocket creates a new unix socket at the provided path to accept a
|
// NewConsoleSocket creates a new unix socket at the provided path to accept a
|
||||||
@ -20,13 +20,16 @@ func NewConsoleSocket(path string) (*Socket, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
l, err := net.Listen("unix", abs)
|
addr, err := net.ResolveUnixAddr("unix", abs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
l, err := net.ListenUnix("unix", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &Socket{
|
return &Socket{
|
||||||
l: l,
|
l: l,
|
||||||
path: abs,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,27 +44,73 @@ func NewTempConsoleSocket() (*Socket, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
l, err := net.Listen("unix", abs)
|
addr, err := net.ResolveUnixAddr("unix", abs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
l, err := net.ListenUnix("unix", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &Socket{
|
return &Socket{
|
||||||
l: l,
|
l: l,
|
||||||
rmdir: true,
|
rmdir: true,
|
||||||
path: abs,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Socket is a unix socket that accepts the pty master created by runc
|
// Socket is a unix socket that accepts the pty master created by runc
|
||||||
type Socket struct {
|
type Socket struct {
|
||||||
path string
|
|
||||||
rmdir bool
|
rmdir bool
|
||||||
l net.Listener
|
l *net.UnixListener
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path returns the path to the unix socket on disk
|
// Path returns the path to the unix socket on disk
|
||||||
func (c *Socket) Path() string {
|
func (c *Socket) Path() string {
|
||||||
return c.path
|
return c.l.Addr().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// recvFd waits for a file descriptor to be sent over the given AF_UNIX
|
||||||
|
// socket. The file name of the remote file descriptor will be recreated
|
||||||
|
// locally (it is sent as non-auxiliary data in the same payload).
|
||||||
|
func recvFd(socket *net.UnixConn) (*os.File, error) {
|
||||||
|
const MaxNameLen = 4096
|
||||||
|
var oobSpace = unix.CmsgSpace(4)
|
||||||
|
|
||||||
|
name := make([]byte, MaxNameLen)
|
||||||
|
oob := make([]byte, oobSpace)
|
||||||
|
|
||||||
|
n, oobn, _, _, err := socket.ReadMsgUnix(name, oob)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if n >= MaxNameLen || oobn != oobSpace {
|
||||||
|
return nil, fmt.Errorf("recvfd: incorrect number of bytes read (n=%d oobn=%d)", n, oobn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Truncate.
|
||||||
|
name = name[:n]
|
||||||
|
oob = oob[:oobn]
|
||||||
|
|
||||||
|
scms, err := unix.ParseSocketControlMessage(oob)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(scms) != 1 {
|
||||||
|
return nil, fmt.Errorf("recvfd: number of SCMs is not 1: %d", len(scms))
|
||||||
|
}
|
||||||
|
scm := scms[0]
|
||||||
|
|
||||||
|
fds, err := unix.ParseUnixRights(&scm)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(fds) != 1 {
|
||||||
|
return nil, fmt.Errorf("recvfd: number of fds is not 1: %d", len(fds))
|
||||||
|
}
|
||||||
|
fd := uintptr(fds[0])
|
||||||
|
|
||||||
|
return os.NewFile(fd, string(name)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReceiveMaster blocks until the socket receives the pty master
|
// ReceiveMaster blocks until the socket receives the pty master
|
||||||
@ -71,15 +120,11 @@ func (c *Socket) ReceiveMaster() (console.Console, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
unix, ok := conn.(*net.UnixConn)
|
uc, ok := conn.(*net.UnixConn)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("received connection which was not a unix socket")
|
return nil, fmt.Errorf("received connection which was not a unix socket")
|
||||||
}
|
}
|
||||||
sock, err := unix.File()
|
f, err := recvFd(uc)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
f, err := utils.RecvFd(sock)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -90,7 +135,7 @@ func (c *Socket) ReceiveMaster() (console.Console, error) {
|
|||||||
func (c *Socket) Close() error {
|
func (c *Socket) Close() error {
|
||||||
err := c.l.Close()
|
err := c.l.Close()
|
||||||
if c.rmdir {
|
if c.rmdir {
|
||||||
if rerr := os.RemoveAll(filepath.Dir(c.path)); err == nil {
|
if rerr := os.RemoveAll(filepath.Dir(c.Path())); err == nil {
|
||||||
err = rerr
|
err = rerr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
14
vendor/github.com/containerd/go-runc/runc.go
generated
vendored
14
vendor/github.com/containerd/go-runc/runc.go
generated
vendored
@ -523,20 +523,6 @@ func (r *Runc) args() (out []string) {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Runc) command(context context.Context, args ...string) *exec.Cmd {
|
|
||||||
command := r.Command
|
|
||||||
if command == "" {
|
|
||||||
command = DefaultCommand
|
|
||||||
}
|
|
||||||
cmd := exec.CommandContext(context, command, append(r.args(), args...)...)
|
|
||||||
if r.PdeathSignal != 0 {
|
|
||||||
cmd.SysProcAttr = &syscall.SysProcAttr{
|
|
||||||
Pdeathsig: r.PdeathSignal,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
// runOrError will run the provided command. If an error is
|
// runOrError will run the provided command. If an error is
|
||||||
// encountered and neither Stdout or Stderr was set the error and the
|
// encountered and neither Stdout or Stderr was set the error and the
|
||||||
// stderr of the command will be returned in the format of <error>:
|
// stderr of the command will be returned in the format of <error>:
|
||||||
|
95
vendor/github.com/opencontainers/runc/libcontainer/utils/cmsg.go
generated
vendored
95
vendor/github.com/opencontainers/runc/libcontainer/utils/cmsg.go
generated
vendored
@ -1,95 +0,0 @@
|
|||||||
// +build linux
|
|
||||||
|
|
||||||
package utils
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright 2016, 2017 SUSE LLC
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
// MaxSendfdLen is the maximum length of the name of a file descriptor being
|
|
||||||
// sent using SendFd. The name of the file handle returned by RecvFd will never
|
|
||||||
// be larger than this value.
|
|
||||||
const MaxNameLen = 4096
|
|
||||||
|
|
||||||
// oobSpace is the size of the oob slice required to store a single FD. Note
|
|
||||||
// that unix.UnixRights appears to make the assumption that fd is always int32,
|
|
||||||
// so sizeof(fd) = 4.
|
|
||||||
var oobSpace = unix.CmsgSpace(4)
|
|
||||||
|
|
||||||
// RecvFd waits for a file descriptor to be sent over the given AF_UNIX
|
|
||||||
// socket. The file name of the remote file descriptor will be recreated
|
|
||||||
// locally (it is sent as non-auxiliary data in the same payload).
|
|
||||||
func RecvFd(socket *os.File) (*os.File, error) {
|
|
||||||
// For some reason, unix.Recvmsg uses the length rather than the capacity
|
|
||||||
// when passing the msg_controllen and other attributes to recvmsg. So we
|
|
||||||
// have to actually set the length.
|
|
||||||
name := make([]byte, MaxNameLen)
|
|
||||||
oob := make([]byte, oobSpace)
|
|
||||||
|
|
||||||
sockfd := socket.Fd()
|
|
||||||
n, oobn, _, _, err := unix.Recvmsg(int(sockfd), name, oob, 0)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if n >= MaxNameLen || oobn != oobSpace {
|
|
||||||
return nil, fmt.Errorf("recvfd: incorrect number of bytes read (n=%d oobn=%d)", n, oobn)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Truncate.
|
|
||||||
name = name[:n]
|
|
||||||
oob = oob[:oobn]
|
|
||||||
|
|
||||||
scms, err := unix.ParseSocketControlMessage(oob)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(scms) != 1 {
|
|
||||||
return nil, fmt.Errorf("recvfd: number of SCMs is not 1: %d", len(scms))
|
|
||||||
}
|
|
||||||
scm := scms[0]
|
|
||||||
|
|
||||||
fds, err := unix.ParseUnixRights(&scm)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(fds) != 1 {
|
|
||||||
return nil, fmt.Errorf("recvfd: number of fds is not 1: %d", len(fds))
|
|
||||||
}
|
|
||||||
fd := uintptr(fds[0])
|
|
||||||
|
|
||||||
return os.NewFile(fd, string(name)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SendFd sends a file descriptor over the given AF_UNIX socket. In
|
|
||||||
// addition, the file.Name() of the given file will also be sent as
|
|
||||||
// non-auxiliary data in the same payload (allowing to send contextual
|
|
||||||
// information for a file descriptor).
|
|
||||||
func SendFd(socket, file *os.File) error {
|
|
||||||
name := []byte(file.Name())
|
|
||||||
if len(name) >= MaxNameLen {
|
|
||||||
return fmt.Errorf("sendfd: filename too long: %s", file.Name())
|
|
||||||
}
|
|
||||||
oob := unix.UnixRights(int(file.Fd()))
|
|
||||||
|
|
||||||
return unix.Sendmsg(int(socket.Fd()), name, oob, nil, 0)
|
|
||||||
}
|
|
126
vendor/github.com/opencontainers/runc/libcontainer/utils/utils.go
generated
vendored
126
vendor/github.com/opencontainers/runc/libcontainer/utils/utils.go
generated
vendored
@ -1,126 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rand"
|
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
exitSignalOffset = 128
|
|
||||||
)
|
|
||||||
|
|
||||||
// GenerateRandomName returns a new name joined with a prefix. This size
|
|
||||||
// specified is used to truncate the randomly generated value
|
|
||||||
func GenerateRandomName(prefix string, size int) (string, error) {
|
|
||||||
id := make([]byte, 32)
|
|
||||||
if _, err := io.ReadFull(rand.Reader, id); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if size > 64 {
|
|
||||||
size = 64
|
|
||||||
}
|
|
||||||
return prefix + hex.EncodeToString(id)[:size], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResolveRootfs ensures that the current working directory is
|
|
||||||
// not a symlink and returns the absolute path to the rootfs
|
|
||||||
func ResolveRootfs(uncleanRootfs string) (string, error) {
|
|
||||||
rootfs, err := filepath.Abs(uncleanRootfs)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return filepath.EvalSymlinks(rootfs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExitStatus returns the correct exit status for a process based on if it
|
|
||||||
// was signaled or exited cleanly
|
|
||||||
func ExitStatus(status syscall.WaitStatus) int {
|
|
||||||
if status.Signaled() {
|
|
||||||
return exitSignalOffset + int(status.Signal())
|
|
||||||
}
|
|
||||||
return status.ExitStatus()
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteJSON writes the provided struct v to w using standard json marshaling
|
|
||||||
func WriteJSON(w io.Writer, v interface{}) error {
|
|
||||||
data, err := json.Marshal(v)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = w.Write(data)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// CleanPath makes a path safe for use with filepath.Join. This is done by not
|
|
||||||
// only cleaning the path, but also (if the path is relative) adding a leading
|
|
||||||
// '/' and cleaning it (then removing the leading '/'). This ensures that a
|
|
||||||
// path resulting from prepending another path will always resolve to lexically
|
|
||||||
// be a subdirectory of the prefixed path. This is all done lexically, so paths
|
|
||||||
// that include symlinks won't be safe as a result of using CleanPath.
|
|
||||||
func CleanPath(path string) string {
|
|
||||||
// Deal with empty strings nicely.
|
|
||||||
if path == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure that all paths are cleaned (especially problematic ones like
|
|
||||||
// "/../../../../../" which can cause lots of issues).
|
|
||||||
path = filepath.Clean(path)
|
|
||||||
|
|
||||||
// If the path isn't absolute, we need to do more processing to fix paths
|
|
||||||
// such as "../../../../<etc>/some/path". We also shouldn't convert absolute
|
|
||||||
// paths to relative ones.
|
|
||||||
if !filepath.IsAbs(path) {
|
|
||||||
path = filepath.Clean(string(os.PathSeparator) + path)
|
|
||||||
// This can't fail, as (by definition) all paths are relative to root.
|
|
||||||
path, _ = filepath.Rel(string(os.PathSeparator), path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean the path again for good measure.
|
|
||||||
return filepath.Clean(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SearchLabels searches a list of key-value pairs for the provided key and
|
|
||||||
// returns the corresponding value. The pairs must be separated with '='.
|
|
||||||
func SearchLabels(labels []string, query string) string {
|
|
||||||
for _, l := range labels {
|
|
||||||
parts := strings.SplitN(l, "=", 2)
|
|
||||||
if len(parts) < 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if parts[0] == query {
|
|
||||||
return parts[1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// Annotations returns the bundle path and user defined annotations from the
|
|
||||||
// libcontainer state. We need to remove the bundle because that is a label
|
|
||||||
// added by libcontainer.
|
|
||||||
func Annotations(labels []string) (bundle string, userAnnotations map[string]string) {
|
|
||||||
userAnnotations = make(map[string]string)
|
|
||||||
for _, l := range labels {
|
|
||||||
parts := strings.SplitN(l, "=", 2)
|
|
||||||
if len(parts) < 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if parts[0] == "bundle" {
|
|
||||||
bundle = parts[1]
|
|
||||||
} else {
|
|
||||||
userAnnotations[parts[0]] = parts[1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetIntSize() int {
|
|
||||||
return int(unsafe.Sizeof(1))
|
|
||||||
}
|
|
43
vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go
generated
vendored
43
vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go
generated
vendored
@ -1,43 +0,0 @@
|
|||||||
// +build !windows
|
|
||||||
|
|
||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
func CloseExecFrom(minFd int) error {
|
|
||||||
fdList, err := ioutil.ReadDir("/proc/self/fd")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, fi := range fdList {
|
|
||||||
fd, err := strconv.Atoi(fi.Name())
|
|
||||||
if err != nil {
|
|
||||||
// ignore non-numeric file names
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if fd < minFd {
|
|
||||||
// ignore descriptors lower than our specified minimum
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// intentionally ignore errors from syscall.CloseOnExec
|
|
||||||
syscall.CloseOnExec(fd)
|
|
||||||
// the cases where this might fail are basically file descriptors that have already been closed (including and especially the one that was created when ioutil.ReadDir did the "opendir" syscall)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSockPair returns a new unix socket pair
|
|
||||||
func NewSockPair(name string) (parent *os.File, child *os.File, err error) {
|
|
||||||
fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM|syscall.SOCK_CLOEXEC, 0)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
return os.NewFile(uintptr(fds[1]), name+"-p"), os.NewFile(uintptr(fds[0]), name+"-c"), nil
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user