diff --git a/archive/tar_linux.go b/archive/tar_unix.go similarity index 99% rename from archive/tar_linux.go rename to archive/tar_unix.go index 6ec8f4cba..107d1a572 100644 --- a/archive/tar_linux.go +++ b/archive/tar_unix.go @@ -1,3 +1,5 @@ +// +build !windows + package archive import ( diff --git a/archive/time_darwin.go b/archive/time_darwin.go new file mode 100644 index 000000000..2ac517a91 --- /dev/null +++ b/archive/time_darwin.go @@ -0,0 +1,14 @@ +package archive + +import ( + "time" + + "github.com/pkg/errors" +) + +// as at MacOS 10.12 there is apparently no way to set timestamps +// with nanosecond precision. We could fall back to utimes/lutimes +// and lose the precision as a temporary workaround. +func chtimes(path string, atime, mtime time.Time) error { + return errors.New("OSX missing UtimesNanoAt") +} diff --git a/archive/time_linux.go b/archive/time_unix.go similarity index 94% rename from archive/time_linux.go rename to archive/time_unix.go index 486360881..5f17084f2 100644 --- a/archive/time_linux.go +++ b/archive/time_unix.go @@ -1,3 +1,5 @@ +// +build linux freebsd + package archive import ( diff --git a/cmd/containerd/builtins_unix.go b/cmd/containerd/builtins_unix.go new file mode 100644 index 000000000..15133150e --- /dev/null +++ b/cmd/containerd/builtins_unix.go @@ -0,0 +1,7 @@ +// +build darwin freebsd + +package main + +import ( + _ "github.com/containerd/containerd/snapshot/naive" +) diff --git a/cmd/containerd/config_linux.go b/cmd/containerd/config_linux.go new file mode 100644 index 000000000..64863fa02 --- /dev/null +++ b/cmd/containerd/config_linux.go @@ -0,0 +1,16 @@ +package main + +func defaultConfig() *config { + return &config{ + Root: "/var/lib/containerd", + State: "/run/containerd", + GRPC: grpcConfig{ + Address: "/run/containerd/containerd.sock", + }, + Debug: debug{ + Level: "info", + Address: "/run/containerd/debug.sock", + }, + Snapshotter: "overlay", + } +} diff --git a/cmd/containerd/config_unix.go b/cmd/containerd/config_unix.go index 7cb00625f..358969bae 100644 --- a/cmd/containerd/config_unix.go +++ b/cmd/containerd/config_unix.go @@ -1,4 +1,4 @@ -// +build !windows +// +build darwin freebsd package main @@ -13,6 +13,6 @@ func defaultConfig() *config { Level: "info", Address: "/run/containerd/debug.sock", }, - Snapshotter: "overlay", + Snapshotter: "naive", } } diff --git a/cmd/containerd/main_linux.go b/cmd/containerd/main_linux.go new file mode 100644 index 000000000..0717e785b --- /dev/null +++ b/cmd/containerd/main_linux.go @@ -0,0 +1,59 @@ +package main + +import ( + "os" + + "golang.org/x/sys/unix" + + "github.com/containerd/containerd/log" + "github.com/containerd/containerd/reaper" + "github.com/containerd/containerd/sys" + "github.com/urfave/cli" + "google.golang.org/grpc" +) + +const ( + defaultConfigPath = "/etc/containerd/config.toml" +) + +var ( + handledSignals = []os.Signal{unix.SIGTERM, unix.SIGINT, unix.SIGUSR1, unix.SIGCHLD} +) + +func platformInit(context *cli.Context) error { + if conf.Subreaper { + log.G(global).Info("setting subreaper...") + if err := sys.SetSubreaper(1); err != nil { + return err + } + } + if conf.OOMScore != 0 { + log.G(global).Infof("changing OOM score to %d", conf.OOMScore) + if err := sys.SetOOMScore(os.Getpid(), conf.OOMScore); err != nil { + return err + } + } + if err := os.MkdirAll(conf.State, 0750); err != nil { + return err + } + if err := os.Chown(conf.State, conf.GRPC.Uid, conf.GRPC.Gid); err != nil { + return err + } + return nil +} + +func handleSignals(signals chan os.Signal, server *grpc.Server) error { + for s := range signals { + log.G(global).WithField("signal", s).Debug("received signal") + switch s { + case unix.SIGCHLD: + if err := reaper.Reap(); err != nil { + log.G(global).WithError(err).Error("reap containerd processes") + } + default: + server.Stop() + return nil + } + } + return nil +} diff --git a/cmd/containerd/main_unix.go b/cmd/containerd/main_unix.go index 74274f211..24ccab7e2 100644 --- a/cmd/containerd/main_unix.go +++ b/cmd/containerd/main_unix.go @@ -1,4 +1,4 @@ -// +build !windows +// +build darwin freebsd package main @@ -9,7 +9,6 @@ import ( "github.com/containerd/containerd/log" "github.com/containerd/containerd/reaper" - "github.com/containerd/containerd/sys" "github.com/urfave/cli" "google.golang.org/grpc" ) @@ -23,18 +22,6 @@ var ( ) func platformInit(context *cli.Context) error { - if conf.Subreaper { - log.G(global).Info("setting subreaper...") - if err := sys.SetSubreaper(1); err != nil { - return err - } - } - if conf.OOMScore != 0 { - log.G(global).Infof("changing OOM score to %d", conf.OOMScore) - if err := sys.SetOOMScore(os.Getpid(), conf.OOMScore); err != nil { - return err - } - } if err := os.MkdirAll(conf.State, 0750); err != nil { return err } diff --git a/cmd/ctr/shim.go b/cmd/ctr/shim.go index 44165b8d7..a7e823561 100644 --- a/cmd/ctr/shim.go +++ b/cmd/ctr/shim.go @@ -1,4 +1,4 @@ -// +build linux +// +build !windows package main diff --git a/cmd/ctr/signals_linux.go b/cmd/ctr/signals_linux.go new file mode 100644 index 000000000..cb17133c2 --- /dev/null +++ b/cmd/ctr/signals_linux.go @@ -0,0 +1,45 @@ +package main + +import ( + "syscall" + + "golang.org/x/sys/unix" +) + +var signalMap = map[string]syscall.Signal{ + "ABRT": unix.SIGABRT, + "ALRM": unix.SIGALRM, + "BUS": unix.SIGBUS, + "CHLD": unix.SIGCHLD, + "CLD": unix.SIGCLD, + "CONT": unix.SIGCONT, + "FPE": unix.SIGFPE, + "HUP": unix.SIGHUP, + "ILL": unix.SIGILL, + "INT": unix.SIGINT, + "IO": unix.SIGIO, + "IOT": unix.SIGIOT, + "KILL": unix.SIGKILL, + "PIPE": unix.SIGPIPE, + "POLL": unix.SIGPOLL, + "PROF": unix.SIGPROF, + "PWR": unix.SIGPWR, + "QUIT": unix.SIGQUIT, + "SEGV": unix.SIGSEGV, + "STKFLT": unix.SIGSTKFLT, + "STOP": unix.SIGSTOP, + "SYS": unix.SIGSYS, + "TERM": unix.SIGTERM, + "TRAP": unix.SIGTRAP, + "TSTP": unix.SIGTSTP, + "TTIN": unix.SIGTTIN, + "TTOU": unix.SIGTTOU, + "UNUSED": unix.SIGUNUSED, + "URG": unix.SIGURG, + "USR1": unix.SIGUSR1, + "USR2": unix.SIGUSR2, + "VTALRM": unix.SIGVTALRM, + "WINCH": unix.SIGWINCH, + "XCPU": unix.SIGXCPU, + "XFSZ": unix.SIGXFSZ, +} diff --git a/cmd/ctr/signals_unix.go b/cmd/ctr/signals_unix.go new file mode 100644 index 000000000..f7b962f17 --- /dev/null +++ b/cmd/ctr/signals_unix.go @@ -0,0 +1,42 @@ +// +build darwin freebsd + +package main + +import ( + "syscall" + + "golang.org/x/sys/unix" +) + +var signalMap = map[string]syscall.Signal{ + "ABRT": unix.SIGABRT, + "ALRM": unix.SIGALRM, + "BUS": unix.SIGBUS, + "CHLD": unix.SIGCHLD, + "CONT": unix.SIGCONT, + "FPE": unix.SIGFPE, + "HUP": unix.SIGHUP, + "ILL": unix.SIGILL, + "INT": unix.SIGINT, + "IO": unix.SIGIO, + "IOT": unix.SIGIOT, + "KILL": unix.SIGKILL, + "PIPE": unix.SIGPIPE, + "PROF": unix.SIGPROF, + "QUIT": unix.SIGQUIT, + "SEGV": unix.SIGSEGV, + "STOP": unix.SIGSTOP, + "SYS": unix.SIGSYS, + "TERM": unix.SIGTERM, + "TRAP": unix.SIGTRAP, + "TSTP": unix.SIGTSTP, + "TTIN": unix.SIGTTIN, + "TTOU": unix.SIGTTOU, + "URG": unix.SIGURG, + "USR1": unix.SIGUSR1, + "USR2": unix.SIGUSR2, + "VTALRM": unix.SIGVTALRM, + "WINCH": unix.SIGWINCH, + "XCPU": unix.SIGXCPU, + "XFSZ": unix.SIGXFSZ, +} diff --git a/cmd/ctr/utils_unix.go b/cmd/ctr/utils_unix.go index 6d07f25b9..9ef2fcd37 100644 --- a/cmd/ctr/utils_unix.go +++ b/cmd/ctr/utils_unix.go @@ -17,7 +17,6 @@ import ( "github.com/pkg/errors" "github.com/tonistiigi/fifo" "github.com/urfave/cli" - "golang.org/x/sys/unix" "google.golang.org/grpc" "google.golang.org/grpc/grpclog" ) @@ -100,41 +99,3 @@ func getGRPCConnection(context *cli.Context) (*grpc.ClientConn, error) { grpcConn = conn return grpcConn, nil } - -var signalMap = map[string]syscall.Signal{ - "ABRT": unix.SIGABRT, - "ALRM": unix.SIGALRM, - "BUS": unix.SIGBUS, - "CHLD": unix.SIGCHLD, - "CLD": unix.SIGCLD, - "CONT": unix.SIGCONT, - "FPE": unix.SIGFPE, - "HUP": unix.SIGHUP, - "ILL": unix.SIGILL, - "INT": unix.SIGINT, - "IO": unix.SIGIO, - "IOT": unix.SIGIOT, - "KILL": unix.SIGKILL, - "PIPE": unix.SIGPIPE, - "POLL": unix.SIGPOLL, - "PROF": unix.SIGPROF, - "PWR": unix.SIGPWR, - "QUIT": unix.SIGQUIT, - "SEGV": unix.SIGSEGV, - "STKFLT": unix.SIGSTKFLT, - "STOP": unix.SIGSTOP, - "SYS": unix.SIGSYS, - "TERM": unix.SIGTERM, - "TRAP": unix.SIGTRAP, - "TSTP": unix.SIGTSTP, - "TTIN": unix.SIGTTIN, - "TTOU": unix.SIGTTOU, - "UNUSED": unix.SIGUNUSED, - "URG": unix.SIGURG, - "USR1": unix.SIGUSR1, - "USR2": unix.SIGUSR2, - "VTALRM": unix.SIGVTALRM, - "WINCH": unix.SIGWINCH, - "XCPU": unix.SIGXCPU, - "XFSZ": unix.SIGXFSZ, -} diff --git a/content/store_linux.go b/content/store_linux.go new file mode 100644 index 000000000..ed25f0c8e --- /dev/null +++ b/content/store_linux.go @@ -0,0 +1,15 @@ +package content + +import ( + "os" + "syscall" + "time" +) + +func getStartTime(fi os.FileInfo) time.Time { + if st, ok := fi.Sys().(*syscall.Stat_t); ok { + return time.Unix(int64(st.Ctim.Sec), int64(st.Ctim.Nsec)) + } + + return fi.ModTime() +} diff --git a/content/store_unix.go b/content/store_unix.go index 9d334c909..a7c6b1b5a 100644 --- a/content/store_unix.go +++ b/content/store_unix.go @@ -1,4 +1,4 @@ -// +build linux +// +build darwin freebsd package content @@ -10,7 +10,7 @@ import ( func getStartTime(fi os.FileInfo) time.Time { if st, ok := fi.Sys().(*syscall.Stat_t); ok { - return time.Unix(int64(st.Ctim.Sec), int64(st.Ctim.Nsec)) + return time.Unix(int64(st.Ctimespec.Sec), int64(st.Ctimespec.Nsec)) } return fi.ModTime() diff --git a/fs/copy_unix.go b/fs/copy_unix.go new file mode 100644 index 000000000..4a6cce49d --- /dev/null +++ b/fs/copy_unix.go @@ -0,0 +1,65 @@ +// +build darwin freebsd + +package fs + +import ( + "io" + "os" + "syscall" + + "github.com/containerd/continuity/sysx" + "github.com/pkg/errors" +) + +func copyFileInfo(fi os.FileInfo, name string) error { + st := fi.Sys().(*syscall.Stat_t) + if err := os.Lchown(name, int(st.Uid), int(st.Gid)); err != nil { + return errors.Wrapf(err, "failed to chown %s", name) + } + + if (fi.Mode() & os.ModeSymlink) != os.ModeSymlink { + if err := os.Chmod(name, fi.Mode()); err != nil { + return errors.Wrapf(err, "failed to chmod %s", name) + } + } + + if err := syscall.UtimesNano(name, []syscall.Timespec{st.Atimespec, st.Mtimespec}); err != nil { + return errors.Wrapf(err, "failed to utime %s", name) + } + + return nil +} + +func copyFileContent(dst, src *os.File) error { + buf := bufferPool.Get().([]byte) + _, err := io.CopyBuffer(dst, src, buf) + bufferPool.Put(buf) + + return err +} + +func copyXAttrs(dst, src string) error { + xattrKeys, err := sysx.LListxattr(src) + if err != nil { + return errors.Wrapf(err, "failed to list xattrs on %s", src) + } + for _, xattr := range xattrKeys { + data, err := sysx.LGetxattr(src, xattr) + if err != nil { + return errors.Wrapf(err, "failed to get xattr %q on %s", xattr, src) + } + if err := sysx.LSetxattr(dst, xattr, data, 0); err != nil { + return errors.Wrapf(err, "failed to set xattr %q on %s", xattr, dst) + } + } + + return nil +} + +func copyDevice(dst string, fi os.FileInfo) error { + st, ok := fi.Sys().(*syscall.Stat_t) + if !ok { + return errors.New("unsupported stat type") + } + return syscall.Mknod(dst, uint32(fi.Mode()), int(st.Rdev)) +} diff --git a/fs/diff_linux.go b/fs/diff_unix.go similarity index 99% rename from fs/diff_linux.go rename to fs/diff_unix.go index 7580f09bc..14add16cd 100644 --- a/fs/diff_linux.go +++ b/fs/diff_unix.go @@ -1,3 +1,5 @@ +// +build !windows + package fs import ( diff --git a/fs/du_unix.go b/fs/du_unix.go index ad9bfe5b3..3178df5ca 100644 --- a/fs/du_unix.go +++ b/fs/du_unix.go @@ -27,7 +27,7 @@ func diskUsage(roots ...string) (Usage, error) { } stat := fi.Sys().(*syscall.Stat_t) - inodes[inode{dev: stat.Dev, ino: stat.Ino}] = struct{}{} + inodes[inode{dev: uint64(stat.Dev), ino: stat.Ino}] = struct{}{} size += fi.Size() return nil }); err != nil { diff --git a/mount_linux.go b/mount_linux.go new file mode 100644 index 000000000..85c652a70 --- /dev/null +++ b/mount_linux.go @@ -0,0 +1,70 @@ +package containerd + +import ( + "strings" + + "golang.org/x/sys/unix" +) + +func (m *Mount) Mount(target string) error { + flags, data := parseMountOptions(m.Options) + return unix.Mount(m.Source, target, m.Type, uintptr(flags), data) +} + +func Unmount(mount string, flags int) error { + return unix.Unmount(mount, flags) +} + +// parseMountOptions takes fstab style mount options and parses them for +// use with a standard mount() syscall +func parseMountOptions(options []string) (int, string) { + var ( + flag int + data []string + ) + flags := map[string]struct { + clear bool + flag int + }{ + "async": {true, unix.MS_SYNCHRONOUS}, + "atime": {true, unix.MS_NOATIME}, + "bind": {false, unix.MS_BIND}, + "defaults": {false, 0}, + "dev": {true, unix.MS_NODEV}, + "diratime": {true, unix.MS_NODIRATIME}, + "dirsync": {false, unix.MS_DIRSYNC}, + "exec": {true, unix.MS_NOEXEC}, + "mand": {false, unix.MS_MANDLOCK}, + "noatime": {false, unix.MS_NOATIME}, + "nodev": {false, unix.MS_NODEV}, + "nodiratime": {false, unix.MS_NODIRATIME}, + "noexec": {false, unix.MS_NOEXEC}, + "nomand": {true, unix.MS_MANDLOCK}, + "norelatime": {true, unix.MS_RELATIME}, + "nostrictatime": {true, unix.MS_STRICTATIME}, + "nosuid": {false, unix.MS_NOSUID}, + "rbind": {false, unix.MS_BIND | unix.MS_REC}, + "relatime": {false, unix.MS_RELATIME}, + "remount": {false, unix.MS_REMOUNT}, + "ro": {false, unix.MS_RDONLY}, + "rw": {true, unix.MS_RDONLY}, + "strictatime": {false, unix.MS_STRICTATIME}, + "suid": {true, unix.MS_NOSUID}, + "sync": {false, unix.MS_SYNCHRONOUS}, + } + for _, o := range options { + // If the option does not exist in the flags table or the flag + // is not supported on the platform, + // then it is a data value for a specific fs type + if f, exists := flags[o]; exists && f.flag != 0 { + if f.clear { + flag &^= f.flag + } else { + flag |= f.flag + } + } else { + data = append(data, o) + } + } + return flag, strings.Join(data, ",") +} diff --git a/mount_unix.go b/mount_unix.go index 8ed402388..8746424fb 100644 --- a/mount_unix.go +++ b/mount_unix.go @@ -1,72 +1,17 @@ -// +build linux +// +build darwin freebsd package containerd -import ( - "strings" +import "github.com/pkg/errors" - "golang.org/x/sys/unix" +var ( + ErrNotImplementOnUnix = errors.New("not implemented under unix") ) func (m *Mount) Mount(target string) error { - flags, data := parseMountOptions(m.Options) - return unix.Mount(m.Source, target, m.Type, uintptr(flags), data) + return ErrNotImplementOnUnix } func Unmount(mount string, flags int) error { - return unix.Unmount(mount, flags) -} - -// parseMountOptions takes fstab style mount options and parses them for -// use with a standard mount() syscall -func parseMountOptions(options []string) (int, string) { - var ( - flag int - data []string - ) - flags := map[string]struct { - clear bool - flag int - }{ - "async": {true, unix.MS_SYNCHRONOUS}, - "atime": {true, unix.MS_NOATIME}, - "bind": {false, unix.MS_BIND}, - "defaults": {false, 0}, - "dev": {true, unix.MS_NODEV}, - "diratime": {true, unix.MS_NODIRATIME}, - "dirsync": {false, unix.MS_DIRSYNC}, - "exec": {true, unix.MS_NOEXEC}, - "mand": {false, unix.MS_MANDLOCK}, - "noatime": {false, unix.MS_NOATIME}, - "nodev": {false, unix.MS_NODEV}, - "nodiratime": {false, unix.MS_NODIRATIME}, - "noexec": {false, unix.MS_NOEXEC}, - "nomand": {true, unix.MS_MANDLOCK}, - "norelatime": {true, unix.MS_RELATIME}, - "nostrictatime": {true, unix.MS_STRICTATIME}, - "nosuid": {false, unix.MS_NOSUID}, - "rbind": {false, unix.MS_BIND | unix.MS_REC}, - "relatime": {false, unix.MS_RELATIME}, - "remount": {false, unix.MS_REMOUNT}, - "ro": {false, unix.MS_RDONLY}, - "rw": {true, unix.MS_RDONLY}, - "strictatime": {false, unix.MS_STRICTATIME}, - "suid": {true, unix.MS_NOSUID}, - "sync": {false, unix.MS_SYNCHRONOUS}, - } - for _, o := range options { - // If the option does not exist in the flags table or the flag - // is not supported on the platform, - // then it is a data value for a specific fs type - if f, exists := flags[o]; exists && f.flag != 0 { - if f.clear { - flag &^= f.flag - } else { - flag |= f.flag - } - } else { - data = append(data, o) - } - } - return flag, strings.Join(data, ",") + return ErrNotImplementOnUnix } diff --git a/vendor.conf b/vendor.conf index 38ffe2c59..c3725b635 100644 --- a/vendor.conf +++ b/vendor.conf @@ -20,7 +20,7 @@ github.com/containerd/btrfs e9c546f46bccffefe71a6bc137e4c21b5503cc18 github.com/stretchr/testify v1.1.4 github.com/davecgh/go-spew v1.1.0 github.com/pmezard/go-difflib v1.0.0 -github.com/tonistiigi/fifo fe870ccf293940774c2b44e23f6c71fff8f7547d +github.com/tonistiigi/fifo f071cd4a2739654fec4e768a14efd9332b3e8af1 github.com/urfave/cli 8ba6f23b6e36d03666a14bd9421f5e3efcb59aca golang.org/x/net 8b4af36cd21a1f85a7484b49feb7c79363106d8e google.golang.org/grpc v1.0.5 diff --git a/vendor/github.com/tonistiigi/fifo/handle_linux.go b/vendor/github.com/tonistiigi/fifo/handle_linux.go index 7bda64ca6..520ef262a 100644 --- a/vendor/github.com/tonistiigi/fifo/handle_linux.go +++ b/vendor/github.com/tonistiigi/fifo/handle_linux.go @@ -36,7 +36,7 @@ func getHandle(fn string) (*handle, error) { h := &handle{ f: f, name: fn, - dev: stat.Dev, + dev: uint64(stat.Dev), ino: stat.Ino, } @@ -62,7 +62,7 @@ func (h *handle) Path() (string, error) { if err := syscall.Stat(h.procPath(), &stat); err != nil { return "", errors.Wrapf(err, "path %v could not be statted", h.procPath()) } - if stat.Dev != h.dev || stat.Ino != h.ino { + if uint64(stat.Dev) != h.dev || 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.procPath(), nil diff --git a/vendor/github.com/tonistiigi/fifo/handle_nolinux.go b/vendor/github.com/tonistiigi/fifo/handle_nolinux.go index d9648d8bf..f0c8485da 100644 --- a/vendor/github.com/tonistiigi/fifo/handle_nolinux.go +++ b/vendor/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 for %v", stat.Dev, h.dev, stat.Ino, h.ino, h.fn) } return h.fn, nil