diff --git a/Makefile b/Makefile index c822bf76..e1ca88de 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,18 @@ PROJECT=github.com/containerd/containerd GIT_COMMIT := $(shell git rev-parse HEAD 2> /dev/null || true) GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2> /dev/null) -LDFLAGS := -X github.com/containerd/containerd.GitCommit=${GIT_COMMIT} ${LDFLAGS} +# -------------------------------------------------------------------- +# +# epoll library flags for epoll_freebsd.go +# @(kris-nova) +# +# +CFLAGS=-I /usr/local/include/libepoll-shim ${CFLAGS} +LDFLAGS := -I ld -X github.com/containerd/containerd.GitCommit=${GIT_COMMIT} ${LDFLAGS} +# +# +# -------------------------------------------------------------------- + TEST_TIMEOUT ?= 5m TEST_SUITE_TIMEOUT ?= 10m diff --git a/api/grpc/server/server_freebsd.go b/api/grpc/server/server_freebsd.go new file mode 100644 index 00000000..20bec5db --- /dev/null +++ b/api/grpc/server/server_freebsd.go @@ -0,0 +1,43 @@ +package server + +// +build freebsd + +import ( + "fmt" + + "github.com/containerd/containerd/api/grpc/types" + "github.com/containerd/containerd/specs" + "github.com/containerd/containerd/supervisor" + "golang.org/x/net/context" +) + +var clockTicksPerSecond uint64 + +func (s *apiServer) AddProcess(ctx context.Context, r *types.AddProcessRequest) (*types.AddProcessResponse, error) { + process := &specs.ProcessSpec{ + Terminal: r.Terminal, + Args: r.Args, + Env: r.Env, + Cwd: r.Cwd, + } + if r.Id == "" { + return nil, fmt.Errorf("container id cannot be empty") + } + if r.Pid == "" { + return nil, fmt.Errorf("process id cannot be empty") + } + e := &supervisor.AddProcessTask{} + e.ID = r.Id + e.PID = r.Pid + e.ProcessSpec = process + e.Stdin = r.Stdin + e.Stdout = r.Stdout + e.Stderr = r.Stderr + e.StartResponse = make(chan supervisor.StartResponse, 1) + s.sv.SendTask(e) + if err := <-e.ErrorCh(); err != nil { + return nil, err + } + <-e.StartResponse + return &types.AddProcessResponse{}, nil +} diff --git a/archutils/epoll_freebsd.go b/archutils/epoll_freebsd.go new file mode 100644 index 00000000..b638a7e7 --- /dev/null +++ b/archutils/epoll_freebsd.go @@ -0,0 +1,126 @@ +// +build freebsd + +// ----------------------------------------------------------------------------------------- +// +// (@kris-nova) +// +// Probably most of my god awful hacking is done in this file, most of this is in place to +// hack around the Go standard library since we are using a Linux package in FreeBSD.. we +// need to have certain constants defined that usually are only found based on $GOOS,. +// +// For more information or just to yell at me shoot me a line at kris@nivenly.com +// + +package archutils + +// #cgo CFLAGS: -I/usr/local/include/libepoll-shim +// #cgo LDFLAGS: -L/usr/local/lib -Ild -lepoll-shim -lrt +// #include +/* +int EpollCreate1(int flag) { + return epoll_create1(flag); +} + +int EpollCtl(int efd, int op,int sfd, int events, int fd) { + struct epoll_event event; + event.events = events; + event.data.fd = fd; + + return epoll_ctl(efd, op, sfd, &event); +} + +struct event_t { + uint32_t events; + int fd; +}; + +struct epoll_event events[128]; +int run_epoll_wait(int fd, struct event_t *event) { + int n, i; + n = epoll_wait(fd, events, 128, -1); + for (i = 0; i < n; i++) { + event[i].events = events[i].events; + event[i].fd = events[i].data.fd; + } + return n; +} +*/ +import "C" + +import ( + "fmt" + "unsafe" +) + +// EpollCreate1 calls a C implementation +func EpollCreate1(flag int) (int, error) { + fd := int(C.EpollCreate1(C.int(flag))) + if fd < 0 { + return fd, fmt.Errorf("failed to create epoll, errno is %d", fd) + } + return fd, nil +} + +type FreeBSDEpollEventInterface interface { +} + +type FreeBSDEpollEvent struct { + Events uint32 + Fd int32 + Pad int32 +} + +const ( + // ----------------------------------------------------- + // Hacking in control constants for FreeBSD Epoll port + // Note: these are not defined in the Go standard library + // so we define them here manually. Once the constants make it + // to the epoll.h file, the declaration in Go shouldn't matter. + // + // (@kris-nova) + // + FREEBSD_EPOLL_CTL_ADD = 0x1 + FREEBSD_EPOLL_CLOEXEC = 0x80000 + FREEBSD_EPOLL_CTL_DEL = 0x2 + FREEBSD_EPOLLHUP = 0x10 + FREEBSD_EPOLLIN = 0x1 + FREEBSD_SYS_EPOLL_CTL = 233 +) + +// EpollCtl is a another hack to get the sys call running without having a dependency on linux +//func EpollCtl(epfd int, op int, fd int, eventInterface FreeBSDEpollEventInterface) (err error) { +// event := eventInterface.(*FreeBSDEpollEvent) +// _, _, e1 := syscall.RawSyscall6(FREEBSD_SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0) +// if e1 != 0 {= +// err = e1 +// } +// return +//} + +// EpollCtl calls a C implementation +func EpollCtl(epfd int, op int, fd int, eventInterface FreeBSDEpollEventInterface) error { + event := eventInterface.(*FreeBSDEpollEvent) + errno := C.EpollCtl(C.int(epfd), C.int(FREEBSD_EPOLL_CTL_ADD), C.int(fd), C.int(event.Events), C.int(event.Fd)) + if errno < 0 { + return fmt.Errorf("Failed to ctl epoll") + } + return nil +} + +// EpollWait calls a C implementation +func EpollWait(epfd int, events []FreeBSDEpollEvent, msec int) (int, error) { + //var events []FreeBSDEpollEvent + //for _, e := range eventInterfaces { + // events = append(events, e.(FreeBSDEpollEvent)) + //} + var c_events [128]C.struct_event_t + n := int(C.run_epoll_wait(C.int(epfd), (*C.struct_event_t)(unsafe.Pointer(&c_events)))) + if n < 0 { + return int(n), fmt.Errorf("Failed to wait epoll") + } + for i := 0; i < n; i++ { + events[i].Fd = int32(c_events[i].fd) + events[i].Events = uint32(c_events[i].events) + } + return int(n), nil +} diff --git a/containerd-shim/console.go b/containerd-shim/console.go index 1d3262df..b18a4669 100644 --- a/containerd-shim/console.go +++ b/containerd-shim/console.go @@ -39,11 +39,15 @@ func ioctl(fd uintptr, flag, data uintptr) error { return nil } +const ( + FREEBSD_TIOCSPTLCK = 0x40045431 +) + // 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))) + return ioctl(f.Fd(), FREEBSD_TIOCSPTLCK, uintptr(unsafe.Pointer(&u))) } // ptsname retrieves the name of the first available pts for the given master. diff --git a/containerd-shim/process_freebsd.go b/containerd-shim/process_freebsd.go new file mode 100644 index 00000000..bb4cdd0a --- /dev/null +++ b/containerd-shim/process_freebsd.go @@ -0,0 +1,190 @@ +// +build freebsd + +package main + +import ( + "fmt" + "io" + "os/exec" + "syscall" + "time" + + "github.com/containerd/console" + "github.com/containerd/containerd/osutils" + runc "github.com/containerd/go-runc" + "github.com/tonistiigi/fifo" + "golang.org/x/net/context" +) + +// openIO opens the pre-created fifo's for use with the container +// in RDWR so that they remain open if the other side stops listening +func (p *process) openIO() error { + p.stdio = &stdio{} + var ( + uid = p.state.RootUID + gid = p.state.RootGID + ) + + ctx, _ := context.WithTimeout(context.Background(), 15*time.Second) + + stdinCloser, err := fifo.OpenFifo(ctx, p.state.Stdin, syscall.O_WRONLY|syscall.O_NONBLOCK, 0) + if err != nil { + return err + } + p.stdinCloser = stdinCloser + + if p.state.Terminal { + socket, err := runc.NewTempConsoleSocket() + if err != nil { + return err + } + p.socket = socket + consoleCh := p.waitConsole(socket) + + stdin, err := fifo.OpenFifo(ctx, p.state.Stdin, syscall.O_RDONLY, 0) + if err != nil { + return err + } + stdoutw, err := fifo.OpenFifo(ctx, p.state.Stdout, syscall.O_WRONLY, 0) + if err != nil { + return err + } + stdoutr, err := fifo.OpenFifo(ctx, p.state.Stdout, syscall.O_RDONLY, 0) + if err != nil { + return err + } + // open the fifos but wait until we receive the console before we start + // copying data back and forth between the two + go p.setConsole(consoleCh, stdin, stdoutw) + + p.Add(1) + p.ioCleanupFn = func() { + stdoutr.Close() + stdoutw.Close() + } + return nil + } + close(p.consoleErrCh) + i, err := p.initializeIO(uid, gid) + if err != nil { + return err + } + p.shimIO = i + // non-tty + ioClosers := []io.Closer{} + for _, pair := range []struct { + name string + dest func(wc io.WriteCloser, rc io.Closer) + }{ + { + p.state.Stdout, + func(wc io.WriteCloser, rc io.Closer) { + p.Add(1) + go func() { + io.Copy(wc, i.Stdout) + p.Done() + }() + }, + }, + { + p.state.Stderr, + func(wc io.WriteCloser, rc io.Closer) { + p.Add(1) + go func() { + io.Copy(wc, i.Stderr) + p.Done() + }() + }, + }, + } { + fw, err := fifo.OpenFifo(ctx, pair.name, syscall.O_WRONLY, 0) + if err != nil { + return fmt.Errorf("containerd-shim: opening %s failed: %s", pair.name, err) + } + fr, err := fifo.OpenFifo(ctx, pair.name, syscall.O_RDONLY, 0) + if err != nil { + return fmt.Errorf("containerd-shim: opening %s failed: %s", pair.name, err) + } + pair.dest(fw, fr) + ioClosers = append(ioClosers, fw, fr) + } + + f, err := fifo.OpenFifo(ctx, p.state.Stdin, syscall.O_RDONLY, 0) + if err != nil { + return fmt.Errorf("containerd-shim: opening %s failed: %s", p.state.Stdin, err) + } + p.ioCleanupFn = func() { + for _, c := range ioClosers { + c.Close() + } + } + go func() { + io.Copy(i.Stdin, f) + i.Stdin.Close() + f.Close() + }() + + return nil +} + +func (p *process) Wait() { + p.WaitGroup.Wait() + if p.ioCleanupFn != nil { + p.ioCleanupFn() + } + if p.console != nil { + p.console.Close() + } +} + +func (p *process) killAll() error { + if !p.state.Exec { + cmd := exec.Command(p.runtime, append(p.state.RuntimeArgs, "kill", "--all", p.id, "SIGKILL")...) + cmd.SysProcAttr = osutils.SetPDeathSig() + out, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("%s: %v", out, err) + } + } + return nil +} + +func (p *process) setConsole(c <-chan *consoleR, stdin io.Reader, stdout io.Writer) { + r := <-c + if r.err != nil { + p.consoleErrCh <- r.err + return + } + close(p.consoleErrCh) + p.console = r.c + // copy from the console into the provided fifos + go io.Copy(r.c, stdin) + go func() { + io.Copy(stdout, r.c) + p.Done() + }() +} + +type consoleR struct { + c console.Console + err error +} + +func (p *process) waitConsole(socket *runc.Socket) <-chan *consoleR { + c := make(chan *consoleR, 1) + go func() { + master, err := socket.ReceiveMaster() + socket.Close() + if err != nil { + c <- &consoleR{ + err: err, + } + return + } + c <- &consoleR{ + c: master, + } + }() + return c + +} diff --git a/containerd/main_freebsd.go b/containerd/main_freebsd.go new file mode 100644 index 00000000..cdc877d0 --- /dev/null +++ b/containerd/main_freebsd.go @@ -0,0 +1,6 @@ +package main + +// +build freebsd + +func processMetrics() { +} diff --git a/osutils/pdeathsig_freebsd.go b/osutils/pdeathsig_freebsd.go new file mode 100644 index 00000000..4dea8939 --- /dev/null +++ b/osutils/pdeathsig_freebsd.go @@ -0,0 +1,15 @@ +// +build freebsd + +package osutils + +import ( + "syscall" +) + +// SetPDeathSig sets the parent death signal to SIGKILL so that if the +// shim dies the container process also dies. +func SetPDeathSig() *syscall.SysProcAttr { + return &syscall.SysProcAttr{ + //Pdeathsig: syscall.SIGKILL, + } +} diff --git a/osutils/prctl_freebsd.go b/osutils/prctl_freebsd.go new file mode 100644 index 00000000..04d923d2 --- /dev/null +++ b/osutils/prctl_freebsd.go @@ -0,0 +1,17 @@ +// +build freebsd + +package osutils + +import ( + "errors" +) + +// GetSubreaper returns the subreaper setting for the calling process +func GetSubreaper() (int, error) { + return 0, errors.New("osutils GetSubreaper not implemented on FreeBSD") +} + +// SetSubreaper sets the value i as the subreaper setting for the calling process +func SetSubreaper(i int) error { + return nil +} diff --git a/runtime/container_freebsd.go b/runtime/container_freebsd.go new file mode 100644 index 00000000..5b8744a0 --- /dev/null +++ b/runtime/container_freebsd.go @@ -0,0 +1,192 @@ +package runtime + +// +build freebsd + +import ( + "bufio" + "bytes" + "encoding/json" + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + "syscall" + + "github.com/containerd/containerd/specs" + ocs "github.com/opencontainers/runtime-spec/specs-go" +) + +func findCgroupMountpointAndRoot(pid int, subsystem string) (string, string, error) { + f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid)) + if err != nil { + return "", "", err + } + defer f.Close() + + scanner := bufio.NewScanner(f) + for scanner.Scan() { + txt := scanner.Text() + fields := strings.Split(txt, " ") + for _, opt := range strings.Split(fields[len(fields)-1], ",") { + if opt == subsystem { + return fields[4], fields[3], nil + } + } + } + if err := scanner.Err(); err != nil { + return "", "", err + } + + return "", "", fmt.Errorf("cgroup path for %s not found", subsystem) +} + +func parseCgroupFile(path string) (map[string]string, error) { + f, err := os.Open(path) + if err != nil { + return nil, err + } + defer f.Close() + + s := bufio.NewScanner(f) + cgroups := make(map[string]string) + + for s.Scan() { + if err := s.Err(); err != nil { + return nil, err + } + + text := s.Text() + parts := strings.Split(text, ":") + + for _, subs := range strings.Split(parts[1], ",") { + cgroups[subs] = parts[2] + } + } + return cgroups, nil +} + +func (c *container) OOM() (OOM, error) { + p := c.processes[InitProcessID] + if p == nil { + return nil, fmt.Errorf("no init process found") + } + + mountpoint, hostRoot, err := findCgroupMountpointAndRoot(os.Getpid(), "memory") + if err != nil { + return nil, err + } + + cgroups, err := parseCgroupFile(fmt.Sprintf("/proc/%d/cgroup", p.pid)) + if err != nil { + return nil, err + } + + root, ok := cgroups["memory"] + if !ok { + return nil, fmt.Errorf("no memory cgroup for container %s", c.ID()) + } + + // Take care of the case were we're running inside a container + // ourself + root = strings.TrimPrefix(root, hostRoot) + + return c.getMemoryEventFD(filepath.Join(mountpoint, root)) +} + +func (c *container) Pids() ([]int, error) { + var pids []int + args := c.runtimeArgs + args = append(args, "ps", "--format=json", c.id) + out, err := exec.Command(c.runtime, args...).CombinedOutput() + if err != nil { + return nil, fmt.Errorf("%s: %q", err.Error(), out) + } + if err := json.Unmarshal(out, &pids); err != nil { + return nil, err + } + return pids, nil +} + +func u64Ptr(i uint64) *uint64 { return &i } +func i64Ptr(i int64) *int64 { return &i } + +func (c *container) UpdateResources(r *Resource) error { + sr := ocs.LinuxResources{ + Memory: &ocs.LinuxMemory{ + Limit: u64Ptr(uint64(r.Memory)), + Reservation: u64Ptr(uint64(r.MemoryReservation)), + Swap: u64Ptr(uint64(r.MemorySwap)), + Kernel: u64Ptr(uint64(r.KernelMemory)), + KernelTCP: u64Ptr(uint64(r.KernelTCPMemory)), + }, + CPU: &ocs.LinuxCPU{ + Shares: u64Ptr(uint64(r.CPUShares)), + Quota: i64Ptr(int64(r.CPUQuota)), + Period: u64Ptr(uint64(r.CPUPeriod)), + Cpus: r.CpusetCpus, + Mems: r.CpusetMems, + }, + BlockIO: &ocs.LinuxBlockIO{ + Weight: &r.BlkioWeight, + }, + Pids: &ocs.LinuxPids{ + Limit: r.PidsLimit, + }, + } + + srStr := bytes.NewBuffer(nil) + if err := json.NewEncoder(srStr).Encode(&sr); err != nil { + return err + } + + args := c.runtimeArgs + args = append(args, "update", "-r", "-", c.id) + cmd := exec.Command(c.runtime, args...) + cmd.Stdin = srStr + b, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf(string(b)) + } + return nil +} + +func getRootIDs(s *specs.Spec) (int, int, error) { + if s == nil { + return 0, 0, nil + } + var hasUserns bool + for _, ns := range s.Linux.Namespaces { + if ns.Type == ocs.UserNamespace { + hasUserns = true + break + } + } + if !hasUserns { + return 0, 0, nil + } + uid := hostIDFromMap(0, s.Linux.UIDMappings) + gid := hostIDFromMap(0, s.Linux.GIDMappings) + return uid, gid, nil +} + +func (c *container) getMemoryEventFD(root string) (*oom, error) { + f, err := os.Open(filepath.Join(root, "memory.oom_control")) + if err != nil { + return nil, err + } + defer f.Close() + fd, _, serr := syscall.RawSyscall(syscall.SYS_KEVENT, 0, syscall.FD_CLOEXEC, 0) + if serr != 0 { + return nil, serr + } + if err := c.writeEventFD(root, int(f.Fd()), int(fd)); err != nil { + syscall.Close(int(fd)) + return nil, err + } + return &oom{ + root: root, + id: c.id, + eventfd: int(fd), + }, nil +} diff --git a/runtime/process_freebsd.go b/runtime/process_freebsd.go new file mode 100644 index 00000000..03e686a2 --- /dev/null +++ b/runtime/process_freebsd.go @@ -0,0 +1,22 @@ +// +build freebsd + +package runtime + +import ( + "io/ioutil" + "path/filepath" + "strconv" +) + +func (p *process) getPidFromFile() (int, error) { + data, err := ioutil.ReadFile(filepath.Join(p.root, "pid")) + if err != nil { + return -1, err + } + i, err := strconv.Atoi(string(data)) + if err != nil { + return -1, errInvalidPidInt + } + p.pid = i + return i, nil +} diff --git a/supervisor/monitor_freebsd.go b/supervisor/monitor_freebsd.go new file mode 100644 index 00000000..895e3979 --- /dev/null +++ b/supervisor/monitor_freebsd.go @@ -0,0 +1,149 @@ +// +build freebsd + +package supervisor + +import ( + "sync" + "syscall" + + "github.com/Sirupsen/logrus" + "github.com/containerd/containerd/archutils" + "github.com/containerd/containerd/runtime" +) + +// NewMonitor starts a new process monitor and returns it +func NewMonitor() (*Monitor, error) { + m := &Monitor{ + receivers: make(map[int]interface{}), + exits: make(chan runtime.Process, 1024), + ooms: make(chan string, 1024), + } + fd, err := archutils.EpollCreate1(archutils.FREEBSD_EPOLL_CLOEXEC) + if err != nil { + return nil, err + } + m.epollFd = fd + go m.start() + return m, nil +} + +// Monitor represents a runtime.Process monitor +type Monitor struct { + m sync.Mutex + receivers map[int]interface{} + exits chan runtime.Process + ooms chan string + epollFd int +} + +// Exits returns the channel used to notify of a process exit +func (m *Monitor) Exits() chan runtime.Process { + return m.exits +} + +// OOMs returns the channel used to notify of a container exit due to OOM +func (m *Monitor) OOMs() chan string { + return m.ooms +} + +// Monitor adds a process to the list of the one being monitored +func (m *Monitor) Monitor(p runtime.Process) error { + m.m.Lock() + defer m.m.Unlock() + fd := p.ExitFD() + event := archutils.FreeBSDEpollEvent{ + Fd: int32(fd), + Events: archutils.FREEBSD_EPOLLHUP, + } + if err := archutils.EpollCtl(m.epollFd, archutils.FREEBSD_EPOLL_CTL_ADD, fd, &event); err != nil { + return err + } + EpollFdCounter.Inc(1) + m.receivers[fd] = p + return nil +} + +// MonitorOOM adds a container to the list of the ones monitored for OOM +func (m *Monitor) MonitorOOM(c runtime.Container) error { + m.m.Lock() + defer m.m.Unlock() + o, err := c.OOM() + if err != nil { + return err + } + fd := o.FD() + event := archutils.FreeBSDEpollEvent{ + Fd: int32(fd), + Events: archutils.FREEBSD_EPOLLHUP | archutils.FREEBSD_EPOLLIN, + } + if err := archutils.EpollCtl(m.epollFd, archutils.FREEBSD_EPOLL_CTL_ADD, fd, &event); err != nil { + return err + } + EpollFdCounter.Inc(1) + m.receivers[fd] = o + return nil +} + +// Close cleans up resources allocated by NewMonitor() +func (m *Monitor) Close() error { + return syscall.Close(m.epollFd) +} + +func (m *Monitor) processEvent(fd int, event uint32) { + m.m.Lock() + r := m.receivers[fd] + switch t := r.(type) { + case runtime.Process: + if event == archutils.FREEBSD_EPOLLHUP { + delete(m.receivers, fd) + if err := archutils.EpollCtl(m.epollFd, archutils.FREEBSD_EPOLL_CTL_DEL, fd, &archutils.FreeBSDEpollEvent{ + Events: archutils.FREEBSD_EPOLLHUP, + Fd: int32(fd), + }); err != nil { + logrus.WithField("error", err).Error("containerd: epoll remove fd") + } + if err := t.Close(); err != nil { + logrus.WithField("error", err).Error("containerd: close process IO") + } + EpollFdCounter.Dec(1) + // defer until lock is released + defer func() { + m.exits <- t + }() + } + case runtime.OOM: + // always flush the event fd + t.Flush() + if t.Removed() { + delete(m.receivers, fd) + // epoll will remove the fd from its set after it has been closed + t.Close() + EpollFdCounter.Dec(1) + } else { + // defer until lock is released + defer func() { + m.ooms <- t.ContainerID() + }() + } + } + // This cannot be a defer to avoid a deadlock in case the channels + // above get full + m.m.Unlock() +} + +func (m *Monitor) start() { + var events [128]archutils.FreeBSDEpollEvent + for { + n, err := archutils.EpollWait(m.epollFd, events[:], -1) + if err != nil { + if err == syscall.EINTR { + continue + } + logrus.WithField("error", err).Fatal("containerd: epoll wait") + } + // process events + for i := 0; i < n; i++ { + m.processEvent(int(events[i].Fd), events[i].Events) + } + } +} diff --git a/vendor/src/github.com/cloudfoundry/gosigar/sigar_freebsd.go b/vendor/src/github.com/cloudfoundry/gosigar/sigar_freebsd.go new file mode 100644 index 00000000..e81bcfa6 --- /dev/null +++ b/vendor/src/github.com/cloudfoundry/gosigar/sigar_freebsd.go @@ -0,0 +1,52 @@ +// ------------------------------------------------------- +// FreeBSD stub for compiling sigar +// @(kris-nova) +// +// Adding out stubs here to get sigar compiling without an +// implementation, this patch should handle getting docker +// working, and the Go compiler happy and NOTHING more. + +// +build freebsd + +package sigar + +import "syscall" + +func (self *FileSystemUsage) Get(path string) error { + stat := syscall.Statfs_t{} + err := syscall.Statfs(path, &stat) + if err != nil { + return err + } + + bsize := stat.Bsize / 512 + + self.Total = (uint64(stat.Blocks) * uint64(bsize)) >> 1 + self.Free = (uint64(stat.Bfree) * uint64(bsize)) >> 1 + self.Avail = (uint64(stat.Bavail) * uint64(bsize)) >> 1 + self.Used = self.Total - self.Free + self.Files = stat.Files + self.FreeFiles = uint64(stat.Ffree) + + return nil +} + +func (self *Cpu) Get() error { + return nil +} + +func (self *Mem) Get() error { + return nil +} + +func (self *Swap) Get() error { + return nil +} + +func (self *LoadAverage) Get() error { + return nil +} + +func (self *CpuList) Get() error { + return nil +} diff --git a/vendor/src/github.com/cloudfoundry/gosigar/sigar_unix.go b/vendor/src/github.com/cloudfoundry/gosigar/sigar_unix.go index 39f18784..fe8c5fba 100644 --- a/vendor/src/github.com/cloudfoundry/gosigar/sigar_unix.go +++ b/vendor/src/github.com/cloudfoundry/gosigar/sigar_unix.go @@ -1,6 +1,6 @@ // Copyright (c) 2012 VMware, Inc. -// +build darwin freebsd linux netbsd openbsd +// +build darwin linux netbsd openbsd package sigar @@ -23,4 +23,4 @@ func (self *FileSystemUsage) Get(path string) error { self.FreeFiles = stat.Ffree return nil -} +} \ No newline at end of file diff --git a/vendor/src/github.com/containerd/go-runc/runc.go b/vendor/src/github.com/containerd/go-runc/runc.go index 9515deb7..e49110b5 100644 --- a/vendor/src/github.com/containerd/go-runc/runc.go +++ b/vendor/src/github.com/containerd/go-runc/runc.go @@ -531,7 +531,7 @@ func (r *Runc) command(context context.Context, args ...string) *exec.Cmd { cmd := exec.CommandContext(context, command, append(r.args(), args...)...) if r.PdeathSignal != 0 { cmd.SysProcAttr = &syscall.SysProcAttr{ - Pdeathsig: r.PdeathSignal, + //Pdeathsig: r.PdeathSignal, } } return cmd diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/utils/cmsg_freebsd.go b/vendor/src/github.com/opencontainers/runc/libcontainer/utils/cmsg_freebsd.go new file mode 100644 index 00000000..2f69d2f2 --- /dev/null +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/utils/cmsg_freebsd.go @@ -0,0 +1,95 @@ +// +build freebsd + +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) +} diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/utils/utils.go b/vendor/src/github.com/opencontainers/runc/libcontainer/utils/utils.go index 2b35b9a7..fc5ca117 100644 --- a/vendor/src/github.com/opencontainers/runc/libcontainer/utils/utils.go +++ b/vendor/src/github.com/opencontainers/runc/libcontainer/utils/utils.go @@ -124,3 +124,4 @@ func Annotations(labels []string) (bundle string, userAnnotations map[string]str func GetIntSize() int { return int(unsafe.Sizeof(1)) } + diff --git a/vendor/src/github.com/tonistiigi/fifo/handle_nolinux.go b/vendor/src/github.com/tonistiigi/fifo/handle_nolinux.go index 8c20e074..75597390 100644 --- a/vendor/src/github.com/tonistiigi/fifo/handle_nolinux.go +++ b/vendor/src/github.com/tonistiigi/fifo/handle_nolinux.go @@ -23,7 +23,7 @@ func getHandle(fn string) (*handle, error) { h := &handle{ fn: fn, dev: uint64(stat.Dev), - ino: stat.Ino, + ino: uint64(stat.Ino), } return h, nil @@ -34,7 +34,7 @@ func (h *handle) Path() (string, error) { if err := syscall.Stat(h.fn, &stat); err != nil { return "", errors.Wrapf(err, "path %v could not be statted", h.fn) } - if uint64(stat.Dev) != h.dev || stat.Ino != h.ino { + if uint64(stat.Dev) != h.dev || uint64(stat.Ino) != h.ino { return "", errors.Errorf("failed to verify handle %v/%v %v/%v", stat.Dev, h.dev, stat.Ino, h.ino) } return h.fn, nil