diff --git a/vendor/github.com/checkpoint-restore/go-criu/rpc/rpc.pb.go b/vendor/github.com/checkpoint-restore/go-criu/rpc/rpc.pb.go
deleted file mode 100644
index 230faace5..000000000
--- a/vendor/github.com/checkpoint-restore/go-criu/rpc/rpc.pb.go
+++ /dev/null
@@ -1,1211 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// source: rpc/rpc.proto
-
-/*
-Package rpc is a generated protocol buffer package.
-
-It is generated from these files:
- rpc/rpc.proto
-
-It has these top-level messages:
- CriuPageServerInfo
- CriuVethPair
- ExtMountMap
- JoinNamespace
- InheritFd
- CgroupRoot
- UnixSk
- CriuOpts
- CriuDumpResp
- CriuRestoreResp
- CriuNotify
- CriuFeatures
- CriuReq
- CriuResp
- CriuVersion
-*/
-package rpc
-
-import proto "github.com/golang/protobuf/proto"
-import fmt "fmt"
-import math "math"
-
-// Reference imports to suppress errors if they are not otherwise used.
-var _ = proto.Marshal
-var _ = fmt.Errorf
-var _ = math.Inf
-
-// This is a compile-time assertion to ensure that this generated file
-// is compatible with the proto package it is being compiled against.
-// A compilation error at this line likely means your copy of the
-// proto package needs to be updated.
-const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
-
-type CriuCgMode int32
-
-const (
- CriuCgMode_IGNORE CriuCgMode = 0
- CriuCgMode_CG_NONE CriuCgMode = 1
- CriuCgMode_PROPS CriuCgMode = 2
- CriuCgMode_SOFT CriuCgMode = 3
- CriuCgMode_FULL CriuCgMode = 4
- CriuCgMode_STRICT CriuCgMode = 5
- CriuCgMode_DEFAULT CriuCgMode = 6
-)
-
-var CriuCgMode_name = map[int32]string{
- 0: "IGNORE",
- 1: "CG_NONE",
- 2: "PROPS",
- 3: "SOFT",
- 4: "FULL",
- 5: "STRICT",
- 6: "DEFAULT",
-}
-var CriuCgMode_value = map[string]int32{
- "IGNORE": 0,
- "CG_NONE": 1,
- "PROPS": 2,
- "SOFT": 3,
- "FULL": 4,
- "STRICT": 5,
- "DEFAULT": 6,
-}
-
-func (x CriuCgMode) Enum() *CriuCgMode {
- p := new(CriuCgMode)
- *p = x
- return p
-}
-func (x CriuCgMode) String() string {
- return proto.EnumName(CriuCgMode_name, int32(x))
-}
-func (x *CriuCgMode) UnmarshalJSON(data []byte) error {
- value, err := proto.UnmarshalJSONEnum(CriuCgMode_value, data, "CriuCgMode")
- if err != nil {
- return err
- }
- *x = CriuCgMode(value)
- return nil
-}
-func (CriuCgMode) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
-
-type CriuReqType int32
-
-const (
- CriuReqType_EMPTY CriuReqType = 0
- CriuReqType_DUMP CriuReqType = 1
- CriuReqType_RESTORE CriuReqType = 2
- CriuReqType_CHECK CriuReqType = 3
- CriuReqType_PRE_DUMP CriuReqType = 4
- CriuReqType_PAGE_SERVER CriuReqType = 5
- CriuReqType_NOTIFY CriuReqType = 6
- CriuReqType_CPUINFO_DUMP CriuReqType = 7
- CriuReqType_CPUINFO_CHECK CriuReqType = 8
- CriuReqType_FEATURE_CHECK CriuReqType = 9
- CriuReqType_VERSION CriuReqType = 10
- CriuReqType_WAIT_PID CriuReqType = 11
- CriuReqType_PAGE_SERVER_CHLD CriuReqType = 12
-)
-
-var CriuReqType_name = map[int32]string{
- 0: "EMPTY",
- 1: "DUMP",
- 2: "RESTORE",
- 3: "CHECK",
- 4: "PRE_DUMP",
- 5: "PAGE_SERVER",
- 6: "NOTIFY",
- 7: "CPUINFO_DUMP",
- 8: "CPUINFO_CHECK",
- 9: "FEATURE_CHECK",
- 10: "VERSION",
- 11: "WAIT_PID",
- 12: "PAGE_SERVER_CHLD",
-}
-var CriuReqType_value = map[string]int32{
- "EMPTY": 0,
- "DUMP": 1,
- "RESTORE": 2,
- "CHECK": 3,
- "PRE_DUMP": 4,
- "PAGE_SERVER": 5,
- "NOTIFY": 6,
- "CPUINFO_DUMP": 7,
- "CPUINFO_CHECK": 8,
- "FEATURE_CHECK": 9,
- "VERSION": 10,
- "WAIT_PID": 11,
- "PAGE_SERVER_CHLD": 12,
-}
-
-func (x CriuReqType) Enum() *CriuReqType {
- p := new(CriuReqType)
- *p = x
- return p
-}
-func (x CriuReqType) String() string {
- return proto.EnumName(CriuReqType_name, int32(x))
-}
-func (x *CriuReqType) UnmarshalJSON(data []byte) error {
- value, err := proto.UnmarshalJSONEnum(CriuReqType_value, data, "CriuReqType")
- if err != nil {
- return err
- }
- *x = CriuReqType(value)
- return nil
-}
-func (CriuReqType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
-
-type CriuPageServerInfo struct {
- Address *string `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"`
- Port *int32 `protobuf:"varint,2,opt,name=port" json:"port,omitempty"`
- Pid *int32 `protobuf:"varint,3,opt,name=pid" json:"pid,omitempty"`
- Fd *int32 `protobuf:"varint,4,opt,name=fd" json:"fd,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *CriuPageServerInfo) Reset() { *m = CriuPageServerInfo{} }
-func (m *CriuPageServerInfo) String() string { return proto.CompactTextString(m) }
-func (*CriuPageServerInfo) ProtoMessage() {}
-func (*CriuPageServerInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
-
-func (m *CriuPageServerInfo) GetAddress() string {
- if m != nil && m.Address != nil {
- return *m.Address
- }
- return ""
-}
-
-func (m *CriuPageServerInfo) GetPort() int32 {
- if m != nil && m.Port != nil {
- return *m.Port
- }
- return 0
-}
-
-func (m *CriuPageServerInfo) GetPid() int32 {
- if m != nil && m.Pid != nil {
- return *m.Pid
- }
- return 0
-}
-
-func (m *CriuPageServerInfo) GetFd() int32 {
- if m != nil && m.Fd != nil {
- return *m.Fd
- }
- return 0
-}
-
-type CriuVethPair struct {
- IfIn *string `protobuf:"bytes,1,req,name=if_in,json=ifIn" json:"if_in,omitempty"`
- IfOut *string `protobuf:"bytes,2,req,name=if_out,json=ifOut" json:"if_out,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *CriuVethPair) Reset() { *m = CriuVethPair{} }
-func (m *CriuVethPair) String() string { return proto.CompactTextString(m) }
-func (*CriuVethPair) ProtoMessage() {}
-func (*CriuVethPair) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
-
-func (m *CriuVethPair) GetIfIn() string {
- if m != nil && m.IfIn != nil {
- return *m.IfIn
- }
- return ""
-}
-
-func (m *CriuVethPair) GetIfOut() string {
- if m != nil && m.IfOut != nil {
- return *m.IfOut
- }
- return ""
-}
-
-type ExtMountMap struct {
- Key *string `protobuf:"bytes,1,req,name=key" json:"key,omitempty"`
- Val *string `protobuf:"bytes,2,req,name=val" json:"val,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *ExtMountMap) Reset() { *m = ExtMountMap{} }
-func (m *ExtMountMap) String() string { return proto.CompactTextString(m) }
-func (*ExtMountMap) ProtoMessage() {}
-func (*ExtMountMap) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
-
-func (m *ExtMountMap) GetKey() string {
- if m != nil && m.Key != nil {
- return *m.Key
- }
- return ""
-}
-
-func (m *ExtMountMap) GetVal() string {
- if m != nil && m.Val != nil {
- return *m.Val
- }
- return ""
-}
-
-type JoinNamespace struct {
- Ns *string `protobuf:"bytes,1,req,name=ns" json:"ns,omitempty"`
- NsFile *string `protobuf:"bytes,2,req,name=ns_file,json=nsFile" json:"ns_file,omitempty"`
- ExtraOpt *string `protobuf:"bytes,3,opt,name=extra_opt,json=extraOpt" json:"extra_opt,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *JoinNamespace) Reset() { *m = JoinNamespace{} }
-func (m *JoinNamespace) String() string { return proto.CompactTextString(m) }
-func (*JoinNamespace) ProtoMessage() {}
-func (*JoinNamespace) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
-
-func (m *JoinNamespace) GetNs() string {
- if m != nil && m.Ns != nil {
- return *m.Ns
- }
- return ""
-}
-
-func (m *JoinNamespace) GetNsFile() string {
- if m != nil && m.NsFile != nil {
- return *m.NsFile
- }
- return ""
-}
-
-func (m *JoinNamespace) GetExtraOpt() string {
- if m != nil && m.ExtraOpt != nil {
- return *m.ExtraOpt
- }
- return ""
-}
-
-type InheritFd struct {
- Key *string `protobuf:"bytes,1,req,name=key" json:"key,omitempty"`
- Fd *int32 `protobuf:"varint,2,req,name=fd" json:"fd,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *InheritFd) Reset() { *m = InheritFd{} }
-func (m *InheritFd) String() string { return proto.CompactTextString(m) }
-func (*InheritFd) ProtoMessage() {}
-func (*InheritFd) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
-
-func (m *InheritFd) GetKey() string {
- if m != nil && m.Key != nil {
- return *m.Key
- }
- return ""
-}
-
-func (m *InheritFd) GetFd() int32 {
- if m != nil && m.Fd != nil {
- return *m.Fd
- }
- return 0
-}
-
-type CgroupRoot struct {
- Ctrl *string `protobuf:"bytes,1,opt,name=ctrl" json:"ctrl,omitempty"`
- Path *string `protobuf:"bytes,2,req,name=path" json:"path,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *CgroupRoot) Reset() { *m = CgroupRoot{} }
-func (m *CgroupRoot) String() string { return proto.CompactTextString(m) }
-func (*CgroupRoot) ProtoMessage() {}
-func (*CgroupRoot) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
-
-func (m *CgroupRoot) GetCtrl() string {
- if m != nil && m.Ctrl != nil {
- return *m.Ctrl
- }
- return ""
-}
-
-func (m *CgroupRoot) GetPath() string {
- if m != nil && m.Path != nil {
- return *m.Path
- }
- return ""
-}
-
-type UnixSk struct {
- Inode *uint32 `protobuf:"varint,1,req,name=inode" json:"inode,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *UnixSk) Reset() { *m = UnixSk{} }
-func (m *UnixSk) String() string { return proto.CompactTextString(m) }
-func (*UnixSk) ProtoMessage() {}
-func (*UnixSk) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} }
-
-func (m *UnixSk) GetInode() uint32 {
- if m != nil && m.Inode != nil {
- return *m.Inode
- }
- return 0
-}
-
-type CriuOpts struct {
- ImagesDirFd *int32 `protobuf:"varint,1,req,name=images_dir_fd,json=imagesDirFd" json:"images_dir_fd,omitempty"`
- Pid *int32 `protobuf:"varint,2,opt,name=pid" json:"pid,omitempty"`
- LeaveRunning *bool `protobuf:"varint,3,opt,name=leave_running,json=leaveRunning" json:"leave_running,omitempty"`
- ExtUnixSk *bool `protobuf:"varint,4,opt,name=ext_unix_sk,json=extUnixSk" json:"ext_unix_sk,omitempty"`
- TcpEstablished *bool `protobuf:"varint,5,opt,name=tcp_established,json=tcpEstablished" json:"tcp_established,omitempty"`
- EvasiveDevices *bool `protobuf:"varint,6,opt,name=evasive_devices,json=evasiveDevices" json:"evasive_devices,omitempty"`
- ShellJob *bool `protobuf:"varint,7,opt,name=shell_job,json=shellJob" json:"shell_job,omitempty"`
- FileLocks *bool `protobuf:"varint,8,opt,name=file_locks,json=fileLocks" json:"file_locks,omitempty"`
- LogLevel *int32 `protobuf:"varint,9,opt,name=log_level,json=logLevel,def=2" json:"log_level,omitempty"`
- LogFile *string `protobuf:"bytes,10,opt,name=log_file,json=logFile" json:"log_file,omitempty"`
- Ps *CriuPageServerInfo `protobuf:"bytes,11,opt,name=ps" json:"ps,omitempty"`
- NotifyScripts *bool `protobuf:"varint,12,opt,name=notify_scripts,json=notifyScripts" json:"notify_scripts,omitempty"`
- Root *string `protobuf:"bytes,13,opt,name=root" json:"root,omitempty"`
- ParentImg *string `protobuf:"bytes,14,opt,name=parent_img,json=parentImg" json:"parent_img,omitempty"`
- TrackMem *bool `protobuf:"varint,15,opt,name=track_mem,json=trackMem" json:"track_mem,omitempty"`
- AutoDedup *bool `protobuf:"varint,16,opt,name=auto_dedup,json=autoDedup" json:"auto_dedup,omitempty"`
- WorkDirFd *int32 `protobuf:"varint,17,opt,name=work_dir_fd,json=workDirFd" json:"work_dir_fd,omitempty"`
- LinkRemap *bool `protobuf:"varint,18,opt,name=link_remap,json=linkRemap" json:"link_remap,omitempty"`
- Veths []*CriuVethPair `protobuf:"bytes,19,rep,name=veths" json:"veths,omitempty"`
- CpuCap *uint32 `protobuf:"varint,20,opt,name=cpu_cap,json=cpuCap,def=4294967295" json:"cpu_cap,omitempty"`
- ForceIrmap *bool `protobuf:"varint,21,opt,name=force_irmap,json=forceIrmap" json:"force_irmap,omitempty"`
- ExecCmd []string `protobuf:"bytes,22,rep,name=exec_cmd,json=execCmd" json:"exec_cmd,omitempty"`
- ExtMnt []*ExtMountMap `protobuf:"bytes,23,rep,name=ext_mnt,json=extMnt" json:"ext_mnt,omitempty"`
- ManageCgroups *bool `protobuf:"varint,24,opt,name=manage_cgroups,json=manageCgroups" json:"manage_cgroups,omitempty"`
- CgRoot []*CgroupRoot `protobuf:"bytes,25,rep,name=cg_root,json=cgRoot" json:"cg_root,omitempty"`
- RstSibling *bool `protobuf:"varint,26,opt,name=rst_sibling,json=rstSibling" json:"rst_sibling,omitempty"`
- InheritFd []*InheritFd `protobuf:"bytes,27,rep,name=inherit_fd,json=inheritFd" json:"inherit_fd,omitempty"`
- AutoExtMnt *bool `protobuf:"varint,28,opt,name=auto_ext_mnt,json=autoExtMnt" json:"auto_ext_mnt,omitempty"`
- ExtSharing *bool `protobuf:"varint,29,opt,name=ext_sharing,json=extSharing" json:"ext_sharing,omitempty"`
- ExtMasters *bool `protobuf:"varint,30,opt,name=ext_masters,json=extMasters" json:"ext_masters,omitempty"`
- SkipMnt []string `protobuf:"bytes,31,rep,name=skip_mnt,json=skipMnt" json:"skip_mnt,omitempty"`
- EnableFs []string `protobuf:"bytes,32,rep,name=enable_fs,json=enableFs" json:"enable_fs,omitempty"`
- UnixSkIno []*UnixSk `protobuf:"bytes,33,rep,name=unix_sk_ino,json=unixSkIno" json:"unix_sk_ino,omitempty"`
- ManageCgroupsMode *CriuCgMode `protobuf:"varint,34,opt,name=manage_cgroups_mode,json=manageCgroupsMode,enum=CriuCgMode" json:"manage_cgroups_mode,omitempty"`
- GhostLimit *uint32 `protobuf:"varint,35,opt,name=ghost_limit,json=ghostLimit,def=1048576" json:"ghost_limit,omitempty"`
- IrmapScanPaths []string `protobuf:"bytes,36,rep,name=irmap_scan_paths,json=irmapScanPaths" json:"irmap_scan_paths,omitempty"`
- External []string `protobuf:"bytes,37,rep,name=external" json:"external,omitempty"`
- EmptyNs *uint32 `protobuf:"varint,38,opt,name=empty_ns,json=emptyNs" json:"empty_ns,omitempty"`
- JoinNs []*JoinNamespace `protobuf:"bytes,39,rep,name=join_ns,json=joinNs" json:"join_ns,omitempty"`
- CgroupProps *string `protobuf:"bytes,41,opt,name=cgroup_props,json=cgroupProps" json:"cgroup_props,omitempty"`
- CgroupPropsFile *string `protobuf:"bytes,42,opt,name=cgroup_props_file,json=cgroupPropsFile" json:"cgroup_props_file,omitempty"`
- CgroupDumpController []string `protobuf:"bytes,43,rep,name=cgroup_dump_controller,json=cgroupDumpController" json:"cgroup_dump_controller,omitempty"`
- FreezeCgroup *string `protobuf:"bytes,44,opt,name=freeze_cgroup,json=freezeCgroup" json:"freeze_cgroup,omitempty"`
- Timeout *uint32 `protobuf:"varint,45,opt,name=timeout" json:"timeout,omitempty"`
- TcpSkipInFlight *bool `protobuf:"varint,46,opt,name=tcp_skip_in_flight,json=tcpSkipInFlight" json:"tcp_skip_in_flight,omitempty"`
- WeakSysctls *bool `protobuf:"varint,47,opt,name=weak_sysctls,json=weakSysctls" json:"weak_sysctls,omitempty"`
- LazyPages *bool `protobuf:"varint,48,opt,name=lazy_pages,json=lazyPages" json:"lazy_pages,omitempty"`
- StatusFd *int32 `protobuf:"varint,49,opt,name=status_fd,json=statusFd" json:"status_fd,omitempty"`
- OrphanPtsMaster *bool `protobuf:"varint,50,opt,name=orphan_pts_master,json=orphanPtsMaster" json:"orphan_pts_master,omitempty"`
- ConfigFile *string `protobuf:"bytes,51,opt,name=config_file,json=configFile" json:"config_file,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *CriuOpts) Reset() { *m = CriuOpts{} }
-func (m *CriuOpts) String() string { return proto.CompactTextString(m) }
-func (*CriuOpts) ProtoMessage() {}
-func (*CriuOpts) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} }
-
-const Default_CriuOpts_LogLevel int32 = 2
-const Default_CriuOpts_CpuCap uint32 = 4294967295
-const Default_CriuOpts_GhostLimit uint32 = 1048576
-
-func (m *CriuOpts) GetImagesDirFd() int32 {
- if m != nil && m.ImagesDirFd != nil {
- return *m.ImagesDirFd
- }
- return 0
-}
-
-func (m *CriuOpts) GetPid() int32 {
- if m != nil && m.Pid != nil {
- return *m.Pid
- }
- return 0
-}
-
-func (m *CriuOpts) GetLeaveRunning() bool {
- if m != nil && m.LeaveRunning != nil {
- return *m.LeaveRunning
- }
- return false
-}
-
-func (m *CriuOpts) GetExtUnixSk() bool {
- if m != nil && m.ExtUnixSk != nil {
- return *m.ExtUnixSk
- }
- return false
-}
-
-func (m *CriuOpts) GetTcpEstablished() bool {
- if m != nil && m.TcpEstablished != nil {
- return *m.TcpEstablished
- }
- return false
-}
-
-func (m *CriuOpts) GetEvasiveDevices() bool {
- if m != nil && m.EvasiveDevices != nil {
- return *m.EvasiveDevices
- }
- return false
-}
-
-func (m *CriuOpts) GetShellJob() bool {
- if m != nil && m.ShellJob != nil {
- return *m.ShellJob
- }
- return false
-}
-
-func (m *CriuOpts) GetFileLocks() bool {
- if m != nil && m.FileLocks != nil {
- return *m.FileLocks
- }
- return false
-}
-
-func (m *CriuOpts) GetLogLevel() int32 {
- if m != nil && m.LogLevel != nil {
- return *m.LogLevel
- }
- return Default_CriuOpts_LogLevel
-}
-
-func (m *CriuOpts) GetLogFile() string {
- if m != nil && m.LogFile != nil {
- return *m.LogFile
- }
- return ""
-}
-
-func (m *CriuOpts) GetPs() *CriuPageServerInfo {
- if m != nil {
- return m.Ps
- }
- return nil
-}
-
-func (m *CriuOpts) GetNotifyScripts() bool {
- if m != nil && m.NotifyScripts != nil {
- return *m.NotifyScripts
- }
- return false
-}
-
-func (m *CriuOpts) GetRoot() string {
- if m != nil && m.Root != nil {
- return *m.Root
- }
- return ""
-}
-
-func (m *CriuOpts) GetParentImg() string {
- if m != nil && m.ParentImg != nil {
- return *m.ParentImg
- }
- return ""
-}
-
-func (m *CriuOpts) GetTrackMem() bool {
- if m != nil && m.TrackMem != nil {
- return *m.TrackMem
- }
- return false
-}
-
-func (m *CriuOpts) GetAutoDedup() bool {
- if m != nil && m.AutoDedup != nil {
- return *m.AutoDedup
- }
- return false
-}
-
-func (m *CriuOpts) GetWorkDirFd() int32 {
- if m != nil && m.WorkDirFd != nil {
- return *m.WorkDirFd
- }
- return 0
-}
-
-func (m *CriuOpts) GetLinkRemap() bool {
- if m != nil && m.LinkRemap != nil {
- return *m.LinkRemap
- }
- return false
-}
-
-func (m *CriuOpts) GetVeths() []*CriuVethPair {
- if m != nil {
- return m.Veths
- }
- return nil
-}
-
-func (m *CriuOpts) GetCpuCap() uint32 {
- if m != nil && m.CpuCap != nil {
- return *m.CpuCap
- }
- return Default_CriuOpts_CpuCap
-}
-
-func (m *CriuOpts) GetForceIrmap() bool {
- if m != nil && m.ForceIrmap != nil {
- return *m.ForceIrmap
- }
- return false
-}
-
-func (m *CriuOpts) GetExecCmd() []string {
- if m != nil {
- return m.ExecCmd
- }
- return nil
-}
-
-func (m *CriuOpts) GetExtMnt() []*ExtMountMap {
- if m != nil {
- return m.ExtMnt
- }
- return nil
-}
-
-func (m *CriuOpts) GetManageCgroups() bool {
- if m != nil && m.ManageCgroups != nil {
- return *m.ManageCgroups
- }
- return false
-}
-
-func (m *CriuOpts) GetCgRoot() []*CgroupRoot {
- if m != nil {
- return m.CgRoot
- }
- return nil
-}
-
-func (m *CriuOpts) GetRstSibling() bool {
- if m != nil && m.RstSibling != nil {
- return *m.RstSibling
- }
- return false
-}
-
-func (m *CriuOpts) GetInheritFd() []*InheritFd {
- if m != nil {
- return m.InheritFd
- }
- return nil
-}
-
-func (m *CriuOpts) GetAutoExtMnt() bool {
- if m != nil && m.AutoExtMnt != nil {
- return *m.AutoExtMnt
- }
- return false
-}
-
-func (m *CriuOpts) GetExtSharing() bool {
- if m != nil && m.ExtSharing != nil {
- return *m.ExtSharing
- }
- return false
-}
-
-func (m *CriuOpts) GetExtMasters() bool {
- if m != nil && m.ExtMasters != nil {
- return *m.ExtMasters
- }
- return false
-}
-
-func (m *CriuOpts) GetSkipMnt() []string {
- if m != nil {
- return m.SkipMnt
- }
- return nil
-}
-
-func (m *CriuOpts) GetEnableFs() []string {
- if m != nil {
- return m.EnableFs
- }
- return nil
-}
-
-func (m *CriuOpts) GetUnixSkIno() []*UnixSk {
- if m != nil {
- return m.UnixSkIno
- }
- return nil
-}
-
-func (m *CriuOpts) GetManageCgroupsMode() CriuCgMode {
- if m != nil && m.ManageCgroupsMode != nil {
- return *m.ManageCgroupsMode
- }
- return CriuCgMode_IGNORE
-}
-
-func (m *CriuOpts) GetGhostLimit() uint32 {
- if m != nil && m.GhostLimit != nil {
- return *m.GhostLimit
- }
- return Default_CriuOpts_GhostLimit
-}
-
-func (m *CriuOpts) GetIrmapScanPaths() []string {
- if m != nil {
- return m.IrmapScanPaths
- }
- return nil
-}
-
-func (m *CriuOpts) GetExternal() []string {
- if m != nil {
- return m.External
- }
- return nil
-}
-
-func (m *CriuOpts) GetEmptyNs() uint32 {
- if m != nil && m.EmptyNs != nil {
- return *m.EmptyNs
- }
- return 0
-}
-
-func (m *CriuOpts) GetJoinNs() []*JoinNamespace {
- if m != nil {
- return m.JoinNs
- }
- return nil
-}
-
-func (m *CriuOpts) GetCgroupProps() string {
- if m != nil && m.CgroupProps != nil {
- return *m.CgroupProps
- }
- return ""
-}
-
-func (m *CriuOpts) GetCgroupPropsFile() string {
- if m != nil && m.CgroupPropsFile != nil {
- return *m.CgroupPropsFile
- }
- return ""
-}
-
-func (m *CriuOpts) GetCgroupDumpController() []string {
- if m != nil {
- return m.CgroupDumpController
- }
- return nil
-}
-
-func (m *CriuOpts) GetFreezeCgroup() string {
- if m != nil && m.FreezeCgroup != nil {
- return *m.FreezeCgroup
- }
- return ""
-}
-
-func (m *CriuOpts) GetTimeout() uint32 {
- if m != nil && m.Timeout != nil {
- return *m.Timeout
- }
- return 0
-}
-
-func (m *CriuOpts) GetTcpSkipInFlight() bool {
- if m != nil && m.TcpSkipInFlight != nil {
- return *m.TcpSkipInFlight
- }
- return false
-}
-
-func (m *CriuOpts) GetWeakSysctls() bool {
- if m != nil && m.WeakSysctls != nil {
- return *m.WeakSysctls
- }
- return false
-}
-
-func (m *CriuOpts) GetLazyPages() bool {
- if m != nil && m.LazyPages != nil {
- return *m.LazyPages
- }
- return false
-}
-
-func (m *CriuOpts) GetStatusFd() int32 {
- if m != nil && m.StatusFd != nil {
- return *m.StatusFd
- }
- return 0
-}
-
-func (m *CriuOpts) GetOrphanPtsMaster() bool {
- if m != nil && m.OrphanPtsMaster != nil {
- return *m.OrphanPtsMaster
- }
- return false
-}
-
-func (m *CriuOpts) GetConfigFile() string {
- if m != nil && m.ConfigFile != nil {
- return *m.ConfigFile
- }
- return ""
-}
-
-type CriuDumpResp struct {
- Restored *bool `protobuf:"varint,1,opt,name=restored" json:"restored,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *CriuDumpResp) Reset() { *m = CriuDumpResp{} }
-func (m *CriuDumpResp) String() string { return proto.CompactTextString(m) }
-func (*CriuDumpResp) ProtoMessage() {}
-func (*CriuDumpResp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} }
-
-func (m *CriuDumpResp) GetRestored() bool {
- if m != nil && m.Restored != nil {
- return *m.Restored
- }
- return false
-}
-
-type CriuRestoreResp struct {
- Pid *int32 `protobuf:"varint,1,req,name=pid" json:"pid,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *CriuRestoreResp) Reset() { *m = CriuRestoreResp{} }
-func (m *CriuRestoreResp) String() string { return proto.CompactTextString(m) }
-func (*CriuRestoreResp) ProtoMessage() {}
-func (*CriuRestoreResp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} }
-
-func (m *CriuRestoreResp) GetPid() int32 {
- if m != nil && m.Pid != nil {
- return *m.Pid
- }
- return 0
-}
-
-type CriuNotify struct {
- Script *string `protobuf:"bytes,1,opt,name=script" json:"script,omitempty"`
- Pid *int32 `protobuf:"varint,2,opt,name=pid" json:"pid,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *CriuNotify) Reset() { *m = CriuNotify{} }
-func (m *CriuNotify) String() string { return proto.CompactTextString(m) }
-func (*CriuNotify) ProtoMessage() {}
-func (*CriuNotify) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} }
-
-func (m *CriuNotify) GetScript() string {
- if m != nil && m.Script != nil {
- return *m.Script
- }
- return ""
-}
-
-func (m *CriuNotify) GetPid() int32 {
- if m != nil && m.Pid != nil {
- return *m.Pid
- }
- return 0
-}
-
-//
-// List of features which can queried via
-// CRIU_REQ_TYPE__FEATURE_CHECK
-type CriuFeatures struct {
- MemTrack *bool `protobuf:"varint,1,opt,name=mem_track,json=memTrack" json:"mem_track,omitempty"`
- LazyPages *bool `protobuf:"varint,2,opt,name=lazy_pages,json=lazyPages" json:"lazy_pages,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *CriuFeatures) Reset() { *m = CriuFeatures{} }
-func (m *CriuFeatures) String() string { return proto.CompactTextString(m) }
-func (*CriuFeatures) ProtoMessage() {}
-func (*CriuFeatures) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} }
-
-func (m *CriuFeatures) GetMemTrack() bool {
- if m != nil && m.MemTrack != nil {
- return *m.MemTrack
- }
- return false
-}
-
-func (m *CriuFeatures) GetLazyPages() bool {
- if m != nil && m.LazyPages != nil {
- return *m.LazyPages
- }
- return false
-}
-
-type CriuReq struct {
- Type *CriuReqType `protobuf:"varint,1,req,name=type,enum=CriuReqType" json:"type,omitempty"`
- Opts *CriuOpts `protobuf:"bytes,2,opt,name=opts" json:"opts,omitempty"`
- NotifySuccess *bool `protobuf:"varint,3,opt,name=notify_success,json=notifySuccess" json:"notify_success,omitempty"`
- //
- // When set service won't close the connection but
- // will wait for more req-s to appear. Works not
- // for all request types.
- KeepOpen *bool `protobuf:"varint,4,opt,name=keep_open,json=keepOpen" json:"keep_open,omitempty"`
- //
- // 'features' can be used to query which features
- // are supported by the installed criu/kernel
- // via RPC.
- Features *CriuFeatures `protobuf:"bytes,5,opt,name=features" json:"features,omitempty"`
- // 'pid' is used for WAIT_PID
- Pid *uint32 `protobuf:"varint,6,opt,name=pid" json:"pid,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *CriuReq) Reset() { *m = CriuReq{} }
-func (m *CriuReq) String() string { return proto.CompactTextString(m) }
-func (*CriuReq) ProtoMessage() {}
-func (*CriuReq) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} }
-
-func (m *CriuReq) GetType() CriuReqType {
- if m != nil && m.Type != nil {
- return *m.Type
- }
- return CriuReqType_EMPTY
-}
-
-func (m *CriuReq) GetOpts() *CriuOpts {
- if m != nil {
- return m.Opts
- }
- return nil
-}
-
-func (m *CriuReq) GetNotifySuccess() bool {
- if m != nil && m.NotifySuccess != nil {
- return *m.NotifySuccess
- }
- return false
-}
-
-func (m *CriuReq) GetKeepOpen() bool {
- if m != nil && m.KeepOpen != nil {
- return *m.KeepOpen
- }
- return false
-}
-
-func (m *CriuReq) GetFeatures() *CriuFeatures {
- if m != nil {
- return m.Features
- }
- return nil
-}
-
-func (m *CriuReq) GetPid() uint32 {
- if m != nil && m.Pid != nil {
- return *m.Pid
- }
- return 0
-}
-
-type CriuResp struct {
- Type *CriuReqType `protobuf:"varint,1,req,name=type,enum=CriuReqType" json:"type,omitempty"`
- Success *bool `protobuf:"varint,2,req,name=success" json:"success,omitempty"`
- Dump *CriuDumpResp `protobuf:"bytes,3,opt,name=dump" json:"dump,omitempty"`
- Restore *CriuRestoreResp `protobuf:"bytes,4,opt,name=restore" json:"restore,omitempty"`
- Notify *CriuNotify `protobuf:"bytes,5,opt,name=notify" json:"notify,omitempty"`
- Ps *CriuPageServerInfo `protobuf:"bytes,6,opt,name=ps" json:"ps,omitempty"`
- CrErrno *int32 `protobuf:"varint,7,opt,name=cr_errno,json=crErrno" json:"cr_errno,omitempty"`
- Features *CriuFeatures `protobuf:"bytes,8,opt,name=features" json:"features,omitempty"`
- CrErrmsg *string `protobuf:"bytes,9,opt,name=cr_errmsg,json=crErrmsg" json:"cr_errmsg,omitempty"`
- Version *CriuVersion `protobuf:"bytes,10,opt,name=version" json:"version,omitempty"`
- Status *int32 `protobuf:"varint,11,opt,name=status" json:"status,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *CriuResp) Reset() { *m = CriuResp{} }
-func (m *CriuResp) String() string { return proto.CompactTextString(m) }
-func (*CriuResp) ProtoMessage() {}
-func (*CriuResp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} }
-
-func (m *CriuResp) GetType() CriuReqType {
- if m != nil && m.Type != nil {
- return *m.Type
- }
- return CriuReqType_EMPTY
-}
-
-func (m *CriuResp) GetSuccess() bool {
- if m != nil && m.Success != nil {
- return *m.Success
- }
- return false
-}
-
-func (m *CriuResp) GetDump() *CriuDumpResp {
- if m != nil {
- return m.Dump
- }
- return nil
-}
-
-func (m *CriuResp) GetRestore() *CriuRestoreResp {
- if m != nil {
- return m.Restore
- }
- return nil
-}
-
-func (m *CriuResp) GetNotify() *CriuNotify {
- if m != nil {
- return m.Notify
- }
- return nil
-}
-
-func (m *CriuResp) GetPs() *CriuPageServerInfo {
- if m != nil {
- return m.Ps
- }
- return nil
-}
-
-func (m *CriuResp) GetCrErrno() int32 {
- if m != nil && m.CrErrno != nil {
- return *m.CrErrno
- }
- return 0
-}
-
-func (m *CriuResp) GetFeatures() *CriuFeatures {
- if m != nil {
- return m.Features
- }
- return nil
-}
-
-func (m *CriuResp) GetCrErrmsg() string {
- if m != nil && m.CrErrmsg != nil {
- return *m.CrErrmsg
- }
- return ""
-}
-
-func (m *CriuResp) GetVersion() *CriuVersion {
- if m != nil {
- return m.Version
- }
- return nil
-}
-
-func (m *CriuResp) GetStatus() int32 {
- if m != nil && m.Status != nil {
- return *m.Status
- }
- return 0
-}
-
-// Answer for criu_req_type.VERSION requests
-type CriuVersion struct {
- Major *int32 `protobuf:"varint,1,req,name=major" json:"major,omitempty"`
- Minor *int32 `protobuf:"varint,2,req,name=minor" json:"minor,omitempty"`
- Gitid *string `protobuf:"bytes,3,opt,name=gitid" json:"gitid,omitempty"`
- Sublevel *int32 `protobuf:"varint,4,opt,name=sublevel" json:"sublevel,omitempty"`
- Extra *int32 `protobuf:"varint,5,opt,name=extra" json:"extra,omitempty"`
- Name *string `protobuf:"bytes,6,opt,name=name" json:"name,omitempty"`
- XXX_unrecognized []byte `json:"-"`
-}
-
-func (m *CriuVersion) Reset() { *m = CriuVersion{} }
-func (m *CriuVersion) String() string { return proto.CompactTextString(m) }
-func (*CriuVersion) ProtoMessage() {}
-func (*CriuVersion) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} }
-
-func (m *CriuVersion) GetMajor() int32 {
- if m != nil && m.Major != nil {
- return *m.Major
- }
- return 0
-}
-
-func (m *CriuVersion) GetMinor() int32 {
- if m != nil && m.Minor != nil {
- return *m.Minor
- }
- return 0
-}
-
-func (m *CriuVersion) GetGitid() string {
- if m != nil && m.Gitid != nil {
- return *m.Gitid
- }
- return ""
-}
-
-func (m *CriuVersion) GetSublevel() int32 {
- if m != nil && m.Sublevel != nil {
- return *m.Sublevel
- }
- return 0
-}
-
-func (m *CriuVersion) GetExtra() int32 {
- if m != nil && m.Extra != nil {
- return *m.Extra
- }
- return 0
-}
-
-func (m *CriuVersion) GetName() string {
- if m != nil && m.Name != nil {
- return *m.Name
- }
- return ""
-}
-
-func init() {
- proto.RegisterType((*CriuPageServerInfo)(nil), "criu_page_server_info")
- proto.RegisterType((*CriuVethPair)(nil), "criu_veth_pair")
- proto.RegisterType((*ExtMountMap)(nil), "ext_mount_map")
- proto.RegisterType((*JoinNamespace)(nil), "join_namespace")
- proto.RegisterType((*InheritFd)(nil), "inherit_fd")
- proto.RegisterType((*CgroupRoot)(nil), "cgroup_root")
- proto.RegisterType((*UnixSk)(nil), "unix_sk")
- proto.RegisterType((*CriuOpts)(nil), "criu_opts")
- proto.RegisterType((*CriuDumpResp)(nil), "criu_dump_resp")
- proto.RegisterType((*CriuRestoreResp)(nil), "criu_restore_resp")
- proto.RegisterType((*CriuNotify)(nil), "criu_notify")
- proto.RegisterType((*CriuFeatures)(nil), "criu_features")
- proto.RegisterType((*CriuReq)(nil), "criu_req")
- proto.RegisterType((*CriuResp)(nil), "criu_resp")
- proto.RegisterType((*CriuVersion)(nil), "criu_version")
- proto.RegisterEnum("CriuCgMode", CriuCgMode_name, CriuCgMode_value)
- proto.RegisterEnum("CriuReqType", CriuReqType_name, CriuReqType_value)
-}
-
-func init() { proto.RegisterFile("rpc/rpc.proto", fileDescriptor0) }
-
-var fileDescriptor0 = []byte{
- // 1835 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x56, 0xeb, 0x72, 0x5b, 0xb7,
- 0x11, 0x0e, 0x29, 0xf1, 0x06, 0x5e, 0x7c, 0x0c, 0x5f, 0x02, 0xc7, 0xb5, 0xad, 0xd0, 0x51, 0xa2,
- 0x2a, 0x2e, 0x93, 0x30, 0x76, 0x5c, 0x67, 0xda, 0x1f, 0x1e, 0x8a, 0x74, 0xd8, 0x48, 0x22, 0x07,
- 0xa4, 0xdc, 0xc9, 0x2f, 0xcc, 0xd1, 0x39, 0x20, 0x05, 0xf3, 0xdc, 0x0a, 0x80, 0x8a, 0xe4, 0x97,
- 0xe8, 0xbf, 0x3e, 0x57, 0xde, 0xa4, 0xaf, 0xd0, 0xd9, 0x05, 0x28, 0x4b, 0x49, 0x66, 0xd2, 0x7f,
- 0xd8, 0x0f, 0xbb, 0xc0, 0xde, 0x77, 0x49, 0x5b, 0x17, 0xd1, 0x57, 0xba, 0x88, 0x7a, 0x85, 0xce,
- 0x6d, 0xde, 0x5d, 0x92, 0x7b, 0x91, 0x56, 0x6b, 0x51, 0x84, 0x4b, 0x29, 0x8c, 0xd4, 0xe7, 0x52,
- 0x0b, 0x95, 0x2d, 0x72, 0xca, 0x48, 0x2d, 0x8c, 0x63, 0x2d, 0x8d, 0x61, 0xa5, 0x9d, 0xd2, 0x5e,
- 0x83, 0x6f, 0x48, 0x4a, 0xc9, 0x76, 0x91, 0x6b, 0xcb, 0xca, 0x3b, 0xa5, 0xbd, 0x0a, 0xc7, 0x33,
- 0x0d, 0xc8, 0x56, 0xa1, 0x62, 0xb6, 0x85, 0x10, 0x1c, 0x69, 0x87, 0x94, 0x17, 0x31, 0xdb, 0x46,
- 0xa0, 0xbc, 0x88, 0xbb, 0x7f, 0x23, 0x1d, 0xfc, 0xe8, 0x5c, 0xda, 0x33, 0x51, 0x84, 0x4a, 0xd3,
- 0x3b, 0xa4, 0xa2, 0x16, 0x42, 0x65, 0xac, 0xb4, 0x53, 0xde, 0x6b, 0xf0, 0x6d, 0xb5, 0x18, 0x67,
- 0xf4, 0x1e, 0xa9, 0xaa, 0x85, 0xc8, 0xd7, 0xf0, 0x3c, 0xa0, 0x15, 0xb5, 0x98, 0xac, 0x6d, 0xf7,
- 0x5b, 0xd2, 0x96, 0x17, 0x56, 0xa4, 0xf9, 0x3a, 0xb3, 0x22, 0x0d, 0x0b, 0xf8, 0x70, 0x25, 0x2f,
- 0xbd, 0x28, 0x1c, 0x01, 0x39, 0x0f, 0x13, 0x2f, 0x06, 0xc7, 0xee, 0x5b, 0xd2, 0x79, 0x97, 0xab,
- 0x4c, 0x64, 0x61, 0x2a, 0x4d, 0x11, 0x46, 0x12, 0x94, 0xca, 0x8c, 0x17, 0x2a, 0x67, 0x86, 0x7e,
- 0x4c, 0x6a, 0x99, 0x11, 0x0b, 0x95, 0x48, 0x2f, 0x57, 0xcd, 0xcc, 0x48, 0x25, 0x92, 0x3e, 0x24,
- 0x0d, 0x79, 0x61, 0x75, 0x28, 0xf2, 0xc2, 0xa2, 0x55, 0x0d, 0x5e, 0x47, 0x60, 0x52, 0xd8, 0x6e,
- 0x8f, 0x10, 0x95, 0x9d, 0x49, 0xad, 0xac, 0x58, 0xc4, 0xbf, 0xa3, 0x89, 0x33, 0x1d, 0x1e, 0x74,
- 0xa6, 0xbf, 0x20, 0xcd, 0x68, 0xa9, 0xf3, 0x75, 0x21, 0x74, 0x9e, 0x5b, 0xf0, 0x5f, 0x64, 0x75,
- 0xe2, 0xdd, 0x8a, 0x67, 0xf4, 0x69, 0x68, 0xcf, 0xbc, 0x16, 0x78, 0xee, 0x3e, 0x21, 0xb5, 0x75,
- 0xa6, 0x2e, 0x84, 0x59, 0xd1, 0xbb, 0xa4, 0xa2, 0xb2, 0x3c, 0x96, 0xf8, 0x4b, 0x9b, 0x3b, 0xa2,
- 0xfb, 0xdf, 0x36, 0x69, 0xa0, 0x4f, 0xf3, 0xc2, 0x1a, 0xda, 0x25, 0x6d, 0x95, 0x86, 0x4b, 0x69,
- 0x44, 0xac, 0xb4, 0x58, 0xc4, 0xc8, 0x5b, 0xe1, 0x4d, 0x07, 0x1e, 0x28, 0x3d, 0x8a, 0x37, 0x61,
- 0x2a, 0x7f, 0x08, 0xd3, 0x53, 0xd2, 0x4e, 0x64, 0x78, 0x2e, 0x85, 0x5e, 0x67, 0x99, 0xca, 0x96,
- 0x68, 0x6c, 0x9d, 0xb7, 0x10, 0xe4, 0x0e, 0xa3, 0x8f, 0x49, 0x13, 0xbc, 0xef, 0xb5, 0xc1, 0xa0,
- 0xd6, 0x39, 0x38, 0xe8, 0x24, 0x53, 0x17, 0xb3, 0x15, 0xfd, 0x82, 0xdc, 0xb2, 0x51, 0x21, 0xa4,
- 0xb1, 0xe1, 0x69, 0xa2, 0xcc, 0x99, 0x8c, 0x59, 0x05, 0x79, 0x3a, 0x36, 0x2a, 0x86, 0x1f, 0x50,
- 0x60, 0x94, 0xe7, 0xa1, 0x51, 0xe7, 0x52, 0xc4, 0xf2, 0x5c, 0x45, 0xd2, 0xb0, 0xaa, 0x63, 0xf4,
- 0xf0, 0x81, 0x43, 0xc1, 0xff, 0xe6, 0x4c, 0x26, 0x89, 0x78, 0x97, 0x9f, 0xb2, 0x1a, 0xb2, 0xd4,
- 0x11, 0xf8, 0x47, 0x7e, 0x4a, 0x1f, 0x11, 0x02, 0x21, 0x13, 0x49, 0x1e, 0xad, 0x0c, 0xab, 0x3b,
- 0x6d, 0x00, 0x39, 0x04, 0x80, 0x3e, 0x26, 0x8d, 0x24, 0x5f, 0x8a, 0x44, 0x9e, 0xcb, 0x84, 0x35,
- 0xc0, 0xd4, 0xef, 0x4b, 0x7d, 0x5e, 0x4f, 0xf2, 0xe5, 0x21, 0x40, 0xf4, 0x01, 0x81, 0xb3, 0x8b,
- 0x3a, 0x71, 0xa9, 0x9d, 0xe4, 0x4b, 0x0c, 0xfb, 0xe7, 0xa4, 0x5c, 0x18, 0xd6, 0xdc, 0x29, 0xed,
- 0x35, 0xfb, 0xf7, 0x7b, 0xbf, 0x5b, 0x18, 0xbc, 0x5c, 0x18, 0xba, 0x4b, 0x3a, 0x59, 0x6e, 0xd5,
- 0xe2, 0x52, 0x98, 0x48, 0xab, 0xc2, 0x1a, 0xd6, 0x42, 0x2d, 0xda, 0x0e, 0x9d, 0x39, 0x10, 0xa2,
- 0x0a, 0x11, 0x67, 0x6d, 0x17, 0x69, 0x8c, 0xfe, 0x23, 0x42, 0x8a, 0x50, 0xcb, 0xcc, 0x0a, 0x95,
- 0x2e, 0x59, 0x07, 0x6f, 0x1a, 0x0e, 0x19, 0xa7, 0x4b, 0x30, 0xdc, 0xea, 0x30, 0x5a, 0x89, 0x54,
- 0xa6, 0xec, 0x96, 0x33, 0x1c, 0x81, 0x23, 0x99, 0x82, 0x6c, 0xb8, 0xb6, 0xb9, 0x88, 0x65, 0xbc,
- 0x2e, 0x58, 0xe0, 0x0c, 0x07, 0xe4, 0x00, 0x00, 0x08, 0xd3, 0xcf, 0xb9, 0x5e, 0x6d, 0xe2, 0x7f,
- 0x1b, 0xa3, 0xdc, 0x00, 0xc8, 0x45, 0xff, 0x11, 0x21, 0x89, 0xca, 0x56, 0x42, 0xcb, 0x34, 0x2c,
- 0x18, 0x75, 0xe2, 0x80, 0x70, 0x00, 0xe8, 0x2e, 0xa9, 0x40, 0x71, 0x1a, 0x76, 0x67, 0x67, 0x6b,
- 0xaf, 0xd9, 0xbf, 0xd5, 0xbb, 0x59, 0xaf, 0xdc, 0xdd, 0xd2, 0xa7, 0xa4, 0x16, 0x15, 0x6b, 0x11,
- 0x85, 0x05, 0xbb, 0xbb, 0x53, 0xda, 0x6b, 0x7f, 0x4f, 0x9e, 0xf7, 0x5f, 0x3d, 0x7f, 0xf5, 0xdd,
- 0xcb, 0xfe, 0xab, 0x17, 0xbc, 0x1a, 0x15, 0xeb, 0x41, 0x58, 0xd0, 0x27, 0xa4, 0xb9, 0xc8, 0x75,
- 0x24, 0x85, 0xd2, 0xf0, 0xd7, 0x3d, 0xfc, 0x8b, 0x20, 0x34, 0x06, 0x04, 0x82, 0x20, 0x2f, 0x64,
- 0x24, 0xa2, 0x34, 0x66, 0xf7, 0x77, 0xb6, 0x20, 0x08, 0x40, 0x0f, 0x52, 0x48, 0x92, 0x1a, 0xd6,
- 0x7a, 0x66, 0xd9, 0xc7, 0xa8, 0x49, 0xa7, 0x77, 0xa3, 0xf6, 0x79, 0x55, 0x5e, 0xd8, 0xa3, 0xcc,
- 0x42, 0x14, 0xd2, 0x30, 0x83, 0xf8, 0xb8, 0xf2, 0x32, 0x8c, 0xb9, 0x28, 0x38, 0x74, 0xe0, 0x40,
- 0xba, 0x4b, 0x6a, 0xd1, 0x12, 0x4b, 0x8f, 0x3d, 0xc0, 0xf7, 0x5a, 0xbd, 0x6b, 0xe5, 0xc8, 0xab,
- 0xd1, 0x92, 0x43, 0x60, 0x9e, 0x90, 0xa6, 0x36, 0x56, 0x18, 0x75, 0x9a, 0x40, 0x1d, 0x7c, 0xe2,
- 0x54, 0xd6, 0xc6, 0xce, 0x1c, 0x42, 0xf7, 0xaf, 0x97, 0x3d, 0x7b, 0x88, 0x4f, 0x35, 0x7b, 0x1f,
- 0x20, 0xde, 0xf0, 0xe7, 0x51, 0x4c, 0x77, 0x48, 0x0b, 0x23, 0xb5, 0x31, 0xe4, 0x4f, 0xee, 0x35,
- 0xc0, 0x86, 0x4e, 0xf9, 0x27, 0xae, 0xa6, 0xcc, 0x59, 0xa8, 0xe1, 0xbb, 0x47, 0x8e, 0x41, 0x5e,
- 0xd8, 0x99, 0x43, 0x36, 0x0c, 0x69, 0x68, 0xac, 0xd4, 0x86, 0x3d, 0xbe, 0x62, 0x38, 0x72, 0x08,
- 0xb8, 0xd0, 0xac, 0x54, 0x81, 0xef, 0x3f, 0x71, 0x2e, 0x04, 0x1a, 0x1e, 0x87, 0xf6, 0x95, 0x85,
- 0xa7, 0x89, 0x14, 0x0b, 0xc3, 0x76, 0xf0, 0xae, 0xee, 0x80, 0x91, 0xa1, 0x7b, 0xa4, 0xe9, 0x2b,
- 0x59, 0xa8, 0x2c, 0x67, 0x9f, 0xa2, 0x21, 0xf5, 0x9e, 0xc7, 0x78, 0x63, 0x8d, 0x45, 0x3d, 0xce,
- 0x72, 0xfa, 0x77, 0x72, 0xe7, 0xa6, 0x83, 0x45, 0x0a, 0x4d, 0xa8, 0xbb, 0x53, 0xda, 0xeb, 0xf4,
- 0xdb, 0x2e, 0x3f, 0xa2, 0x25, 0x82, 0xfc, 0xf6, 0x0d, 0xa7, 0x1f, 0xe5, 0xb1, 0x84, 0x8f, 0x96,
- 0x67, 0xb9, 0xb1, 0x22, 0x51, 0xa9, 0xb2, 0xec, 0x29, 0x66, 0x4b, 0xed, 0x9b, 0xaf, 0x9f, 0xff,
- 0xf5, 0xc5, 0xcb, 0xef, 0x38, 0xc1, 0xbb, 0x43, 0xb8, 0xa2, 0x7b, 0x24, 0xc0, 0x44, 0x11, 0x26,
- 0x0a, 0x33, 0x01, 0xdd, 0xcf, 0xb0, 0xcf, 0x50, 0xed, 0x0e, 0xe2, 0xb3, 0x28, 0xcc, 0xa6, 0x80,
- 0xd2, 0x4f, 0x20, 0x6f, 0xac, 0xd4, 0x59, 0x98, 0xb0, 0x5d, 0x6f, 0x98, 0xa7, 0x31, 0xa7, 0xd2,
- 0xc2, 0x5e, 0x8a, 0xcc, 0xb0, 0xcf, 0xe1, 0x33, 0x5e, 0x43, 0xfa, 0x18, 0x6c, 0xae, 0xb9, 0x51,
- 0x60, 0xd8, 0x17, 0x3e, 0xbb, 0x6f, 0x8e, 0x06, 0x5e, 0x05, 0xfa, 0xd8, 0xd0, 0x4f, 0x49, 0xcb,
- 0x67, 0x47, 0xa1, 0xf3, 0xc2, 0xb0, 0x3f, 0x63, 0x85, 0xfa, 0x06, 0x3e, 0x05, 0x88, 0xee, 0x93,
- 0xdb, 0xd7, 0x59, 0x5c, 0x27, 0xd9, 0x47, 0xbe, 0x5b, 0xd7, 0xf8, 0xb0, 0xa3, 0x3c, 0x27, 0xf7,
- 0x3d, 0x6f, 0xbc, 0x4e, 0x0b, 0x11, 0xe5, 0x99, 0xd5, 0x79, 0x92, 0x48, 0xcd, 0xbe, 0x44, 0xed,
- 0xef, 0xba, 0xdb, 0x83, 0x75, 0x5a, 0x0c, 0xae, 0xee, 0xa0, 0x2b, 0x2f, 0xb4, 0x94, 0xef, 0x37,
- 0x8e, 0x67, 0xcf, 0xf0, 0xf5, 0x96, 0x03, 0x9d, 0x8f, 0x61, 0x42, 0x5b, 0x95, 0x4a, 0x98, 0x95,
- 0x7f, 0x71, 0xd6, 0x7a, 0x92, 0x7e, 0x49, 0x28, 0xf4, 0x63, 0xcc, 0x0e, 0x95, 0x89, 0x45, 0xa2,
- 0x96, 0x67, 0x96, 0xf5, 0x30, 0x83, 0xa0, 0x53, 0xcf, 0x56, 0xaa, 0x18, 0x67, 0x23, 0x84, 0xc1,
- 0xe0, 0x9f, 0x65, 0xb8, 0x12, 0xe6, 0xd2, 0x44, 0x36, 0x31, 0xec, 0x2b, 0x64, 0x6b, 0x02, 0x36,
- 0x73, 0x10, 0x36, 0x8e, 0xf0, 0xfd, 0x25, 0xf6, 0x42, 0xc3, 0xbe, 0xf6, 0x8d, 0x23, 0x7c, 0x7f,
- 0x39, 0x05, 0x00, 0x9b, 0xb5, 0x0d, 0xed, 0xda, 0x40, 0x5d, 0x7c, 0x83, 0x5d, 0xa7, 0xee, 0x80,
- 0x51, 0x0c, 0xce, 0xca, 0x75, 0x71, 0x06, 0x61, 0xb5, 0xc6, 0x67, 0x33, 0xeb, 0x3b, 0x55, 0xdc,
- 0xc5, 0xd4, 0x1a, 0x97, 0xd2, 0x90, 0xf2, 0x51, 0x9e, 0x2d, 0x94, 0x6f, 0xce, 0xdf, 0xa2, 0xd1,
- 0xc4, 0x41, 0xe0, 0xcd, 0xee, 0x33, 0xbf, 0x44, 0xa0, 0x2f, 0xb5, 0x34, 0x05, 0xe4, 0x83, 0x96,
- 0xc6, 0xe6, 0x5a, 0xc6, 0x38, 0x50, 0xeb, 0xfc, 0x8a, 0xee, 0xee, 0x92, 0xdb, 0xc8, 0xed, 0x01,
- 0x27, 0xe0, 0x47, 0xa0, 0x1b, 0x8e, 0x70, 0xec, 0xbe, 0x24, 0x4d, 0x64, 0x73, 0xbd, 0x9b, 0xde,
- 0x27, 0x55, 0xd7, 0xd4, 0xfd, 0x80, 0xf6, 0xd4, 0x6f, 0x67, 0x67, 0xf7, 0x47, 0xd2, 0x46, 0xc1,
- 0x85, 0x0c, 0xed, 0x5a, 0x3b, 0x47, 0xa4, 0x32, 0x15, 0xd8, 0xaf, 0x37, 0xda, 0xa4, 0x32, 0x9d,
- 0x03, 0xfd, 0x2b, 0x27, 0x96, 0x7f, 0xe5, 0xc4, 0xee, 0x2f, 0x25, 0x52, 0xf7, 0xda, 0xfe, 0x8b,
- 0x76, 0xc9, 0xb6, 0xbd, 0x2c, 0xdc, 0xb8, 0xef, 0xf4, 0x3b, 0xbd, 0xcd, 0x85, 0x00, 0x94, 0xe3,
- 0x1d, 0x7d, 0x4c, 0xb6, 0x61, 0xee, 0xe3, 0x4b, 0xcd, 0x3e, 0xe9, 0x5d, 0x6d, 0x02, 0x1c, 0xf1,
- 0xeb, 0x33, 0x6a, 0x1d, 0x45, 0xb0, 0xc7, 0x6d, 0xdd, 0x98, 0x51, 0x0e, 0x04, 0x9d, 0x57, 0x52,
- 0x16, 0x22, 0x2f, 0x64, 0xe6, 0x27, 0x7b, 0x1d, 0x80, 0x49, 0x21, 0x33, 0xba, 0x4f, 0xea, 0x1b,
- 0xe3, 0x70, 0xa2, 0x37, 0x37, 0xba, 0x6c, 0x50, 0x7e, 0x75, 0xbf, 0xf1, 0x4f, 0x15, 0x53, 0x11,
- 0xfd, 0xf3, 0xef, 0x2d, 0xbf, 0x9f, 0xa0, 0xe3, 0xff, 0x1f, 0x9b, 0x18, 0xa9, 0x6d, 0x94, 0x85,
- 0x4d, 0xa8, 0xce, 0x37, 0x24, 0x7d, 0x4a, 0xb6, 0x21, 0xe8, 0x68, 0xc3, 0xd5, 0x6c, 0xba, 0x4a,
- 0x03, 0x8e, 0x97, 0xf4, 0x19, 0xa9, 0xf9, 0x58, 0xa3, 0x25, 0xcd, 0x3e, 0xed, 0xfd, 0x26, 0x01,
- 0xf8, 0x86, 0x85, 0x7e, 0x46, 0xaa, 0xce, 0x15, 0xde, 0xb4, 0x56, 0xef, 0x5a, 0x1a, 0x70, 0x7f,
- 0xe7, 0x57, 0x82, 0xea, 0x1f, 0xae, 0x04, 0x0f, 0x20, 0x7c, 0x42, 0x6a, 0x9d, 0xe5, 0xb8, 0xb0,
- 0x54, 0x78, 0x2d, 0xd2, 0x43, 0x20, 0x6f, 0x78, 0xb1, 0xfe, 0x07, 0x5e, 0x7c, 0x08, 0x2e, 0x83,
- 0x67, 0x52, 0xb3, 0xc4, 0xe5, 0xa5, 0xc1, 0xeb, 0xf8, 0x4e, 0x6a, 0x96, 0x30, 0x19, 0xcf, 0xa5,
- 0x36, 0x2a, 0xcf, 0x70, 0x71, 0x69, 0x6e, 0x7a, 0xb0, 0x07, 0xf9, 0xe6, 0x16, 0x73, 0x18, 0x0b,
- 0x10, 0x77, 0x99, 0x0a, 0xf7, 0x54, 0xf7, 0x3f, 0x25, 0xd2, 0xba, 0x2e, 0x01, 0x8b, 0x65, 0x1a,
- 0xbe, 0xcb, 0xb5, 0xaf, 0x07, 0x47, 0x20, 0xaa, 0xb2, 0x5c, 0xfb, 0x1d, 0xd6, 0x11, 0x80, 0x2e,
- 0x95, 0xf5, 0x5b, 0x7e, 0x83, 0x3b, 0x02, 0x0a, 0xd0, 0xac, 0x4f, 0xdd, 0xb2, 0xb5, 0xed, 0x6b,
- 0xdf, 0xd3, 0x20, 0x81, 0x4b, 0x33, 0x3a, 0xb8, 0xc2, 0x1d, 0x01, 0x5b, 0x11, 0xb4, 0x5d, 0xf4,
- 0x69, 0x83, 0xe3, 0x79, 0x5f, 0x78, 0xbd, 0xfc, 0x34, 0xa1, 0x84, 0x54, 0xc7, 0x6f, 0x8e, 0x27,
- 0x7c, 0x18, 0x7c, 0x44, 0x9b, 0xa4, 0x36, 0x78, 0x23, 0x8e, 0x27, 0xc7, 0xc3, 0xa0, 0x44, 0x1b,
- 0xa4, 0x32, 0xe5, 0x93, 0xe9, 0x2c, 0x28, 0xd3, 0x3a, 0xd9, 0x9e, 0x4d, 0x46, 0xf3, 0x60, 0x0b,
- 0x4e, 0xa3, 0x93, 0xc3, 0xc3, 0x60, 0x1b, 0xe4, 0x66, 0x73, 0x3e, 0x1e, 0xcc, 0x83, 0x0a, 0xc8,
- 0x1d, 0x0c, 0x47, 0xaf, 0x4f, 0x0e, 0xe7, 0x41, 0x75, 0xff, 0x97, 0x92, 0x2f, 0xd6, 0x4d, 0xc6,
- 0xc1, 0x4b, 0xc3, 0xa3, 0xe9, 0xfc, 0xa7, 0xe0, 0x23, 0x90, 0x3f, 0x38, 0x39, 0x9a, 0x06, 0x25,
- 0x90, 0xe1, 0xc3, 0xd9, 0x1c, 0x3e, 0x2e, 0x03, 0xc7, 0xe0, 0x87, 0xe1, 0xe0, 0xc7, 0x60, 0x8b,
- 0xb6, 0x48, 0x7d, 0xca, 0x87, 0x02, 0xb9, 0xb6, 0xe9, 0x2d, 0xd2, 0x9c, 0xbe, 0x7e, 0x33, 0x14,
- 0xb3, 0x21, 0x7f, 0x3b, 0xe4, 0x41, 0x05, 0xbe, 0x3d, 0x9e, 0xcc, 0xc7, 0xa3, 0x9f, 0x82, 0x2a,
- 0x0d, 0x48, 0x6b, 0x30, 0x3d, 0x19, 0x1f, 0x8f, 0x26, 0x8e, 0xbd, 0x46, 0x6f, 0x93, 0xf6, 0x06,
- 0x71, 0xef, 0xd5, 0x01, 0x1a, 0x0d, 0x5f, 0xcf, 0x4f, 0xf8, 0xd0, 0x43, 0x0d, 0xf8, 0xfa, 0xed,
- 0x90, 0xcf, 0xc6, 0x93, 0xe3, 0x80, 0xc0, 0x7f, 0xff, 0x7c, 0x3d, 0x9e, 0x8b, 0xe9, 0xf8, 0x20,
- 0x68, 0xd2, 0xbb, 0x24, 0xb8, 0xf6, 0x9f, 0x18, 0xfc, 0x70, 0x78, 0x10, 0xb4, 0xfe, 0x17, 0x00,
- 0x00, 0xff, 0xff, 0xf8, 0x9f, 0x0e, 0x7d, 0xca, 0x0d, 0x00, 0x00,
-}
diff --git a/vendor/github.com/checkpoint-restore/go-criu/v4/.gitignore b/vendor/github.com/checkpoint-restore/go-criu/v4/.gitignore
new file mode 100644
index 000000000..f1c90e3d5
--- /dev/null
+++ b/vendor/github.com/checkpoint-restore/go-criu/v4/.gitignore
@@ -0,0 +1,5 @@
+test/test
+test/piggie
+test/phaul
+image
+rpc/rpc.proto
diff --git a/vendor/github.com/checkpoint-restore/go-criu/v4/.travis.yml b/vendor/github.com/checkpoint-restore/go-criu/v4/.travis.yml
new file mode 100644
index 000000000..85e0cde37
--- /dev/null
+++ b/vendor/github.com/checkpoint-restore/go-criu/v4/.travis.yml
@@ -0,0 +1,28 @@
+language: go
+dist: bionic
+os:
+ - linux
+go:
+ - "1.14.x"
+ - "1.13.x"
+ - tip
+env:
+ # Run the tests with CRIU master and criu-dev
+ - CRIU_BRANCH="master"
+ - CRIU_BRANCH="criu-dev"
+install:
+ - sudo apt-get update
+ - sudo apt-get install -y libprotobuf-dev libprotobuf-c0-dev protobuf-c-compiler protobuf-compiler python-protobuf libnl-3-dev libnet-dev libcap-dev
+ - make install.tools
+ - go get github.com/checkpoint-restore/go-criu
+ - git clone --single-branch -b ${CRIU_BRANCH} https://github.com/checkpoint-restore/criu.git
+ - cd criu; make
+ - sudo install -D -m 755 criu/criu /usr/sbin/
+ - cd ..
+script:
+ # This builds the code without running the tests.
+ - make lint build phaul test/test test/phaul test/piggie
+ # Run actual test as root as it uses CRIU.
+ - sudo make test phaul-test
+ # This builds crit-go
+ - make -C crit-go/magic-gen lint build magicgen test
diff --git a/vendor/github.com/checkpoint-restore/go-criu/LICENSE b/vendor/github.com/checkpoint-restore/go-criu/v4/LICENSE
similarity index 100%
rename from vendor/github.com/checkpoint-restore/go-criu/LICENSE
rename to vendor/github.com/checkpoint-restore/go-criu/v4/LICENSE
diff --git a/vendor/github.com/checkpoint-restore/go-criu/v4/Makefile b/vendor/github.com/checkpoint-restore/go-criu/v4/Makefile
new file mode 100644
index 000000000..10356304b
--- /dev/null
+++ b/vendor/github.com/checkpoint-restore/go-criu/v4/Makefile
@@ -0,0 +1,60 @@
+GO ?= go
+CC ?= gcc
+ifeq ($(GOPATH),)
+export GOPATH := $(shell $(GO) env GOPATH)
+endif
+FIRST_GOPATH := $(firstword $(subst :, ,$(GOPATH)))
+GOBIN := $(shell $(GO) env GOBIN)
+ifeq ($(GOBIN),)
+ GOBIN := $(FIRST_GOPATH)/bin
+endif
+
+all: build test phaul phaul-test
+
+lint:
+ @golint -set_exit_status . test phaul
+build:
+ @$(GO) build -v
+
+test/piggie: test/piggie.c
+ @$(CC) $^ -o $@
+
+test/test: test/main.go
+ @$(GO) build -v -o test/test test/main.go
+
+test: test/test test/piggie
+ mkdir -p image
+ test/piggie
+ test/test dump `pidof piggie` image
+ test/test restore image
+ pkill -9 piggie || :
+
+phaul:
+ @cd phaul; go build -v
+
+test/phaul: test/phaul-main.go
+ @$(GO) build -v -o test/phaul test/phaul-main.go
+
+phaul-test: test/phaul test/piggie
+ rm -rf image
+ test/piggie
+ test/phaul `pidof piggie`
+ pkill -9 piggie || :
+
+clean:
+ @rm -f test/test test/piggie test/phaul
+ @rm -rf image
+ @rm -f rpc/rpc.proto
+
+install.tools:
+ if [ ! -x "$(GOBIN)/golint" ]; then \
+ $(GO) get -u golang.org/x/lint/golint; \
+ fi
+
+rpc/rpc.proto:
+ curl -s https://raw.githubusercontent.com/checkpoint-restore/criu/master/images/rpc.proto -o $@
+
+rpc/rpc.pb.go: rpc/rpc.proto
+ protoc --go_out=. $^
+
+.PHONY: build test clean lint phaul
diff --git a/vendor/github.com/checkpoint-restore/go-criu/v4/README.md b/vendor/github.com/checkpoint-restore/go-criu/v4/README.md
new file mode 100644
index 000000000..ace01564c
--- /dev/null
+++ b/vendor/github.com/checkpoint-restore/go-criu/v4/README.md
@@ -0,0 +1,75 @@
+[![master](https://travis-ci.org/checkpoint-restore/go-criu.svg?branch=master)](https://travis-ci.org/checkpoint-restore/go-criu)
+
+## go-criu -- Go bindings for [CRIU](https://criu.org/)
+
+This repository provides Go bindings for CRIU. The code is based on the Go based PHaul
+implementation from the CRIU repository. For easier inclusion into other Go projects the
+CRIU Go bindings have been moved to this repository.
+
+The Go bindings provide an easy way to use the CRIU RPC calls from Go without the need
+to set up all the infrastructure to make the actual RPC connection to CRIU.
+
+The following example would print the version of CRIU:
+```
+ c := criu.MakeCriu()
+ version, err := c.GetCriuVersion()
+ fmt.Println(version)
+```
+or to just check if at least a certain CRIU version is installed:
+```
+ c := criu.MakeCriu()
+ result, err := c.IsCriuAtLeast(31100)
+```
+
+## Releases
+
+The first go-criu release was 3.11 based on CRIU 3.11. The initial plan
+was to follow CRIU so that go-criu would carry the same version number as
+CRIU.
+
+As go-criu is imported in other projects and as Go modules are expected
+to follow Semantic Versioning go-criu will also follow Semantic Versioning
+starting with the 4.0.0 release.
+
+4.0.0 is based on CRIU 3.14
+
+## How to contribute
+
+While bug fixes can first be identified via an "issue", that is not required.
+It's ok to just open up a PR with the fix, but make sure you include the same
+information you would have included in an issue - like how to reproduce it.
+
+PRs for new features should include some background on what use cases the
+new code is trying to address. When possible and when it makes sense, try to
+break-up larger PRs into smaller ones - it's easier to review smaller
+code changes. But only if those smaller ones make sense as stand-alone PRs.
+
+Regardless of the type of PR, all PRs should include:
+* well documented code changes
+* additional testcases. Ideally, they should fail w/o your code change applied
+* documentation changes
+
+Squash your commits into logical pieces of work that might want to be reviewed
+separate from the rest of the PRs. Ideally, each commit should implement a
+single idea, and the PR branch should pass the tests at every commit. GitHub
+makes it easy to review the cumulative effect of many commits; so, when in
+doubt, use smaller commits.
+
+PRs that fix issues should include a reference like `Closes #XXXX` in the
+commit message so that github will automatically close the referenced issue
+when the PR is merged.
+
+Contributors must assert that they are in compliance with the [Developer
+Certificate of Origin 1.1](http://developercertificate.org/). This is achieved
+by adding a "Signed-off-by" line containing the contributor's name and e-mail
+to every commit message. Your signature certifies that you wrote the patch or
+otherwise have the right to pass it on as an open-source patch.
+
+### License and copyright
+
+Unless mentioned otherwise in a specific file's header, all code in
+this project is released under the Apache 2.0 license.
+
+The author of a change remains the copyright holder of their code
+(no copyright assignment). The list of authors and contributors can be
+retrieved from the git commit history and in some cases, the file headers.
diff --git a/vendor/github.com/checkpoint-restore/go-criu/v4/go.mod b/vendor/github.com/checkpoint-restore/go-criu/v4/go.mod
new file mode 100644
index 000000000..496666906
--- /dev/null
+++ b/vendor/github.com/checkpoint-restore/go-criu/v4/go.mod
@@ -0,0 +1,5 @@
+module github.com/checkpoint-restore/go-criu/v4
+
+go 1.13
+
+require github.com/golang/protobuf v1.3.5
diff --git a/vendor/github.com/checkpoint-restore/go-criu/v4/go.sum b/vendor/github.com/checkpoint-restore/go-criu/v4/go.sum
new file mode 100644
index 000000000..6124ed3e4
--- /dev/null
+++ b/vendor/github.com/checkpoint-restore/go-criu/v4/go.sum
@@ -0,0 +1,2 @@
+github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls=
+github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
diff --git a/vendor/github.com/checkpoint-restore/go-criu/v4/main.go b/vendor/github.com/checkpoint-restore/go-criu/v4/main.go
new file mode 100644
index 000000000..d0a6da478
--- /dev/null
+++ b/vendor/github.com/checkpoint-restore/go-criu/v4/main.go
@@ -0,0 +1,259 @@
+package criu
+
+import (
+ "errors"
+ "fmt"
+ "os"
+ "os/exec"
+ "strconv"
+ "syscall"
+
+ "github.com/checkpoint-restore/go-criu/v4/rpc"
+ "github.com/golang/protobuf/proto"
+)
+
+// Criu struct
+type Criu struct {
+ swrkCmd *exec.Cmd
+ swrkSk *os.File
+ swrkPath string
+}
+
+// MakeCriu returns the Criu object required for most operations
+func MakeCriu() *Criu {
+ return &Criu{
+ swrkPath: "criu",
+ }
+}
+
+// SetCriuPath allows setting the path to the CRIU binary
+// if it is in a non standard location
+func (c *Criu) SetCriuPath(path string) {
+ c.swrkPath = path
+}
+
+// Prepare sets up everything for the RPC communication to CRIU
+func (c *Criu) Prepare() error {
+ fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_SEQPACKET, 0)
+ if err != nil {
+ return err
+ }
+
+ cln := os.NewFile(uintptr(fds[0]), "criu-xprt-cln")
+ syscall.CloseOnExec(fds[0])
+ srv := os.NewFile(uintptr(fds[1]), "criu-xprt-srv")
+ defer srv.Close()
+
+ args := []string{"swrk", strconv.Itoa(fds[1])}
+ cmd := exec.Command(c.swrkPath, args...)
+
+ err = cmd.Start()
+ if err != nil {
+ cln.Close()
+ return err
+ }
+
+ c.swrkCmd = cmd
+ c.swrkSk = cln
+
+ return nil
+}
+
+// Cleanup cleans up
+func (c *Criu) Cleanup() {
+ if c.swrkCmd != nil {
+ c.swrkSk.Close()
+ c.swrkSk = nil
+ c.swrkCmd.Wait()
+ c.swrkCmd = nil
+ }
+}
+
+func (c *Criu) sendAndRecv(reqB []byte) ([]byte, int, error) {
+ cln := c.swrkSk
+ _, err := cln.Write(reqB)
+ if err != nil {
+ return nil, 0, err
+ }
+
+ respB := make([]byte, 2*4096)
+ n, err := cln.Read(respB)
+ if err != nil {
+ return nil, 0, err
+ }
+
+ return respB, n, nil
+}
+
+func (c *Criu) doSwrk(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy Notify) error {
+ resp, err := c.doSwrkWithResp(reqType, opts, nfy)
+ if err != nil {
+ return err
+ }
+ respType := resp.GetType()
+ if respType != reqType {
+ return errors.New("unexpected responce")
+ }
+
+ return nil
+}
+
+func (c *Criu) doSwrkWithResp(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy Notify) (*rpc.CriuResp, error) {
+ var resp *rpc.CriuResp
+
+ req := rpc.CriuReq{
+ Type: &reqType,
+ Opts: opts,
+ }
+
+ if nfy != nil {
+ opts.NotifyScripts = proto.Bool(true)
+ }
+
+ if c.swrkCmd == nil {
+ err := c.Prepare()
+ if err != nil {
+ return nil, err
+ }
+
+ defer c.Cleanup()
+ }
+
+ for {
+ reqB, err := proto.Marshal(&req)
+ if err != nil {
+ return nil, err
+ }
+
+ respB, respS, err := c.sendAndRecv(reqB)
+ if err != nil {
+ return nil, err
+ }
+
+ resp = &rpc.CriuResp{}
+ err = proto.Unmarshal(respB[:respS], resp)
+ if err != nil {
+ return nil, err
+ }
+
+ if !resp.GetSuccess() {
+ return resp, fmt.Errorf("operation failed (msg:%s err:%d)",
+ resp.GetCrErrmsg(), resp.GetCrErrno())
+ }
+
+ respType := resp.GetType()
+ if respType != rpc.CriuReqType_NOTIFY {
+ break
+ }
+ if nfy == nil {
+ return resp, errors.New("unexpected notify")
+ }
+
+ notify := resp.GetNotify()
+ switch notify.GetScript() {
+ case "pre-dump":
+ err = nfy.PreDump()
+ case "post-dump":
+ err = nfy.PostDump()
+ case "pre-restore":
+ err = nfy.PreRestore()
+ case "post-restore":
+ err = nfy.PostRestore(notify.GetPid())
+ case "network-lock":
+ err = nfy.NetworkLock()
+ case "network-unlock":
+ err = nfy.NetworkUnlock()
+ case "setup-namespaces":
+ err = nfy.SetupNamespaces(notify.GetPid())
+ case "post-setup-namespaces":
+ err = nfy.PostSetupNamespaces()
+ case "post-resume":
+ err = nfy.PostResume()
+ default:
+ err = nil
+ }
+
+ if err != nil {
+ return resp, err
+ }
+
+ req = rpc.CriuReq{
+ Type: &respType,
+ NotifySuccess: proto.Bool(true),
+ }
+ }
+
+ return resp, nil
+}
+
+// Dump dumps a process
+func (c *Criu) Dump(opts rpc.CriuOpts, nfy Notify) error {
+ return c.doSwrk(rpc.CriuReqType_DUMP, &opts, nfy)
+}
+
+// Restore restores a process
+func (c *Criu) Restore(opts rpc.CriuOpts, nfy Notify) error {
+ return c.doSwrk(rpc.CriuReqType_RESTORE, &opts, nfy)
+}
+
+// PreDump does a pre-dump
+func (c *Criu) PreDump(opts rpc.CriuOpts, nfy Notify) error {
+ return c.doSwrk(rpc.CriuReqType_PRE_DUMP, &opts, nfy)
+}
+
+// StartPageServer starts the page server
+func (c *Criu) StartPageServer(opts rpc.CriuOpts) error {
+ return c.doSwrk(rpc.CriuReqType_PAGE_SERVER, &opts, nil)
+}
+
+// StartPageServerChld starts the page server and returns PID and port
+func (c *Criu) StartPageServerChld(opts rpc.CriuOpts) (int, int, error) {
+ resp, err := c.doSwrkWithResp(rpc.CriuReqType_PAGE_SERVER_CHLD, &opts, nil)
+ if err != nil {
+ return 0, 0, err
+ }
+
+ return int(resp.Ps.GetPid()), int(resp.Ps.GetPort()), nil
+}
+
+// GetCriuVersion executes the VERSION RPC call and returns the version
+// as an integer. Major * 10000 + Minor * 100 + SubLevel
+func (c *Criu) GetCriuVersion() (int, error) {
+ resp, err := c.doSwrkWithResp(rpc.CriuReqType_VERSION, nil, nil)
+ if err != nil {
+ return 0, err
+ }
+
+ if resp.GetType() != rpc.CriuReqType_VERSION {
+ return 0, fmt.Errorf("Unexpected CRIU RPC response")
+ }
+
+ version := int(*resp.GetVersion().MajorNumber) * 10000
+ version += int(*resp.GetVersion().MinorNumber) * 100
+ if resp.GetVersion().Sublevel != nil {
+ version += int(*resp.GetVersion().Sublevel)
+ }
+
+ if resp.GetVersion().Gitid != nil {
+ // taken from runc: if it is a git release -> increase minor by 1
+ version -= (version % 100)
+ version += 100
+ }
+
+ return version, nil
+}
+
+// IsCriuAtLeast checks if the version is at least the same
+// as the parameter version
+func (c *Criu) IsCriuAtLeast(version int) (bool, error) {
+ criuVersion, err := c.GetCriuVersion()
+ if err != nil {
+ return false, err
+ }
+
+ if criuVersion >= version {
+ return true, nil
+ }
+
+ return false, nil
+}
diff --git a/vendor/github.com/checkpoint-restore/go-criu/v4/notify.go b/vendor/github.com/checkpoint-restore/go-criu/v4/notify.go
new file mode 100644
index 000000000..1c8547b43
--- /dev/null
+++ b/vendor/github.com/checkpoint-restore/go-criu/v4/notify.go
@@ -0,0 +1,63 @@
+package criu
+
+//Notify interface
+type Notify interface {
+ PreDump() error
+ PostDump() error
+ PreRestore() error
+ PostRestore(pid int32) error
+ NetworkLock() error
+ NetworkUnlock() error
+ SetupNamespaces(pid int32) error
+ PostSetupNamespaces() error
+ PostResume() error
+}
+
+// NoNotify struct
+type NoNotify struct {
+}
+
+// PreDump NoNotify
+func (c NoNotify) PreDump() error {
+ return nil
+}
+
+// PostDump NoNotify
+func (c NoNotify) PostDump() error {
+ return nil
+}
+
+// PreRestore NoNotify
+func (c NoNotify) PreRestore() error {
+ return nil
+}
+
+// PostRestore NoNotify
+func (c NoNotify) PostRestore(pid int32) error {
+ return nil
+}
+
+// NetworkLock NoNotify
+func (c NoNotify) NetworkLock() error {
+ return nil
+}
+
+// NetworkUnlock NoNotify
+func (c NoNotify) NetworkUnlock() error {
+ return nil
+}
+
+// SetupNamespaces NoNotify
+func (c NoNotify) SetupNamespaces(pid int32) error {
+ return nil
+}
+
+// PostSetupNamespaces NoNotify
+func (c NoNotify) PostSetupNamespaces() error {
+ return nil
+}
+
+// PostResume NoNotify
+func (c NoNotify) PostResume() error {
+ return nil
+}
diff --git a/vendor/github.com/checkpoint-restore/go-criu/v4/rpc/rpc.pb.go b/vendor/github.com/checkpoint-restore/go-criu/v4/rpc/rpc.pb.go
new file mode 100644
index 000000000..f9baece4e
--- /dev/null
+++ b/vendor/github.com/checkpoint-restore/go-criu/v4/rpc/rpc.pb.go
@@ -0,0 +1,1667 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: rpc/rpc.proto
+
+package rpc
+
+import (
+ fmt "fmt"
+ proto "github.com/golang/protobuf/proto"
+ math "math"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
+
+type CriuCgMode int32
+
+const (
+ CriuCgMode_IGNORE CriuCgMode = 0
+ CriuCgMode_CG_NONE CriuCgMode = 1
+ CriuCgMode_PROPS CriuCgMode = 2
+ CriuCgMode_SOFT CriuCgMode = 3
+ CriuCgMode_FULL CriuCgMode = 4
+ CriuCgMode_STRICT CriuCgMode = 5
+ CriuCgMode_DEFAULT CriuCgMode = 6
+)
+
+var CriuCgMode_name = map[int32]string{
+ 0: "IGNORE",
+ 1: "CG_NONE",
+ 2: "PROPS",
+ 3: "SOFT",
+ 4: "FULL",
+ 5: "STRICT",
+ 6: "DEFAULT",
+}
+
+var CriuCgMode_value = map[string]int32{
+ "IGNORE": 0,
+ "CG_NONE": 1,
+ "PROPS": 2,
+ "SOFT": 3,
+ "FULL": 4,
+ "STRICT": 5,
+ "DEFAULT": 6,
+}
+
+func (x CriuCgMode) Enum() *CriuCgMode {
+ p := new(CriuCgMode)
+ *p = x
+ return p
+}
+
+func (x CriuCgMode) String() string {
+ return proto.EnumName(CriuCgMode_name, int32(x))
+}
+
+func (x *CriuCgMode) UnmarshalJSON(data []byte) error {
+ value, err := proto.UnmarshalJSONEnum(CriuCgMode_value, data, "CriuCgMode")
+ if err != nil {
+ return err
+ }
+ *x = CriuCgMode(value)
+ return nil
+}
+
+func (CriuCgMode) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_d9874a201429861e, []int{0}
+}
+
+type CriuPreDumpMode int32
+
+const (
+ CriuPreDumpMode_SPLICE CriuPreDumpMode = 1
+ CriuPreDumpMode_VM_READ CriuPreDumpMode = 2
+)
+
+var CriuPreDumpMode_name = map[int32]string{
+ 1: "SPLICE",
+ 2: "VM_READ",
+}
+
+var CriuPreDumpMode_value = map[string]int32{
+ "SPLICE": 1,
+ "VM_READ": 2,
+}
+
+func (x CriuPreDumpMode) Enum() *CriuPreDumpMode {
+ p := new(CriuPreDumpMode)
+ *p = x
+ return p
+}
+
+func (x CriuPreDumpMode) String() string {
+ return proto.EnumName(CriuPreDumpMode_name, int32(x))
+}
+
+func (x *CriuPreDumpMode) UnmarshalJSON(data []byte) error {
+ value, err := proto.UnmarshalJSONEnum(CriuPreDumpMode_value, data, "CriuPreDumpMode")
+ if err != nil {
+ return err
+ }
+ *x = CriuPreDumpMode(value)
+ return nil
+}
+
+func (CriuPreDumpMode) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_d9874a201429861e, []int{1}
+}
+
+type CriuReqType int32
+
+const (
+ CriuReqType_EMPTY CriuReqType = 0
+ CriuReqType_DUMP CriuReqType = 1
+ CriuReqType_RESTORE CriuReqType = 2
+ CriuReqType_CHECK CriuReqType = 3
+ CriuReqType_PRE_DUMP CriuReqType = 4
+ CriuReqType_PAGE_SERVER CriuReqType = 5
+ CriuReqType_NOTIFY CriuReqType = 6
+ CriuReqType_CPUINFO_DUMP CriuReqType = 7
+ CriuReqType_CPUINFO_CHECK CriuReqType = 8
+ CriuReqType_FEATURE_CHECK CriuReqType = 9
+ CriuReqType_VERSION CriuReqType = 10
+ CriuReqType_WAIT_PID CriuReqType = 11
+ CriuReqType_PAGE_SERVER_CHLD CriuReqType = 12
+)
+
+var CriuReqType_name = map[int32]string{
+ 0: "EMPTY",
+ 1: "DUMP",
+ 2: "RESTORE",
+ 3: "CHECK",
+ 4: "PRE_DUMP",
+ 5: "PAGE_SERVER",
+ 6: "NOTIFY",
+ 7: "CPUINFO_DUMP",
+ 8: "CPUINFO_CHECK",
+ 9: "FEATURE_CHECK",
+ 10: "VERSION",
+ 11: "WAIT_PID",
+ 12: "PAGE_SERVER_CHLD",
+}
+
+var CriuReqType_value = map[string]int32{
+ "EMPTY": 0,
+ "DUMP": 1,
+ "RESTORE": 2,
+ "CHECK": 3,
+ "PRE_DUMP": 4,
+ "PAGE_SERVER": 5,
+ "NOTIFY": 6,
+ "CPUINFO_DUMP": 7,
+ "CPUINFO_CHECK": 8,
+ "FEATURE_CHECK": 9,
+ "VERSION": 10,
+ "WAIT_PID": 11,
+ "PAGE_SERVER_CHLD": 12,
+}
+
+func (x CriuReqType) Enum() *CriuReqType {
+ p := new(CriuReqType)
+ *p = x
+ return p
+}
+
+func (x CriuReqType) String() string {
+ return proto.EnumName(CriuReqType_name, int32(x))
+}
+
+func (x *CriuReqType) UnmarshalJSON(data []byte) error {
+ value, err := proto.UnmarshalJSONEnum(CriuReqType_value, data, "CriuReqType")
+ if err != nil {
+ return err
+ }
+ *x = CriuReqType(value)
+ return nil
+}
+
+func (CriuReqType) EnumDescriptor() ([]byte, []int) {
+ return fileDescriptor_d9874a201429861e, []int{2}
+}
+
+type CriuPageServerInfo struct {
+ Address *string `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"`
+ Port *int32 `protobuf:"varint,2,opt,name=port" json:"port,omitempty"`
+ Pid *int32 `protobuf:"varint,3,opt,name=pid" json:"pid,omitempty"`
+ Fd *int32 `protobuf:"varint,4,opt,name=fd" json:"fd,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CriuPageServerInfo) Reset() { *m = CriuPageServerInfo{} }
+func (m *CriuPageServerInfo) String() string { return proto.CompactTextString(m) }
+func (*CriuPageServerInfo) ProtoMessage() {}
+func (*CriuPageServerInfo) Descriptor() ([]byte, []int) {
+ return fileDescriptor_d9874a201429861e, []int{0}
+}
+
+func (m *CriuPageServerInfo) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CriuPageServerInfo.Unmarshal(m, b)
+}
+func (m *CriuPageServerInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CriuPageServerInfo.Marshal(b, m, deterministic)
+}
+func (m *CriuPageServerInfo) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CriuPageServerInfo.Merge(m, src)
+}
+func (m *CriuPageServerInfo) XXX_Size() int {
+ return xxx_messageInfo_CriuPageServerInfo.Size(m)
+}
+func (m *CriuPageServerInfo) XXX_DiscardUnknown() {
+ xxx_messageInfo_CriuPageServerInfo.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CriuPageServerInfo proto.InternalMessageInfo
+
+func (m *CriuPageServerInfo) GetAddress() string {
+ if m != nil && m.Address != nil {
+ return *m.Address
+ }
+ return ""
+}
+
+func (m *CriuPageServerInfo) GetPort() int32 {
+ if m != nil && m.Port != nil {
+ return *m.Port
+ }
+ return 0
+}
+
+func (m *CriuPageServerInfo) GetPid() int32 {
+ if m != nil && m.Pid != nil {
+ return *m.Pid
+ }
+ return 0
+}
+
+func (m *CriuPageServerInfo) GetFd() int32 {
+ if m != nil && m.Fd != nil {
+ return *m.Fd
+ }
+ return 0
+}
+
+type CriuVethPair struct {
+ IfIn *string `protobuf:"bytes,1,req,name=if_in,json=ifIn" json:"if_in,omitempty"`
+ IfOut *string `protobuf:"bytes,2,req,name=if_out,json=ifOut" json:"if_out,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CriuVethPair) Reset() { *m = CriuVethPair{} }
+func (m *CriuVethPair) String() string { return proto.CompactTextString(m) }
+func (*CriuVethPair) ProtoMessage() {}
+func (*CriuVethPair) Descriptor() ([]byte, []int) {
+ return fileDescriptor_d9874a201429861e, []int{1}
+}
+
+func (m *CriuVethPair) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CriuVethPair.Unmarshal(m, b)
+}
+func (m *CriuVethPair) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CriuVethPair.Marshal(b, m, deterministic)
+}
+func (m *CriuVethPair) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CriuVethPair.Merge(m, src)
+}
+func (m *CriuVethPair) XXX_Size() int {
+ return xxx_messageInfo_CriuVethPair.Size(m)
+}
+func (m *CriuVethPair) XXX_DiscardUnknown() {
+ xxx_messageInfo_CriuVethPair.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CriuVethPair proto.InternalMessageInfo
+
+func (m *CriuVethPair) GetIfIn() string {
+ if m != nil && m.IfIn != nil {
+ return *m.IfIn
+ }
+ return ""
+}
+
+func (m *CriuVethPair) GetIfOut() string {
+ if m != nil && m.IfOut != nil {
+ return *m.IfOut
+ }
+ return ""
+}
+
+type ExtMountMap struct {
+ Key *string `protobuf:"bytes,1,req,name=key" json:"key,omitempty"`
+ Val *string `protobuf:"bytes,2,req,name=val" json:"val,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *ExtMountMap) Reset() { *m = ExtMountMap{} }
+func (m *ExtMountMap) String() string { return proto.CompactTextString(m) }
+func (*ExtMountMap) ProtoMessage() {}
+func (*ExtMountMap) Descriptor() ([]byte, []int) {
+ return fileDescriptor_d9874a201429861e, []int{2}
+}
+
+func (m *ExtMountMap) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_ExtMountMap.Unmarshal(m, b)
+}
+func (m *ExtMountMap) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_ExtMountMap.Marshal(b, m, deterministic)
+}
+func (m *ExtMountMap) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_ExtMountMap.Merge(m, src)
+}
+func (m *ExtMountMap) XXX_Size() int {
+ return xxx_messageInfo_ExtMountMap.Size(m)
+}
+func (m *ExtMountMap) XXX_DiscardUnknown() {
+ xxx_messageInfo_ExtMountMap.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_ExtMountMap proto.InternalMessageInfo
+
+func (m *ExtMountMap) GetKey() string {
+ if m != nil && m.Key != nil {
+ return *m.Key
+ }
+ return ""
+}
+
+func (m *ExtMountMap) GetVal() string {
+ if m != nil && m.Val != nil {
+ return *m.Val
+ }
+ return ""
+}
+
+type JoinNamespace struct {
+ Ns *string `protobuf:"bytes,1,req,name=ns" json:"ns,omitempty"`
+ NsFile *string `protobuf:"bytes,2,req,name=ns_file,json=nsFile" json:"ns_file,omitempty"`
+ ExtraOpt *string `protobuf:"bytes,3,opt,name=extra_opt,json=extraOpt" json:"extra_opt,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *JoinNamespace) Reset() { *m = JoinNamespace{} }
+func (m *JoinNamespace) String() string { return proto.CompactTextString(m) }
+func (*JoinNamespace) ProtoMessage() {}
+func (*JoinNamespace) Descriptor() ([]byte, []int) {
+ return fileDescriptor_d9874a201429861e, []int{3}
+}
+
+func (m *JoinNamespace) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_JoinNamespace.Unmarshal(m, b)
+}
+func (m *JoinNamespace) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_JoinNamespace.Marshal(b, m, deterministic)
+}
+func (m *JoinNamespace) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_JoinNamespace.Merge(m, src)
+}
+func (m *JoinNamespace) XXX_Size() int {
+ return xxx_messageInfo_JoinNamespace.Size(m)
+}
+func (m *JoinNamespace) XXX_DiscardUnknown() {
+ xxx_messageInfo_JoinNamespace.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_JoinNamespace proto.InternalMessageInfo
+
+func (m *JoinNamespace) GetNs() string {
+ if m != nil && m.Ns != nil {
+ return *m.Ns
+ }
+ return ""
+}
+
+func (m *JoinNamespace) GetNsFile() string {
+ if m != nil && m.NsFile != nil {
+ return *m.NsFile
+ }
+ return ""
+}
+
+func (m *JoinNamespace) GetExtraOpt() string {
+ if m != nil && m.ExtraOpt != nil {
+ return *m.ExtraOpt
+ }
+ return ""
+}
+
+type InheritFd struct {
+ Key *string `protobuf:"bytes,1,req,name=key" json:"key,omitempty"`
+ Fd *int32 `protobuf:"varint,2,req,name=fd" json:"fd,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *InheritFd) Reset() { *m = InheritFd{} }
+func (m *InheritFd) String() string { return proto.CompactTextString(m) }
+func (*InheritFd) ProtoMessage() {}
+func (*InheritFd) Descriptor() ([]byte, []int) {
+ return fileDescriptor_d9874a201429861e, []int{4}
+}
+
+func (m *InheritFd) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_InheritFd.Unmarshal(m, b)
+}
+func (m *InheritFd) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_InheritFd.Marshal(b, m, deterministic)
+}
+func (m *InheritFd) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_InheritFd.Merge(m, src)
+}
+func (m *InheritFd) XXX_Size() int {
+ return xxx_messageInfo_InheritFd.Size(m)
+}
+func (m *InheritFd) XXX_DiscardUnknown() {
+ xxx_messageInfo_InheritFd.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_InheritFd proto.InternalMessageInfo
+
+func (m *InheritFd) GetKey() string {
+ if m != nil && m.Key != nil {
+ return *m.Key
+ }
+ return ""
+}
+
+func (m *InheritFd) GetFd() int32 {
+ if m != nil && m.Fd != nil {
+ return *m.Fd
+ }
+ return 0
+}
+
+type CgroupRoot struct {
+ Ctrl *string `protobuf:"bytes,1,opt,name=ctrl" json:"ctrl,omitempty"`
+ Path *string `protobuf:"bytes,2,req,name=path" json:"path,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CgroupRoot) Reset() { *m = CgroupRoot{} }
+func (m *CgroupRoot) String() string { return proto.CompactTextString(m) }
+func (*CgroupRoot) ProtoMessage() {}
+func (*CgroupRoot) Descriptor() ([]byte, []int) {
+ return fileDescriptor_d9874a201429861e, []int{5}
+}
+
+func (m *CgroupRoot) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CgroupRoot.Unmarshal(m, b)
+}
+func (m *CgroupRoot) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CgroupRoot.Marshal(b, m, deterministic)
+}
+func (m *CgroupRoot) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CgroupRoot.Merge(m, src)
+}
+func (m *CgroupRoot) XXX_Size() int {
+ return xxx_messageInfo_CgroupRoot.Size(m)
+}
+func (m *CgroupRoot) XXX_DiscardUnknown() {
+ xxx_messageInfo_CgroupRoot.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CgroupRoot proto.InternalMessageInfo
+
+func (m *CgroupRoot) GetCtrl() string {
+ if m != nil && m.Ctrl != nil {
+ return *m.Ctrl
+ }
+ return ""
+}
+
+func (m *CgroupRoot) GetPath() string {
+ if m != nil && m.Path != nil {
+ return *m.Path
+ }
+ return ""
+}
+
+type UnixSk struct {
+ Inode *uint32 `protobuf:"varint,1,req,name=inode" json:"inode,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *UnixSk) Reset() { *m = UnixSk{} }
+func (m *UnixSk) String() string { return proto.CompactTextString(m) }
+func (*UnixSk) ProtoMessage() {}
+func (*UnixSk) Descriptor() ([]byte, []int) {
+ return fileDescriptor_d9874a201429861e, []int{6}
+}
+
+func (m *UnixSk) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_UnixSk.Unmarshal(m, b)
+}
+func (m *UnixSk) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_UnixSk.Marshal(b, m, deterministic)
+}
+func (m *UnixSk) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_UnixSk.Merge(m, src)
+}
+func (m *UnixSk) XXX_Size() int {
+ return xxx_messageInfo_UnixSk.Size(m)
+}
+func (m *UnixSk) XXX_DiscardUnknown() {
+ xxx_messageInfo_UnixSk.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_UnixSk proto.InternalMessageInfo
+
+func (m *UnixSk) GetInode() uint32 {
+ if m != nil && m.Inode != nil {
+ return *m.Inode
+ }
+ return 0
+}
+
+type CriuOpts struct {
+ ImagesDirFd *int32 `protobuf:"varint,1,req,name=images_dir_fd,json=imagesDirFd" json:"images_dir_fd,omitempty"`
+ Pid *int32 `protobuf:"varint,2,opt,name=pid" json:"pid,omitempty"`
+ LeaveRunning *bool `protobuf:"varint,3,opt,name=leave_running,json=leaveRunning" json:"leave_running,omitempty"`
+ ExtUnixSk *bool `protobuf:"varint,4,opt,name=ext_unix_sk,json=extUnixSk" json:"ext_unix_sk,omitempty"`
+ TcpEstablished *bool `protobuf:"varint,5,opt,name=tcp_established,json=tcpEstablished" json:"tcp_established,omitempty"`
+ EvasiveDevices *bool `protobuf:"varint,6,opt,name=evasive_devices,json=evasiveDevices" json:"evasive_devices,omitempty"`
+ ShellJob *bool `protobuf:"varint,7,opt,name=shell_job,json=shellJob" json:"shell_job,omitempty"`
+ FileLocks *bool `protobuf:"varint,8,opt,name=file_locks,json=fileLocks" json:"file_locks,omitempty"`
+ LogLevel *int32 `protobuf:"varint,9,opt,name=log_level,json=logLevel,def=2" json:"log_level,omitempty"`
+ LogFile *string `protobuf:"bytes,10,opt,name=log_file,json=logFile" json:"log_file,omitempty"`
+ Ps *CriuPageServerInfo `protobuf:"bytes,11,opt,name=ps" json:"ps,omitempty"`
+ NotifyScripts *bool `protobuf:"varint,12,opt,name=notify_scripts,json=notifyScripts" json:"notify_scripts,omitempty"`
+ Root *string `protobuf:"bytes,13,opt,name=root" json:"root,omitempty"`
+ ParentImg *string `protobuf:"bytes,14,opt,name=parent_img,json=parentImg" json:"parent_img,omitempty"`
+ TrackMem *bool `protobuf:"varint,15,opt,name=track_mem,json=trackMem" json:"track_mem,omitempty"`
+ AutoDedup *bool `protobuf:"varint,16,opt,name=auto_dedup,json=autoDedup" json:"auto_dedup,omitempty"`
+ WorkDirFd *int32 `protobuf:"varint,17,opt,name=work_dir_fd,json=workDirFd" json:"work_dir_fd,omitempty"`
+ LinkRemap *bool `protobuf:"varint,18,opt,name=link_remap,json=linkRemap" json:"link_remap,omitempty"`
+ Veths []*CriuVethPair `protobuf:"bytes,19,rep,name=veths" json:"veths,omitempty"`
+ CpuCap *uint32 `protobuf:"varint,20,opt,name=cpu_cap,json=cpuCap,def=4294967295" json:"cpu_cap,omitempty"`
+ ForceIrmap *bool `protobuf:"varint,21,opt,name=force_irmap,json=forceIrmap" json:"force_irmap,omitempty"`
+ ExecCmd []string `protobuf:"bytes,22,rep,name=exec_cmd,json=execCmd" json:"exec_cmd,omitempty"`
+ ExtMnt []*ExtMountMap `protobuf:"bytes,23,rep,name=ext_mnt,json=extMnt" json:"ext_mnt,omitempty"`
+ ManageCgroups *bool `protobuf:"varint,24,opt,name=manage_cgroups,json=manageCgroups" json:"manage_cgroups,omitempty"`
+ CgRoot []*CgroupRoot `protobuf:"bytes,25,rep,name=cg_root,json=cgRoot" json:"cg_root,omitempty"`
+ RstSibling *bool `protobuf:"varint,26,opt,name=rst_sibling,json=rstSibling" json:"rst_sibling,omitempty"`
+ InheritFd []*InheritFd `protobuf:"bytes,27,rep,name=inherit_fd,json=inheritFd" json:"inherit_fd,omitempty"`
+ AutoExtMnt *bool `protobuf:"varint,28,opt,name=auto_ext_mnt,json=autoExtMnt" json:"auto_ext_mnt,omitempty"`
+ ExtSharing *bool `protobuf:"varint,29,opt,name=ext_sharing,json=extSharing" json:"ext_sharing,omitempty"`
+ ExtMasters *bool `protobuf:"varint,30,opt,name=ext_masters,json=extMasters" json:"ext_masters,omitempty"`
+ SkipMnt []string `protobuf:"bytes,31,rep,name=skip_mnt,json=skipMnt" json:"skip_mnt,omitempty"`
+ EnableFs []string `protobuf:"bytes,32,rep,name=enable_fs,json=enableFs" json:"enable_fs,omitempty"`
+ UnixSkIno []*UnixSk `protobuf:"bytes,33,rep,name=unix_sk_ino,json=unixSkIno" json:"unix_sk_ino,omitempty"`
+ ManageCgroupsMode *CriuCgMode `protobuf:"varint,34,opt,name=manage_cgroups_mode,json=manageCgroupsMode,enum=CriuCgMode" json:"manage_cgroups_mode,omitempty"`
+ GhostLimit *uint32 `protobuf:"varint,35,opt,name=ghost_limit,json=ghostLimit,def=1048576" json:"ghost_limit,omitempty"`
+ IrmapScanPaths []string `protobuf:"bytes,36,rep,name=irmap_scan_paths,json=irmapScanPaths" json:"irmap_scan_paths,omitempty"`
+ External []string `protobuf:"bytes,37,rep,name=external" json:"external,omitempty"`
+ EmptyNs *uint32 `protobuf:"varint,38,opt,name=empty_ns,json=emptyNs" json:"empty_ns,omitempty"`
+ JoinNs []*JoinNamespace `protobuf:"bytes,39,rep,name=join_ns,json=joinNs" json:"join_ns,omitempty"`
+ CgroupProps *string `protobuf:"bytes,41,opt,name=cgroup_props,json=cgroupProps" json:"cgroup_props,omitempty"`
+ CgroupPropsFile *string `protobuf:"bytes,42,opt,name=cgroup_props_file,json=cgroupPropsFile" json:"cgroup_props_file,omitempty"`
+ CgroupDumpController []string `protobuf:"bytes,43,rep,name=cgroup_dump_controller,json=cgroupDumpController" json:"cgroup_dump_controller,omitempty"`
+ FreezeCgroup *string `protobuf:"bytes,44,opt,name=freeze_cgroup,json=freezeCgroup" json:"freeze_cgroup,omitempty"`
+ Timeout *uint32 `protobuf:"varint,45,opt,name=timeout" json:"timeout,omitempty"`
+ TcpSkipInFlight *bool `protobuf:"varint,46,opt,name=tcp_skip_in_flight,json=tcpSkipInFlight" json:"tcp_skip_in_flight,omitempty"`
+ WeakSysctls *bool `protobuf:"varint,47,opt,name=weak_sysctls,json=weakSysctls" json:"weak_sysctls,omitempty"`
+ LazyPages *bool `protobuf:"varint,48,opt,name=lazy_pages,json=lazyPages" json:"lazy_pages,omitempty"`
+ StatusFd *int32 `protobuf:"varint,49,opt,name=status_fd,json=statusFd" json:"status_fd,omitempty"`
+ OrphanPtsMaster *bool `protobuf:"varint,50,opt,name=orphan_pts_master,json=orphanPtsMaster" json:"orphan_pts_master,omitempty"`
+ ConfigFile *string `protobuf:"bytes,51,opt,name=config_file,json=configFile" json:"config_file,omitempty"`
+ TcpClose *bool `protobuf:"varint,52,opt,name=tcp_close,json=tcpClose" json:"tcp_close,omitempty"`
+ LsmProfile *string `protobuf:"bytes,53,opt,name=lsm_profile,json=lsmProfile" json:"lsm_profile,omitempty"`
+ TlsCacert *string `protobuf:"bytes,54,opt,name=tls_cacert,json=tlsCacert" json:"tls_cacert,omitempty"`
+ TlsCacrl *string `protobuf:"bytes,55,opt,name=tls_cacrl,json=tlsCacrl" json:"tls_cacrl,omitempty"`
+ TlsCert *string `protobuf:"bytes,56,opt,name=tls_cert,json=tlsCert" json:"tls_cert,omitempty"`
+ TlsKey *string `protobuf:"bytes,57,opt,name=tls_key,json=tlsKey" json:"tls_key,omitempty"`
+ Tls *bool `protobuf:"varint,58,opt,name=tls" json:"tls,omitempty"`
+ TlsNoCnVerify *bool `protobuf:"varint,59,opt,name=tls_no_cn_verify,json=tlsNoCnVerify" json:"tls_no_cn_verify,omitempty"`
+ CgroupYard *string `protobuf:"bytes,60,opt,name=cgroup_yard,json=cgroupYard" json:"cgroup_yard,omitempty"`
+ PreDumpMode *CriuPreDumpMode `protobuf:"varint,61,opt,name=pre_dump_mode,json=preDumpMode,enum=CriuPreDumpMode,def=1" json:"pre_dump_mode,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CriuOpts) Reset() { *m = CriuOpts{} }
+func (m *CriuOpts) String() string { return proto.CompactTextString(m) }
+func (*CriuOpts) ProtoMessage() {}
+func (*CriuOpts) Descriptor() ([]byte, []int) {
+ return fileDescriptor_d9874a201429861e, []int{7}
+}
+
+func (m *CriuOpts) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CriuOpts.Unmarshal(m, b)
+}
+func (m *CriuOpts) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CriuOpts.Marshal(b, m, deterministic)
+}
+func (m *CriuOpts) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CriuOpts.Merge(m, src)
+}
+func (m *CriuOpts) XXX_Size() int {
+ return xxx_messageInfo_CriuOpts.Size(m)
+}
+func (m *CriuOpts) XXX_DiscardUnknown() {
+ xxx_messageInfo_CriuOpts.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CriuOpts proto.InternalMessageInfo
+
+const Default_CriuOpts_LogLevel int32 = 2
+const Default_CriuOpts_CpuCap uint32 = 4294967295
+const Default_CriuOpts_GhostLimit uint32 = 1048576
+const Default_CriuOpts_PreDumpMode CriuPreDumpMode = CriuPreDumpMode_SPLICE
+
+func (m *CriuOpts) GetImagesDirFd() int32 {
+ if m != nil && m.ImagesDirFd != nil {
+ return *m.ImagesDirFd
+ }
+ return 0
+}
+
+func (m *CriuOpts) GetPid() int32 {
+ if m != nil && m.Pid != nil {
+ return *m.Pid
+ }
+ return 0
+}
+
+func (m *CriuOpts) GetLeaveRunning() bool {
+ if m != nil && m.LeaveRunning != nil {
+ return *m.LeaveRunning
+ }
+ return false
+}
+
+func (m *CriuOpts) GetExtUnixSk() bool {
+ if m != nil && m.ExtUnixSk != nil {
+ return *m.ExtUnixSk
+ }
+ return false
+}
+
+func (m *CriuOpts) GetTcpEstablished() bool {
+ if m != nil && m.TcpEstablished != nil {
+ return *m.TcpEstablished
+ }
+ return false
+}
+
+func (m *CriuOpts) GetEvasiveDevices() bool {
+ if m != nil && m.EvasiveDevices != nil {
+ return *m.EvasiveDevices
+ }
+ return false
+}
+
+func (m *CriuOpts) GetShellJob() bool {
+ if m != nil && m.ShellJob != nil {
+ return *m.ShellJob
+ }
+ return false
+}
+
+func (m *CriuOpts) GetFileLocks() bool {
+ if m != nil && m.FileLocks != nil {
+ return *m.FileLocks
+ }
+ return false
+}
+
+func (m *CriuOpts) GetLogLevel() int32 {
+ if m != nil && m.LogLevel != nil {
+ return *m.LogLevel
+ }
+ return Default_CriuOpts_LogLevel
+}
+
+func (m *CriuOpts) GetLogFile() string {
+ if m != nil && m.LogFile != nil {
+ return *m.LogFile
+ }
+ return ""
+}
+
+func (m *CriuOpts) GetPs() *CriuPageServerInfo {
+ if m != nil {
+ return m.Ps
+ }
+ return nil
+}
+
+func (m *CriuOpts) GetNotifyScripts() bool {
+ if m != nil && m.NotifyScripts != nil {
+ return *m.NotifyScripts
+ }
+ return false
+}
+
+func (m *CriuOpts) GetRoot() string {
+ if m != nil && m.Root != nil {
+ return *m.Root
+ }
+ return ""
+}
+
+func (m *CriuOpts) GetParentImg() string {
+ if m != nil && m.ParentImg != nil {
+ return *m.ParentImg
+ }
+ return ""
+}
+
+func (m *CriuOpts) GetTrackMem() bool {
+ if m != nil && m.TrackMem != nil {
+ return *m.TrackMem
+ }
+ return false
+}
+
+func (m *CriuOpts) GetAutoDedup() bool {
+ if m != nil && m.AutoDedup != nil {
+ return *m.AutoDedup
+ }
+ return false
+}
+
+func (m *CriuOpts) GetWorkDirFd() int32 {
+ if m != nil && m.WorkDirFd != nil {
+ return *m.WorkDirFd
+ }
+ return 0
+}
+
+func (m *CriuOpts) GetLinkRemap() bool {
+ if m != nil && m.LinkRemap != nil {
+ return *m.LinkRemap
+ }
+ return false
+}
+
+func (m *CriuOpts) GetVeths() []*CriuVethPair {
+ if m != nil {
+ return m.Veths
+ }
+ return nil
+}
+
+func (m *CriuOpts) GetCpuCap() uint32 {
+ if m != nil && m.CpuCap != nil {
+ return *m.CpuCap
+ }
+ return Default_CriuOpts_CpuCap
+}
+
+func (m *CriuOpts) GetForceIrmap() bool {
+ if m != nil && m.ForceIrmap != nil {
+ return *m.ForceIrmap
+ }
+ return false
+}
+
+func (m *CriuOpts) GetExecCmd() []string {
+ if m != nil {
+ return m.ExecCmd
+ }
+ return nil
+}
+
+func (m *CriuOpts) GetExtMnt() []*ExtMountMap {
+ if m != nil {
+ return m.ExtMnt
+ }
+ return nil
+}
+
+func (m *CriuOpts) GetManageCgroups() bool {
+ if m != nil && m.ManageCgroups != nil {
+ return *m.ManageCgroups
+ }
+ return false
+}
+
+func (m *CriuOpts) GetCgRoot() []*CgroupRoot {
+ if m != nil {
+ return m.CgRoot
+ }
+ return nil
+}
+
+func (m *CriuOpts) GetRstSibling() bool {
+ if m != nil && m.RstSibling != nil {
+ return *m.RstSibling
+ }
+ return false
+}
+
+func (m *CriuOpts) GetInheritFd() []*InheritFd {
+ if m != nil {
+ return m.InheritFd
+ }
+ return nil
+}
+
+func (m *CriuOpts) GetAutoExtMnt() bool {
+ if m != nil && m.AutoExtMnt != nil {
+ return *m.AutoExtMnt
+ }
+ return false
+}
+
+func (m *CriuOpts) GetExtSharing() bool {
+ if m != nil && m.ExtSharing != nil {
+ return *m.ExtSharing
+ }
+ return false
+}
+
+func (m *CriuOpts) GetExtMasters() bool {
+ if m != nil && m.ExtMasters != nil {
+ return *m.ExtMasters
+ }
+ return false
+}
+
+func (m *CriuOpts) GetSkipMnt() []string {
+ if m != nil {
+ return m.SkipMnt
+ }
+ return nil
+}
+
+func (m *CriuOpts) GetEnableFs() []string {
+ if m != nil {
+ return m.EnableFs
+ }
+ return nil
+}
+
+func (m *CriuOpts) GetUnixSkIno() []*UnixSk {
+ if m != nil {
+ return m.UnixSkIno
+ }
+ return nil
+}
+
+func (m *CriuOpts) GetManageCgroupsMode() CriuCgMode {
+ if m != nil && m.ManageCgroupsMode != nil {
+ return *m.ManageCgroupsMode
+ }
+ return CriuCgMode_IGNORE
+}
+
+func (m *CriuOpts) GetGhostLimit() uint32 {
+ if m != nil && m.GhostLimit != nil {
+ return *m.GhostLimit
+ }
+ return Default_CriuOpts_GhostLimit
+}
+
+func (m *CriuOpts) GetIrmapScanPaths() []string {
+ if m != nil {
+ return m.IrmapScanPaths
+ }
+ return nil
+}
+
+func (m *CriuOpts) GetExternal() []string {
+ if m != nil {
+ return m.External
+ }
+ return nil
+}
+
+func (m *CriuOpts) GetEmptyNs() uint32 {
+ if m != nil && m.EmptyNs != nil {
+ return *m.EmptyNs
+ }
+ return 0
+}
+
+func (m *CriuOpts) GetJoinNs() []*JoinNamespace {
+ if m != nil {
+ return m.JoinNs
+ }
+ return nil
+}
+
+func (m *CriuOpts) GetCgroupProps() string {
+ if m != nil && m.CgroupProps != nil {
+ return *m.CgroupProps
+ }
+ return ""
+}
+
+func (m *CriuOpts) GetCgroupPropsFile() string {
+ if m != nil && m.CgroupPropsFile != nil {
+ return *m.CgroupPropsFile
+ }
+ return ""
+}
+
+func (m *CriuOpts) GetCgroupDumpController() []string {
+ if m != nil {
+ return m.CgroupDumpController
+ }
+ return nil
+}
+
+func (m *CriuOpts) GetFreezeCgroup() string {
+ if m != nil && m.FreezeCgroup != nil {
+ return *m.FreezeCgroup
+ }
+ return ""
+}
+
+func (m *CriuOpts) GetTimeout() uint32 {
+ if m != nil && m.Timeout != nil {
+ return *m.Timeout
+ }
+ return 0
+}
+
+func (m *CriuOpts) GetTcpSkipInFlight() bool {
+ if m != nil && m.TcpSkipInFlight != nil {
+ return *m.TcpSkipInFlight
+ }
+ return false
+}
+
+func (m *CriuOpts) GetWeakSysctls() bool {
+ if m != nil && m.WeakSysctls != nil {
+ return *m.WeakSysctls
+ }
+ return false
+}
+
+func (m *CriuOpts) GetLazyPages() bool {
+ if m != nil && m.LazyPages != nil {
+ return *m.LazyPages
+ }
+ return false
+}
+
+func (m *CriuOpts) GetStatusFd() int32 {
+ if m != nil && m.StatusFd != nil {
+ return *m.StatusFd
+ }
+ return 0
+}
+
+func (m *CriuOpts) GetOrphanPtsMaster() bool {
+ if m != nil && m.OrphanPtsMaster != nil {
+ return *m.OrphanPtsMaster
+ }
+ return false
+}
+
+func (m *CriuOpts) GetConfigFile() string {
+ if m != nil && m.ConfigFile != nil {
+ return *m.ConfigFile
+ }
+ return ""
+}
+
+func (m *CriuOpts) GetTcpClose() bool {
+ if m != nil && m.TcpClose != nil {
+ return *m.TcpClose
+ }
+ return false
+}
+
+func (m *CriuOpts) GetLsmProfile() string {
+ if m != nil && m.LsmProfile != nil {
+ return *m.LsmProfile
+ }
+ return ""
+}
+
+func (m *CriuOpts) GetTlsCacert() string {
+ if m != nil && m.TlsCacert != nil {
+ return *m.TlsCacert
+ }
+ return ""
+}
+
+func (m *CriuOpts) GetTlsCacrl() string {
+ if m != nil && m.TlsCacrl != nil {
+ return *m.TlsCacrl
+ }
+ return ""
+}
+
+func (m *CriuOpts) GetTlsCert() string {
+ if m != nil && m.TlsCert != nil {
+ return *m.TlsCert
+ }
+ return ""
+}
+
+func (m *CriuOpts) GetTlsKey() string {
+ if m != nil && m.TlsKey != nil {
+ return *m.TlsKey
+ }
+ return ""
+}
+
+func (m *CriuOpts) GetTls() bool {
+ if m != nil && m.Tls != nil {
+ return *m.Tls
+ }
+ return false
+}
+
+func (m *CriuOpts) GetTlsNoCnVerify() bool {
+ if m != nil && m.TlsNoCnVerify != nil {
+ return *m.TlsNoCnVerify
+ }
+ return false
+}
+
+func (m *CriuOpts) GetCgroupYard() string {
+ if m != nil && m.CgroupYard != nil {
+ return *m.CgroupYard
+ }
+ return ""
+}
+
+func (m *CriuOpts) GetPreDumpMode() CriuPreDumpMode {
+ if m != nil && m.PreDumpMode != nil {
+ return *m.PreDumpMode
+ }
+ return Default_CriuOpts_PreDumpMode
+}
+
+type CriuDumpResp struct {
+ Restored *bool `protobuf:"varint,1,opt,name=restored" json:"restored,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CriuDumpResp) Reset() { *m = CriuDumpResp{} }
+func (m *CriuDumpResp) String() string { return proto.CompactTextString(m) }
+func (*CriuDumpResp) ProtoMessage() {}
+func (*CriuDumpResp) Descriptor() ([]byte, []int) {
+ return fileDescriptor_d9874a201429861e, []int{8}
+}
+
+func (m *CriuDumpResp) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CriuDumpResp.Unmarshal(m, b)
+}
+func (m *CriuDumpResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CriuDumpResp.Marshal(b, m, deterministic)
+}
+func (m *CriuDumpResp) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CriuDumpResp.Merge(m, src)
+}
+func (m *CriuDumpResp) XXX_Size() int {
+ return xxx_messageInfo_CriuDumpResp.Size(m)
+}
+func (m *CriuDumpResp) XXX_DiscardUnknown() {
+ xxx_messageInfo_CriuDumpResp.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CriuDumpResp proto.InternalMessageInfo
+
+func (m *CriuDumpResp) GetRestored() bool {
+ if m != nil && m.Restored != nil {
+ return *m.Restored
+ }
+ return false
+}
+
+type CriuRestoreResp struct {
+ Pid *int32 `protobuf:"varint,1,req,name=pid" json:"pid,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CriuRestoreResp) Reset() { *m = CriuRestoreResp{} }
+func (m *CriuRestoreResp) String() string { return proto.CompactTextString(m) }
+func (*CriuRestoreResp) ProtoMessage() {}
+func (*CriuRestoreResp) Descriptor() ([]byte, []int) {
+ return fileDescriptor_d9874a201429861e, []int{9}
+}
+
+func (m *CriuRestoreResp) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CriuRestoreResp.Unmarshal(m, b)
+}
+func (m *CriuRestoreResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CriuRestoreResp.Marshal(b, m, deterministic)
+}
+func (m *CriuRestoreResp) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CriuRestoreResp.Merge(m, src)
+}
+func (m *CriuRestoreResp) XXX_Size() int {
+ return xxx_messageInfo_CriuRestoreResp.Size(m)
+}
+func (m *CriuRestoreResp) XXX_DiscardUnknown() {
+ xxx_messageInfo_CriuRestoreResp.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CriuRestoreResp proto.InternalMessageInfo
+
+func (m *CriuRestoreResp) GetPid() int32 {
+ if m != nil && m.Pid != nil {
+ return *m.Pid
+ }
+ return 0
+}
+
+type CriuNotify struct {
+ Script *string `protobuf:"bytes,1,opt,name=script" json:"script,omitempty"`
+ Pid *int32 `protobuf:"varint,2,opt,name=pid" json:"pid,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CriuNotify) Reset() { *m = CriuNotify{} }
+func (m *CriuNotify) String() string { return proto.CompactTextString(m) }
+func (*CriuNotify) ProtoMessage() {}
+func (*CriuNotify) Descriptor() ([]byte, []int) {
+ return fileDescriptor_d9874a201429861e, []int{10}
+}
+
+func (m *CriuNotify) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CriuNotify.Unmarshal(m, b)
+}
+func (m *CriuNotify) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CriuNotify.Marshal(b, m, deterministic)
+}
+func (m *CriuNotify) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CriuNotify.Merge(m, src)
+}
+func (m *CriuNotify) XXX_Size() int {
+ return xxx_messageInfo_CriuNotify.Size(m)
+}
+func (m *CriuNotify) XXX_DiscardUnknown() {
+ xxx_messageInfo_CriuNotify.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CriuNotify proto.InternalMessageInfo
+
+func (m *CriuNotify) GetScript() string {
+ if m != nil && m.Script != nil {
+ return *m.Script
+ }
+ return ""
+}
+
+func (m *CriuNotify) GetPid() int32 {
+ if m != nil && m.Pid != nil {
+ return *m.Pid
+ }
+ return 0
+}
+
+//
+// List of features which can queried via
+// CRIU_REQ_TYPE__FEATURE_CHECK
+type CriuFeatures struct {
+ MemTrack *bool `protobuf:"varint,1,opt,name=mem_track,json=memTrack" json:"mem_track,omitempty"`
+ LazyPages *bool `protobuf:"varint,2,opt,name=lazy_pages,json=lazyPages" json:"lazy_pages,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CriuFeatures) Reset() { *m = CriuFeatures{} }
+func (m *CriuFeatures) String() string { return proto.CompactTextString(m) }
+func (*CriuFeatures) ProtoMessage() {}
+func (*CriuFeatures) Descriptor() ([]byte, []int) {
+ return fileDescriptor_d9874a201429861e, []int{11}
+}
+
+func (m *CriuFeatures) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CriuFeatures.Unmarshal(m, b)
+}
+func (m *CriuFeatures) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CriuFeatures.Marshal(b, m, deterministic)
+}
+func (m *CriuFeatures) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CriuFeatures.Merge(m, src)
+}
+func (m *CriuFeatures) XXX_Size() int {
+ return xxx_messageInfo_CriuFeatures.Size(m)
+}
+func (m *CriuFeatures) XXX_DiscardUnknown() {
+ xxx_messageInfo_CriuFeatures.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CriuFeatures proto.InternalMessageInfo
+
+func (m *CriuFeatures) GetMemTrack() bool {
+ if m != nil && m.MemTrack != nil {
+ return *m.MemTrack
+ }
+ return false
+}
+
+func (m *CriuFeatures) GetLazyPages() bool {
+ if m != nil && m.LazyPages != nil {
+ return *m.LazyPages
+ }
+ return false
+}
+
+type CriuReq struct {
+ Type *CriuReqType `protobuf:"varint,1,req,name=type,enum=CriuReqType" json:"type,omitempty"`
+ Opts *CriuOpts `protobuf:"bytes,2,opt,name=opts" json:"opts,omitempty"`
+ NotifySuccess *bool `protobuf:"varint,3,opt,name=notify_success,json=notifySuccess" json:"notify_success,omitempty"`
+ //
+ // When set service won't close the connection but
+ // will wait for more req-s to appear. Works not
+ // for all request types.
+ KeepOpen *bool `protobuf:"varint,4,opt,name=keep_open,json=keepOpen" json:"keep_open,omitempty"`
+ //
+ // 'features' can be used to query which features
+ // are supported by the installed criu/kernel
+ // via RPC.
+ Features *CriuFeatures `protobuf:"bytes,5,opt,name=features" json:"features,omitempty"`
+ // 'pid' is used for WAIT_PID
+ Pid *uint32 `protobuf:"varint,6,opt,name=pid" json:"pid,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CriuReq) Reset() { *m = CriuReq{} }
+func (m *CriuReq) String() string { return proto.CompactTextString(m) }
+func (*CriuReq) ProtoMessage() {}
+func (*CriuReq) Descriptor() ([]byte, []int) {
+ return fileDescriptor_d9874a201429861e, []int{12}
+}
+
+func (m *CriuReq) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CriuReq.Unmarshal(m, b)
+}
+func (m *CriuReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CriuReq.Marshal(b, m, deterministic)
+}
+func (m *CriuReq) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CriuReq.Merge(m, src)
+}
+func (m *CriuReq) XXX_Size() int {
+ return xxx_messageInfo_CriuReq.Size(m)
+}
+func (m *CriuReq) XXX_DiscardUnknown() {
+ xxx_messageInfo_CriuReq.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CriuReq proto.InternalMessageInfo
+
+func (m *CriuReq) GetType() CriuReqType {
+ if m != nil && m.Type != nil {
+ return *m.Type
+ }
+ return CriuReqType_EMPTY
+}
+
+func (m *CriuReq) GetOpts() *CriuOpts {
+ if m != nil {
+ return m.Opts
+ }
+ return nil
+}
+
+func (m *CriuReq) GetNotifySuccess() bool {
+ if m != nil && m.NotifySuccess != nil {
+ return *m.NotifySuccess
+ }
+ return false
+}
+
+func (m *CriuReq) GetKeepOpen() bool {
+ if m != nil && m.KeepOpen != nil {
+ return *m.KeepOpen
+ }
+ return false
+}
+
+func (m *CriuReq) GetFeatures() *CriuFeatures {
+ if m != nil {
+ return m.Features
+ }
+ return nil
+}
+
+func (m *CriuReq) GetPid() uint32 {
+ if m != nil && m.Pid != nil {
+ return *m.Pid
+ }
+ return 0
+}
+
+type CriuResp struct {
+ Type *CriuReqType `protobuf:"varint,1,req,name=type,enum=CriuReqType" json:"type,omitempty"`
+ Success *bool `protobuf:"varint,2,req,name=success" json:"success,omitempty"`
+ Dump *CriuDumpResp `protobuf:"bytes,3,opt,name=dump" json:"dump,omitempty"`
+ Restore *CriuRestoreResp `protobuf:"bytes,4,opt,name=restore" json:"restore,omitempty"`
+ Notify *CriuNotify `protobuf:"bytes,5,opt,name=notify" json:"notify,omitempty"`
+ Ps *CriuPageServerInfo `protobuf:"bytes,6,opt,name=ps" json:"ps,omitempty"`
+ CrErrno *int32 `protobuf:"varint,7,opt,name=cr_errno,json=crErrno" json:"cr_errno,omitempty"`
+ Features *CriuFeatures `protobuf:"bytes,8,opt,name=features" json:"features,omitempty"`
+ CrErrmsg *string `protobuf:"bytes,9,opt,name=cr_errmsg,json=crErrmsg" json:"cr_errmsg,omitempty"`
+ Version *CriuVersion `protobuf:"bytes,10,opt,name=version" json:"version,omitempty"`
+ Status *int32 `protobuf:"varint,11,opt,name=status" json:"status,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CriuResp) Reset() { *m = CriuResp{} }
+func (m *CriuResp) String() string { return proto.CompactTextString(m) }
+func (*CriuResp) ProtoMessage() {}
+func (*CriuResp) Descriptor() ([]byte, []int) {
+ return fileDescriptor_d9874a201429861e, []int{13}
+}
+
+func (m *CriuResp) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CriuResp.Unmarshal(m, b)
+}
+func (m *CriuResp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CriuResp.Marshal(b, m, deterministic)
+}
+func (m *CriuResp) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CriuResp.Merge(m, src)
+}
+func (m *CriuResp) XXX_Size() int {
+ return xxx_messageInfo_CriuResp.Size(m)
+}
+func (m *CriuResp) XXX_DiscardUnknown() {
+ xxx_messageInfo_CriuResp.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CriuResp proto.InternalMessageInfo
+
+func (m *CriuResp) GetType() CriuReqType {
+ if m != nil && m.Type != nil {
+ return *m.Type
+ }
+ return CriuReqType_EMPTY
+}
+
+func (m *CriuResp) GetSuccess() bool {
+ if m != nil && m.Success != nil {
+ return *m.Success
+ }
+ return false
+}
+
+func (m *CriuResp) GetDump() *CriuDumpResp {
+ if m != nil {
+ return m.Dump
+ }
+ return nil
+}
+
+func (m *CriuResp) GetRestore() *CriuRestoreResp {
+ if m != nil {
+ return m.Restore
+ }
+ return nil
+}
+
+func (m *CriuResp) GetNotify() *CriuNotify {
+ if m != nil {
+ return m.Notify
+ }
+ return nil
+}
+
+func (m *CriuResp) GetPs() *CriuPageServerInfo {
+ if m != nil {
+ return m.Ps
+ }
+ return nil
+}
+
+func (m *CriuResp) GetCrErrno() int32 {
+ if m != nil && m.CrErrno != nil {
+ return *m.CrErrno
+ }
+ return 0
+}
+
+func (m *CriuResp) GetFeatures() *CriuFeatures {
+ if m != nil {
+ return m.Features
+ }
+ return nil
+}
+
+func (m *CriuResp) GetCrErrmsg() string {
+ if m != nil && m.CrErrmsg != nil {
+ return *m.CrErrmsg
+ }
+ return ""
+}
+
+func (m *CriuResp) GetVersion() *CriuVersion {
+ if m != nil {
+ return m.Version
+ }
+ return nil
+}
+
+func (m *CriuResp) GetStatus() int32 {
+ if m != nil && m.Status != nil {
+ return *m.Status
+ }
+ return 0
+}
+
+// Answer for criu_req_type.VERSION requests
+type CriuVersion struct {
+ MajorNumber *int32 `protobuf:"varint,1,req,name=major_number,json=majorNumber" json:"major_number,omitempty"`
+ MinorNumber *int32 `protobuf:"varint,2,req,name=minor_number,json=minorNumber" json:"minor_number,omitempty"`
+ Gitid *string `protobuf:"bytes,3,opt,name=gitid" json:"gitid,omitempty"`
+ Sublevel *int32 `protobuf:"varint,4,opt,name=sublevel" json:"sublevel,omitempty"`
+ Extra *int32 `protobuf:"varint,5,opt,name=extra" json:"extra,omitempty"`
+ Name *string `protobuf:"bytes,6,opt,name=name" json:"name,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CriuVersion) Reset() { *m = CriuVersion{} }
+func (m *CriuVersion) String() string { return proto.CompactTextString(m) }
+func (*CriuVersion) ProtoMessage() {}
+func (*CriuVersion) Descriptor() ([]byte, []int) {
+ return fileDescriptor_d9874a201429861e, []int{14}
+}
+
+func (m *CriuVersion) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CriuVersion.Unmarshal(m, b)
+}
+func (m *CriuVersion) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CriuVersion.Marshal(b, m, deterministic)
+}
+func (m *CriuVersion) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CriuVersion.Merge(m, src)
+}
+func (m *CriuVersion) XXX_Size() int {
+ return xxx_messageInfo_CriuVersion.Size(m)
+}
+func (m *CriuVersion) XXX_DiscardUnknown() {
+ xxx_messageInfo_CriuVersion.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CriuVersion proto.InternalMessageInfo
+
+func (m *CriuVersion) GetMajorNumber() int32 {
+ if m != nil && m.MajorNumber != nil {
+ return *m.MajorNumber
+ }
+ return 0
+}
+
+func (m *CriuVersion) GetMinorNumber() int32 {
+ if m != nil && m.MinorNumber != nil {
+ return *m.MinorNumber
+ }
+ return 0
+}
+
+func (m *CriuVersion) GetGitid() string {
+ if m != nil && m.Gitid != nil {
+ return *m.Gitid
+ }
+ return ""
+}
+
+func (m *CriuVersion) GetSublevel() int32 {
+ if m != nil && m.Sublevel != nil {
+ return *m.Sublevel
+ }
+ return 0
+}
+
+func (m *CriuVersion) GetExtra() int32 {
+ if m != nil && m.Extra != nil {
+ return *m.Extra
+ }
+ return 0
+}
+
+func (m *CriuVersion) GetName() string {
+ if m != nil && m.Name != nil {
+ return *m.Name
+ }
+ return ""
+}
+
+func init() {
+ proto.RegisterEnum("CriuCgMode", CriuCgMode_name, CriuCgMode_value)
+ proto.RegisterEnum("CriuPreDumpMode", CriuPreDumpMode_name, CriuPreDumpMode_value)
+ proto.RegisterEnum("CriuReqType", CriuReqType_name, CriuReqType_value)
+ proto.RegisterType((*CriuPageServerInfo)(nil), "criu_page_server_info")
+ proto.RegisterType((*CriuVethPair)(nil), "criu_veth_pair")
+ proto.RegisterType((*ExtMountMap)(nil), "ext_mount_map")
+ proto.RegisterType((*JoinNamespace)(nil), "join_namespace")
+ proto.RegisterType((*InheritFd)(nil), "inherit_fd")
+ proto.RegisterType((*CgroupRoot)(nil), "cgroup_root")
+ proto.RegisterType((*UnixSk)(nil), "unix_sk")
+ proto.RegisterType((*CriuOpts)(nil), "criu_opts")
+ proto.RegisterType((*CriuDumpResp)(nil), "criu_dump_resp")
+ proto.RegisterType((*CriuRestoreResp)(nil), "criu_restore_resp")
+ proto.RegisterType((*CriuNotify)(nil), "criu_notify")
+ proto.RegisterType((*CriuFeatures)(nil), "criu_features")
+ proto.RegisterType((*CriuReq)(nil), "criu_req")
+ proto.RegisterType((*CriuResp)(nil), "criu_resp")
+ proto.RegisterType((*CriuVersion)(nil), "criu_version")
+}
+
+func init() { proto.RegisterFile("rpc/rpc.proto", fileDescriptor_d9874a201429861e) }
+
+var fileDescriptor_d9874a201429861e = []byte{
+ // 2033 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x57, 0xe9, 0x72, 0x1b, 0x37,
+ 0x12, 0x0e, 0x29, 0xf1, 0x02, 0x45, 0x79, 0x0c, 0x5f, 0x70, 0xbc, 0xb6, 0x15, 0x3a, 0x8e, 0xb5,
+ 0x8a, 0xc3, 0x24, 0x8a, 0x8f, 0xd8, 0x9b, 0xd4, 0x96, 0x8b, 0x22, 0x1d, 0xae, 0x75, 0xb0, 0x40,
+ 0xc9, 0x5b, 0xfe, 0x85, 0x1a, 0xcd, 0x80, 0x14, 0xac, 0x19, 0xcc, 0x2c, 0x00, 0x2a, 0x92, 0x5f,
+ 0x62, 0x5f, 0x65, 0x7f, 0xef, 0x53, 0xe4, 0x91, 0xb6, 0xba, 0x01, 0xca, 0x52, 0x9c, 0xaa, 0xec,
+ 0xbf, 0xe9, 0xaf, 0xbb, 0x81, 0xbe, 0xd1, 0x43, 0x3a, 0xa6, 0x4c, 0xbe, 0x35, 0x65, 0xd2, 0x2b,
+ 0x4d, 0xe1, 0x8a, 0xee, 0x8c, 0xdc, 0x48, 0x8c, 0x9a, 0x8b, 0x32, 0x9e, 0x49, 0x61, 0xa5, 0x39,
+ 0x91, 0x46, 0x28, 0x3d, 0x2d, 0x28, 0x23, 0x8d, 0x38, 0x4d, 0x8d, 0xb4, 0x96, 0x55, 0xd6, 0x2a,
+ 0xeb, 0x2d, 0xbe, 0x20, 0x29, 0x25, 0xcb, 0x65, 0x61, 0x1c, 0xab, 0xae, 0x55, 0xd6, 0x6b, 0x1c,
+ 0xbf, 0x69, 0x44, 0x96, 0x4a, 0x95, 0xb2, 0x25, 0x84, 0xe0, 0x93, 0xae, 0x92, 0xea, 0x34, 0x65,
+ 0xcb, 0x08, 0x54, 0xa7, 0x69, 0xf7, 0x27, 0xb2, 0x8a, 0x17, 0x9d, 0x48, 0x77, 0x24, 0xca, 0x58,
+ 0x19, 0x7a, 0x8d, 0xd4, 0xd4, 0x54, 0x28, 0xcd, 0x2a, 0x6b, 0xd5, 0xf5, 0x16, 0x5f, 0x56, 0xd3,
+ 0x91, 0xa6, 0x37, 0x48, 0x5d, 0x4d, 0x45, 0x31, 0x87, 0xe3, 0x01, 0xad, 0xa9, 0xe9, 0xde, 0xdc,
+ 0x75, 0x7f, 0x20, 0x1d, 0x79, 0xea, 0x44, 0x5e, 0xcc, 0xb5, 0x13, 0x79, 0x5c, 0xc2, 0x85, 0xc7,
+ 0xf2, 0x2c, 0xa8, 0xc2, 0x27, 0x20, 0x27, 0x71, 0x16, 0xd4, 0xe0, 0xb3, 0xfb, 0x96, 0xac, 0xbe,
+ 0x2f, 0x94, 0x16, 0x3a, 0xce, 0xa5, 0x2d, 0xe3, 0x44, 0x82, 0x51, 0xda, 0x06, 0xa5, 0xaa, 0xb6,
+ 0xf4, 0x16, 0x69, 0x68, 0x2b, 0xa6, 0x2a, 0x93, 0x41, 0xaf, 0xae, 0xed, 0x50, 0x65, 0x92, 0xde,
+ 0x21, 0x2d, 0x79, 0xea, 0x4c, 0x2c, 0x8a, 0xd2, 0xa1, 0x57, 0x2d, 0xde, 0x44, 0x60, 0xaf, 0x74,
+ 0xdd, 0x1e, 0x21, 0x4a, 0x1f, 0x49, 0xa3, 0x9c, 0x98, 0xa6, 0x7f, 0x60, 0x89, 0x77, 0x1d, 0x0e,
+ 0xf4, 0xae, 0x3f, 0x25, 0xed, 0x64, 0x66, 0x8a, 0x79, 0x29, 0x4c, 0x51, 0x38, 0x88, 0x5f, 0xe2,
+ 0x4c, 0x16, 0xc2, 0x8a, 0xdf, 0x18, 0xd3, 0xd8, 0x1d, 0x05, 0x2b, 0xf0, 0xbb, 0x7b, 0x9f, 0x34,
+ 0xe6, 0x5a, 0x9d, 0x0a, 0x7b, 0x4c, 0xaf, 0x93, 0x9a, 0xd2, 0x45, 0x2a, 0xf1, 0x96, 0x0e, 0xf7,
+ 0x44, 0xf7, 0xbf, 0x11, 0x69, 0x61, 0x4c, 0x8b, 0xd2, 0x59, 0xda, 0x25, 0x1d, 0x95, 0xc7, 0x33,
+ 0x69, 0x45, 0xaa, 0x8c, 0x98, 0xa6, 0x28, 0x5b, 0xe3, 0x6d, 0x0f, 0x6e, 0x29, 0x33, 0x4c, 0x17,
+ 0x69, 0xaa, 0x7e, 0x4c, 0xd3, 0x03, 0xd2, 0xc9, 0x64, 0x7c, 0x22, 0x85, 0x99, 0x6b, 0xad, 0xf4,
+ 0x0c, 0x9d, 0x6d, 0xf2, 0x15, 0x04, 0xb9, 0xc7, 0xe8, 0x3d, 0xd2, 0x86, 0xe8, 0x07, 0x6b, 0x30,
+ 0xa9, 0x4d, 0x0e, 0x01, 0x3a, 0xd0, 0xea, 0x74, 0x72, 0x4c, 0x1f, 0x91, 0x2b, 0x2e, 0x29, 0x85,
+ 0xb4, 0x2e, 0x3e, 0xcc, 0x94, 0x3d, 0x92, 0x29, 0xab, 0xa1, 0xcc, 0xaa, 0x4b, 0xca, 0xc1, 0x47,
+ 0x14, 0x04, 0xe5, 0x49, 0x6c, 0xd5, 0x89, 0x14, 0xa9, 0x3c, 0x51, 0x89, 0xb4, 0xac, 0xee, 0x05,
+ 0x03, 0xbc, 0xe5, 0x51, 0x88, 0xbf, 0x3d, 0x92, 0x59, 0x26, 0xde, 0x17, 0x87, 0xac, 0x81, 0x22,
+ 0x4d, 0x04, 0xfe, 0x51, 0x1c, 0xd2, 0xbb, 0x84, 0x40, 0xca, 0x44, 0x56, 0x24, 0xc7, 0x96, 0x35,
+ 0xbd, 0x35, 0x80, 0x6c, 0x03, 0x40, 0xef, 0x91, 0x56, 0x56, 0xcc, 0x44, 0x26, 0x4f, 0x64, 0xc6,
+ 0x5a, 0xe0, 0xea, 0xcb, 0xca, 0x26, 0x6f, 0x66, 0xc5, 0x6c, 0x1b, 0x20, 0x7a, 0x9b, 0xc0, 0xb7,
+ 0xcf, 0x3a, 0xf1, 0xa5, 0x9d, 0x15, 0x33, 0x4c, 0xfb, 0x57, 0xa4, 0x5a, 0x5a, 0xd6, 0x5e, 0xab,
+ 0xac, 0xb7, 0x37, 0x6f, 0xf6, 0xfe, 0xb0, 0x31, 0x78, 0xb5, 0xb4, 0xf4, 0x21, 0x59, 0xd5, 0x85,
+ 0x53, 0xd3, 0x33, 0x61, 0x13, 0xa3, 0x4a, 0x67, 0xd9, 0x0a, 0x5a, 0xd1, 0xf1, 0xe8, 0xc4, 0x83,
+ 0x90, 0x55, 0xc8, 0x38, 0xeb, 0xf8, 0x4c, 0x63, 0xf6, 0xef, 0x12, 0x52, 0xc6, 0x46, 0x6a, 0x27,
+ 0x54, 0x3e, 0x63, 0xab, 0xc8, 0x69, 0x79, 0x64, 0x94, 0xcf, 0xc0, 0x71, 0x67, 0xe2, 0xe4, 0x58,
+ 0xe4, 0x32, 0x67, 0x57, 0xbc, 0xe3, 0x08, 0xec, 0xc8, 0x1c, 0x74, 0xe3, 0xb9, 0x2b, 0x44, 0x2a,
+ 0xd3, 0x79, 0xc9, 0x22, 0xef, 0x38, 0x20, 0x5b, 0x00, 0x40, 0x9a, 0x7e, 0x2d, 0xcc, 0xf1, 0x22,
+ 0xff, 0x57, 0x31, 0xcb, 0x2d, 0x80, 0x7c, 0xf6, 0xef, 0x12, 0x92, 0x29, 0x7d, 0x2c, 0x8c, 0xcc,
+ 0xe3, 0x92, 0x51, 0xaf, 0x0e, 0x08, 0x07, 0x80, 0x3e, 0x24, 0x35, 0x68, 0x4e, 0xcb, 0xae, 0xad,
+ 0x2d, 0xad, 0xb7, 0x37, 0xaf, 0xf4, 0x2e, 0xf7, 0x2b, 0xf7, 0x5c, 0xfa, 0x80, 0x34, 0x92, 0x72,
+ 0x2e, 0x92, 0xb8, 0x64, 0xd7, 0xd7, 0x2a, 0xeb, 0x9d, 0x97, 0xe4, 0xc9, 0xe6, 0x8b, 0x27, 0x2f,
+ 0x9e, 0x3d, 0xdf, 0x7c, 0xf1, 0x94, 0xd7, 0x93, 0x72, 0xde, 0x8f, 0x4b, 0x7a, 0x9f, 0xb4, 0xa7,
+ 0x85, 0x49, 0xa4, 0x50, 0x06, 0xee, 0xba, 0x81, 0x77, 0x11, 0x84, 0x46, 0x80, 0x40, 0x12, 0xe4,
+ 0xa9, 0x4c, 0x44, 0x92, 0xa7, 0xec, 0xe6, 0xda, 0x12, 0x24, 0x01, 0xe8, 0x7e, 0x0e, 0x45, 0xd2,
+ 0xc0, 0x5e, 0xd7, 0x8e, 0xdd, 0x42, 0x4b, 0x56, 0x7b, 0x97, 0x7a, 0x9f, 0xd7, 0xe5, 0xa9, 0xdb,
+ 0xd1, 0x0e, 0xb2, 0x90, 0xc7, 0x1a, 0xf2, 0xe3, 0xdb, 0xcb, 0x32, 0xe6, 0xb3, 0xe0, 0xd1, 0xbe,
+ 0x07, 0xe9, 0x43, 0xd2, 0x48, 0x66, 0xd8, 0x7a, 0xec, 0x36, 0x9e, 0xb7, 0xd2, 0xbb, 0xd0, 0x8e,
+ 0xbc, 0x9e, 0xcc, 0x38, 0x24, 0xe6, 0x3e, 0x69, 0x1b, 0xeb, 0x84, 0x55, 0x87, 0x19, 0xf4, 0xc1,
+ 0xe7, 0xde, 0x64, 0x63, 0xdd, 0xc4, 0x23, 0x74, 0xe3, 0x62, 0xdb, 0xb3, 0x3b, 0x78, 0x54, 0xbb,
+ 0xf7, 0x11, 0xe2, 0xad, 0xf0, 0x3d, 0x4c, 0xe9, 0x1a, 0x59, 0xc1, 0x4c, 0x2d, 0x1c, 0xf9, 0x8b,
+ 0x3f, 0x0d, 0xb0, 0x81, 0x37, 0xfe, 0xbe, 0xef, 0x29, 0x7b, 0x14, 0x1b, 0xb8, 0xee, 0xae, 0x17,
+ 0x90, 0xa7, 0x6e, 0xe2, 0x91, 0x85, 0x40, 0x1e, 0x5b, 0x27, 0x8d, 0x65, 0xf7, 0xce, 0x05, 0x76,
+ 0x3c, 0x02, 0x21, 0xb4, 0xc7, 0xaa, 0xc4, 0xf3, 0xef, 0xfb, 0x10, 0x02, 0x0d, 0x87, 0xc3, 0xf8,
+ 0xd2, 0xf1, 0x61, 0x26, 0xc5, 0xd4, 0xb2, 0x35, 0xe4, 0x35, 0x3d, 0x30, 0xb4, 0x74, 0x9d, 0xb4,
+ 0x43, 0x27, 0x0b, 0xa5, 0x0b, 0xf6, 0x05, 0x3a, 0xd2, 0xec, 0x05, 0x8c, 0xb7, 0xe6, 0xd8, 0xd4,
+ 0x23, 0x5d, 0xd0, 0x9f, 0xc9, 0xb5, 0xcb, 0x01, 0x16, 0x39, 0x0c, 0xa1, 0xee, 0x5a, 0x65, 0x7d,
+ 0x75, 0xb3, 0xe3, 0xeb, 0x23, 0x99, 0x21, 0xc8, 0xaf, 0x5e, 0x0a, 0xfa, 0x4e, 0x91, 0x4a, 0xb8,
+ 0x68, 0x76, 0x54, 0x58, 0x27, 0x32, 0x95, 0x2b, 0xc7, 0x1e, 0x60, 0xb5, 0x34, 0xbe, 0xff, 0xee,
+ 0xc9, 0x8f, 0x4f, 0x9f, 0x3f, 0xe3, 0x04, 0x79, 0xdb, 0xc0, 0xa2, 0xeb, 0x24, 0xc2, 0x42, 0x11,
+ 0x36, 0x89, 0xb5, 0x80, 0xe9, 0x67, 0xd9, 0x97, 0x68, 0xf6, 0x2a, 0xe2, 0x93, 0x24, 0xd6, 0x63,
+ 0x40, 0xe9, 0xe7, 0x50, 0x37, 0x4e, 0x1a, 0x1d, 0x67, 0xec, 0x61, 0x70, 0x2c, 0xd0, 0x58, 0x53,
+ 0x79, 0xe9, 0xce, 0x84, 0xb6, 0xec, 0x2b, 0xb8, 0x8c, 0x37, 0x90, 0xde, 0x05, 0x9f, 0x1b, 0xfe,
+ 0x29, 0xb0, 0xec, 0x51, 0xa8, 0xee, 0xcb, 0x4f, 0x03, 0xaf, 0x03, 0xbd, 0x6b, 0xe9, 0x17, 0x64,
+ 0x25, 0x54, 0x47, 0x69, 0x8a, 0xd2, 0xb2, 0xbf, 0x62, 0x87, 0x86, 0x01, 0x3e, 0x06, 0x88, 0x6e,
+ 0x90, 0xab, 0x17, 0x45, 0xfc, 0x24, 0xd9, 0x40, 0xb9, 0x2b, 0x17, 0xe4, 0x70, 0xa2, 0x3c, 0x21,
+ 0x37, 0x83, 0x6c, 0x3a, 0xcf, 0x4b, 0x91, 0x14, 0xda, 0x99, 0x22, 0xcb, 0xa4, 0x61, 0x5f, 0xa3,
+ 0xf5, 0xd7, 0x3d, 0x77, 0x6b, 0x9e, 0x97, 0xfd, 0x73, 0x1e, 0x4c, 0xe5, 0xa9, 0x91, 0xf2, 0xc3,
+ 0x22, 0xf0, 0xec, 0x31, 0x9e, 0xbe, 0xe2, 0x41, 0x1f, 0x63, 0x78, 0xa1, 0x9d, 0xca, 0x25, 0xbc,
+ 0x95, 0xdf, 0x78, 0x6f, 0x03, 0x49, 0xbf, 0x26, 0x14, 0xe6, 0x31, 0x56, 0x87, 0xd2, 0x62, 0x9a,
+ 0xa9, 0xd9, 0x91, 0x63, 0x3d, 0xac, 0x20, 0x98, 0xd4, 0x93, 0x63, 0x55, 0x8e, 0xf4, 0x10, 0x61,
+ 0x70, 0xf8, 0x57, 0x19, 0x1f, 0x0b, 0x7b, 0x66, 0x13, 0x97, 0x59, 0xf6, 0x2d, 0x8a, 0xb5, 0x01,
+ 0x9b, 0x78, 0x08, 0x07, 0x47, 0xfc, 0xe1, 0x0c, 0x67, 0xa1, 0x65, 0xdf, 0x85, 0xc1, 0x11, 0x7f,
+ 0x38, 0x1b, 0x03, 0x80, 0xc3, 0xda, 0xc5, 0x6e, 0x6e, 0xa1, 0x2f, 0xbe, 0xc7, 0xa9, 0xd3, 0xf4,
+ 0xc0, 0x30, 0x85, 0x60, 0x15, 0xa6, 0x3c, 0x82, 0xb4, 0x3a, 0x1b, 0xaa, 0x99, 0x6d, 0x7a, 0x53,
+ 0x3c, 0x63, 0xec, 0xac, 0x2f, 0x69, 0x28, 0xf9, 0xa4, 0xd0, 0x53, 0x15, 0x86, 0xf3, 0x0f, 0xe8,
+ 0x34, 0xf1, 0xd0, 0xe2, 0x59, 0x06, 0xc7, 0x92, 0xac, 0xb0, 0x92, 0x3d, 0x09, 0xd3, 0x31, 0x29,
+ 0xfb, 0x40, 0x83, 0x76, 0x66, 0x73, 0xc8, 0x09, 0x6a, 0x3f, 0xf5, 0xda, 0x99, 0xcd, 0xc7, 0x1e,
+ 0x01, 0x37, 0x5c, 0x66, 0x45, 0x12, 0x27, 0xd2, 0x38, 0xf6, 0xcc, 0x8f, 0x5e, 0x97, 0xd9, 0x3e,
+ 0x02, 0x78, 0xb8, 0x67, 0x9b, 0x8c, 0x3d, 0xf7, 0x6f, 0xbe, 0xe7, 0x1a, 0xac, 0x2d, 0x64, 0x82,
+ 0xe6, 0x8f, 0xfe, 0xd1, 0x00, 0x1e, 0xe8, 0xdd, 0x22, 0xf0, 0x29, 0x60, 0x09, 0x78, 0x81, 0x9c,
+ 0xba, 0xcb, 0xec, 0x1b, 0xbf, 0x91, 0x40, 0x40, 0x5f, 0xa2, 0x9d, 0xf0, 0x49, 0x1f, 0x91, 0x08,
+ 0x44, 0x75, 0x21, 0x12, 0x2d, 0x4e, 0xa4, 0x51, 0xd3, 0x33, 0xf6, 0x37, 0x3f, 0xb3, 0x5c, 0x66,
+ 0x77, 0x8b, 0xbe, 0x7e, 0x8b, 0x20, 0x46, 0xc2, 0x97, 0xcd, 0x59, 0x6c, 0x52, 0xf6, 0x53, 0x88,
+ 0x04, 0x42, 0xef, 0x62, 0x93, 0xd2, 0xbf, 0x93, 0x4e, 0x69, 0xa4, 0x2f, 0x2a, 0x6c, 0xca, 0x9f,
+ 0xb1, 0x29, 0xaf, 0x85, 0x47, 0xeb, 0x22, 0xeb, 0x65, 0x7d, 0x32, 0xde, 0x1e, 0xf5, 0x07, 0xbc,
+ 0x5d, 0x1a, 0x09, 0x85, 0x06, 0xcd, 0xd9, 0x7d, 0x1c, 0xf6, 0x31, 0x14, 0x33, 0xd2, 0x96, 0xd0,
+ 0x5a, 0x46, 0x5a, 0x57, 0x18, 0x99, 0xe2, 0x6e, 0xd2, 0xe4, 0xe7, 0x74, 0xf7, 0x21, 0xb9, 0x8a,
+ 0xd2, 0x01, 0xf0, 0x0a, 0x61, 0x9b, 0xf0, 0x7b, 0x06, 0x7c, 0x76, 0x9f, 0x93, 0x36, 0x8a, 0xf9,
+ 0x67, 0x90, 0xde, 0x24, 0x75, 0xff, 0x3e, 0x86, 0x5d, 0x27, 0x50, 0x9f, 0xae, 0x21, 0xdd, 0x37,
+ 0xa4, 0x83, 0x8a, 0x53, 0x19, 0xbb, 0xb9, 0xf1, 0x35, 0x95, 0xcb, 0x5c, 0xe0, 0xd3, 0xb7, 0xb0,
+ 0x26, 0x97, 0xf9, 0x3e, 0xd0, 0xbf, 0xab, 0xc7, 0xea, 0xef, 0xea, 0xb1, 0xfb, 0x5b, 0x85, 0x34,
+ 0x83, 0xb5, 0xff, 0xa2, 0x5d, 0xb2, 0xec, 0xce, 0x4a, 0xbf, 0x39, 0xad, 0x6e, 0xae, 0xf6, 0x16,
+ 0x0c, 0x01, 0x28, 0x47, 0x1e, 0xbd, 0x47, 0x96, 0x61, 0x85, 0xc2, 0x93, 0xda, 0x9b, 0xa4, 0x77,
+ 0xbe, 0x54, 0x71, 0xc4, 0x2f, 0x3e, 0xf7, 0xf3, 0x24, 0x81, 0x95, 0x78, 0xe9, 0xd2, 0x73, 0xef,
+ 0x41, 0xb0, 0xf9, 0x58, 0xca, 0x52, 0x14, 0xa5, 0xd4, 0x61, 0x49, 0x6a, 0x02, 0xb0, 0x57, 0x4a,
+ 0x4d, 0x37, 0x48, 0x73, 0xe1, 0x1c, 0x2e, 0x47, 0xed, 0x85, 0x2d, 0x0b, 0x94, 0x9f, 0xf3, 0x17,
+ 0xf1, 0xa9, 0x63, 0x57, 0x63, 0x7c, 0xfe, 0xbd, 0x14, 0x56, 0x3d, 0x0c, 0xfc, 0xff, 0xe3, 0x13,
+ 0x23, 0x8d, 0x85, 0xb1, 0xb0, 0x54, 0x36, 0xf9, 0x82, 0xa4, 0x0f, 0xc8, 0x32, 0x24, 0x1d, 0x7d,
+ 0x38, 0x7f, 0xe6, 0xcf, 0xcb, 0x80, 0x23, 0x93, 0x3e, 0x26, 0x8d, 0x90, 0x6b, 0xf4, 0xa4, 0xbd,
+ 0x49, 0x7b, 0x9f, 0x14, 0x00, 0x5f, 0x88, 0xd0, 0x2f, 0x49, 0xdd, 0x87, 0x22, 0xb8, 0xb6, 0xd2,
+ 0xbb, 0x50, 0x06, 0x3c, 0xf0, 0xc2, 0x76, 0x55, 0xff, 0xd3, 0xed, 0xea, 0x36, 0xa4, 0x4f, 0x48,
+ 0x63, 0x74, 0x81, 0xbb, 0x5f, 0x8d, 0x37, 0x12, 0x33, 0x00, 0xf2, 0x52, 0x14, 0x9b, 0x7f, 0x12,
+ 0xc5, 0x3b, 0x10, 0x32, 0x38, 0x26, 0xb7, 0x33, 0xdc, 0x03, 0x5b, 0xbc, 0x89, 0xe7, 0xe4, 0x76,
+ 0x06, 0x4b, 0xc6, 0x89, 0x34, 0x56, 0x15, 0x1a, 0x77, 0xc0, 0xf6, 0xe2, 0x39, 0x0b, 0x20, 0x5f,
+ 0x70, 0xb1, 0x86, 0x71, 0x96, 0xe1, 0x5a, 0x58, 0xe3, 0x81, 0xea, 0xfe, 0xa7, 0x42, 0x56, 0x2e,
+ 0x6a, 0xc0, 0x1c, 0xcd, 0xe3, 0xf7, 0x85, 0x11, 0x7a, 0x9e, 0x1f, 0x4a, 0xb3, 0x58, 0xbf, 0x11,
+ 0xdb, 0x45, 0x08, 0x45, 0x94, 0xfe, 0x28, 0x52, 0x0d, 0x22, 0x80, 0x05, 0x91, 0xeb, 0xa4, 0x36,
+ 0x53, 0x2e, 0xfc, 0x4a, 0xb5, 0xb8, 0x27, 0xa0, 0x35, 0xed, 0xfc, 0xd0, 0x6f, 0xb4, 0xcb, 0x61,
+ 0xc0, 0x06, 0x1a, 0x34, 0xf0, 0xcf, 0x04, 0x43, 0x5f, 0xe3, 0x9e, 0x80, 0xd5, 0x13, 0xde, 0x36,
+ 0x8c, 0x76, 0x8b, 0xe3, 0xf7, 0x86, 0x08, 0x16, 0x87, 0x27, 0x9b, 0x12, 0x52, 0x1f, 0xbd, 0xde,
+ 0xdd, 0xe3, 0x83, 0xe8, 0x33, 0xda, 0x26, 0x8d, 0xfe, 0x6b, 0xb1, 0xbb, 0xb7, 0x3b, 0x88, 0x2a,
+ 0xb4, 0x45, 0x6a, 0x63, 0xbe, 0x37, 0x9e, 0x44, 0x55, 0xda, 0x24, 0xcb, 0x93, 0xbd, 0xe1, 0x7e,
+ 0xb4, 0x04, 0x5f, 0xc3, 0x83, 0xed, 0xed, 0x68, 0x19, 0xf4, 0x26, 0xfb, 0x7c, 0xd4, 0xdf, 0x8f,
+ 0x6a, 0xa0, 0xb7, 0x35, 0x18, 0xbe, 0x3a, 0xd8, 0xde, 0x8f, 0xea, 0x1b, 0xdf, 0x10, 0xfa, 0xe9,
+ 0xf8, 0x41, 0x71, 0x1c, 0x40, 0x51, 0x05, 0xc4, 0xdf, 0xee, 0x08, 0x3e, 0x78, 0xb5, 0x15, 0x55,
+ 0x37, 0x7e, 0xab, 0x84, 0xae, 0x5f, 0x94, 0x2e, 0x5c, 0x3c, 0xd8, 0x19, 0xef, 0xbf, 0x8b, 0x3e,
+ 0x83, 0xeb, 0xb6, 0x0e, 0x76, 0xc6, 0x5e, 0x87, 0x0f, 0x26, 0xfb, 0x60, 0x67, 0x15, 0x24, 0xfa,
+ 0xbf, 0x0c, 0xfa, 0x6f, 0xa2, 0x25, 0xba, 0x42, 0x9a, 0x63, 0x3e, 0x10, 0x28, 0xb5, 0x4c, 0xaf,
+ 0x90, 0xf6, 0xf8, 0xd5, 0xeb, 0x81, 0x98, 0x0c, 0xf8, 0xdb, 0x01, 0x8f, 0x6a, 0x70, 0xed, 0xee,
+ 0xde, 0xfe, 0x68, 0xf8, 0x2e, 0xaa, 0xd3, 0x88, 0xac, 0xf4, 0xc7, 0x07, 0xa3, 0xdd, 0xe1, 0x9e,
+ 0x17, 0x6f, 0xd0, 0xab, 0xa4, 0xb3, 0x40, 0xfc, 0x79, 0x4d, 0x80, 0x86, 0x83, 0x57, 0xfb, 0x07,
+ 0x7c, 0x10, 0xa0, 0x16, 0x9a, 0x3b, 0xe0, 0x93, 0xd1, 0xde, 0x6e, 0x44, 0xe0, 0xbe, 0x7f, 0xbe,
+ 0x1a, 0xed, 0x8b, 0xf1, 0x68, 0x2b, 0x6a, 0xd3, 0xeb, 0x24, 0xba, 0x70, 0x9f, 0xe8, 0xff, 0xb2,
+ 0xbd, 0x15, 0xad, 0xfc, 0x2f, 0x00, 0x00, 0xff, 0xff, 0xc4, 0x45, 0x96, 0x6d, 0x5e, 0x0f, 0x00,
+ 0x00,
+}
diff --git a/vendor/github.com/cilium/ebpf/abi.go b/vendor/github.com/cilium/ebpf/abi.go
index fd6139c59..d432eb46f 100644
--- a/vendor/github.com/cilium/ebpf/abi.go
+++ b/vendor/github.com/cilium/ebpf/abi.go
@@ -3,14 +3,13 @@ package ebpf
import (
"bufio"
"bytes"
+ "errors"
"fmt"
"io"
"os"
"syscall"
"github.com/cilium/ebpf/internal"
-
- "golang.org/x/xerrors"
)
// MapABI are the attributes of a Map which are available across all supported kernels.
@@ -35,7 +34,7 @@ func newMapABIFromSpec(spec *MapSpec) *MapABI {
func newMapABIFromFd(fd *internal.FD) (string, *MapABI, error) {
info, err := bpfGetMapInfoByFD(fd)
if err != nil {
- if xerrors.Is(err, syscall.EINVAL) {
+ if errors.Is(err, syscall.EINVAL) {
abi, err := newMapABIFromProc(fd)
return "", abi, err
}
@@ -98,7 +97,7 @@ func newProgramABIFromSpec(spec *ProgramSpec) *ProgramABI {
func newProgramABIFromFd(fd *internal.FD) (string, *ProgramABI, error) {
info, err := bpfGetProgInfoByFD(fd)
if err != nil {
- if xerrors.Is(err, syscall.EINVAL) {
+ if errors.Is(err, syscall.EINVAL) {
return newProgramABIFromProc(fd)
}
@@ -127,7 +126,7 @@ func newProgramABIFromProc(fd *internal.FD) (string, *ProgramABI, error) {
"prog_type": &abi.Type,
"prog_tag": &name,
})
- if xerrors.Is(err, errMissingFields) {
+ if errors.Is(err, errMissingFields) {
return "", nil, &internal.UnsupportedFeatureError{
Name: "reading ABI from /proc/self/fdinfo",
MinimumVersion: internal.Version{4, 11, 0},
@@ -153,12 +152,12 @@ func scanFdInfo(fd *internal.FD, fields map[string]interface{}) error {
defer fh.Close()
if err := scanFdInfoReader(fh, fields); err != nil {
- return xerrors.Errorf("%s: %w", fh.Name(), err)
+ return fmt.Errorf("%s: %w", fh.Name(), err)
}
return nil
}
-var errMissingFields = xerrors.New("missing fields")
+var errMissingFields = errors.New("missing fields")
func scanFdInfoReader(r io.Reader, fields map[string]interface{}) error {
var (
@@ -179,7 +178,7 @@ func scanFdInfoReader(r io.Reader, fields map[string]interface{}) error {
}
if n, err := fmt.Fscanln(bytes.NewReader(parts[1]), field); err != nil || n != 1 {
- return xerrors.Errorf("can't parse field %s: %v", name, err)
+ return fmt.Errorf("can't parse field %s: %v", name, err)
}
scanned++
diff --git a/vendor/github.com/cilium/ebpf/asm/instruction.go b/vendor/github.com/cilium/ebpf/asm/instruction.go
index 02ed6c6af..8fbcf5664 100644
--- a/vendor/github.com/cilium/ebpf/asm/instruction.go
+++ b/vendor/github.com/cilium/ebpf/asm/instruction.go
@@ -2,12 +2,11 @@ package asm
import (
"encoding/binary"
+ "errors"
"fmt"
"io"
"math"
"strings"
-
- "golang.org/x/xerrors"
)
// InstructionSize is the size of a BPF instruction in bytes
@@ -43,7 +42,7 @@ func (ins *Instruction) Unmarshal(r io.Reader, bo binary.ByteOrder) (uint64, err
ins.Constant = int64(bi.Constant)
ins.Dst, ins.Src, err = bi.Registers.Unmarshal(bo)
if err != nil {
- return 0, xerrors.Errorf("can't unmarshal registers: %s", err)
+ return 0, fmt.Errorf("can't unmarshal registers: %s", err)
}
if !bi.OpCode.isDWordLoad() {
@@ -53,10 +52,10 @@ func (ins *Instruction) Unmarshal(r io.Reader, bo binary.ByteOrder) (uint64, err
var bi2 bpfInstruction
if err := binary.Read(r, bo, &bi2); err != nil {
// No Wrap, to avoid io.EOF clash
- return 0, xerrors.New("64bit immediate is missing second half")
+ return 0, errors.New("64bit immediate is missing second half")
}
if bi2.OpCode != 0 || bi2.Offset != 0 || bi2.Registers != 0 {
- return 0, xerrors.New("64bit immediate has non-zero fields")
+ return 0, errors.New("64bit immediate has non-zero fields")
}
ins.Constant = int64(uint64(uint32(bi2.Constant))<<32 | uint64(uint32(bi.Constant)))
@@ -66,7 +65,7 @@ func (ins *Instruction) Unmarshal(r io.Reader, bo binary.ByteOrder) (uint64, err
// Marshal encodes a BPF instruction.
func (ins Instruction) Marshal(w io.Writer, bo binary.ByteOrder) (uint64, error) {
if ins.OpCode == InvalidOpCode {
- return 0, xerrors.New("invalid opcode")
+ return 0, errors.New("invalid opcode")
}
isDWordLoad := ins.OpCode.isDWordLoad()
@@ -79,7 +78,7 @@ func (ins Instruction) Marshal(w io.Writer, bo binary.ByteOrder) (uint64, error)
regs, err := newBPFRegisters(ins.Dst, ins.Src, bo)
if err != nil {
- return 0, xerrors.Errorf("can't marshal registers: %s", err)
+ return 0, fmt.Errorf("can't marshal registers: %s", err)
}
bpfi := bpfInstruction{
@@ -113,11 +112,11 @@ func (ins Instruction) Marshal(w io.Writer, bo binary.ByteOrder) (uint64, error)
// Returns an error if the instruction doesn't load a map.
func (ins *Instruction) RewriteMapPtr(fd int) error {
if !ins.OpCode.isDWordLoad() {
- return xerrors.Errorf("%s is not a 64 bit load", ins.OpCode)
+ return fmt.Errorf("%s is not a 64 bit load", ins.OpCode)
}
if ins.Src != PseudoMapFD && ins.Src != PseudoMapValue {
- return xerrors.New("not a load from a map")
+ return errors.New("not a load from a map")
}
// Preserve the offset value for direct map loads.
@@ -136,11 +135,11 @@ func (ins *Instruction) mapPtr() uint32 {
// Returns an error if the instruction is not a direct load.
func (ins *Instruction) RewriteMapOffset(offset uint32) error {
if !ins.OpCode.isDWordLoad() {
- return xerrors.Errorf("%s is not a 64 bit load", ins.OpCode)
+ return fmt.Errorf("%s is not a 64 bit load", ins.OpCode)
}
if ins.Src != PseudoMapValue {
- return xerrors.New("not a direct load from a map")
+ return errors.New("not a direct load from a map")
}
fd := uint64(ins.Constant) & math.MaxUint32
@@ -251,7 +250,7 @@ func (insns Instructions) String() string {
// Returns an error if the symbol isn't used, see IsUnreferencedSymbol.
func (insns Instructions) RewriteMapPtr(symbol string, fd int) error {
if symbol == "" {
- return xerrors.New("empty symbol")
+ return errors.New("empty symbol")
}
found := false
@@ -286,7 +285,7 @@ func (insns Instructions) SymbolOffsets() (map[string]int, error) {
}
if _, ok := offsets[ins.Symbol]; ok {
- return nil, xerrors.Errorf("duplicate symbol %s", ins.Symbol)
+ return nil, fmt.Errorf("duplicate symbol %s", ins.Symbol)
}
offsets[ins.Symbol] = i
@@ -324,7 +323,7 @@ func (insns Instructions) marshalledOffsets() (map[string]int, error) {
}
if _, ok := symbols[ins.Symbol]; ok {
- return nil, xerrors.Errorf("duplicate symbol %s", ins.Symbol)
+ return nil, fmt.Errorf("duplicate symbol %s", ins.Symbol)
}
symbols[ins.Symbol] = currentPos
@@ -405,7 +404,7 @@ func (insns Instructions) Marshal(w io.Writer, bo binary.ByteOrder) error {
// Rewrite bpf to bpf call
offset, ok := absoluteOffsets[ins.Reference]
if !ok {
- return xerrors.Errorf("instruction %d: reference to missing symbol %s", i, ins.Reference)
+ return fmt.Errorf("instruction %d: reference to missing symbol %s", i, ins.Reference)
}
ins.Constant = int64(offset - num - 1)
@@ -414,7 +413,7 @@ func (insns Instructions) Marshal(w io.Writer, bo binary.ByteOrder) error {
// Rewrite jump to label
offset, ok := absoluteOffsets[ins.Reference]
if !ok {
- return xerrors.Errorf("instruction %d: reference to missing symbol %s", i, ins.Reference)
+ return fmt.Errorf("instruction %d: reference to missing symbol %s", i, ins.Reference)
}
ins.Offset = int16(offset - num - 1)
@@ -422,7 +421,7 @@ func (insns Instructions) Marshal(w io.Writer, bo binary.ByteOrder) error {
n, err := ins.Marshal(w, bo)
if err != nil {
- return xerrors.Errorf("instruction %d: %w", i, err)
+ return fmt.Errorf("instruction %d: %w", i, err)
}
num += int(n / InstructionSize)
@@ -446,7 +445,7 @@ func newBPFRegisters(dst, src Register, bo binary.ByteOrder) (bpfRegisters, erro
case binary.BigEndian:
return bpfRegisters((dst << 4) | (src & 0xF)), nil
default:
- return 0, xerrors.Errorf("unrecognized ByteOrder %T", bo)
+ return 0, fmt.Errorf("unrecognized ByteOrder %T", bo)
}
}
@@ -457,7 +456,7 @@ func (r bpfRegisters) Unmarshal(bo binary.ByteOrder) (dst, src Register, err err
case binary.BigEndian:
return Register(r >> 4), Register(r & 0xf), nil
default:
- return 0, 0, xerrors.Errorf("unrecognized ByteOrder %T", bo)
+ return 0, 0, fmt.Errorf("unrecognized ByteOrder %T", bo)
}
}
diff --git a/vendor/github.com/cilium/ebpf/collection.go b/vendor/github.com/cilium/ebpf/collection.go
index 5b3ed58f1..0c8b65d94 100644
--- a/vendor/github.com/cilium/ebpf/collection.go
+++ b/vendor/github.com/cilium/ebpf/collection.go
@@ -1,12 +1,13 @@
package ebpf
import (
+ "errors"
+ "fmt"
"math"
"github.com/cilium/ebpf/asm"
"github.com/cilium/ebpf/internal"
"github.com/cilium/ebpf/internal/btf"
- "golang.org/x/xerrors"
)
// CollectionOptions control loading a collection into the kernel.
@@ -64,12 +65,12 @@ func (cs *CollectionSpec) RewriteMaps(maps map[string]*Map) error {
// Not all programs need to use the map
default:
- return xerrors.Errorf("program %s: %w", progName, err)
+ return fmt.Errorf("program %s: %w", progName, err)
}
}
if !seen {
- return xerrors.Errorf("map %s not referenced by any programs", symbol)
+ return fmt.Errorf("map %s not referenced by any programs", symbol)
}
// Prevent NewCollection from creating rewritten maps
@@ -96,21 +97,21 @@ func (cs *CollectionSpec) RewriteMaps(maps map[string]*Map) error {
func (cs *CollectionSpec) RewriteConstants(consts map[string]interface{}) error {
rodata := cs.Maps[".rodata"]
if rodata == nil {
- return xerrors.New("missing .rodata section")
+ return errors.New("missing .rodata section")
}
if rodata.BTF == nil {
- return xerrors.New(".rodata section has no BTF")
+ return errors.New(".rodata section has no BTF")
}
if n := len(rodata.Contents); n != 1 {
- return xerrors.Errorf("expected one key in .rodata, found %d", n)
+ return fmt.Errorf("expected one key in .rodata, found %d", n)
}
kv := rodata.Contents[0]
value, ok := kv.Value.([]byte)
if !ok {
- return xerrors.Errorf("first value in .rodata is %T not []byte", kv.Value)
+ return fmt.Errorf("first value in .rodata is %T not []byte", kv.Value)
}
buf := make([]byte, len(value))
@@ -185,14 +186,14 @@ func NewCollectionWithOptions(spec *CollectionSpec, opts CollectionOptions) (col
var handle *btf.Handle
if mapSpec.BTF != nil {
handle, err = loadBTF(btf.MapSpec(mapSpec.BTF))
- if err != nil && !xerrors.Is(err, btf.ErrNotSupported) {
+ if err != nil && !errors.Is(err, btf.ErrNotSupported) {
return nil, err
}
}
m, err := newMapWithBTF(mapSpec, handle)
if err != nil {
- return nil, xerrors.Errorf("map %s: %w", mapName, err)
+ return nil, fmt.Errorf("map %s: %w", mapName, err)
}
maps[mapName] = m
}
@@ -216,29 +217,29 @@ func NewCollectionWithOptions(spec *CollectionSpec, opts CollectionOptions) (col
m := maps[ins.Reference]
if m == nil {
- return nil, xerrors.Errorf("program %s: missing map %s", progName, ins.Reference)
+ return nil, fmt.Errorf("program %s: missing map %s", progName, ins.Reference)
}
fd := m.FD()
if fd < 0 {
- return nil, xerrors.Errorf("map %s: %w", ins.Reference, internal.ErrClosedFd)
+ return nil, fmt.Errorf("map %s: %w", ins.Reference, internal.ErrClosedFd)
}
if err := ins.RewriteMapPtr(m.FD()); err != nil {
- return nil, xerrors.Errorf("progam %s: map %s: %w", progName, ins.Reference, err)
+ return nil, fmt.Errorf("progam %s: map %s: %w", progName, ins.Reference, err)
}
}
var handle *btf.Handle
if progSpec.BTF != nil {
handle, err = loadBTF(btf.ProgramSpec(progSpec.BTF))
- if err != nil && !xerrors.Is(err, btf.ErrNotSupported) {
+ if err != nil && !errors.Is(err, btf.ErrNotSupported) {
return nil, err
}
}
prog, err := newProgramWithBTF(progSpec, handle, opts.Programs)
if err != nil {
- return nil, xerrors.Errorf("program %s: %w", progName, err)
+ return nil, fmt.Errorf("program %s: %w", progName, err)
}
progs[progName] = prog
}
diff --git a/vendor/github.com/cilium/ebpf/elf_reader.go b/vendor/github.com/cilium/ebpf/elf_reader.go
index 2c0cbc79b..77acaed8d 100644
--- a/vendor/github.com/cilium/ebpf/elf_reader.go
+++ b/vendor/github.com/cilium/ebpf/elf_reader.go
@@ -4,6 +4,8 @@ import (
"bytes"
"debug/elf"
"encoding/binary"
+ "errors"
+ "fmt"
"io"
"math"
"os"
@@ -13,8 +15,6 @@ import (
"github.com/cilium/ebpf/internal"
"github.com/cilium/ebpf/internal/btf"
"github.com/cilium/ebpf/internal/unix"
-
- "golang.org/x/xerrors"
)
type elfCode struct {
@@ -35,7 +35,7 @@ func LoadCollectionSpec(file string) (*CollectionSpec, error) {
spec, err := LoadCollectionSpecFromReader(f)
if err != nil {
- return nil, xerrors.Errorf("file %s: %w", file, err)
+ return nil, fmt.Errorf("file %s: %w", file, err)
}
return spec, nil
}
@@ -50,7 +50,7 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
symbols, err := f.Symbols()
if err != nil {
- return nil, xerrors.Errorf("load symbols: %v", err)
+ return nil, fmt.Errorf("load symbols: %v", err)
}
ec := &elfCode{f, symbols, symbolsPerSection(symbols), "", 0}
@@ -79,13 +79,13 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
dataSections[elf.SectionIndex(i)] = sec
case sec.Type == elf.SHT_REL:
if int(sec.Info) >= len(ec.Sections) {
- return nil, xerrors.Errorf("found relocation section %v for missing section %v", i, sec.Info)
+ return nil, fmt.Errorf("found relocation section %v for missing section %v", i, sec.Info)
}
// Store relocations under the section index of the target
idx := elf.SectionIndex(sec.Info)
if relSections[idx] != nil {
- return nil, xerrors.Errorf("section %d has multiple relocation sections", sec.Info)
+ return nil, fmt.Errorf("section %d has multiple relocation sections", sec.Info)
}
relSections[idx] = sec
case sec.Type == elf.SHT_PROGBITS && (sec.Flags&elf.SHF_EXECINSTR) != 0 && sec.Size > 0:
@@ -95,44 +95,52 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
ec.license, err = loadLicense(licenseSection)
if err != nil {
- return nil, xerrors.Errorf("load license: %w", err)
+ return nil, fmt.Errorf("load license: %w", err)
}
ec.version, err = loadVersion(versionSection, ec.ByteOrder)
if err != nil {
- return nil, xerrors.Errorf("load version: %w", err)
+ return nil, fmt.Errorf("load version: %w", err)
}
btfSpec, err := btf.LoadSpecFromReader(rd)
if err != nil {
- return nil, xerrors.Errorf("load BTF: %w", err)
+ return nil, fmt.Errorf("load BTF: %w", err)
+ }
+
+ relocations, referencedSections, err := ec.loadRelocations(relSections)
+ if err != nil {
+ return nil, fmt.Errorf("load relocations: %w", err)
}
maps := make(map[string]*MapSpec)
if err := ec.loadMaps(maps, mapSections); err != nil {
- return nil, xerrors.Errorf("load maps: %w", err)
+ return nil, fmt.Errorf("load maps: %w", err)
}
if len(btfMaps) > 0 {
if err := ec.loadBTFMaps(maps, btfMaps, btfSpec); err != nil {
- return nil, xerrors.Errorf("load BTF maps: %w", err)
+ return nil, fmt.Errorf("load BTF maps: %w", err)
}
}
if len(dataSections) > 0 {
- if err := ec.loadDataSections(maps, dataSections, btfSpec); err != nil {
- return nil, xerrors.Errorf("load data sections: %w", err)
+ for idx := range dataSections {
+ if !referencedSections[idx] {
+ // Prune data sections which are not referenced by any
+ // instructions.
+ delete(dataSections, idx)
+ }
}
- }
- relocations, err := ec.loadRelocations(relSections)
- if err != nil {
- return nil, xerrors.Errorf("load relocations: %w", err)
+ if err := ec.loadDataSections(maps, dataSections, btfSpec); err != nil {
+ return nil, fmt.Errorf("load data sections: %w", err)
+ }
}
progs, err := ec.loadPrograms(progSections, relocations, btfSpec)
if err != nil {
- return nil, xerrors.Errorf("load programs: %w", err)
+ return nil, fmt.Errorf("load programs: %w", err)
}
return &CollectionSpec{maps, progs}, nil
@@ -140,11 +148,12 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
func loadLicense(sec *elf.Section) (string, error) {
if sec == nil {
- return "", xerrors.New("missing license section")
+ return "", nil
}
+
data, err := sec.Data()
if err != nil {
- return "", xerrors.Errorf("section %s: %v", sec.Name, err)
+ return "", fmt.Errorf("section %s: %v", sec.Name, err)
}
return string(bytes.TrimRight(data, "\000")), nil
}
@@ -156,12 +165,12 @@ func loadVersion(sec *elf.Section, bo binary.ByteOrder) (uint32, error) {
var version uint32
if err := binary.Read(sec.Open(), bo, &version); err != nil {
- return 0, xerrors.Errorf("section %s: %v", sec.Name, err)
+ return 0, fmt.Errorf("section %s: %v", sec.Name, err)
}
return version, nil
}
-func (ec *elfCode) loadPrograms(progSections map[elf.SectionIndex]*elf.Section, relocations map[elf.SectionIndex]map[uint64]elf.Symbol, btf *btf.Spec) (map[string]*ProgramSpec, error) {
+func (ec *elfCode) loadPrograms(progSections map[elf.SectionIndex]*elf.Section, relocations map[elf.SectionIndex]map[uint64]elf.Symbol, btfSpec *btf.Spec) (map[string]*ProgramSpec, error) {
var (
progs []*ProgramSpec
libs []*ProgramSpec
@@ -170,17 +179,17 @@ func (ec *elfCode) loadPrograms(progSections map[elf.SectionIndex]*elf.Section,
for idx, sec := range progSections {
syms := ec.symbolsPerSection[idx]
if len(syms) == 0 {
- return nil, xerrors.Errorf("section %v: missing symbols", sec.Name)
+ return nil, fmt.Errorf("section %v: missing symbols", sec.Name)
}
funcSym, ok := syms[0]
if !ok {
- return nil, xerrors.Errorf("section %v: no label at start", sec.Name)
+ return nil, fmt.Errorf("section %v: no label at start", sec.Name)
}
insns, length, err := ec.loadInstructions(sec, syms, relocations[idx])
if err != nil {
- return nil, xerrors.Errorf("program %s: can't unmarshal instructions: %w", funcSym.Name, err)
+ return nil, fmt.Errorf("program %s: can't unmarshal instructions: %w", funcSym.Name, err)
}
progType, attachType, attachTo := getProgType(sec.Name)
@@ -196,10 +205,10 @@ func (ec *elfCode) loadPrograms(progSections map[elf.SectionIndex]*elf.Section,
ByteOrder: ec.ByteOrder,
}
- if btf != nil {
- spec.BTF, err = btf.Program(sec.Name, length)
- if err != nil {
- return nil, xerrors.Errorf("BTF for section %s (program %s): %w", sec.Name, funcSym.Name, err)
+ if btfSpec != nil {
+ spec.BTF, err = btfSpec.Program(sec.Name, length)
+ if err != nil && !errors.Is(err, btf.ErrNoExtendedInfo) {
+ return nil, fmt.Errorf("program %s: %w", funcSym.Name, err)
}
}
@@ -217,7 +226,7 @@ func (ec *elfCode) loadPrograms(progSections map[elf.SectionIndex]*elf.Section,
for _, prog := range progs {
err := link(prog, libs)
if err != nil {
- return nil, xerrors.Errorf("program %s: %w", prog.Name, err)
+ return nil, fmt.Errorf("program %s: %w", prog.Name, err)
}
res[prog.Name] = prog
}
@@ -238,14 +247,14 @@ func (ec *elfCode) loadInstructions(section *elf.Section, symbols, relocations m
return insns, offset, nil
}
if err != nil {
- return nil, 0, xerrors.Errorf("offset %d: %w", offset, err)
+ return nil, 0, fmt.Errorf("offset %d: %w", offset, err)
}
ins.Symbol = symbols[offset].Name
if rel, ok := relocations[offset]; ok {
if err = ec.relocateInstruction(&ins, rel); err != nil {
- return nil, 0, xerrors.Errorf("offset %d: can't relocate instruction: %w", offset, err)
+ return nil, 0, fmt.Errorf("offset %d: can't relocate instruction: %w", offset, err)
}
}
@@ -266,7 +275,7 @@ func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) err
// from the section itself.
idx := int(rel.Section)
if idx > len(ec.Sections) {
- return xerrors.New("out-of-bounds section index")
+ return errors.New("out-of-bounds section index")
}
name = ec.Sections[idx].Name
@@ -286,7 +295,7 @@ outer:
// section. Weirdly, the offset of the real symbol in the
// section is encoded in the instruction stream.
if bind != elf.STB_LOCAL {
- return xerrors.Errorf("direct load: %s: unsupported relocation %s", name, bind)
+ return fmt.Errorf("direct load: %s: unsupported relocation %s", name, bind)
}
// For some reason, clang encodes the offset of the symbol its
@@ -308,13 +317,13 @@ outer:
case elf.STT_OBJECT:
if bind != elf.STB_GLOBAL {
- return xerrors.Errorf("load: %s: unsupported binding: %s", name, bind)
+ return fmt.Errorf("load: %s: unsupported binding: %s", name, bind)
}
ins.Src = asm.PseudoMapFD
default:
- return xerrors.Errorf("load: %s: unsupported relocation: %s", name, typ)
+ return fmt.Errorf("load: %s: unsupported relocation: %s", name, typ)
}
// Mark the instruction as needing an update when creating the
@@ -325,18 +334,18 @@ outer:
case ins.OpCode.JumpOp() == asm.Call:
if ins.Src != asm.PseudoCall {
- return xerrors.Errorf("call: %s: incorrect source register", name)
+ return fmt.Errorf("call: %s: incorrect source register", name)
}
switch typ {
case elf.STT_NOTYPE, elf.STT_FUNC:
if bind != elf.STB_GLOBAL {
- return xerrors.Errorf("call: %s: unsupported binding: %s", name, bind)
+ return fmt.Errorf("call: %s: unsupported binding: %s", name, bind)
}
case elf.STT_SECTION:
if bind != elf.STB_LOCAL {
- return xerrors.Errorf("call: %s: unsupported binding: %s", name, bind)
+ return fmt.Errorf("call: %s: unsupported binding: %s", name, bind)
}
// The function we want to call is in the indicated section,
@@ -345,23 +354,23 @@ outer:
// A value of -1 references the first instruction in the section.
offset := int64(int32(ins.Constant)+1) * asm.InstructionSize
if offset < 0 {
- return xerrors.Errorf("call: %s: invalid offset %d", name, offset)
+ return fmt.Errorf("call: %s: invalid offset %d", name, offset)
}
sym, ok := ec.symbolsPerSection[rel.Section][uint64(offset)]
if !ok {
- return xerrors.Errorf("call: %s: no symbol at offset %d", name, offset)
+ return fmt.Errorf("call: %s: no symbol at offset %d", name, offset)
}
ins.Constant = -1
name = sym.Name
default:
- return xerrors.Errorf("call: %s: invalid symbol type %s", name, typ)
+ return fmt.Errorf("call: %s: invalid symbol type %s", name, typ)
}
default:
- return xerrors.Errorf("relocation for unsupported instruction: %s", ins.OpCode)
+ return fmt.Errorf("relocation for unsupported instruction: %s", ins.OpCode)
}
ins.Reference = name
@@ -372,11 +381,11 @@ func (ec *elfCode) loadMaps(maps map[string]*MapSpec, mapSections map[elf.Sectio
for idx, sec := range mapSections {
syms := ec.symbolsPerSection[idx]
if len(syms) == 0 {
- return xerrors.Errorf("section %v: no symbols", sec.Name)
+ return fmt.Errorf("section %v: no symbols", sec.Name)
}
if sec.Size%uint64(len(syms)) != 0 {
- return xerrors.Errorf("section %v: map descriptors are not of equal size", sec.Name)
+ return fmt.Errorf("section %v: map descriptors are not of equal size", sec.Name)
}
var (
@@ -386,11 +395,11 @@ func (ec *elfCode) loadMaps(maps map[string]*MapSpec, mapSections map[elf.Sectio
for i, offset := 0, uint64(0); i < len(syms); i, offset = i+1, offset+size {
mapSym, ok := syms[offset]
if !ok {
- return xerrors.Errorf("section %s: missing symbol for map at offset %d", sec.Name, offset)
+ return fmt.Errorf("section %s: missing symbol for map at offset %d", sec.Name, offset)
}
if maps[mapSym.Name] != nil {
- return xerrors.Errorf("section %v: map %v already exists", sec.Name, mapSym)
+ return fmt.Errorf("section %v: map %v already exists", sec.Name, mapSym)
}
lr := io.LimitReader(r, int64(size))
@@ -400,19 +409,19 @@ func (ec *elfCode) loadMaps(maps map[string]*MapSpec, mapSections map[elf.Sectio
}
switch {
case binary.Read(lr, ec.ByteOrder, &spec.Type) != nil:
- return xerrors.Errorf("map %v: missing type", mapSym)
+ return fmt.Errorf("map %v: missing type", mapSym)
case binary.Read(lr, ec.ByteOrder, &spec.KeySize) != nil:
- return xerrors.Errorf("map %v: missing key size", mapSym)
+ return fmt.Errorf("map %v: missing key size", mapSym)
case binary.Read(lr, ec.ByteOrder, &spec.ValueSize) != nil:
- return xerrors.Errorf("map %v: missing value size", mapSym)
+ return fmt.Errorf("map %v: missing value size", mapSym)
case binary.Read(lr, ec.ByteOrder, &spec.MaxEntries) != nil:
- return xerrors.Errorf("map %v: missing max entries", mapSym)
+ return fmt.Errorf("map %v: missing max entries", mapSym)
case binary.Read(lr, ec.ByteOrder, &spec.Flags) != nil:
- return xerrors.Errorf("map %v: missing flags", mapSym)
+ return fmt.Errorf("map %v: missing flags", mapSym)
}
if _, err := io.Copy(internal.DiscardZeroes{}, lr); err != nil {
- return xerrors.Errorf("map %v: unknown and non-zero fields in definition", mapSym)
+ return fmt.Errorf("map %v: unknown and non-zero fields in definition", mapSym)
}
maps[mapSym.Name] = &spec
@@ -424,84 +433,116 @@ func (ec *elfCode) loadMaps(maps map[string]*MapSpec, mapSections map[elf.Sectio
func (ec *elfCode) loadBTFMaps(maps map[string]*MapSpec, mapSections map[elf.SectionIndex]*elf.Section, spec *btf.Spec) error {
if spec == nil {
- return xerrors.Errorf("missing BTF")
+ return fmt.Errorf("missing BTF")
}
for idx, sec := range mapSections {
syms := ec.symbolsPerSection[idx]
if len(syms) == 0 {
- return xerrors.Errorf("section %v: no symbols", sec.Name)
+ return fmt.Errorf("section %v: no symbols", sec.Name)
}
for _, sym := range syms {
name := sym.Name
if maps[name] != nil {
- return xerrors.Errorf("section %v: map %v already exists", sec.Name, sym)
+ return fmt.Errorf("section %v: map %v already exists", sec.Name, sym)
}
- btfMap, btfMapMembers, err := spec.Map(name)
+ mapSpec, err := mapSpecFromBTF(spec, name)
if err != nil {
- return xerrors.Errorf("map %v: can't get BTF: %w", name, err)
+ return fmt.Errorf("map %v: %w", name, err)
}
- spec, err := mapSpecFromBTF(btfMap, btfMapMembers)
- if err != nil {
- return xerrors.Errorf("map %v: %w", name, err)
- }
-
- maps[name] = spec
+ maps[name] = mapSpec
}
}
return nil
}
-func mapSpecFromBTF(btfMap *btf.Map, btfMapMembers []btf.Member) (*MapSpec, error) {
+func mapSpecFromBTF(spec *btf.Spec, name string) (*MapSpec, error) {
+ btfMap, btfMapMembers, err := spec.Map(name)
+ if err != nil {
+ return nil, fmt.Errorf("can't get BTF: %w", err)
+ }
+
+ keyType := btf.MapKey(btfMap)
+ size, err := btf.Sizeof(keyType)
+ if err != nil {
+ return nil, fmt.Errorf("can't get size of BTF key: %w", err)
+ }
+ keySize := uint32(size)
+
+ valueType := btf.MapValue(btfMap)
+ size, err = btf.Sizeof(valueType)
+ if err != nil {
+ return nil, fmt.Errorf("can't get size of BTF value: %w", err)
+ }
+ valueSize := uint32(size)
+
var (
mapType, flags, maxEntries uint32
- err error
)
for _, member := range btfMapMembers {
switch member.Name {
case "type":
mapType, err = uintFromBTF(member.Type)
if err != nil {
- return nil, xerrors.Errorf("can't get type: %w", err)
+ return nil, fmt.Errorf("can't get type: %w", err)
}
case "map_flags":
flags, err = uintFromBTF(member.Type)
if err != nil {
- return nil, xerrors.Errorf("can't get BTF map flags: %w", err)
+ return nil, fmt.Errorf("can't get BTF map flags: %w", err)
}
case "max_entries":
maxEntries, err = uintFromBTF(member.Type)
if err != nil {
- return nil, xerrors.Errorf("can't get BTF map max entries: %w", err)
+ return nil, fmt.Errorf("can't get BTF map max entries: %w", err)
}
- case "key":
- case "value":
+ case "key_size":
+ if _, isVoid := keyType.(*btf.Void); !isVoid {
+ return nil, errors.New("both key and key_size given")
+ }
+
+ keySize, err = uintFromBTF(member.Type)
+ if err != nil {
+ return nil, fmt.Errorf("can't get BTF key size: %w", err)
+ }
+
+ case "value_size":
+ if _, isVoid := valueType.(*btf.Void); !isVoid {
+ return nil, errors.New("both value and value_size given")
+ }
+
+ valueSize, err = uintFromBTF(member.Type)
+ if err != nil {
+ return nil, fmt.Errorf("can't get BTF value size: %w", err)
+ }
+
+ case "pinning":
+ pinning, err := uintFromBTF(member.Type)
+ if err != nil {
+ return nil, fmt.Errorf("can't get pinning: %w", err)
+ }
+
+ if pinning != 0 {
+ return nil, fmt.Errorf("'pinning' attribute not supported: %w", ErrNotSupported)
+ }
+
+ case "key", "value":
default:
- return nil, xerrors.Errorf("unrecognized field %s in BTF map definition", member.Name)
+ return nil, fmt.Errorf("unrecognized field %s in BTF map definition", member.Name)
}
}
- keySize, err := btf.Sizeof(btf.MapKey(btfMap))
- if err != nil {
- return nil, xerrors.Errorf("can't get size of BTF key: %w", err)
- }
-
- valueSize, err := btf.Sizeof(btf.MapValue(btfMap))
- if err != nil {
- return nil, xerrors.Errorf("can't get size of BTF value: %w", err)
- }
-
return &MapSpec{
Type: MapType(mapType),
- KeySize: uint32(keySize),
- ValueSize: uint32(valueSize),
+ KeySize: keySize,
+ ValueSize: valueSize,
MaxEntries: maxEntries,
Flags: flags,
BTF: btfMap,
@@ -513,12 +554,12 @@ func mapSpecFromBTF(btfMap *btf.Map, btfMapMembers []btf.Member) (*MapSpec, erro
func uintFromBTF(typ btf.Type) (uint32, error) {
ptr, ok := typ.(*btf.Pointer)
if !ok {
- return 0, xerrors.Errorf("not a pointer: %v", typ)
+ return 0, fmt.Errorf("not a pointer: %v", typ)
}
arr, ok := ptr.Target.(*btf.Array)
if !ok {
- return 0, xerrors.Errorf("not a pointer to array: %v", typ)
+ return 0, fmt.Errorf("not a pointer to array: %v", typ)
}
return arr.Nelems, nil
@@ -526,7 +567,7 @@ func uintFromBTF(typ btf.Type) (uint32, error) {
func (ec *elfCode) loadDataSections(maps map[string]*MapSpec, dataSections map[elf.SectionIndex]*elf.Section, spec *btf.Spec) error {
if spec == nil {
- return xerrors.New("data sections require BTF, make sure all consts are marked as static")
+ return errors.New("data sections require BTF, make sure all consts are marked as static")
}
for _, sec := range dataSections {
@@ -537,11 +578,11 @@ func (ec *elfCode) loadDataSections(maps map[string]*MapSpec, dataSections map[e
data, err := sec.Data()
if err != nil {
- return xerrors.Errorf("data section %s: can't get contents: %w", sec.Name, err)
+ return fmt.Errorf("data section %s: can't get contents: %w", sec.Name, err)
}
if uint64(len(data)) > math.MaxUint32 {
- return xerrors.Errorf("data section %s: contents exceed maximum size", sec.Name)
+ return fmt.Errorf("data section %s: contents exceed maximum size", sec.Name)
}
mapSpec := &MapSpec{
@@ -633,13 +674,14 @@ func getProgType(sectionName string) (ProgramType, AttachType, string) {
return UnspecifiedProgram, AttachNone, ""
}
-func (ec *elfCode) loadRelocations(sections map[elf.SectionIndex]*elf.Section) (map[elf.SectionIndex]map[uint64]elf.Symbol, error) {
+func (ec *elfCode) loadRelocations(sections map[elf.SectionIndex]*elf.Section) (map[elf.SectionIndex]map[uint64]elf.Symbol, map[elf.SectionIndex]bool, error) {
result := make(map[elf.SectionIndex]map[uint64]elf.Symbol)
+ targets := make(map[elf.SectionIndex]bool)
for idx, sec := range sections {
rels := make(map[uint64]elf.Symbol)
if sec.Entsize < 16 {
- return nil, xerrors.Errorf("section %s: relocations are less than 16 bytes", sec.Name)
+ return nil, nil, fmt.Errorf("section %s: relocations are less than 16 bytes", sec.Name)
}
r := sec.Open()
@@ -648,20 +690,22 @@ func (ec *elfCode) loadRelocations(sections map[elf.SectionIndex]*elf.Section) (
var rel elf.Rel64
if binary.Read(ent, ec.ByteOrder, &rel) != nil {
- return nil, xerrors.Errorf("can't parse relocation at offset %v", off)
+ return nil, nil, fmt.Errorf("can't parse relocation at offset %v", off)
}
symNo := int(elf.R_SYM64(rel.Info) - 1)
if symNo >= len(ec.symbols) {
- return nil, xerrors.Errorf("relocation at offset %d: symbol %v doesnt exist", off, symNo)
+ return nil, nil, fmt.Errorf("relocation at offset %d: symbol %v doesnt exist", off, symNo)
}
+ symbol := ec.symbols[symNo]
+ targets[symbol.Section] = true
rels[rel.Off] = ec.symbols[symNo]
}
result[idx] = rels
}
- return result, nil
+ return result, targets, nil
}
func symbolsPerSection(symbols []elf.Symbol) map[elf.SectionIndex]map[uint64]elf.Symbol {
diff --git a/vendor/github.com/cilium/ebpf/go.mod b/vendor/github.com/cilium/ebpf/go.mod
index 1d3420b85..a05cf85ed 100644
--- a/vendor/github.com/cilium/ebpf/go.mod
+++ b/vendor/github.com/cilium/ebpf/go.mod
@@ -1,8 +1,5 @@
module github.com/cilium/ebpf
-go 1.12
+go 1.13
-require (
- golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9
- golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543
-)
+require golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9
diff --git a/vendor/github.com/cilium/ebpf/go.sum b/vendor/github.com/cilium/ebpf/go.sum
index c4e24f505..e8b62417e 100644
--- a/vendor/github.com/cilium/ebpf/go.sum
+++ b/vendor/github.com/cilium/ebpf/go.sum
@@ -1,6 +1,2 @@
-golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7 h1:HmbHVPwrPEKPGLAcHSrMe6+hqSUlvZU0rab6x5EXfGU=
-golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 h1:1/DFK4b7JH8DmkqhUk48onnSfrPzImPoVxuomtbT2nk=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/vendor/github.com/cilium/ebpf/internal/btf/btf.go b/vendor/github.com/cilium/ebpf/internal/btf/btf.go
index 971078f50..3dd000a28 100644
--- a/vendor/github.com/cilium/ebpf/internal/btf/btf.go
+++ b/vendor/github.com/cilium/ebpf/internal/btf/btf.go
@@ -4,6 +4,8 @@ import (
"bytes"
"debug/elf"
"encoding/binary"
+ "errors"
+ "fmt"
"io"
"io/ioutil"
"math"
@@ -14,16 +16,15 @@ import (
"github.com/cilium/ebpf/internal"
"github.com/cilium/ebpf/internal/unix"
-
- "golang.org/x/xerrors"
)
const btfMagic = 0xeB9F
// Errors returned by BTF functions.
var (
- ErrNotSupported = internal.ErrNotSupported
- ErrNotFound = xerrors.New("not found")
+ ErrNotSupported = internal.ErrNotSupported
+ ErrNotFound = errors.New("not found")
+ ErrNoExtendedInfo = errors.New("no extended info")
)
// Spec represents decoded BTF.
@@ -76,7 +77,7 @@ func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) {
}
if sec.Size > math.MaxUint32 {
- return nil, xerrors.Errorf("section %s exceeds maximum size", sec.Name)
+ return nil, fmt.Errorf("section %s exceeds maximum size", sec.Name)
}
sectionSizes[sec.Name] = uint32(sec.Size)
@@ -89,7 +90,7 @@ func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) {
symbols, err := file.Symbols()
if err != nil {
- return nil, xerrors.Errorf("can't read symbols: %v", err)
+ return nil, fmt.Errorf("can't read symbols: %v", err)
}
variableOffsets := make(map[variable]uint32)
@@ -105,7 +106,7 @@ func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) {
}
if symbol.Value > math.MaxUint32 {
- return nil, xerrors.Errorf("section %s: symbol %s: size exceeds maximum", secName, symbol.Name)
+ return nil, fmt.Errorf("section %s: symbol %s: size exceeds maximum", secName, symbol.Name)
}
variableOffsets[variable{secName, symbol.Name}] = uint32(symbol.Value)
@@ -122,7 +123,7 @@ func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) {
spec.funcInfos, spec.lineInfos, err = parseExtInfos(btfExtSection.Open(), file.ByteOrder, spec.strings)
if err != nil {
- return nil, xerrors.Errorf("can't read ext info: %w", err)
+ return nil, fmt.Errorf("can't read ext info: %w", err)
}
return spec, nil
@@ -177,10 +178,10 @@ func LoadKernelSpec() (*Spec, error) {
func loadKernelSpec() (*Spec, error) {
fh, err := os.Open("/sys/kernel/btf/vmlinux")
if os.IsNotExist(err) {
- return nil, xerrors.Errorf("can't open kernel BTF at /sys/kernel/btf/vmlinux: %w", ErrNotFound)
+ return nil, fmt.Errorf("can't open kernel BTF at /sys/kernel/btf/vmlinux: %w", ErrNotFound)
}
if err != nil {
- return nil, xerrors.Errorf("can't read kernel BTF: %s", err)
+ return nil, fmt.Errorf("can't read kernel BTF: %s", err)
}
defer fh.Close()
@@ -190,53 +191,53 @@ func loadKernelSpec() (*Spec, error) {
func parseBTF(btf io.ReadSeeker, bo binary.ByteOrder) ([]rawType, stringTable, error) {
rawBTF, err := ioutil.ReadAll(btf)
if err != nil {
- return nil, nil, xerrors.Errorf("can't read BTF: %v", err)
+ return nil, nil, fmt.Errorf("can't read BTF: %v", err)
}
rd := bytes.NewReader(rawBTF)
var header btfHeader
if err := binary.Read(rd, bo, &header); err != nil {
- return nil, nil, xerrors.Errorf("can't read header: %v", err)
+ return nil, nil, fmt.Errorf("can't read header: %v", err)
}
if header.Magic != btfMagic {
- return nil, nil, xerrors.Errorf("incorrect magic value %v", header.Magic)
+ return nil, nil, fmt.Errorf("incorrect magic value %v", header.Magic)
}
if header.Version != 1 {
- return nil, nil, xerrors.Errorf("unexpected version %v", header.Version)
+ return nil, nil, fmt.Errorf("unexpected version %v", header.Version)
}
if header.Flags != 0 {
- return nil, nil, xerrors.Errorf("unsupported flags %v", header.Flags)
+ return nil, nil, fmt.Errorf("unsupported flags %v", header.Flags)
}
remainder := int64(header.HdrLen) - int64(binary.Size(&header))
if remainder < 0 {
- return nil, nil, xerrors.New("header is too short")
+ return nil, nil, errors.New("header is too short")
}
if _, err := io.CopyN(internal.DiscardZeroes{}, rd, remainder); err != nil {
- return nil, nil, xerrors.Errorf("header padding: %v", err)
+ return nil, nil, fmt.Errorf("header padding: %v", err)
}
if _, err := rd.Seek(int64(header.HdrLen+header.StringOff), io.SeekStart); err != nil {
- return nil, nil, xerrors.Errorf("can't seek to start of string section: %v", err)
+ return nil, nil, fmt.Errorf("can't seek to start of string section: %v", err)
}
rawStrings, err := readStringTable(io.LimitReader(rd, int64(header.StringLen)))
if err != nil {
- return nil, nil, xerrors.Errorf("can't read type names: %w", err)
+ return nil, nil, fmt.Errorf("can't read type names: %w", err)
}
if _, err := rd.Seek(int64(header.HdrLen+header.TypeOff), io.SeekStart); err != nil {
- return nil, nil, xerrors.Errorf("can't seek to start of type section: %v", err)
+ return nil, nil, fmt.Errorf("can't seek to start of type section: %v", err)
}
rawTypes, err := readTypes(io.LimitReader(rd, int64(header.TypeLen)), bo)
if err != nil {
- return nil, nil, xerrors.Errorf("can't read types: %w", err)
+ return nil, nil, fmt.Errorf("can't read types: %w", err)
}
return rawTypes, rawStrings, nil
@@ -258,9 +259,13 @@ func fixupDatasec(rawTypes []rawType, rawStrings stringTable, sectionSizes map[s
return err
}
+ if name == ".kconfig" || name == ".ksym" {
+ return fmt.Errorf("reference to %s: %w", name, ErrNotSupported)
+ }
+
size, ok := sectionSizes[name]
if !ok {
- return xerrors.Errorf("data section %s: missing size", name)
+ return fmt.Errorf("data section %s: missing size", name)
}
rawTypes[i].SizeType = size
@@ -269,17 +274,17 @@ func fixupDatasec(rawTypes []rawType, rawStrings stringTable, sectionSizes map[s
for j, secInfo := range secinfos {
id := int(secInfo.Type - 1)
if id >= len(rawTypes) {
- return xerrors.Errorf("data section %s: invalid type id %d for variable %d", name, id, j)
+ return fmt.Errorf("data section %s: invalid type id %d for variable %d", name, id, j)
}
varName, err := rawStrings.Lookup(rawTypes[id].NameOff)
if err != nil {
- return xerrors.Errorf("data section %s: can't get name for type %d: %w", name, id, err)
+ return fmt.Errorf("data section %s: can't get name for type %d: %w", name, id, err)
}
offset, ok := variableOffsets[variable{name, varName}]
if !ok {
- return xerrors.Errorf("data section %s: missing offset for variable %s", name, varName)
+ return fmt.Errorf("data section %s: missing offset for variable %s", name, varName)
}
secinfos[j].Offset = offset
@@ -289,7 +294,12 @@ func fixupDatasec(rawTypes []rawType, rawStrings stringTable, sectionSizes map[s
return nil
}
-func (s *Spec) marshal(bo binary.ByteOrder) ([]byte, error) {
+type marshalOpts struct {
+ ByteOrder binary.ByteOrder
+ StripFuncLinkage bool
+}
+
+func (s *Spec) marshal(opts marshalOpts) ([]byte, error) {
var (
buf bytes.Buffer
header = new(btfHeader)
@@ -301,9 +311,14 @@ func (s *Spec) marshal(bo binary.ByteOrder) ([]byte, error) {
_, _ = buf.Write(make([]byte, headerLen))
// Write type section, just after the header.
- for _, typ := range s.rawTypes {
- if err := typ.Marshal(&buf, bo); err != nil {
- return nil, xerrors.Errorf("can't marshal BTF: %w", err)
+ for _, raw := range s.rawTypes {
+ switch {
+ case opts.StripFuncLinkage && raw.Kind() == kindFunc:
+ raw.SetLinkage(linkageStatic)
+ }
+
+ if err := raw.Marshal(&buf, opts.ByteOrder); err != nil {
+ return nil, fmt.Errorf("can't marshal BTF: %w", err)
}
}
@@ -325,9 +340,9 @@ func (s *Spec) marshal(bo binary.ByteOrder) ([]byte, error) {
}
raw := buf.Bytes()
- err := binary.Write(sliceWriter(raw[:headerLen]), bo, header)
+ err := binary.Write(sliceWriter(raw[:headerLen]), opts.ByteOrder, header)
if err != nil {
- return nil, xerrors.Errorf("can't write header: %v", err)
+ return nil, fmt.Errorf("can't write header: %v", err)
}
return raw, nil
@@ -337,7 +352,7 @@ type sliceWriter []byte
func (sw sliceWriter) Write(p []byte) (int, error) {
if len(p) != len(sw) {
- return 0, xerrors.New("size doesn't match")
+ return 0, errors.New("size doesn't match")
}
return copy(sw, p), nil
@@ -347,17 +362,22 @@ func (sw sliceWriter) Write(p []byte) (int, error) {
//
// Length is the number of bytes in the raw BPF instruction stream.
//
-// Returns an error if there is no BTF.
+// Returns an error which may wrap ErrNoExtendedInfo if the Spec doesn't
+// contain extended BTF info.
func (s *Spec) Program(name string, length uint64) (*Program, error) {
if length == 0 {
- return nil, xerrors.New("length musn't be zero")
+ return nil, errors.New("length musn't be zero")
+ }
+
+ if s.funcInfos == nil && s.lineInfos == nil {
+ return nil, fmt.Errorf("BTF for section %s: %w", name, ErrNoExtendedInfo)
}
funcInfos, funcOK := s.funcInfos[name]
lineInfos, lineOK := s.lineInfos[name]
if !funcOK && !lineOK {
- return nil, xerrors.Errorf("no BTF for program %s", name)
+ return nil, fmt.Errorf("no extended BTF info for section %s", name)
}
return &Program{s, length, funcInfos, lineInfos}, nil
@@ -374,7 +394,7 @@ func (s *Spec) Map(name string) (*Map, []Member, error) {
mapStruct, ok := mapVar.Type.(*Struct)
if !ok {
- return nil, nil, xerrors.Errorf("expected struct, have %s", mapVar.Type)
+ return nil, nil, fmt.Errorf("expected struct, have %s", mapVar.Type)
}
var key, value Type
@@ -389,11 +409,11 @@ func (s *Spec) Map(name string) (*Map, []Member, error) {
}
if key == nil {
- return nil, nil, xerrors.Errorf("map %s: missing 'key' in type", name)
+ key = (*Void)(nil)
}
if value == nil {
- return nil, nil, xerrors.Errorf("map %s: missing 'value' in type", name)
+ value = (*Void)(nil)
}
return &Map{s, key, value}, mapStruct.Members, nil
@@ -403,7 +423,7 @@ func (s *Spec) Map(name string) (*Map, []Member, error) {
func (s *Spec) Datasec(name string) (*Map, error) {
var datasec Datasec
if err := s.FindType(name, &datasec); err != nil {
- return nil, xerrors.Errorf("data section %s: can't get BTF: %w", name, err)
+ return nil, fmt.Errorf("data section %s: can't get BTF: %w", name, err)
}
return &Map{s, &Void{}, &datasec}, nil
@@ -427,14 +447,14 @@ func (s *Spec) FindType(name string, typ Type) error {
}
if candidate != nil {
- return xerrors.Errorf("type %s: multiple candidates for %T", name, typ)
+ return fmt.Errorf("type %s: multiple candidates for %T", name, typ)
}
candidate = typ
}
if candidate == nil {
- return xerrors.Errorf("type %s: %w", name, ErrNotFound)
+ return fmt.Errorf("type %s: %w", name, ErrNotFound)
}
value := reflect.Indirect(reflect.ValueOf(copyType(candidate)))
@@ -456,16 +476,19 @@ func NewHandle(spec *Spec) (*Handle, error) {
}
if spec.byteOrder != internal.NativeEndian {
- return nil, xerrors.Errorf("can't load %s BTF on %s", spec.byteOrder, internal.NativeEndian)
+ return nil, fmt.Errorf("can't load %s BTF on %s", spec.byteOrder, internal.NativeEndian)
}
- btf, err := spec.marshal(internal.NativeEndian)
+ btf, err := spec.marshal(marshalOpts{
+ ByteOrder: internal.NativeEndian,
+ StripFuncLinkage: haveFuncLinkage() != nil,
+ })
if err != nil {
- return nil, xerrors.Errorf("can't marshal BTF: %w", err)
+ return nil, fmt.Errorf("can't marshal BTF: %w", err)
}
if uint64(len(btf)) > math.MaxUint32 {
- return nil, xerrors.New("BTF exceeds the maximum size")
+ return nil, errors.New("BTF exceeds the maximum size")
}
attr := &bpfLoadBTFAttr{
@@ -549,12 +572,12 @@ func ProgramSpec(s *Program) *Spec {
func ProgramAppend(s, other *Program) error {
funcInfos, err := s.funcInfos.append(other.funcInfos, s.length)
if err != nil {
- return xerrors.Errorf("func infos: %w", err)
+ return fmt.Errorf("func infos: %w", err)
}
lineInfos, err := s.lineInfos.append(other.lineInfos, s.length)
if err != nil {
- return xerrors.Errorf("line infos: %w", err)
+ return fmt.Errorf("line infos: %w", err)
}
s.length += other.length
@@ -608,26 +631,36 @@ func bpfLoadBTF(attr *bpfLoadBTFAttr) (*internal.FD, error) {
return internal.NewFD(uint32(fd)), nil
}
-func minimalBTF(bo binary.ByteOrder) []byte {
+func marshalBTF(types interface{}, strings []byte, bo binary.ByteOrder) []byte {
const minHeaderLength = 24
+ typesLen := uint32(binary.Size(types))
+ header := btfHeader{
+ Magic: btfMagic,
+ Version: 1,
+ HdrLen: minHeaderLength,
+ TypeOff: 0,
+ TypeLen: typesLen,
+ StringOff: typesLen,
+ StringLen: uint32(len(strings)),
+ }
+
+ buf := new(bytes.Buffer)
+ _ = binary.Write(buf, bo, &header)
+ _ = binary.Write(buf, bo, types)
+ buf.Write(strings)
+
+ return buf.Bytes()
+}
+
+var haveBTF = internal.FeatureTest("BTF", "5.1", func() (bool, error) {
var (
types struct {
Integer btfType
Var btfType
btfVar struct{ Linkage uint32 }
}
- typLen = uint32(binary.Size(&types))
strings = []byte{0, 'a', 0}
- header = btfHeader{
- Magic: btfMagic,
- Version: 1,
- HdrLen: minHeaderLength,
- TypeOff: 0,
- TypeLen: typLen,
- StringOff: typLen,
- StringLen: uint32(len(strings)),
- }
)
// We use a BTF_KIND_VAR here, to make sure that
@@ -638,16 +671,8 @@ func minimalBTF(bo binary.ByteOrder) []byte {
types.Var.SetKind(kindVar)
types.Var.SizeType = 1
- buf := new(bytes.Buffer)
- _ = binary.Write(buf, bo, &header)
- _ = binary.Write(buf, bo, &types)
- buf.Write(strings)
+ btf := marshalBTF(&types, strings, internal.NativeEndian)
- return buf.Bytes()
-}
-
-var haveBTF = internal.FeatureTest("BTF", "5.1", func() (bool, error) {
- btf := minimalBTF(internal.NativeEndian)
fd, err := bpfLoadBTF(&bpfLoadBTFAttr{
btf: internal.NewSlicePointer(btf),
btfSize: uint32(len(btf)),
@@ -657,5 +682,35 @@ var haveBTF = internal.FeatureTest("BTF", "5.1", func() (bool, error) {
}
// Check for EINVAL specifically, rather than err != nil since we
// otherwise misdetect due to insufficient permissions.
- return !xerrors.Is(err, unix.EINVAL), nil
+ return !errors.Is(err, unix.EINVAL), nil
+})
+
+var haveFuncLinkage = internal.FeatureTest("BTF func linkage", "5.6", func() (bool, error) {
+ var (
+ types struct {
+ FuncProto btfType
+ Func btfType
+ }
+ strings = []byte{0, 'a', 0}
+ )
+
+ types.FuncProto.SetKind(kindFuncProto)
+ types.Func.SetKind(kindFunc)
+ types.Func.SizeType = 1 // aka FuncProto
+ types.Func.NameOff = 1
+ types.Func.SetLinkage(linkageGlobal)
+
+ btf := marshalBTF(&types, strings, internal.NativeEndian)
+
+ fd, err := bpfLoadBTF(&bpfLoadBTFAttr{
+ btf: internal.NewSlicePointer(btf),
+ btfSize: uint32(len(btf)),
+ })
+ if err == nil {
+ fd.Close()
+ }
+
+ // Check for EINVAL specifically, rather than err != nil since we
+ // otherwise misdetect due to insufficient permissions.
+ return !errors.Is(err, unix.EINVAL), nil
})
diff --git a/vendor/github.com/cilium/ebpf/internal/btf/btf_types.go b/vendor/github.com/cilium/ebpf/internal/btf/btf_types.go
index d11240d24..e34a87ecb 100644
--- a/vendor/github.com/cilium/ebpf/internal/btf/btf_types.go
+++ b/vendor/github.com/cilium/ebpf/internal/btf/btf_types.go
@@ -4,8 +4,6 @@ import (
"encoding/binary"
"fmt"
"io"
-
- "golang.org/x/xerrors"
)
// btfKind describes a Type.
@@ -33,6 +31,14 @@ const (
kindDatasec
)
+type btfFuncLinkage uint8
+
+const (
+ linkageStatic btfFuncLinkage = iota
+ linkageGlobal
+ linkageExtern
+)
+
const (
btfTypeKindShift = 24
btfTypeKindLen = 4
@@ -44,7 +50,7 @@ const (
type btfType struct {
NameOff uint32
/* "info" bits arrangement
- * bits 0-15: vlen (e.g. # of struct's members)
+ * bits 0-15: vlen (e.g. # of struct's members), linkage
* bits 16-23: unused
* bits 24-27: kind (e.g. int, ptr, array...etc)
* bits 28-30: unused
@@ -130,6 +136,14 @@ func (bt *btfType) SetVlen(vlen int) {
bt.setInfo(uint32(vlen), btfTypeVlenMask, btfTypeVlenShift)
}
+func (bt *btfType) Linkage() btfFuncLinkage {
+ return btfFuncLinkage(bt.info(btfTypeVlenMask, btfTypeVlenShift))
+}
+
+func (bt *btfType) SetLinkage(linkage btfFuncLinkage) {
+ bt.setInfo(uint32(linkage), btfTypeVlenMask, btfTypeVlenShift)
+}
+
func (bt *btfType) Type() TypeID {
// TODO: Panic here if wrong kind?
return TypeID(bt.SizeType)
@@ -199,7 +213,7 @@ func readTypes(r io.Reader, bo binary.ByteOrder) ([]rawType, error) {
if err := binary.Read(r, bo, &header); err == io.EOF {
return types, nil
} else if err != nil {
- return nil, xerrors.Errorf("can't read type info for id %v: %v", id, err)
+ return nil, fmt.Errorf("can't read type info for id %v: %v", id, err)
}
var data interface{}
@@ -228,7 +242,7 @@ func readTypes(r io.Reader, bo binary.ByteOrder) ([]rawType, error) {
case kindDatasec:
data = make([]btfVarSecinfo, header.Vlen())
default:
- return nil, xerrors.Errorf("type id %v: unknown kind: %v", id, header.Kind())
+ return nil, fmt.Errorf("type id %v: unknown kind: %v", id, header.Kind())
}
if data == nil {
@@ -237,7 +251,7 @@ func readTypes(r io.Reader, bo binary.ByteOrder) ([]rawType, error) {
}
if err := binary.Read(r, bo, data); err != nil {
- return nil, xerrors.Errorf("type id %d: kind %v: can't read %T: %v", id, header.Kind(), data, err)
+ return nil, fmt.Errorf("type id %d: kind %v: can't read %T: %v", id, header.Kind(), data, err)
}
types = append(types, rawType{header, data})
diff --git a/vendor/github.com/cilium/ebpf/internal/btf/ext_info.go b/vendor/github.com/cilium/ebpf/internal/btf/ext_info.go
index 1b1e33c4d..28918ae9e 100644
--- a/vendor/github.com/cilium/ebpf/internal/btf/ext_info.go
+++ b/vendor/github.com/cilium/ebpf/internal/btf/ext_info.go
@@ -3,13 +3,13 @@ package btf
import (
"bytes"
"encoding/binary"
+ "errors"
+ "fmt"
"io"
"io/ioutil"
"github.com/cilium/ebpf/asm"
"github.com/cilium/ebpf/internal"
-
- "golang.org/x/xerrors"
)
type btfExtHeader struct {
@@ -27,49 +27,49 @@ type btfExtHeader struct {
func parseExtInfos(r io.ReadSeeker, bo binary.ByteOrder, strings stringTable) (funcInfo, lineInfo map[string]extInfo, err error) {
var header btfExtHeader
if err := binary.Read(r, bo, &header); err != nil {
- return nil, nil, xerrors.Errorf("can't read header: %v", err)
+ return nil, nil, fmt.Errorf("can't read header: %v", err)
}
if header.Magic != btfMagic {
- return nil, nil, xerrors.Errorf("incorrect magic value %v", header.Magic)
+ return nil, nil, fmt.Errorf("incorrect magic value %v", header.Magic)
}
if header.Version != 1 {
- return nil, nil, xerrors.Errorf("unexpected version %v", header.Version)
+ return nil, nil, fmt.Errorf("unexpected version %v", header.Version)
}
if header.Flags != 0 {
- return nil, nil, xerrors.Errorf("unsupported flags %v", header.Flags)
+ return nil, nil, fmt.Errorf("unsupported flags %v", header.Flags)
}
remainder := int64(header.HdrLen) - int64(binary.Size(&header))
if remainder < 0 {
- return nil, nil, xerrors.New("header is too short")
+ return nil, nil, errors.New("header is too short")
}
// Of course, the .BTF.ext header has different semantics than the
// .BTF ext header. We need to ignore non-null values.
_, err = io.CopyN(ioutil.Discard, r, remainder)
if err != nil {
- return nil, nil, xerrors.Errorf("header padding: %v", err)
+ return nil, nil, fmt.Errorf("header padding: %v", err)
}
if _, err := r.Seek(int64(header.HdrLen+header.FuncInfoOff), io.SeekStart); err != nil {
- return nil, nil, xerrors.Errorf("can't seek to function info section: %v", err)
+ return nil, nil, fmt.Errorf("can't seek to function info section: %v", err)
}
funcInfo, err = parseExtInfo(io.LimitReader(r, int64(header.FuncInfoLen)), bo, strings)
if err != nil {
- return nil, nil, xerrors.Errorf("function info: %w", err)
+ return nil, nil, fmt.Errorf("function info: %w", err)
}
if _, err := r.Seek(int64(header.HdrLen+header.LineInfoOff), io.SeekStart); err != nil {
- return nil, nil, xerrors.Errorf("can't seek to line info section: %v", err)
+ return nil, nil, fmt.Errorf("can't seek to line info section: %v", err)
}
lineInfo, err = parseExtInfo(io.LimitReader(r, int64(header.LineInfoLen)), bo, strings)
if err != nil {
- return nil, nil, xerrors.Errorf("line info: %w", err)
+ return nil, nil, fmt.Errorf("line info: %w", err)
}
return funcInfo, lineInfo, nil
@@ -92,7 +92,7 @@ type extInfo struct {
func (ei extInfo) append(other extInfo, offset uint64) (extInfo, error) {
if other.recordSize != ei.recordSize {
- return extInfo{}, xerrors.Errorf("ext_info record size mismatch, want %d (got %d)", ei.recordSize, other.recordSize)
+ return extInfo{}, fmt.Errorf("ext_info record size mismatch, want %d (got %d)", ei.recordSize, other.recordSize)
}
records := make([]extInfoRecord, 0, len(ei.records)+len(other.records))
@@ -117,7 +117,7 @@ func (ei extInfo) MarshalBinary() ([]byte, error) {
// while the ELF tracks it in bytes.
insnOff := uint32(info.InsnOff / asm.InstructionSize)
if err := binary.Write(buf, internal.NativeEndian, insnOff); err != nil {
- return nil, xerrors.Errorf("can't write instruction offset: %v", err)
+ return nil, fmt.Errorf("can't write instruction offset: %v", err)
}
buf.Write(info.Opaque)
@@ -129,12 +129,12 @@ func (ei extInfo) MarshalBinary() ([]byte, error) {
func parseExtInfo(r io.Reader, bo binary.ByteOrder, strings stringTable) (map[string]extInfo, error) {
var recordSize uint32
if err := binary.Read(r, bo, &recordSize); err != nil {
- return nil, xerrors.Errorf("can't read record size: %v", err)
+ return nil, fmt.Errorf("can't read record size: %v", err)
}
if recordSize < 4 {
// Need at least insnOff
- return nil, xerrors.New("record size too short")
+ return nil, errors.New("record size too short")
}
result := make(map[string]extInfo)
@@ -143,32 +143,32 @@ func parseExtInfo(r io.Reader, bo binary.ByteOrder, strings stringTable) (map[st
if err := binary.Read(r, bo, &infoHeader); err == io.EOF {
return result, nil
} else if err != nil {
- return nil, xerrors.Errorf("can't read ext info header: %v", err)
+ return nil, fmt.Errorf("can't read ext info header: %v", err)
}
secName, err := strings.Lookup(infoHeader.SecNameOff)
if err != nil {
- return nil, xerrors.Errorf("can't get section name: %w", err)
+ return nil, fmt.Errorf("can't get section name: %w", err)
}
if infoHeader.NumInfo == 0 {
- return nil, xerrors.Errorf("section %s has invalid number of records", secName)
+ return nil, fmt.Errorf("section %s has invalid number of records", secName)
}
var records []extInfoRecord
for i := uint32(0); i < infoHeader.NumInfo; i++ {
var byteOff uint32
if err := binary.Read(r, bo, &byteOff); err != nil {
- return nil, xerrors.Errorf("section %v: can't read extended info offset: %v", secName, err)
+ return nil, fmt.Errorf("section %v: can't read extended info offset: %v", secName, err)
}
buf := make([]byte, int(recordSize-4))
if _, err := io.ReadFull(r, buf); err != nil {
- return nil, xerrors.Errorf("section %v: can't read record: %v", secName, err)
+ return nil, fmt.Errorf("section %v: can't read record: %v", secName, err)
}
if byteOff%asm.InstructionSize != 0 {
- return nil, xerrors.Errorf("section %v: offset %v is not aligned with instruction size", secName, byteOff)
+ return nil, fmt.Errorf("section %v: offset %v is not aligned with instruction size", secName, byteOff)
}
records = append(records, extInfoRecord{uint64(byteOff), buf})
diff --git a/vendor/github.com/cilium/ebpf/internal/btf/strings.go b/vendor/github.com/cilium/ebpf/internal/btf/strings.go
index a5f905f56..8782643a0 100644
--- a/vendor/github.com/cilium/ebpf/internal/btf/strings.go
+++ b/vendor/github.com/cilium/ebpf/internal/btf/strings.go
@@ -2,10 +2,10 @@ package btf
import (
"bytes"
+ "errors"
+ "fmt"
"io"
"io/ioutil"
-
- "golang.org/x/xerrors"
)
type stringTable []byte
@@ -13,19 +13,19 @@ type stringTable []byte
func readStringTable(r io.Reader) (stringTable, error) {
contents, err := ioutil.ReadAll(r)
if err != nil {
- return nil, xerrors.Errorf("can't read string table: %v", err)
+ return nil, fmt.Errorf("can't read string table: %v", err)
}
if len(contents) < 1 {
- return nil, xerrors.New("string table is empty")
+ return nil, errors.New("string table is empty")
}
if contents[0] != '\x00' {
- return nil, xerrors.New("first item in string table is non-empty")
+ return nil, errors.New("first item in string table is non-empty")
}
if contents[len(contents)-1] != '\x00' {
- return nil, xerrors.New("string table isn't null terminated")
+ return nil, errors.New("string table isn't null terminated")
}
return stringTable(contents), nil
@@ -33,22 +33,22 @@ func readStringTable(r io.Reader) (stringTable, error) {
func (st stringTable) Lookup(offset uint32) (string, error) {
if int64(offset) > int64(^uint(0)>>1) {
- return "", xerrors.Errorf("offset %d overflows int", offset)
+ return "", fmt.Errorf("offset %d overflows int", offset)
}
pos := int(offset)
if pos >= len(st) {
- return "", xerrors.Errorf("offset %d is out of bounds", offset)
+ return "", fmt.Errorf("offset %d is out of bounds", offset)
}
if pos > 0 && st[pos-1] != '\x00' {
- return "", xerrors.Errorf("offset %d isn't start of a string", offset)
+ return "", fmt.Errorf("offset %d isn't start of a string", offset)
}
str := st[pos:]
end := bytes.IndexByte(str, '\x00')
if end == -1 {
- return "", xerrors.Errorf("offset %d isn't null terminated", offset)
+ return "", fmt.Errorf("offset %d isn't null terminated", offset)
}
return string(str[:end]), nil
diff --git a/vendor/github.com/cilium/ebpf/internal/btf/types.go b/vendor/github.com/cilium/ebpf/internal/btf/types.go
index 101a40f32..264142abc 100644
--- a/vendor/github.com/cilium/ebpf/internal/btf/types.go
+++ b/vendor/github.com/cilium/ebpf/internal/btf/types.go
@@ -1,9 +1,9 @@
package btf
import (
+ "errors"
+ "fmt"
"math"
-
- "golang.org/x/xerrors"
)
const maxTypeDepth = 32
@@ -38,9 +38,10 @@ func (n Name) name() string {
// Void is the unit type of BTF.
type Void struct{}
-func (v Void) ID() TypeID { return 0 }
-func (v Void) copy() Type { return Void{} }
-func (v Void) walk(*copyStack) {}
+func (v *Void) ID() TypeID { return 0 }
+func (v *Void) size() uint32 { return 0 }
+func (v *Void) copy() Type { return (*Void)(nil) }
+func (v *Void) walk(*copyStack) {}
// Int is an integer of a given length.
type Int struct {
@@ -310,7 +311,7 @@ func Sizeof(typ Type) (int, error) {
switch v := typ.(type) {
case *Array:
if n > 0 && int64(v.Nelems) > math.MaxInt64/n {
- return 0, xerrors.New("overflow")
+ return 0, errors.New("overflow")
}
// Arrays may be of zero length, which allows
@@ -336,22 +337,22 @@ func Sizeof(typ Type) (int, error) {
continue
default:
- return 0, xerrors.Errorf("unrecognized type %T", typ)
+ return 0, fmt.Errorf("unrecognized type %T", typ)
}
if n > 0 && elem > math.MaxInt64/n {
- return 0, xerrors.New("overflow")
+ return 0, errors.New("overflow")
}
size := n * elem
if int64(int(size)) != size {
- return 0, xerrors.New("overflow")
+ return 0, errors.New("overflow")
}
return int(size), nil
}
- return 0, xerrors.New("exceeded type depth")
+ return 0, errors.New("exceeded type depth")
}
// copy a Type recursively.
@@ -433,7 +434,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
for i, btfMember := range raw {
name, err := rawStrings.LookupName(btfMember.NameOff)
if err != nil {
- return nil, xerrors.Errorf("can't get name for member %d: %w", i, err)
+ return nil, fmt.Errorf("can't get name for member %d: %w", i, err)
}
members = append(members, Member{
Name: name,
@@ -447,7 +448,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
}
types := make([]Type, 0, len(rawTypes))
- types = append(types, Void{})
+ types = append(types, (*Void)(nil))
namedTypes = make(map[string][]Type)
for i, raw := range rawTypes {
@@ -460,7 +461,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
name, err := rawStrings.LookupName(raw.NameOff)
if err != nil {
- return nil, xerrors.Errorf("can't get name for type id %d: %w", id, err)
+ return nil, fmt.Errorf("can't get name for type id %d: %w", id, err)
}
switch raw.Kind() {
@@ -484,14 +485,14 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
case kindStruct:
members, err := convertMembers(raw.data.([]btfMember))
if err != nil {
- return nil, xerrors.Errorf("struct %s (id %d): %w", name, id, err)
+ return nil, fmt.Errorf("struct %s (id %d): %w", name, id, err)
}
typ = &Struct{id, name, raw.Size(), members}
case kindUnion:
members, err := convertMembers(raw.data.([]btfMember))
if err != nil {
- return nil, xerrors.Errorf("union %s (id %d): %w", name, id, err)
+ return nil, fmt.Errorf("union %s (id %d): %w", name, id, err)
}
typ = &Union{id, name, raw.Size(), members}
@@ -551,7 +552,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
typ = &Datasec{id, name, raw.SizeType, vars}
default:
- return nil, xerrors.Errorf("type id %d: unknown kind: %v", id, raw.Kind())
+ return nil, fmt.Errorf("type id %d: unknown kind: %v", id, raw.Kind())
}
types = append(types, typ)
@@ -566,7 +567,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
for _, fixup := range fixups {
i := int(fixup.id)
if i >= len(types) {
- return nil, xerrors.Errorf("reference to invalid type id: %d", fixup.id)
+ return nil, fmt.Errorf("reference to invalid type id: %d", fixup.id)
}
// Default void (id 0) to unknown
@@ -576,7 +577,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
}
if expected := fixup.expectedKind; expected != kindUnknown && rawKind != expected {
- return nil, xerrors.Errorf("expected type id %d to have kind %s, found %s", fixup.id, expected, rawKind)
+ return nil, fmt.Errorf("expected type id %d to have kind %s, found %s", fixup.id, expected, rawKind)
}
*fixup.typ = types[i]
diff --git a/vendor/github.com/cilium/ebpf/internal/errors.go b/vendor/github.com/cilium/ebpf/internal/errors.go
index 72dedb477..b6aee81f7 100644
--- a/vendor/github.com/cilium/ebpf/internal/errors.go
+++ b/vendor/github.com/cilium/ebpf/internal/errors.go
@@ -2,11 +2,11 @@ package internal
import (
"bytes"
+ "errors"
"fmt"
"strings"
"github.com/cilium/ebpf/internal/unix"
- "golang.org/x/xerrors"
)
// ErrorWithLog returns an error that includes logs from the
@@ -16,7 +16,7 @@ import (
// the log. It is used to check for truncation of the output.
func ErrorWithLog(err error, log []byte, logErr error) error {
logStr := strings.Trim(CString(log), "\t\r\n ")
- if xerrors.Is(logErr, unix.ENOSPC) {
+ if errors.Is(logErr, unix.ENOSPC) {
logStr += " (truncated...)"
}
diff --git a/vendor/github.com/cilium/ebpf/internal/fd.go b/vendor/github.com/cilium/ebpf/internal/fd.go
index 499f1ec0d..af04955bd 100644
--- a/vendor/github.com/cilium/ebpf/internal/fd.go
+++ b/vendor/github.com/cilium/ebpf/internal/fd.go
@@ -1,16 +1,16 @@
package internal
import (
+ "errors"
+ "fmt"
"os"
"runtime"
"strconv"
"github.com/cilium/ebpf/internal/unix"
-
- "golang.org/x/xerrors"
)
-var ErrClosedFd = xerrors.New("use of closed file descriptor")
+var ErrClosedFd = errors.New("use of closed file descriptor")
type FD struct {
raw int64
@@ -57,7 +57,7 @@ func (fd *FD) Dup() (*FD, error) {
dup, err := unix.FcntlInt(uintptr(fd.raw), unix.F_DUPFD_CLOEXEC, 0)
if err != nil {
- return nil, xerrors.Errorf("can't dup fd: %v", err)
+ return nil, fmt.Errorf("can't dup fd: %v", err)
}
return NewFD(uint32(dup)), nil
diff --git a/vendor/github.com/cilium/ebpf/internal/feature.go b/vendor/github.com/cilium/ebpf/internal/feature.go
index 671a6a0c8..7375b21ef 100644
--- a/vendor/github.com/cilium/ebpf/internal/feature.go
+++ b/vendor/github.com/cilium/ebpf/internal/feature.go
@@ -1,14 +1,13 @@
package internal
import (
+ "errors"
"fmt"
"sync"
-
- "golang.org/x/xerrors"
)
// ErrNotSupported indicates that a feature is not supported by the current kernel.
-var ErrNotSupported = xerrors.New("not supported")
+var ErrNotSupported = errors.New("not supported")
// UnsupportedFeatureError is returned by FeatureTest() functions.
type UnsupportedFeatureError struct {
@@ -67,7 +66,7 @@ func FeatureTest(name, version string, fn FeatureTestFn) func() error {
}
available, err := fn()
- if xerrors.Is(err, ErrNotSupported) {
+ if errors.Is(err, ErrNotSupported) {
// The feature test aborted because a dependent feature
// is missing, which we should cache.
available = false
@@ -75,7 +74,7 @@ func FeatureTest(name, version string, fn FeatureTestFn) func() error {
// We couldn't execute the feature test to a point
// where it could make a determination.
// Don't cache the result, just return it.
- return xerrors.Errorf("can't detect support for %s: %w", name, err)
+ return fmt.Errorf("can't detect support for %s: %w", name, err)
}
ft.successful = true
@@ -99,7 +98,7 @@ func NewVersion(ver string) (Version, error) {
var major, minor, patch uint16
n, _ := fmt.Sscanf(ver, "%d.%d.%d", &major, &minor, &patch)
if n < 2 {
- return Version{}, xerrors.Errorf("invalid version: %s", ver)
+ return Version{}, fmt.Errorf("invalid version: %s", ver)
}
return Version{major, minor, patch}, nil
}
diff --git a/vendor/github.com/cilium/ebpf/internal/io.go b/vendor/github.com/cilium/ebpf/internal/io.go
index f364f2110..fa7402782 100644
--- a/vendor/github.com/cilium/ebpf/internal/io.go
+++ b/vendor/github.com/cilium/ebpf/internal/io.go
@@ -1,6 +1,6 @@
package internal
-import "golang.org/x/xerrors"
+import "errors"
// DiscardZeroes makes sure that all written bytes are zero
// before discarding them.
@@ -9,7 +9,7 @@ type DiscardZeroes struct{}
func (DiscardZeroes) Write(p []byte) (int, error) {
for _, b := range p {
if b != 0 {
- return 0, xerrors.New("encountered non-zero byte")
+ return 0, errors.New("encountered non-zero byte")
}
}
return len(p), nil
diff --git a/vendor/github.com/cilium/ebpf/internal/syscall.go b/vendor/github.com/cilium/ebpf/internal/syscall.go
index b9de045ee..efbf40327 100644
--- a/vendor/github.com/cilium/ebpf/internal/syscall.go
+++ b/vendor/github.com/cilium/ebpf/internal/syscall.go
@@ -1,12 +1,12 @@
package internal
import (
+ "fmt"
"path/filepath"
"runtime"
"unsafe"
"github.com/cilium/ebpf/internal/unix"
- "golang.org/x/xerrors"
)
//go:generate stringer -output syscall_string.go -type=BPFCmd
@@ -107,7 +107,7 @@ func BPFObjPin(fileName string, fd *FD) error {
return err
}
if uint64(statfs.Type) != bpfFSType {
- return xerrors.Errorf("%s is not on a bpf filesystem", fileName)
+ return fmt.Errorf("%s is not on a bpf filesystem", fileName)
}
value, err := fd.Value()
@@ -121,7 +121,7 @@ func BPFObjPin(fileName string, fd *FD) error {
}
_, err = BPF(BPF_OBJ_PIN, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
if err != nil {
- return xerrors.Errorf("pin object %s: %w", fileName, err)
+ return fmt.Errorf("pin object %s: %w", fileName, err)
}
return nil
}
@@ -133,7 +133,7 @@ func BPFObjGet(fileName string) (*FD, error) {
}
ptr, err := BPF(BPF_OBJ_GET, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
if err != nil {
- return nil, xerrors.Errorf("get object %s: %w", fileName, err)
+ return nil, fmt.Errorf("get object %s: %w", fileName, err)
}
return NewFD(uint32(ptr)), nil
}
diff --git a/vendor/github.com/cilium/ebpf/linker.go b/vendor/github.com/cilium/ebpf/linker.go
index b9a54daec..1bb8f61c2 100644
--- a/vendor/github.com/cilium/ebpf/linker.go
+++ b/vendor/github.com/cilium/ebpf/linker.go
@@ -1,10 +1,10 @@
package ebpf
import (
+ "fmt"
+
"github.com/cilium/ebpf/asm"
"github.com/cilium/ebpf/internal/btf"
-
- "golang.org/x/xerrors"
)
// link resolves bpf-to-bpf calls.
@@ -28,7 +28,7 @@ func link(prog *ProgramSpec, libs []*ProgramSpec) error {
needed, err := needSection(insns, lib.Instructions)
if err != nil {
- return xerrors.Errorf("linking %s: %w", lib.Name, err)
+ return fmt.Errorf("linking %s: %w", lib.Name, err)
}
if !needed {
@@ -41,7 +41,7 @@ func link(prog *ProgramSpec, libs []*ProgramSpec) error {
if prog.BTF != nil && lib.BTF != nil {
if err := btf.ProgramAppend(prog.BTF, lib.BTF); err != nil {
- return xerrors.Errorf("linking BTF of %s: %w", lib.Name, err)
+ return fmt.Errorf("linking BTF of %s: %w", lib.Name, err)
}
}
}
diff --git a/vendor/github.com/cilium/ebpf/map.go b/vendor/github.com/cilium/ebpf/map.go
index 31abc17ef..461b995a5 100644
--- a/vendor/github.com/cilium/ebpf/map.go
+++ b/vendor/github.com/cilium/ebpf/map.go
@@ -1,21 +1,20 @@
package ebpf
import (
+ "errors"
"fmt"
"strings"
"github.com/cilium/ebpf/internal"
"github.com/cilium/ebpf/internal/btf"
"github.com/cilium/ebpf/internal/unix"
-
- "golang.org/x/xerrors"
)
// Errors returned by Map and MapIterator methods.
var (
- ErrKeyNotExist = xerrors.New("key does not exist")
- ErrKeyExist = xerrors.New("key already exists")
- ErrIterationAborted = xerrors.New("iteration aborted")
+ ErrKeyNotExist = errors.New("key does not exist")
+ ErrKeyExist = errors.New("key already exists")
+ ErrIterationAborted = errors.New("iteration aborted")
)
// MapID represents the unique ID of an eBPF map
@@ -92,7 +91,7 @@ type Map struct {
// You should not use fd after calling this function.
func NewMapFromFD(fd int) (*Map, error) {
if fd < 0 {
- return nil, xerrors.New("invalid fd")
+ return nil, errors.New("invalid fd")
}
bpfFd := internal.NewFD(uint32(fd))
@@ -118,8 +117,8 @@ func NewMap(spec *MapSpec) (*Map, error) {
}
handle, err := btf.NewHandle(btf.MapSpec(spec.BTF))
- if err != nil && !xerrors.Is(err, btf.ErrNotSupported) {
- return nil, xerrors.Errorf("can't load BTF: %w", err)
+ if err != nil && !errors.Is(err, btf.ErrNotSupported) {
+ return nil, fmt.Errorf("can't load BTF: %w", err)
}
return newMapWithBTF(spec, handle)
@@ -131,7 +130,7 @@ func newMapWithBTF(spec *MapSpec, handle *btf.Handle) (*Map, error) {
}
if spec.InnerMap == nil {
- return nil, xerrors.Errorf("%s requires InnerMap", spec.Type)
+ return nil, fmt.Errorf("%s requires InnerMap", spec.Type)
}
template, err := createMap(spec.InnerMap, nil, handle)
@@ -155,25 +154,25 @@ func createMap(spec *MapSpec, inner *internal.FD, handle *btf.Handle) (*Map, err
}
if abi.ValueSize != 0 && abi.ValueSize != 4 {
- return nil, xerrors.New("ValueSize must be zero or four for map of map")
+ return nil, errors.New("ValueSize must be zero or four for map of map")
}
abi.ValueSize = 4
case PerfEventArray:
if abi.KeySize != 0 && abi.KeySize != 4 {
- return nil, xerrors.New("KeySize must be zero or four for perf event array")
+ return nil, errors.New("KeySize must be zero or four for perf event array")
}
abi.KeySize = 4
if abi.ValueSize != 0 && abi.ValueSize != 4 {
- return nil, xerrors.New("ValueSize must be zero or four for perf event array")
+ return nil, errors.New("ValueSize must be zero or four for perf event array")
}
abi.ValueSize = 4
if abi.MaxEntries == 0 {
n, err := internal.PossibleCPUs()
if err != nil {
- return nil, xerrors.Errorf("perf event array: %w", err)
+ return nil, fmt.Errorf("perf event array: %w", err)
}
abi.MaxEntries = uint32(n)
}
@@ -181,7 +180,7 @@ func createMap(spec *MapSpec, inner *internal.FD, handle *btf.Handle) (*Map, err
if abi.Flags&(unix.BPF_F_RDONLY_PROG|unix.BPF_F_WRONLY_PROG) > 0 || spec.Freeze {
if err := haveMapMutabilityModifiers(); err != nil {
- return nil, xerrors.Errorf("map create: %w", err)
+ return nil, fmt.Errorf("map create: %w", err)
}
}
@@ -197,7 +196,7 @@ func createMap(spec *MapSpec, inner *internal.FD, handle *btf.Handle) (*Map, err
var err error
attr.innerMapFd, err = inner.Value()
if err != nil {
- return nil, xerrors.Errorf("map create: %w", err)
+ return nil, fmt.Errorf("map create: %w", err)
}
}
@@ -213,7 +212,7 @@ func createMap(spec *MapSpec, inner *internal.FD, handle *btf.Handle) (*Map, err
fd, err := bpfMapCreate(&attr)
if err != nil {
- return nil, xerrors.Errorf("map create: %w", err)
+ return nil, fmt.Errorf("map create: %w", err)
}
m, err := newMap(fd, spec.Name, abi)
@@ -223,13 +222,13 @@ func createMap(spec *MapSpec, inner *internal.FD, handle *btf.Handle) (*Map, err
if err := m.populate(spec.Contents); err != nil {
m.Close()
- return nil, xerrors.Errorf("map create: can't set initial contents: %w", err)
+ return nil, fmt.Errorf("map create: can't set initial contents: %w", err)
}
if spec.Freeze {
if err := m.Freeze(); err != nil {
m.Close()
- return nil, xerrors.Errorf("can't freeze map: %w", err)
+ return nil, fmt.Errorf("can't freeze map: %w", err)
}
}
@@ -301,9 +300,9 @@ func (m *Map) Lookup(key, valueOut interface{}) error {
*value = m
return nil
case *Map:
- return xerrors.Errorf("can't unmarshal into %T, need %T", value, (**Map)(nil))
+ return fmt.Errorf("can't unmarshal into %T, need %T", value, (**Map)(nil))
case Map:
- return xerrors.Errorf("can't unmarshal into %T, need %T", value, (**Map)(nil))
+ return fmt.Errorf("can't unmarshal into %T, need %T", value, (**Map)(nil))
case **Program:
p, err := unmarshalProgram(valueBytes)
@@ -315,9 +314,9 @@ func (m *Map) Lookup(key, valueOut interface{}) error {
*value = p
return nil
case *Program:
- return xerrors.Errorf("can't unmarshal into %T, need %T", value, (**Program)(nil))
+ return fmt.Errorf("can't unmarshal into %T, need %T", value, (**Program)(nil))
case Program:
- return xerrors.Errorf("can't unmarshal into %T, need %T", value, (**Program)(nil))
+ return fmt.Errorf("can't unmarshal into %T, need %T", value, (**Program)(nil))
default:
return unmarshalBytes(valueOut, valueBytes)
@@ -332,11 +331,11 @@ func (m *Map) LookupAndDelete(key, valueOut interface{}) error {
keyPtr, err := marshalPtr(key, int(m.abi.KeySize))
if err != nil {
- return xerrors.Errorf("can't marshal key: %w", err)
+ return fmt.Errorf("can't marshal key: %w", err)
}
if err := bpfMapLookupAndDelete(m.fd, keyPtr, valuePtr); err != nil {
- return xerrors.Errorf("lookup and delete failed: %w", err)
+ return fmt.Errorf("lookup and delete failed: %w", err)
}
return unmarshalBytes(valueOut, valueBytes)
@@ -350,7 +349,7 @@ func (m *Map) LookupBytes(key interface{}) ([]byte, error) {
valuePtr := internal.NewSlicePointer(valueBytes)
err := m.lookup(key, valuePtr)
- if xerrors.Is(err, ErrKeyNotExist) {
+ if errors.Is(err, ErrKeyNotExist) {
return nil, nil
}
@@ -360,11 +359,11 @@ func (m *Map) LookupBytes(key interface{}) ([]byte, error) {
func (m *Map) lookup(key interface{}, valueOut internal.Pointer) error {
keyPtr, err := marshalPtr(key, int(m.abi.KeySize))
if err != nil {
- return xerrors.Errorf("can't marshal key: %w", err)
+ return fmt.Errorf("can't marshal key: %w", err)
}
if err = bpfMapLookupElem(m.fd, keyPtr, valueOut); err != nil {
- return xerrors.Errorf("lookup failed: %w", err)
+ return fmt.Errorf("lookup failed: %w", err)
}
return nil
}
@@ -394,7 +393,7 @@ func (m *Map) Put(key, value interface{}) error {
func (m *Map) Update(key, value interface{}, flags MapUpdateFlags) error {
keyPtr, err := marshalPtr(key, int(m.abi.KeySize))
if err != nil {
- return xerrors.Errorf("can't marshal key: %w", err)
+ return fmt.Errorf("can't marshal key: %w", err)
}
var valuePtr internal.Pointer
@@ -404,11 +403,11 @@ func (m *Map) Update(key, value interface{}, flags MapUpdateFlags) error {
valuePtr, err = marshalPtr(value, int(m.abi.ValueSize))
}
if err != nil {
- return xerrors.Errorf("can't marshal value: %w", err)
+ return fmt.Errorf("can't marshal value: %w", err)
}
if err = bpfMapUpdateElem(m.fd, keyPtr, valuePtr, uint64(flags)); err != nil {
- return xerrors.Errorf("update failed: %w", err)
+ return fmt.Errorf("update failed: %w", err)
}
return nil
@@ -420,11 +419,11 @@ func (m *Map) Update(key, value interface{}, flags MapUpdateFlags) error {
func (m *Map) Delete(key interface{}) error {
keyPtr, err := marshalPtr(key, int(m.abi.KeySize))
if err != nil {
- return xerrors.Errorf("can't marshal key: %w", err)
+ return fmt.Errorf("can't marshal key: %w", err)
}
if err = bpfMapDeleteElem(m.fd, keyPtr); err != nil {
- return xerrors.Errorf("delete failed: %w", err)
+ return fmt.Errorf("delete failed: %w", err)
}
return nil
}
@@ -446,7 +445,7 @@ func (m *Map) NextKey(key, nextKeyOut interface{}) error {
}
if err := unmarshalBytes(nextKeyOut, nextKeyBytes); err != nil {
- return xerrors.Errorf("can't unmarshal next key: %w", err)
+ return fmt.Errorf("can't unmarshal next key: %w", err)
}
return nil
}
@@ -463,7 +462,7 @@ func (m *Map) NextKeyBytes(key interface{}) ([]byte, error) {
nextKeyPtr := internal.NewSlicePointer(nextKey)
err := m.nextKey(key, nextKeyPtr)
- if xerrors.Is(err, ErrKeyNotExist) {
+ if errors.Is(err, ErrKeyNotExist) {
return nil, nil
}
@@ -479,12 +478,12 @@ func (m *Map) nextKey(key interface{}, nextKeyOut internal.Pointer) error {
if key != nil {
keyPtr, err = marshalPtr(key, int(m.abi.KeySize))
if err != nil {
- return xerrors.Errorf("can't marshal key: %w", err)
+ return fmt.Errorf("can't marshal key: %w", err)
}
}
if err = bpfMapGetNextKey(m.fd, keyPtr, nextKeyOut); err != nil {
- return xerrors.Errorf("next key failed: %w", err)
+ return fmt.Errorf("next key failed: %w", err)
}
return nil
}
@@ -537,7 +536,7 @@ func (m *Map) Clone() (*Map, error) {
dup, err := m.fd.Dup()
if err != nil {
- return nil, xerrors.Errorf("can't clone map: %w", err)
+ return nil, fmt.Errorf("can't clone map: %w", err)
}
return newMap(dup, m.name, &m.abi)
@@ -555,11 +554,11 @@ func (m *Map) Pin(fileName string) error {
// It makes no changes to kernel-side restrictions.
func (m *Map) Freeze() error {
if err := haveMapMutabilityModifiers(); err != nil {
- return xerrors.Errorf("can't freeze map: %w", err)
+ return fmt.Errorf("can't freeze map: %w", err)
}
if err := bpfMapFreeze(m.fd); err != nil {
- return xerrors.Errorf("can't freeze map: %w", err)
+ return fmt.Errorf("can't freeze map: %w", err)
}
return nil
}
@@ -567,7 +566,7 @@ func (m *Map) Freeze() error {
func (m *Map) populate(contents []MapKV) error {
for _, kv := range contents {
if err := m.Put(kv.Key, kv.Value); err != nil {
- return xerrors.Errorf("key %v: %w", kv.Key, err)
+ return fmt.Errorf("key %v: %w", kv.Key, err)
}
}
return nil
@@ -601,7 +600,7 @@ func LoadPinnedMapExplicit(fileName string, abi *MapABI) (*Map, error) {
func unmarshalMap(buf []byte) (*Map, error) {
if len(buf) != 4 {
- return nil, xerrors.New("map id requires 4 byte value")
+ return nil, errors.New("map id requires 4 byte value")
}
// Looking up an entry in a nested map or prog array returns an id,
@@ -626,12 +625,12 @@ func patchValue(value []byte, typ btf.Type, replacements map[string]interface{})
replaced := make(map[string]bool)
replace := func(name string, offset, size int, replacement interface{}) error {
if offset+size > len(value) {
- return xerrors.Errorf("%s: offset %d(+%d) is out of bounds", name, offset, size)
+ return fmt.Errorf("%s: offset %d(+%d) is out of bounds", name, offset, size)
}
buf, err := marshalBytes(replacement, size)
if err != nil {
- return xerrors.Errorf("marshal %s: %w", name, err)
+ return fmt.Errorf("marshal %s: %w", name, err)
}
copy(value[offset:offset+size], buf)
@@ -655,7 +654,7 @@ func patchValue(value []byte, typ btf.Type, replacements map[string]interface{})
}
default:
- return xerrors.Errorf("patching %T is not supported", typ)
+ return fmt.Errorf("patching %T is not supported", typ)
}
if len(replaced) == len(replacements) {
@@ -670,10 +669,10 @@ func patchValue(value []byte, typ btf.Type, replacements map[string]interface{})
}
if len(missing) == 1 {
- return xerrors.Errorf("unknown field: %s", missing[0])
+ return fmt.Errorf("unknown field: %s", missing[0])
}
- return xerrors.Errorf("unknown fields: %s", strings.Join(missing, ","))
+ return fmt.Errorf("unknown fields: %s", strings.Join(missing, ","))
}
// MapIterator iterates a Map.
@@ -731,7 +730,7 @@ func (mi *MapIterator) Next(keyOut, valueOut interface{}) bool {
mi.prevKey = mi.prevBytes
mi.err = mi.target.Lookup(nextBytes, valueOut)
- if xerrors.Is(mi.err, ErrKeyNotExist) {
+ if errors.Is(mi.err, ErrKeyNotExist) {
// Even though the key should be valid, we couldn't look up
// its value. If we're iterating a hash map this is probably
// because a concurrent delete removed the value before we
@@ -750,7 +749,7 @@ func (mi *MapIterator) Next(keyOut, valueOut interface{}) bool {
return mi.err == nil
}
- mi.err = xerrors.Errorf("%w", ErrIterationAborted)
+ mi.err = fmt.Errorf("%w", ErrIterationAborted)
return false
}
diff --git a/vendor/github.com/cilium/ebpf/marshalers.go b/vendor/github.com/cilium/ebpf/marshalers.go
index 89fdc8602..c0db2f6b0 100644
--- a/vendor/github.com/cilium/ebpf/marshalers.go
+++ b/vendor/github.com/cilium/ebpf/marshalers.go
@@ -4,13 +4,13 @@ import (
"bytes"
"encoding"
"encoding/binary"
+ "errors"
+ "fmt"
"reflect"
"runtime"
"unsafe"
"github.com/cilium/ebpf/internal"
-
- "golang.org/x/xerrors"
)
func marshalPtr(data interface{}, length int) (internal.Pointer, error) {
@@ -18,7 +18,7 @@ func marshalPtr(data interface{}, length int) (internal.Pointer, error) {
if length == 0 {
return internal.NewPointer(nil), nil
}
- return internal.Pointer{}, xerrors.New("can't use nil as key of map")
+ return internal.Pointer{}, errors.New("can't use nil as key of map")
}
if ptr, ok := data.(unsafe.Pointer); ok {
@@ -42,12 +42,12 @@ func marshalBytes(data interface{}, length int) (buf []byte, err error) {
case []byte:
buf = value
case unsafe.Pointer:
- err = xerrors.New("can't marshal from unsafe.Pointer")
+ err = errors.New("can't marshal from unsafe.Pointer")
default:
var wr bytes.Buffer
err = binary.Write(&wr, internal.NativeEndian, value)
if err != nil {
- err = xerrors.Errorf("encoding %T: %v", value, err)
+ err = fmt.Errorf("encoding %T: %v", value, err)
}
buf = wr.Bytes()
}
@@ -56,7 +56,7 @@ func marshalBytes(data interface{}, length int) (buf []byte, err error) {
}
if len(buf) != length {
- return nil, xerrors.Errorf("%T doesn't marshal to %d bytes", data, length)
+ return nil, fmt.Errorf("%T doesn't marshal to %d bytes", data, length)
}
return buf, nil
}
@@ -92,13 +92,13 @@ func unmarshalBytes(data interface{}, buf []byte) error {
*value = buf
return nil
case string:
- return xerrors.New("require pointer to string")
+ return errors.New("require pointer to string")
case []byte:
- return xerrors.New("require pointer to []byte")
+ return errors.New("require pointer to []byte")
default:
rd := bytes.NewReader(buf)
if err := binary.Read(rd, internal.NativeEndian, value); err != nil {
- return xerrors.Errorf("decoding %T: %v", value, err)
+ return fmt.Errorf("decoding %T: %v", value, err)
}
return nil
}
@@ -113,7 +113,7 @@ func unmarshalBytes(data interface{}, buf []byte) error {
func marshalPerCPUValue(slice interface{}, elemLength int) (internal.Pointer, error) {
sliceType := reflect.TypeOf(slice)
if sliceType.Kind() != reflect.Slice {
- return internal.Pointer{}, xerrors.New("per-CPU value requires slice")
+ return internal.Pointer{}, errors.New("per-CPU value requires slice")
}
possibleCPUs, err := internal.PossibleCPUs()
@@ -124,7 +124,7 @@ func marshalPerCPUValue(slice interface{}, elemLength int) (internal.Pointer, er
sliceValue := reflect.ValueOf(slice)
sliceLen := sliceValue.Len()
if sliceLen > possibleCPUs {
- return internal.Pointer{}, xerrors.Errorf("per-CPU value exceeds number of CPUs")
+ return internal.Pointer{}, fmt.Errorf("per-CPU value exceeds number of CPUs")
}
alignedElemLength := align(elemLength, 8)
@@ -151,7 +151,7 @@ func marshalPerCPUValue(slice interface{}, elemLength int) (internal.Pointer, er
func unmarshalPerCPUValue(slicePtr interface{}, elemLength int, buf []byte) error {
slicePtrType := reflect.TypeOf(slicePtr)
if slicePtrType.Kind() != reflect.Ptr || slicePtrType.Elem().Kind() != reflect.Slice {
- return xerrors.Errorf("per-cpu value requires pointer to slice")
+ return fmt.Errorf("per-cpu value requires pointer to slice")
}
possibleCPUs, err := internal.PossibleCPUs()
@@ -170,7 +170,7 @@ func unmarshalPerCPUValue(slicePtr interface{}, elemLength int, buf []byte) erro
step := len(buf) / possibleCPUs
if step < elemLength {
- return xerrors.Errorf("per-cpu element length is larger than available data")
+ return fmt.Errorf("per-cpu element length is larger than available data")
}
for i := 0; i < possibleCPUs; i++ {
var elem interface{}
@@ -188,7 +188,7 @@ func unmarshalPerCPUValue(slicePtr interface{}, elemLength int, buf []byte) erro
err := unmarshalBytes(elem, elemBytes)
if err != nil {
- return xerrors.Errorf("cpu %d: %w", i, err)
+ return fmt.Errorf("cpu %d: %w", i, err)
}
buf = buf[step:]
diff --git a/vendor/github.com/cilium/ebpf/prog.go b/vendor/github.com/cilium/ebpf/prog.go
index fd4430b62..429203f07 100644
--- a/vendor/github.com/cilium/ebpf/prog.go
+++ b/vendor/github.com/cilium/ebpf/prog.go
@@ -3,6 +3,7 @@ package ebpf
import (
"bytes"
"encoding/binary"
+ "errors"
"fmt"
"math"
"strings"
@@ -12,8 +13,6 @@ import (
"github.com/cilium/ebpf/internal"
"github.com/cilium/ebpf/internal/btf"
"github.com/cilium/ebpf/internal/unix"
-
- "golang.org/x/xerrors"
)
// ErrNotSupported is returned whenever the kernel doesn't support a feature.
@@ -120,8 +119,8 @@ func NewProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er
}
handle, err := btf.NewHandle(btf.ProgramSpec(spec.BTF))
- if err != nil && !xerrors.Is(err, btf.ErrNotSupported) {
- return nil, xerrors.Errorf("can't load BTF: %w", err)
+ if err != nil && !errors.Is(err, btf.ErrNotSupported) {
+ return nil, fmt.Errorf("can't load BTF: %w", err)
}
return newProgramWithBTF(spec, handle, opts)
@@ -165,7 +164,7 @@ func newProgramWithBTF(spec *ProgramSpec, btf *btf.Handle, opts ProgramOptions)
}
err = internal.ErrorWithLog(err, logBuf, logErr)
- return nil, xerrors.Errorf("can't load program: %w", err)
+ return nil, fmt.Errorf("can't load program: %w", err)
}
// NewProgramFromFD creates a program from a raw fd.
@@ -175,7 +174,7 @@ func newProgramWithBTF(spec *ProgramSpec, btf *btf.Handle, opts ProgramOptions)
// Requires at least Linux 4.11.
func NewProgramFromFD(fd int) (*Program, error) {
if fd < 0 {
- return nil, xerrors.New("invalid fd")
+ return nil, errors.New("invalid fd")
}
bpfFd := internal.NewFD(uint32(fd))
@@ -198,15 +197,15 @@ func newProgram(fd *internal.FD, name string, abi *ProgramABI) *Program {
func convertProgramSpec(spec *ProgramSpec, handle *btf.Handle) (*bpfProgLoadAttr, error) {
if len(spec.Instructions) == 0 {
- return nil, xerrors.New("Instructions cannot be empty")
+ return nil, errors.New("Instructions cannot be empty")
}
if len(spec.License) == 0 {
- return nil, xerrors.New("License cannot be empty")
+ return nil, errors.New("License cannot be empty")
}
if spec.ByteOrder != nil && spec.ByteOrder != internal.NativeEndian {
- return nil, xerrors.Errorf("can't load %s program on %s", spec.ByteOrder, internal.NativeEndian)
+ return nil, fmt.Errorf("can't load %s program on %s", spec.ByteOrder, internal.NativeEndian)
}
buf := bytes.NewBuffer(make([]byte, 0, len(spec.Instructions)*asm.InstructionSize))
@@ -235,7 +234,7 @@ func convertProgramSpec(spec *ProgramSpec, handle *btf.Handle) (*bpfProgLoadAttr
recSize, bytes, err := btf.ProgramLineInfos(spec.BTF)
if err != nil {
- return nil, xerrors.Errorf("can't get BTF line infos: %w", err)
+ return nil, fmt.Errorf("can't get BTF line infos: %w", err)
}
attr.lineInfoRecSize = recSize
attr.lineInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize))
@@ -243,7 +242,7 @@ func convertProgramSpec(spec *ProgramSpec, handle *btf.Handle) (*bpfProgLoadAttr
recSize, bytes, err = btf.ProgramFuncInfos(spec.BTF)
if err != nil {
- return nil, xerrors.Errorf("can't get BTF function infos: %w", err)
+ return nil, fmt.Errorf("can't get BTF function infos: %w", err)
}
attr.funcInfoRecSize = recSize
attr.funcInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize))
@@ -301,7 +300,7 @@ func (p *Program) Clone() (*Program, error) {
dup, err := p.fd.Dup()
if err != nil {
- return nil, xerrors.Errorf("can't clone program: %w", err)
+ return nil, fmt.Errorf("can't clone program: %w", err)
}
return newProgram(dup, p.name, &p.abi), nil
@@ -312,7 +311,7 @@ func (p *Program) Clone() (*Program, error) {
// This requires bpffs to be mounted above fileName. See http://cilium.readthedocs.io/en/doc-1.0/kubernetes/install/#mounting-the-bpf-fs-optional
func (p *Program) Pin(fileName string) error {
if err := internal.BPFObjPin(fileName, p.fd); err != nil {
- return xerrors.Errorf("can't pin program: %w", err)
+ return fmt.Errorf("can't pin program: %w", err)
}
return nil
}
@@ -336,7 +335,7 @@ func (p *Program) Close() error {
func (p *Program) Test(in []byte) (uint32, []byte, error) {
ret, out, _, err := p.testRun(in, 1, nil)
if err != nil {
- return ret, nil, xerrors.Errorf("can't test program: %w", err)
+ return ret, nil, fmt.Errorf("can't test program: %w", err)
}
return ret, out, nil
}
@@ -355,7 +354,7 @@ func (p *Program) Test(in []byte) (uint32, []byte, error) {
func (p *Program) Benchmark(in []byte, repeat int, reset func()) (uint32, time.Duration, error) {
ret, _, total, err := p.testRun(in, repeat, reset)
if err != nil {
- return ret, total, xerrors.Errorf("can't benchmark program: %w", err)
+ return ret, total, fmt.Errorf("can't benchmark program: %w", err)
}
return ret, total, nil
}
@@ -387,7 +386,7 @@ var haveProgTestRun = internal.FeatureTest("BPF_PROG_TEST_RUN", "4.12", func() (
// Check for EINVAL specifically, rather than err != nil since we
// otherwise misdetect due to insufficient permissions.
- return !xerrors.Is(err, unix.EINVAL), nil
+ return !errors.Is(err, unix.EINVAL), nil
})
func (p *Program) testRun(in []byte, repeat int, reset func()) (uint32, []byte, time.Duration, error) {
@@ -434,14 +433,14 @@ func (p *Program) testRun(in []byte, repeat int, reset func()) (uint32, []byte,
break
}
- if xerrors.Is(err, unix.EINTR) {
+ if errors.Is(err, unix.EINTR) {
if reset != nil {
reset()
}
continue
}
- return 0, nil, 0, xerrors.Errorf("can't run test: %w", err)
+ return 0, nil, 0, fmt.Errorf("can't run test: %w", err)
}
if int(attr.dataSizeOut) > cap(out) {
@@ -457,7 +456,7 @@ func (p *Program) testRun(in []byte, repeat int, reset func()) (uint32, []byte,
func unmarshalProgram(buf []byte) (*Program, error) {
if len(buf) != 4 {
- return nil, xerrors.New("program id requires 4 byte value")
+ return nil, errors.New("program id requires 4 byte value")
}
// Looking up an entry in a nested map or prog array returns an id,
@@ -483,7 +482,7 @@ func (p *Program) MarshalBinary() ([]byte, error) {
// Deprecated: use link.RawAttachProgram instead.
func (p *Program) Attach(fd int, typ AttachType, flags AttachFlags) error {
if fd < 0 {
- return xerrors.New("invalid fd")
+ return errors.New("invalid fd")
}
pfd, err := p.fd.Value()
@@ -506,11 +505,11 @@ func (p *Program) Attach(fd int, typ AttachType, flags AttachFlags) error {
// Deprecated: use link.RawDetachProgram instead.
func (p *Program) Detach(fd int, typ AttachType, flags AttachFlags) error {
if fd < 0 {
- return xerrors.New("invalid fd")
+ return errors.New("invalid fd")
}
if flags != 0 {
- return xerrors.New("flags must be zero")
+ return errors.New("flags must be zero")
}
pfd, err := p.fd.Value()
@@ -539,7 +538,7 @@ func LoadPinnedProgram(fileName string) (*Program, error) {
name, abi, err := newProgramABIFromFd(fd)
if err != nil {
_ = fd.Close()
- return nil, xerrors.Errorf("can't get ABI for %s: %w", fileName, err)
+ return nil, fmt.Errorf("can't get ABI for %s: %w", fileName, err)
}
return newProgram(fd, name, abi), nil
@@ -599,7 +598,7 @@ func (p *Program) ID() (ProgramID, error) {
func resolveBTFType(name string, progType ProgramType, attachType AttachType) (btf.Type, error) {
kernel, err := btf.LoadKernelSpec()
if err != nil {
- return nil, xerrors.Errorf("can't resolve BTF type %s: %w", name, err)
+ return nil, fmt.Errorf("can't resolve BTF type %s: %w", name, err)
}
type match struct {
@@ -612,7 +611,7 @@ func resolveBTFType(name string, progType ProgramType, attachType AttachType) (b
case match{Tracing, AttachTraceIter}:
var target btf.Func
if err := kernel.FindType("bpf_iter_"+name, &target); err != nil {
- return nil, xerrors.Errorf("can't resolve BTF for iterator %s: %w", name, err)
+ return nil, fmt.Errorf("can't resolve BTF for iterator %s: %w", name, err)
}
return &target, nil
diff --git a/vendor/github.com/cilium/ebpf/run-tests.sh b/vendor/github.com/cilium/ebpf/run-tests.sh
index e60c35e25..c43a90ddd 100644
--- a/vendor/github.com/cilium/ebpf/run-tests.sh
+++ b/vendor/github.com/cilium/ebpf/run-tests.sh
@@ -15,8 +15,13 @@ if [[ "${1:-}" = "--in-vm" ]]; then
export GOPROXY=file:///run/go-root/pkg/mod/cache/download
export GOCACHE=/run/go-cache
+ elfs=""
+ if [[ -d "/run/input/bpf" ]]; then
+ elfs="/run/input/bpf"
+ fi
+
echo Running tests...
- /usr/local/bin/go test -coverprofile="$1/coverage.txt" -covermode=atomic -v ./...
+ /usr/local/bin/go test -coverprofile="$1/coverage.txt" -covermode=atomic -v -elfs "$elfs" ./...
touch "$1/success"
exit 0
fi
@@ -39,20 +44,34 @@ if [[ -z "${kernel_version}" ]]; then
fi
readonly kernel="linux-${kernel_version}.bz"
+readonly selftests="linux-${kernel_version}-selftests-bpf.bz"
+readonly input="$(mktemp -d)"
readonly output="$(mktemp -d)"
-readonly tmp_dir="${TMPDIR:-$(mktemp -d)}"
+readonly tmp_dir="${TMPDIR:-/tmp}"
+readonly branch="${BRANCH:-master}"
-test -e "${tmp_dir}/${kernel}" || {
- echo Fetching "${kernel}"
- curl --fail -L "https://github.com/cilium/ci-kernels/blob/master/${kernel}?raw=true" -o "${tmp_dir}/${kernel}"
+fetch() {
+ echo Fetching "${1}"
+ wget -nv -N -P "${tmp_dir}" "https://github.com/cilium/ci-kernels/raw/${branch}/${1}"
}
+fetch "${kernel}"
+
+if fetch "${selftests}"; then
+ mkdir "${input}/bpf"
+ tar --strip-components=4 -xjf "${tmp_dir}/${selftests}" -C "${input}/bpf"
+else
+ echo "No selftests found, disabling"
+fi
+
echo Testing on "${kernel_version}"
$sudo virtme-run --kimg "${tmp_dir}/${kernel}" --memory 512M --pwd \
+ --rwdir=/run/input="${input}" \
--rwdir=/run/output="${output}" \
--rodir=/run/go-path="$(go env GOPATH)" \
--rwdir=/run/go-cache="$(go env GOCACHE)" \
- --script-sh "$(realpath "$0") --in-vm /run/output"
+ --script-sh "$(realpath "$0") --in-vm /run/output" \
+ --qemu-opts -smp 2 # need at least two CPUs for some tests
if [[ ! -e "${output}/success" ]]; then
echo "Test failed on ${kernel_version}"
@@ -66,4 +85,5 @@ else
fi
fi
+$sudo rm -r "${input}"
$sudo rm -r "${output}"
diff --git a/vendor/github.com/cilium/ebpf/syscalls.go b/vendor/github.com/cilium/ebpf/syscalls.go
index ff98cc403..2b713d06a 100644
--- a/vendor/github.com/cilium/ebpf/syscalls.go
+++ b/vendor/github.com/cilium/ebpf/syscalls.go
@@ -1,19 +1,19 @@
package ebpf
import (
+ "errors"
+ "fmt"
"os"
"unsafe"
"github.com/cilium/ebpf/internal"
"github.com/cilium/ebpf/internal/btf"
"github.com/cilium/ebpf/internal/unix"
-
- "golang.org/x/xerrors"
)
// Generic errors returned by BPF syscalls.
var (
- ErrNotExist = xerrors.New("requested object does not exist")
+ ErrNotExist = errors.New("requested object does not exist")
)
// bpfObjName is a null-terminated string made up of
@@ -174,8 +174,8 @@ func bpfProgTestRun(attr *bpfProgTestRunAttr) error {
func bpfMapCreate(attr *bpfMapCreateAttr) (*internal.FD, error) {
fd, err := internal.BPF(internal.BPF_MAP_CREATE, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
- if xerrors.Is(err, os.ErrPermission) {
- return nil, xerrors.New("permission denied or insufficient rlimit to lock memory for map")
+ if errors.Is(err, os.ErrPermission) {
+ return nil, errors.New("permission denied or insufficient rlimit to lock memory for map")
}
if err != nil {
@@ -317,11 +317,11 @@ func wrapObjError(err error) error {
if err == nil {
return nil
}
- if xerrors.Is(err, unix.ENOENT) {
- return xerrors.Errorf("%w", ErrNotExist)
+ if errors.Is(err, unix.ENOENT) {
+ return fmt.Errorf("%w", ErrNotExist)
}
- return xerrors.New(err.Error())
+ return errors.New(err.Error())
}
func wrapMapError(err error) error {
@@ -329,15 +329,15 @@ func wrapMapError(err error) error {
return nil
}
- if xerrors.Is(err, unix.ENOENT) {
+ if errors.Is(err, unix.ENOENT) {
return ErrKeyNotExist
}
- if xerrors.Is(err, unix.EEXIST) {
+ if errors.Is(err, unix.EEXIST) {
return ErrKeyExist
}
- return xerrors.New(err.Error())
+ return errors.New(err.Error())
}
func bpfMapFreeze(m *internal.FD) error {
@@ -367,7 +367,7 @@ func bpfGetObjectInfoByFD(fd *internal.FD, info unsafe.Pointer, size uintptr) er
}
_, err = internal.BPF(internal.BPF_OBJ_GET_INFO_BY_FD, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
if err != nil {
- return xerrors.Errorf("fd %d: %w", fd, err)
+ return fmt.Errorf("fd %d: %w", fd, err)
}
return nil
}
@@ -375,7 +375,7 @@ func bpfGetObjectInfoByFD(fd *internal.FD, info unsafe.Pointer, size uintptr) er
func bpfGetProgInfoByFD(fd *internal.FD) (*bpfProgInfo, error) {
var info bpfProgInfo
if err := bpfGetObjectInfoByFD(fd, unsafe.Pointer(&info), unsafe.Sizeof(info)); err != nil {
- return nil, xerrors.Errorf("can't get program info: %w", err)
+ return nil, fmt.Errorf("can't get program info: %w", err)
}
return &info, nil
}
@@ -384,7 +384,7 @@ func bpfGetMapInfoByFD(fd *internal.FD) (*bpfMapInfo, error) {
var info bpfMapInfo
err := bpfGetObjectInfoByFD(fd, unsafe.Pointer(&info), unsafe.Sizeof(info))
if err != nil {
- return nil, xerrors.Errorf("can't get map info: %w", err)
+ return nil, fmt.Errorf("can't get map info: %w", err)
}
return &info, nil
}
diff --git a/vendor/github.com/coreos/go-systemd/LICENSE b/vendor/github.com/coreos/go-systemd/v22/LICENSE
similarity index 100%
rename from vendor/github.com/coreos/go-systemd/LICENSE
rename to vendor/github.com/coreos/go-systemd/v22/LICENSE
diff --git a/vendor/github.com/coreos/go-systemd/NOTICE b/vendor/github.com/coreos/go-systemd/v22/NOTICE
similarity index 100%
rename from vendor/github.com/coreos/go-systemd/NOTICE
rename to vendor/github.com/coreos/go-systemd/v22/NOTICE
diff --git a/vendor/github.com/coreos/go-systemd/dbus/dbus.go b/vendor/github.com/coreos/go-systemd/v22/dbus/dbus.go
similarity index 99%
rename from vendor/github.com/coreos/go-systemd/dbus/dbus.go
rename to vendor/github.com/coreos/go-systemd/v22/dbus/dbus.go
index f652582e6..91584a166 100644
--- a/vendor/github.com/coreos/go-systemd/dbus/dbus.go
+++ b/vendor/github.com/coreos/go-systemd/v22/dbus/dbus.go
@@ -23,7 +23,7 @@ import (
"strings"
"sync"
- "github.com/godbus/dbus"
+ "github.com/godbus/dbus/v5"
)
const (
diff --git a/vendor/github.com/coreos/go-systemd/dbus/methods.go b/vendor/github.com/coreos/go-systemd/v22/dbus/methods.go
similarity index 99%
rename from vendor/github.com/coreos/go-systemd/dbus/methods.go
rename to vendor/github.com/coreos/go-systemd/v22/dbus/methods.go
index 5859583eb..e38659d7b 100644
--- a/vendor/github.com/coreos/go-systemd/dbus/methods.go
+++ b/vendor/github.com/coreos/go-systemd/v22/dbus/methods.go
@@ -20,7 +20,7 @@ import (
"path"
"strconv"
- "github.com/godbus/dbus"
+ "github.com/godbus/dbus/v5"
)
func (c *Conn) jobComplete(signal *dbus.Signal) {
diff --git a/vendor/github.com/coreos/go-systemd/dbus/properties.go b/vendor/github.com/coreos/go-systemd/v22/dbus/properties.go
similarity index 99%
rename from vendor/github.com/coreos/go-systemd/dbus/properties.go
rename to vendor/github.com/coreos/go-systemd/v22/dbus/properties.go
index 6c8189587..fb42b6273 100644
--- a/vendor/github.com/coreos/go-systemd/dbus/properties.go
+++ b/vendor/github.com/coreos/go-systemd/v22/dbus/properties.go
@@ -15,7 +15,7 @@
package dbus
import (
- "github.com/godbus/dbus"
+ "github.com/godbus/dbus/v5"
)
// From the systemd docs:
@@ -56,7 +56,7 @@ type execStart struct {
// http://www.freedesktop.org/software/systemd/man/systemd.service.html#ExecStart=
func PropExecStart(command []string, uncleanIsFailure bool) Property {
execStarts := []execStart{
- execStart{
+ {
Path: command[0],
Args: command,
UncleanIsFailure: uncleanIsFailure,
diff --git a/vendor/github.com/coreos/go-systemd/dbus/set.go b/vendor/github.com/coreos/go-systemd/v22/dbus/set.go
similarity index 100%
rename from vendor/github.com/coreos/go-systemd/dbus/set.go
rename to vendor/github.com/coreos/go-systemd/v22/dbus/set.go
diff --git a/vendor/github.com/coreos/go-systemd/dbus/subscription.go b/vendor/github.com/coreos/go-systemd/v22/dbus/subscription.go
similarity index 99%
rename from vendor/github.com/coreos/go-systemd/dbus/subscription.go
rename to vendor/github.com/coreos/go-systemd/v22/dbus/subscription.go
index f6d7a08a1..7e370fea2 100644
--- a/vendor/github.com/coreos/go-systemd/dbus/subscription.go
+++ b/vendor/github.com/coreos/go-systemd/v22/dbus/subscription.go
@@ -19,7 +19,7 @@ import (
"log"
"time"
- "github.com/godbus/dbus"
+ "github.com/godbus/dbus/v5"
)
const (
diff --git a/vendor/github.com/coreos/go-systemd/dbus/subscription_set.go b/vendor/github.com/coreos/go-systemd/v22/dbus/subscription_set.go
similarity index 100%
rename from vendor/github.com/coreos/go-systemd/dbus/subscription_set.go
rename to vendor/github.com/coreos/go-systemd/v22/dbus/subscription_set.go
diff --git a/vendor/github.com/godbus/dbus/.travis.yml b/vendor/github.com/godbus/dbus/.travis.yml
deleted file mode 100644
index 9cd57f432..000000000
--- a/vendor/github.com/godbus/dbus/.travis.yml
+++ /dev/null
@@ -1,46 +0,0 @@
-dist: precise
-language: go
-go_import_path: github.com/godbus/dbus
-sudo: true
-
-go:
- - 1.7.3
- - 1.8.7
- - 1.9.5
- - 1.10.1
- - tip
-
-env:
- global:
- matrix:
- - TARGET=amd64
- - TARGET=arm64
- - TARGET=arm
- - TARGET=386
- - TARGET=ppc64le
-
-matrix:
- fast_finish: true
- allow_failures:
- - go: tip
- exclude:
- - go: tip
- env: TARGET=arm
- - go: tip
- env: TARGET=arm64
- - go: tip
- env: TARGET=386
- - go: tip
- env: TARGET=ppc64le
-
-addons:
- apt:
- packages:
- - dbus
- - dbus-x11
-
-before_install:
-
-script:
- - go test -v -race ./... # Run all the tests with the race detector enabled
- - go vet ./... # go vet is the official Go static analyzer
diff --git a/vendor/github.com/godbus/dbus/go.mod b/vendor/github.com/godbus/dbus/go.mod
deleted file mode 100644
index bdcd12598..000000000
--- a/vendor/github.com/godbus/dbus/go.mod
+++ /dev/null
@@ -1 +0,0 @@
-module github.com/godbus/dbus
diff --git a/vendor/github.com/godbus/dbus/v5/.travis.yml b/vendor/github.com/godbus/dbus/v5/.travis.yml
new file mode 100644
index 000000000..dd6767204
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/v5/.travis.yml
@@ -0,0 +1,50 @@
+dist: bionic
+language: go
+go_import_path: github.com/godbus/dbus
+
+go:
+ - 1.11.x
+ - 1.12.x
+ - 1.13.x
+ - tip
+
+matrix:
+ fast_finish: true
+ allow_failures:
+ - go: tip
+
+addons:
+ apt:
+ packages:
+ - dbus
+ - dbus-x11
+
+before_install:
+ - export GO111MODULE=on
+
+script:
+ - go test -v -race -mod=readonly ./... # Run all the tests with the race detector enabled
+ - go vet ./... # go vet is the official Go static analyzer
+
+jobs:
+ include:
+ # The build matrix doesn't cover build stages, so manually expand
+ # the jobs with anchors
+ - &multiarch
+ stage: "Multiarch Test"
+ go: 1.11.x
+ env: TARGETS="386 arm arm64 ppc64le"
+ before_install:
+ - docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
+ script:
+ - |
+ set -e
+ for target in $TARGETS; do
+ printf "\e[1mRunning test suite under ${target}.\e[0m\n"
+ GOARCH="$target" go test -v ./...
+ printf "\n\n"
+ done
+ - <<: *multiarch
+ go: 1.12.x
+ - <<: *multiarch
+ go: 1.13.x
diff --git a/vendor/github.com/godbus/dbus/CONTRIBUTING.md b/vendor/github.com/godbus/dbus/v5/CONTRIBUTING.md
similarity index 100%
rename from vendor/github.com/godbus/dbus/CONTRIBUTING.md
rename to vendor/github.com/godbus/dbus/v5/CONTRIBUTING.md
diff --git a/vendor/github.com/godbus/dbus/LICENSE b/vendor/github.com/godbus/dbus/v5/LICENSE
similarity index 100%
rename from vendor/github.com/godbus/dbus/LICENSE
rename to vendor/github.com/godbus/dbus/v5/LICENSE
diff --git a/vendor/github.com/godbus/dbus/MAINTAINERS b/vendor/github.com/godbus/dbus/v5/MAINTAINERS
similarity index 100%
rename from vendor/github.com/godbus/dbus/MAINTAINERS
rename to vendor/github.com/godbus/dbus/v5/MAINTAINERS
diff --git a/vendor/github.com/godbus/dbus/README.markdown b/vendor/github.com/godbus/dbus/v5/README.markdown
similarity index 100%
rename from vendor/github.com/godbus/dbus/README.markdown
rename to vendor/github.com/godbus/dbus/v5/README.markdown
diff --git a/vendor/github.com/godbus/dbus/auth.go b/vendor/github.com/godbus/dbus/v5/auth.go
similarity index 98%
rename from vendor/github.com/godbus/dbus/auth.go
rename to vendor/github.com/godbus/dbus/v5/auth.go
index b0dcb54e6..31abac629 100644
--- a/vendor/github.com/godbus/dbus/auth.go
+++ b/vendor/github.com/godbus/dbus/v5/auth.go
@@ -77,7 +77,7 @@ func (conn *Conn) Auth(methods []Auth) error {
for _, m := range methods {
if name, data, status := m.FirstData(); bytes.Equal(v, name) {
var ok bool
- err = authWriteLine(conn.transport, []byte("AUTH"), []byte(v), data)
+ err = authWriteLine(conn.transport, []byte("AUTH"), v, data)
if err != nil {
return err
}
@@ -127,7 +127,7 @@ func (conn *Conn) Auth(methods []Auth) error {
// tryAuth tries to authenticate with m as the mechanism, using state as the
// initial authState and in for reading input. It returns (nil, true) on
// success, (nil, false) on a REJECTED and (someErr, false) if some other
-// error occured.
+// error occurred.
func (conn *Conn) tryAuth(m Auth, state authState, in *bufio.Reader) (error, bool) {
for {
s, err := authReadLine(in)
diff --git a/vendor/github.com/godbus/dbus/auth_anonymous.go b/vendor/github.com/godbus/dbus/v5/auth_anonymous.go
similarity index 100%
rename from vendor/github.com/godbus/dbus/auth_anonymous.go
rename to vendor/github.com/godbus/dbus/v5/auth_anonymous.go
diff --git a/vendor/github.com/godbus/dbus/auth_external.go b/vendor/github.com/godbus/dbus/v5/auth_external.go
similarity index 100%
rename from vendor/github.com/godbus/dbus/auth_external.go
rename to vendor/github.com/godbus/dbus/v5/auth_external.go
diff --git a/vendor/github.com/godbus/dbus/auth_sha1.go b/vendor/github.com/godbus/dbus/v5/auth_sha1.go
similarity index 96%
rename from vendor/github.com/godbus/dbus/auth_sha1.go
rename to vendor/github.com/godbus/dbus/v5/auth_sha1.go
index df15b4611..80286700b 100644
--- a/vendor/github.com/godbus/dbus/auth_sha1.go
+++ b/vendor/github.com/godbus/dbus/v5/auth_sha1.go
@@ -60,7 +60,7 @@ func (a authCookieSha1) HandleData(data []byte) ([]byte, AuthStatus) {
// getCookie searches for the cookie identified by id in context and returns
// the cookie content or nil. (Since HandleData can't return a specific error,
-// but only whether an error occured, this function also doesn't bother to
+// but only whether an error occurred, this function also doesn't bother to
// return an error.)
func (a authCookieSha1) getCookie(context, id []byte) []byte {
file, err := os.Open(a.home + "/.dbus-keyrings/" + string(context))
diff --git a/vendor/github.com/godbus/dbus/call.go b/vendor/github.com/godbus/dbus/v5/call.go
similarity index 100%
rename from vendor/github.com/godbus/dbus/call.go
rename to vendor/github.com/godbus/dbus/v5/call.go
diff --git a/vendor/github.com/godbus/dbus/conn.go b/vendor/github.com/godbus/dbus/v5/conn.go
similarity index 86%
rename from vendor/github.com/godbus/dbus/conn.go
rename to vendor/github.com/godbus/dbus/v5/conn.go
index b38920baf..b55bc99c8 100644
--- a/vendor/github.com/godbus/dbus/conn.go
+++ b/vendor/github.com/godbus/dbus/v5/conn.go
@@ -5,7 +5,6 @@ import (
"errors"
"io"
"os"
- "reflect"
"strings"
"sync"
)
@@ -31,6 +30,12 @@ var ErrClosed = errors.New("dbus: connection closed by user")
type Conn struct {
transport
+ ctx context.Context
+ cancelCtx context.CancelFunc
+
+ closeOnce sync.Once
+ closeErr error
+
busObj BusObject
unixFD bool
uuid string
@@ -38,6 +43,8 @@ type Conn struct {
handler Handler
signalHandler SignalHandler
serialGen SerialGenerator
+ inInt Interceptor
+ outInt Interceptor
names *nameTracker
calls *callTracker
@@ -134,6 +141,8 @@ func SystemBus() (conn *Conn, err error) {
}
// SystemBusPrivate returns a new private connection to the system bus.
+// Note: this connection is not ready to use. One must perform Auth and Hello
+// on the connection before it is useable.
func SystemBusPrivate(opts ...ConnOption) (*Conn, error) {
return Dial(getSystemBusPlatformAddress(), opts...)
}
@@ -188,6 +197,33 @@ func WithSerialGenerator(gen SerialGenerator) ConnOption {
}
}
+// Interceptor intercepts incoming and outgoing messages.
+type Interceptor func(msg *Message)
+
+// WithIncomingInterceptor sets the given interceptor for incoming messages.
+func WithIncomingInterceptor(interceptor Interceptor) ConnOption {
+ return func(conn *Conn) error {
+ conn.inInt = interceptor
+ return nil
+ }
+}
+
+// WithOutgoingInterceptor sets the given interceptor for outgoing messages.
+func WithOutgoingInterceptor(interceptor Interceptor) ConnOption {
+ return func(conn *Conn) error {
+ conn.outInt = interceptor
+ return nil
+ }
+}
+
+// WithContext overrides the default context for the connection.
+func WithContext(ctx context.Context) ConnOption {
+ return func(conn *Conn) error {
+ conn.ctx = ctx
+ return nil
+ }
+}
+
// NewConn creates a new private *Conn from an already established connection.
func NewConn(conn io.ReadWriteCloser, opts ...ConnOption) (*Conn, error) {
return newConn(genericTransport{conn}, opts...)
@@ -209,6 +245,15 @@ func newConn(tr transport, opts ...ConnOption) (*Conn, error) {
return nil, err
}
}
+ if conn.ctx == nil {
+ conn.ctx = context.Background()
+ }
+ conn.ctx, conn.cancelCtx = context.WithCancel(conn.ctx)
+ go func() {
+ <-conn.ctx.Done()
+ conn.Close()
+ }()
+
conn.calls = newCallTracker()
if conn.handler == nil {
conn.handler = NewDefaultHandler()
@@ -235,27 +280,38 @@ func (conn *Conn) BusObject() BusObject {
// and the channels passed to Eavesdrop and Signal are closed. This method must
// not be called on shared connections.
func (conn *Conn) Close() error {
- conn.outHandler.close()
- if term, ok := conn.signalHandler.(Terminator); ok {
- term.Terminate()
- }
+ conn.closeOnce.Do(func() {
+ conn.outHandler.close()
+ if term, ok := conn.signalHandler.(Terminator); ok {
+ term.Terminate()
+ }
- if term, ok := conn.handler.(Terminator); ok {
- term.Terminate()
- }
+ if term, ok := conn.handler.(Terminator); ok {
+ term.Terminate()
+ }
- conn.eavesdroppedLck.Lock()
- if conn.eavesdropped != nil {
- close(conn.eavesdropped)
- }
- conn.eavesdroppedLck.Unlock()
+ conn.eavesdroppedLck.Lock()
+ if conn.eavesdropped != nil {
+ close(conn.eavesdropped)
+ }
+ conn.eavesdroppedLck.Unlock()
- return conn.transport.Close()
+ conn.cancelCtx()
+
+ conn.closeErr = conn.transport.Close()
+ })
+ return conn.closeErr
+}
+
+// Context returns the context associated with the connection. The
+// context will be cancelled when the connection is closed.
+func (conn *Conn) Context() context.Context {
+ return conn.ctx
}
// Eavesdrop causes conn to send all incoming messages to the given channel
// without further processing. Method replies, errors and signals will not be
-// sent to the appropiate channels and method calls will not be handled. If nil
+// sent to the appropriate channels and method calls will not be handled. If nil
// is passed, the normal behaviour is restored.
//
// The caller has to make sure that ch is sufficiently buffered;
@@ -267,7 +323,7 @@ func (conn *Conn) Eavesdrop(ch chan<- *Message) {
conn.eavesdroppedLck.Unlock()
}
-// GetSerial returns an unused serial.
+// getSerial returns an unused serial.
func (conn *Conn) getSerial() uint32 {
return conn.serialGen.GetSerial()
}
@@ -292,7 +348,7 @@ func (conn *Conn) inWorker() {
msg, err := conn.ReadMessage()
if err != nil {
if _, ok := err.(InvalidMessageError); !ok {
- // Some read error occured (usually EOF); we can't really do
+ // Some read error occurred (usually EOF); we can't really do
// anything but to shut down all stuff and returns errors to all
// pending replies.
conn.Close()
@@ -321,6 +377,10 @@ func (conn *Conn) inWorker() {
// Ignore it.
continue
}
+
+ if conn.inInt != nil {
+ conn.inInt(msg)
+ }
switch msg.Type {
case TypeError:
conn.serialGen.RetireSerial(conn.calls.handleDBusError(msg))
@@ -381,13 +441,10 @@ func (conn *Conn) Object(dest string, path ObjectPath) BusObject {
return &Object{conn, dest, path}
}
-// outWorker runs in an own goroutine, encoding and sending messages that are
-// sent to conn.out.
-func (conn *Conn) sendMessage(msg *Message) {
- conn.sendMessageAndIfClosed(msg, func() {})
-}
-
func (conn *Conn) sendMessageAndIfClosed(msg *Message, ifClosed func()) {
+ if conn.outInt != nil {
+ conn.outInt(msg)
+ }
err := conn.outHandler.sendAndIfClosed(msg, ifClosed)
conn.calls.handleSendError(msg, err)
if err != nil {
@@ -483,7 +540,7 @@ func (conn *Conn) sendError(err error, dest string, serial uint32) {
if len(e.Body) > 0 {
msg.Headers[FieldSignature] = MakeVariant(SignatureOf(e.Body...))
}
- conn.sendMessage(msg)
+ conn.sendMessageAndIfClosed(msg, nil)
}
// sendReply creates a method reply message corresponding to the parameters and
@@ -501,33 +558,54 @@ func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) {
if len(values) > 0 {
msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...))
}
- conn.sendMessage(msg)
+ conn.sendMessageAndIfClosed(msg, nil)
}
-func (conn *Conn) defaultSignalAction(fn func(h *defaultSignalHandler, ch chan<- *Signal), ch chan<- *Signal) {
- if !isDefaultSignalHandler(conn.signalHandler) {
- return
- }
- handler := conn.signalHandler.(*defaultSignalHandler)
- fn(handler, ch)
+// AddMatchSignal registers the given match rule to receive broadcast
+// signals based on their contents.
+func (conn *Conn) AddMatchSignal(options ...MatchOption) error {
+ options = append([]MatchOption{withMatchType("signal")}, options...)
+ return conn.busObj.Call(
+ "org.freedesktop.DBus.AddMatch", 0,
+ formatMatchOptions(options),
+ ).Store()
+}
+
+// RemoveMatchSignal removes the first rule that matches previously registered with AddMatchSignal.
+func (conn *Conn) RemoveMatchSignal(options ...MatchOption) error {
+ options = append([]MatchOption{withMatchType("signal")}, options...)
+ return conn.busObj.Call(
+ "org.freedesktop.DBus.RemoveMatch", 0,
+ formatMatchOptions(options),
+ ).Store()
}
// Signal registers the given channel to be passed all received signal messages.
-// The caller has to make sure that ch is sufficiently buffered; if a message
-// arrives when a write to c is not possible, it is discarded.
//
// Multiple of these channels can be registered at the same time.
//
// These channels are "overwritten" by Eavesdrop; i.e., if there currently is a
// channel for eavesdropped messages, this channel receives all signals, and
// none of the channels passed to Signal will receive any signals.
+//
+// Panics if the signal handler is not a `SignalRegistrar`.
func (conn *Conn) Signal(ch chan<- *Signal) {
- conn.defaultSignalAction((*defaultSignalHandler).addSignal, ch)
+ handler, ok := conn.signalHandler.(SignalRegistrar)
+ if !ok {
+ panic("cannot use this method with a non SignalRegistrar handler")
+ }
+ handler.AddSignal(ch)
}
// RemoveSignal removes the given channel from the list of the registered channels.
+//
+// Panics if the signal handler is not a `SignalRegistrar`.
func (conn *Conn) RemoveSignal(ch chan<- *Signal) {
- conn.defaultSignalAction((*defaultSignalHandler).removeSignal, ch)
+ handler, ok := conn.signalHandler.(SignalRegistrar)
+ if !ok {
+ panic("cannot use this method with a non SignalRegistrar handler")
+ }
+ handler.RemoveSignal(ch)
}
// SupportsUnixFDs returns whether the underlying transport supports passing of
@@ -614,18 +692,6 @@ func getTransport(address string) (transport, error) {
return nil, err
}
-// dereferenceAll returns a slice that, assuming that vs is a slice of pointers
-// of arbitrary types, containes the values that are obtained from dereferencing
-// all elements in vs.
-func dereferenceAll(vs []interface{}) []interface{} {
- for i := range vs {
- v := reflect.ValueOf(vs[i])
- v = v.Elem()
- vs[i] = v.Interface()
- }
- return vs
-}
-
// getKey gets a key from a the list of keys. Returns "" on error / not found...
func getKey(s, key string) string {
for _, keyEqualsValue := range strings.Split(s, ",") {
@@ -650,7 +716,9 @@ func (h *outputHandler) sendAndIfClosed(msg *Message, ifClosed func()) error {
h.closed.lck.RLock()
defer h.closed.lck.RUnlock()
if h.closed.isClosed {
- ifClosed()
+ if ifClosed != nil {
+ ifClosed()
+ }
return nil
}
h.sendLck.Lock()
@@ -801,7 +869,6 @@ func (tracker *callTracker) finalize(sn uint32) {
delete(tracker.calls, sn)
c.ContextCancel()
}
- return
}
func (tracker *callTracker) finalizeWithBody(sn uint32, body []interface{}) {
@@ -815,7 +882,6 @@ func (tracker *callTracker) finalizeWithBody(sn uint32, body []interface{}) {
c.Body = body
c.done()
}
- return
}
func (tracker *callTracker) finalizeWithError(sn uint32, err error) {
@@ -829,7 +895,6 @@ func (tracker *callTracker) finalizeWithError(sn uint32, err error) {
c.Err = err
c.done()
}
- return
}
func (tracker *callTracker) finalizeAllWithError(err error) {
diff --git a/vendor/github.com/godbus/dbus/conn_darwin.go b/vendor/github.com/godbus/dbus/v5/conn_darwin.go
similarity index 100%
rename from vendor/github.com/godbus/dbus/conn_darwin.go
rename to vendor/github.com/godbus/dbus/v5/conn_darwin.go
diff --git a/vendor/github.com/godbus/dbus/conn_other.go b/vendor/github.com/godbus/dbus/v5/conn_other.go
similarity index 96%
rename from vendor/github.com/godbus/dbus/conn_other.go
rename to vendor/github.com/godbus/dbus/v5/conn_other.go
index 289044a44..616dcf664 100644
--- a/vendor/github.com/godbus/dbus/conn_other.go
+++ b/vendor/github.com/godbus/dbus/v5/conn_other.go
@@ -14,8 +14,10 @@ import (
"strings"
)
+var execCommand = exec.Command
+
func getSessionBusPlatformAddress() (string, error) {
- cmd := exec.Command("dbus-launch")
+ cmd := execCommand("dbus-launch")
b, err := cmd.CombinedOutput()
if err != nil {
@@ -25,7 +27,7 @@ func getSessionBusPlatformAddress() (string, error) {
i := bytes.IndexByte(b, '=')
j := bytes.IndexByte(b, '\n')
- if i == -1 || j == -1 {
+ if i == -1 || j == -1 || i > j {
return "", errors.New("dbus: couldn't determine address of session bus")
}
diff --git a/vendor/github.com/godbus/dbus/conn_unix.go b/vendor/github.com/godbus/dbus/v5/conn_unix.go
similarity index 84%
rename from vendor/github.com/godbus/dbus/conn_unix.go
rename to vendor/github.com/godbus/dbus/v5/conn_unix.go
index 4cba8ae8e..58aee7d2a 100644
--- a/vendor/github.com/godbus/dbus/conn_unix.go
+++ b/vendor/github.com/godbus/dbus/v5/conn_unix.go
@@ -4,7 +4,6 @@ package dbus
import (
"os"
- "fmt"
)
const defaultSystemBusAddress = "unix:path=/var/run/dbus/system_bus_socket"
@@ -12,7 +11,7 @@ const defaultSystemBusAddress = "unix:path=/var/run/dbus/system_bus_socket"
func getSystemBusPlatformAddress() string {
address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS")
if address != "" {
- return fmt.Sprintf("unix:path=%s", address)
+ return address
}
return defaultSystemBusAddress
-}
\ No newline at end of file
+}
diff --git a/vendor/github.com/godbus/dbus/conn_windows.go b/vendor/github.com/godbus/dbus/v5/conn_windows.go
similarity index 100%
rename from vendor/github.com/godbus/dbus/conn_windows.go
rename to vendor/github.com/godbus/dbus/v5/conn_windows.go
diff --git a/vendor/github.com/godbus/dbus/dbus.go b/vendor/github.com/godbus/dbus/v5/dbus.go
similarity index 99%
rename from vendor/github.com/godbus/dbus/dbus.go
rename to vendor/github.com/godbus/dbus/v5/dbus.go
index c6d0d3ce0..428923d26 100644
--- a/vendor/github.com/godbus/dbus/dbus.go
+++ b/vendor/github.com/godbus/dbus/v5/dbus.go
@@ -87,6 +87,7 @@ func setDest(dest, src reflect.Value) error {
}
if isVariant(src.Type()) && !isVariant(dest.Type()) {
src = getVariantValue(src)
+ return store(dest, src)
}
if !src.Type().ConvertibleTo(dest.Type()) {
return fmt.Errorf(
diff --git a/vendor/github.com/godbus/dbus/decoder.go b/vendor/github.com/godbus/dbus/v5/decoder.go
similarity index 81%
rename from vendor/github.com/godbus/dbus/decoder.go
rename to vendor/github.com/godbus/dbus/v5/decoder.go
index 5c27d3b51..ede91575b 100644
--- a/vendor/github.com/godbus/dbus/decoder.go
+++ b/vendor/github.com/godbus/dbus/v5/decoder.go
@@ -188,8 +188,14 @@ func (dec *decoder) decode(s string, depth int) interface{} {
if depth >= 64 {
panic(FormatError("input exceeds container depth limit"))
}
+ sig := s[1:]
length := dec.decode("u", depth).(uint32)
- v := reflect.MakeSlice(reflect.SliceOf(typeFor(s[1:])), 0, int(length))
+ // capacity can be determined only for fixed-size element types
+ var capacity int
+ if s := sigByteSize(sig); s != 0 {
+ capacity = int(length) / s
+ }
+ v := reflect.MakeSlice(reflect.SliceOf(typeFor(sig)), 0, capacity)
// Even for empty arrays, the correct padding must be included
align := alignment(typeFor(s[1:]))
if len(s) > 1 && s[1] == '(' {
@@ -227,6 +233,51 @@ func (dec *decoder) decode(s string, depth int) interface{} {
}
}
+// sigByteSize tries to calculates size of the given signature in bytes.
+//
+// It returns zero when it can't, for example when it contains non-fixed size
+// types such as strings, maps and arrays that require reading of the transmitted
+// data, for that we would need to implement the unread method for Decoder first.
+func sigByteSize(sig string) int {
+ var total int
+ for offset := 0; offset < len(sig); {
+ switch sig[offset] {
+ case 'y':
+ total += 1
+ offset += 1
+ case 'n', 'q':
+ total += 2
+ offset += 1
+ case 'b', 'i', 'u', 'h':
+ total += 4
+ offset += 1
+ case 'x', 't', 'd':
+ total += 8
+ offset += 1
+ case '(':
+ i := 1
+ depth := 1
+ for i < len(sig[offset:]) && depth != 0 {
+ if sig[offset+i] == '(' {
+ depth++
+ } else if sig[offset+i] == ')' {
+ depth--
+ }
+ i++
+ }
+ s := sigByteSize(sig[offset+1 : offset+i-1])
+ if s == 0 {
+ return 0
+ }
+ total += s
+ offset += i
+ default:
+ return 0
+ }
+ }
+ return total
+}
+
// A FormatError is an error in the wire format.
type FormatError string
diff --git a/vendor/github.com/godbus/dbus/default_handler.go b/vendor/github.com/godbus/dbus/v5/default_handler.go
similarity index 82%
rename from vendor/github.com/godbus/dbus/default_handler.go
rename to vendor/github.com/godbus/dbus/v5/default_handler.go
index 81dbcc7e4..6d8bf32f9 100644
--- a/vendor/github.com/godbus/dbus/default_handler.go
+++ b/vendor/github.com/godbus/dbus/v5/default_handler.go
@@ -47,7 +47,7 @@ func (h *defaultHandler) introspectPath(path ObjectPath) string {
subpath := make(map[string]struct{})
var xml bytes.Buffer
xml.WriteString("")
- for obj, _ := range h.objects {
+ for obj := range h.objects {
p := string(path)
if p != "/" {
p += "/"
@@ -57,7 +57,7 @@ func (h *defaultHandler) introspectPath(path ObjectPath) string {
subpath[node_name] = struct{}{}
}
}
- for s, _ := range subpath {
+ for s := range subpath {
xml.WriteString("\n\t")
}
xml.WriteString("\n")
@@ -234,88 +234,95 @@ func (obj *exportedIntf) isFallbackInterface() bool {
//
// Deprecated: this is the default value, don't use it, it will be unexported.
func NewDefaultSignalHandler() *defaultSignalHandler {
- return &defaultSignalHandler{
- closeChan: make(chan struct{}),
- }
-}
-
-func isDefaultSignalHandler(handler SignalHandler) bool {
- _, ok := handler.(*defaultSignalHandler)
- return ok
+ return &defaultSignalHandler{}
}
type defaultSignalHandler struct {
- sync.RWMutex
- closed bool
- signals []chan<- *Signal
- closeChan chan struct{}
+ mu sync.RWMutex
+ closed bool
+ signals []*signalChannelData
}
func (sh *defaultSignalHandler) DeliverSignal(intf, name string, signal *Signal) {
- sh.RLock()
- defer sh.RUnlock()
+ sh.mu.RLock()
+ defer sh.mu.RUnlock()
if sh.closed {
return
}
- for _, ch := range sh.signals {
- select {
- case ch <- signal:
- case <-sh.closeChan:
- return
- default:
- go func() {
- select {
- case ch <- signal:
- case <-sh.closeChan:
- return
- }
- }()
- }
+ for _, scd := range sh.signals {
+ scd.deliver(signal)
}
}
-func (sh *defaultSignalHandler) Init() error {
- sh.Lock()
- sh.signals = make([]chan<- *Signal, 0)
- sh.closeChan = make(chan struct{})
- sh.Unlock()
- return nil
-}
-
func (sh *defaultSignalHandler) Terminate() {
- sh.Lock()
- if !sh.closed {
- close(sh.closeChan)
- }
- sh.closed = true
- for _, ch := range sh.signals {
- close(ch)
- }
- sh.signals = nil
- sh.Unlock()
-}
-
-func (sh *defaultSignalHandler) addSignal(ch chan<- *Signal) {
- sh.Lock()
- defer sh.Unlock()
+ sh.mu.Lock()
+ defer sh.mu.Unlock()
if sh.closed {
return
}
- sh.signals = append(sh.signals, ch)
+ for _, scd := range sh.signals {
+ scd.close()
+ close(scd.ch)
+ }
+ sh.closed = true
+ sh.signals = nil
}
-func (sh *defaultSignalHandler) removeSignal(ch chan<- *Signal) {
- sh.Lock()
- defer sh.Unlock()
+func (sh *defaultSignalHandler) AddSignal(ch chan<- *Signal) {
+ sh.mu.Lock()
+ defer sh.mu.Unlock()
+ if sh.closed {
+ return
+ }
+ sh.signals = append(sh.signals, &signalChannelData{
+ ch: ch,
+ done: make(chan struct{}),
+ })
+}
+
+func (sh *defaultSignalHandler) RemoveSignal(ch chan<- *Signal) {
+ sh.mu.Lock()
+ defer sh.mu.Unlock()
if sh.closed {
return
}
for i := len(sh.signals) - 1; i >= 0; i-- {
- if ch == sh.signals[i] {
+ if ch == sh.signals[i].ch {
+ sh.signals[i].close()
copy(sh.signals[i:], sh.signals[i+1:])
sh.signals[len(sh.signals)-1] = nil
sh.signals = sh.signals[:len(sh.signals)-1]
}
}
}
+
+type signalChannelData struct {
+ wg sync.WaitGroup
+ ch chan<- *Signal
+ done chan struct{}
+}
+
+func (scd *signalChannelData) deliver(signal *Signal) {
+ select {
+ case scd.ch <- signal:
+ case <-scd.done:
+ return
+ default:
+ scd.wg.Add(1)
+ go scd.deferredDeliver(signal)
+ }
+}
+
+func (scd *signalChannelData) deferredDeliver(signal *Signal) {
+ select {
+ case scd.ch <- signal:
+ case <-scd.done:
+ }
+ scd.wg.Done()
+}
+
+func (scd *signalChannelData) close() {
+ close(scd.done)
+ scd.wg.Wait() // wait until all spawned goroutines return
+}
diff --git a/vendor/github.com/godbus/dbus/doc.go b/vendor/github.com/godbus/dbus/v5/doc.go
similarity index 96%
rename from vendor/github.com/godbus/dbus/doc.go
rename to vendor/github.com/godbus/dbus/v5/doc.go
index 895036a8c..ade1df951 100644
--- a/vendor/github.com/godbus/dbus/doc.go
+++ b/vendor/github.com/godbus/dbus/v5/doc.go
@@ -61,7 +61,7 @@ Handling Unix file descriptors deserves special mention. To use them, you should
first check that they are supported on a connection by calling SupportsUnixFDs.
If it returns true, all method of Connection will translate messages containing
UnixFD's to messages that are accompanied by the given file descriptors with the
-UnixFD values being substituted by the correct indices. Similarily, the indices
+UnixFD values being substituted by the correct indices. Similarly, the indices
of incoming messages are automatically resolved. It shouldn't be necessary to use
UnixFDIndex.
diff --git a/vendor/github.com/godbus/dbus/encoder.go b/vendor/github.com/godbus/dbus/v5/encoder.go
similarity index 98%
rename from vendor/github.com/godbus/dbus/encoder.go
rename to vendor/github.com/godbus/dbus/v5/encoder.go
index 8bb717761..adfbb75c5 100644
--- a/vendor/github.com/godbus/dbus/encoder.go
+++ b/vendor/github.com/godbus/dbus/v5/encoder.go
@@ -60,7 +60,7 @@ func (enc *encoder) binwrite(v interface{}) {
}
}
-// Encode encodes the given values to the underyling reader. All written values
+// Encode encodes the given values to the underlying reader. All written values
// are aligned properly as required by the D-Bus spec.
func (enc *encoder) Encode(vs ...interface{}) (err error) {
defer func() {
diff --git a/vendor/github.com/godbus/dbus/export.go b/vendor/github.com/godbus/dbus/v5/export.go
similarity index 99%
rename from vendor/github.com/godbus/dbus/export.go
rename to vendor/github.com/godbus/dbus/v5/export.go
index 95d0e2958..c277ab142 100644
--- a/vendor/github.com/godbus/dbus/export.go
+++ b/vendor/github.com/godbus/dbus/v5/export.go
@@ -171,7 +171,7 @@ func (conn *Conn) handleCall(msg *Message) {
}
reply.Headers[FieldSignature] = MakeVariant(SignatureOf(reply.Body...))
- conn.sendMessage(reply)
+ conn.sendMessageAndIfClosed(reply, nil)
}
}
diff --git a/vendor/github.com/godbus/dbus/v5/go.mod b/vendor/github.com/godbus/dbus/v5/go.mod
new file mode 100644
index 000000000..15b920203
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/v5/go.mod
@@ -0,0 +1,3 @@
+module github.com/godbus/dbus/v5
+
+go 1.12
diff --git a/vendor/github.com/godbus/dbus/v5/go.sum b/vendor/github.com/godbus/dbus/v5/go.sum
new file mode 100644
index 000000000..e69de29bb
diff --git a/vendor/github.com/godbus/dbus/homedir.go b/vendor/github.com/godbus/dbus/v5/homedir.go
similarity index 100%
rename from vendor/github.com/godbus/dbus/homedir.go
rename to vendor/github.com/godbus/dbus/v5/homedir.go
diff --git a/vendor/github.com/godbus/dbus/homedir_dynamic.go b/vendor/github.com/godbus/dbus/v5/homedir_dynamic.go
similarity index 100%
rename from vendor/github.com/godbus/dbus/homedir_dynamic.go
rename to vendor/github.com/godbus/dbus/v5/homedir_dynamic.go
diff --git a/vendor/github.com/godbus/dbus/homedir_static.go b/vendor/github.com/godbus/dbus/v5/homedir_static.go
similarity index 100%
rename from vendor/github.com/godbus/dbus/homedir_static.go
rename to vendor/github.com/godbus/dbus/v5/homedir_static.go
diff --git a/vendor/github.com/godbus/dbus/v5/match.go b/vendor/github.com/godbus/dbus/v5/match.go
new file mode 100644
index 000000000..086ee336a
--- /dev/null
+++ b/vendor/github.com/godbus/dbus/v5/match.go
@@ -0,0 +1,62 @@
+package dbus
+
+import (
+ "strings"
+)
+
+// MatchOption specifies option for dbus routing match rule. Options can be constructed with WithMatch* helpers.
+// For full list of available options consult
+// https://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-routing-match-rules
+type MatchOption struct {
+ key string
+ value string
+}
+
+func formatMatchOptions(options []MatchOption) string {
+ items := make([]string, 0, len(options))
+ for _, option := range options {
+ items = append(items, option.key+"='"+option.value+"'")
+ }
+ return strings.Join(items, ",")
+}
+
+// WithMatchOption creates match option with given key and value
+func WithMatchOption(key, value string) MatchOption {
+ return MatchOption{key, value}
+}
+
+// doesn't make sense to export this option because clients can only
+// subscribe to messages with signal type.
+func withMatchType(typ string) MatchOption {
+ return WithMatchOption("type", typ)
+}
+
+// WithMatchSender sets sender match option.
+func WithMatchSender(sender string) MatchOption {
+ return WithMatchOption("sender", sender)
+}
+
+// WithMatchSender sets interface match option.
+func WithMatchInterface(iface string) MatchOption {
+ return WithMatchOption("interface", iface)
+}
+
+// WithMatchMember sets member match option.
+func WithMatchMember(member string) MatchOption {
+ return WithMatchOption("member", member)
+}
+
+// WithMatchObjectPath creates match option that filters events based on given path
+func WithMatchObjectPath(path ObjectPath) MatchOption {
+ return WithMatchOption("path", string(path))
+}
+
+// WithMatchPathNamespace sets path_namespace match option.
+func WithMatchPathNamespace(namespace ObjectPath) MatchOption {
+ return WithMatchOption("path_namespace", string(namespace))
+}
+
+// WithMatchDestination sets destination match option.
+func WithMatchDestination(destination string) MatchOption {
+ return WithMatchOption("destination", destination)
+}
diff --git a/vendor/github.com/godbus/dbus/message.go b/vendor/github.com/godbus/dbus/v5/message.go
similarity index 100%
rename from vendor/github.com/godbus/dbus/message.go
rename to vendor/github.com/godbus/dbus/v5/message.go
diff --git a/vendor/github.com/godbus/dbus/object.go b/vendor/github.com/godbus/dbus/v5/object.go
similarity index 83%
rename from vendor/github.com/godbus/dbus/object.go
rename to vendor/github.com/godbus/dbus/v5/object.go
index f27ffe144..8acd7fc8b 100644
--- a/vendor/github.com/godbus/dbus/object.go
+++ b/vendor/github.com/godbus/dbus/v5/object.go
@@ -16,6 +16,7 @@ type BusObject interface {
AddMatchSignal(iface, member string, options ...MatchOption) *Call
RemoveMatchSignal(iface, member string, options ...MatchOption) *Call
GetProperty(p string) (Variant, error)
+ SetProperty(p string, v interface{}) error
Destination() string
Path() ObjectPath
}
@@ -37,41 +38,16 @@ func (o *Object) CallWithContext(ctx context.Context, method string, flags Flags
return <-o.createCall(ctx, method, flags, make(chan *Call, 1), args...).Done
}
-// MatchOption specifies option for dbus routing match rule. Options can be constructed with WithMatch* helpers.
-// For full list of available options consult
-// https://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-routing-match-rules
-type MatchOption struct {
- key string
- value string
-}
-
-// WithMatchOption creates match option with given key and value
-func WithMatchOption(key, value string) MatchOption {
- return MatchOption{key, value}
-}
-
-// WithMatchObjectPath creates match option that filters events based on given path
-func WithMatchObjectPath(path ObjectPath) MatchOption {
- return MatchOption{"path", string(path)}
-}
-
-func formatMatchOptions(options []MatchOption) string {
- items := make([]string, 0, len(options))
- for _, option := range options {
- items = append(items, option.key+"='"+option.value+"'")
- }
-
- return strings.Join(items, ",")
-}
-
// AddMatchSignal subscribes BusObject to signals from specified interface,
// method (member). Additional filter rules can be added via WithMatch* option constructors.
// Note: To filter events by object path you have to specify this path via an option.
+//
+// Deprecated: use (*Conn) AddMatchSignal instead.
func (o *Object) AddMatchSignal(iface, member string, options ...MatchOption) *Call {
base := []MatchOption{
- {"type", "signal"},
- {"interface", iface},
- {"member", member},
+ withMatchType("signal"),
+ WithMatchInterface(iface),
+ WithMatchMember(member),
}
options = append(base, options...)
@@ -84,11 +60,13 @@ func (o *Object) AddMatchSignal(iface, member string, options ...MatchOption) *C
// RemoveMatchSignal unsubscribes BusObject from signals from specified interface,
// method (member). Additional filter rules can be added via WithMatch* option constructors
+//
+// Deprecated: use (*Conn) RemoveMatchSignal instead.
func (o *Object) RemoveMatchSignal(iface, member string, options ...MatchOption) *Call {
base := []MatchOption{
- {"type", "signal"},
- {"interface", iface},
- {"member", member},
+ withMatchType("signal"),
+ WithMatchInterface(iface),
+ WithMatchMember(member),
}
options = append(base, options...)
@@ -146,7 +124,7 @@ func (o *Object) createCall(ctx context.Context, method string, flags Flags, ch
}
if msg.Flags&FlagNoReplyExpected == 0 {
if ch == nil {
- ch = make(chan *Call, 10)
+ ch = make(chan *Call, 1)
} else if cap(ch) == 0 {
panic("dbus: unbuffered channel passed to (*Object).Go")
}
@@ -187,7 +165,7 @@ func (o *Object) createCall(ctx context.Context, method string, flags Flags, ch
return call
}
-// GetProperty calls org.freedesktop.DBus.Properties.GetProperty on the given
+// GetProperty calls org.freedesktop.DBus.Properties.Get on the given
// object. The property name must be given in interface.member notation.
func (o *Object) GetProperty(p string) (Variant, error) {
idx := strings.LastIndex(p, ".")
@@ -208,6 +186,20 @@ func (o *Object) GetProperty(p string) (Variant, error) {
return result, nil
}
+// SetProperty calls org.freedesktop.DBus.Properties.Set on the given
+// object. The property name must be given in interface.member notation.
+func (o *Object) SetProperty(p string, v interface{}) error {
+ idx := strings.LastIndex(p, ".")
+ if idx == -1 || idx+1 == len(p) {
+ return errors.New("dbus: invalid property " + p)
+ }
+
+ iface := p[:idx]
+ prop := p[idx+1:]
+
+ return o.Call("org.freedesktop.DBus.Properties.Set", 0, iface, prop, v).Err
+}
+
// Destination returns the destination that calls on (o *Object) are sent to.
func (o *Object) Destination() string {
return o.dest
diff --git a/vendor/github.com/godbus/dbus/server_interfaces.go b/vendor/github.com/godbus/dbus/v5/server_interfaces.go
similarity index 94%
rename from vendor/github.com/godbus/dbus/server_interfaces.go
rename to vendor/github.com/godbus/dbus/v5/server_interfaces.go
index 01166f0bd..79d97edf3 100644
--- a/vendor/github.com/godbus/dbus/server_interfaces.go
+++ b/vendor/github.com/godbus/dbus/v5/server_interfaces.go
@@ -77,6 +77,14 @@ type SignalHandler interface {
DeliverSignal(iface, name string, signal *Signal)
}
+// SignalRegistrar manages signal delivery channels.
+//
+// This is an optional set of methods for `SignalHandler`.
+type SignalRegistrar interface {
+ AddSignal(ch chan<- *Signal)
+ RemoveSignal(ch chan<- *Signal)
+}
+
// A DBusError is used to convert a generic object to a D-Bus error.
//
// Any custom error mechanism may implement this interface to provide
diff --git a/vendor/github.com/godbus/dbus/sig.go b/vendor/github.com/godbus/dbus/v5/sig.go
similarity index 100%
rename from vendor/github.com/godbus/dbus/sig.go
rename to vendor/github.com/godbus/dbus/v5/sig.go
diff --git a/vendor/github.com/godbus/dbus/transport_darwin.go b/vendor/github.com/godbus/dbus/v5/transport_darwin.go
similarity index 100%
rename from vendor/github.com/godbus/dbus/transport_darwin.go
rename to vendor/github.com/godbus/dbus/v5/transport_darwin.go
diff --git a/vendor/github.com/godbus/dbus/transport_generic.go b/vendor/github.com/godbus/dbus/v5/transport_generic.go
similarity index 100%
rename from vendor/github.com/godbus/dbus/transport_generic.go
rename to vendor/github.com/godbus/dbus/v5/transport_generic.go
diff --git a/vendor/github.com/godbus/dbus/transport_nonce_tcp.go b/vendor/github.com/godbus/dbus/v5/transport_nonce_tcp.go
similarity index 100%
rename from vendor/github.com/godbus/dbus/transport_nonce_tcp.go
rename to vendor/github.com/godbus/dbus/v5/transport_nonce_tcp.go
diff --git a/vendor/github.com/godbus/dbus/transport_tcp.go b/vendor/github.com/godbus/dbus/v5/transport_tcp.go
similarity index 97%
rename from vendor/github.com/godbus/dbus/transport_tcp.go
rename to vendor/github.com/godbus/dbus/v5/transport_tcp.go
index dd1c8e59c..f91c9b7d7 100644
--- a/vendor/github.com/godbus/dbus/transport_tcp.go
+++ b/vendor/github.com/godbus/dbus/v5/transport_tcp.go
@@ -1,5 +1,3 @@
-//+build !windows
-
package dbus
import (
diff --git a/vendor/github.com/godbus/dbus/transport_unix.go b/vendor/github.com/godbus/dbus/v5/transport_unix.go
similarity index 99%
rename from vendor/github.com/godbus/dbus/transport_unix.go
rename to vendor/github.com/godbus/dbus/v5/transport_unix.go
index f000c6b5d..c7cd02f97 100644
--- a/vendor/github.com/godbus/dbus/transport_unix.go
+++ b/vendor/github.com/godbus/dbus/v5/transport_unix.go
@@ -203,7 +203,7 @@ func (t *unixTransport) SendMessage(msg *Message) error {
}
} else {
if err := msg.EncodeTo(t, nativeEndian); err != nil {
- return nil
+ return err
}
}
return nil
diff --git a/vendor/github.com/godbus/dbus/transport_unixcred_dragonfly.go b/vendor/github.com/godbus/dbus/v5/transport_unixcred_dragonfly.go
similarity index 100%
rename from vendor/github.com/godbus/dbus/transport_unixcred_dragonfly.go
rename to vendor/github.com/godbus/dbus/v5/transport_unixcred_dragonfly.go
diff --git a/vendor/github.com/godbus/dbus/transport_unixcred_freebsd.go b/vendor/github.com/godbus/dbus/v5/transport_unixcred_freebsd.go
similarity index 100%
rename from vendor/github.com/godbus/dbus/transport_unixcred_freebsd.go
rename to vendor/github.com/godbus/dbus/v5/transport_unixcred_freebsd.go
diff --git a/vendor/github.com/godbus/dbus/transport_unixcred_linux.go b/vendor/github.com/godbus/dbus/v5/transport_unixcred_linux.go
similarity index 100%
rename from vendor/github.com/godbus/dbus/transport_unixcred_linux.go
rename to vendor/github.com/godbus/dbus/v5/transport_unixcred_linux.go
diff --git a/vendor/github.com/godbus/dbus/transport_unixcred_openbsd.go b/vendor/github.com/godbus/dbus/v5/transport_unixcred_openbsd.go
similarity index 100%
rename from vendor/github.com/godbus/dbus/transport_unixcred_openbsd.go
rename to vendor/github.com/godbus/dbus/v5/transport_unixcred_openbsd.go
diff --git a/vendor/github.com/godbus/dbus/variant.go b/vendor/github.com/godbus/dbus/v5/variant.go
similarity index 95%
rename from vendor/github.com/godbus/dbus/variant.go
rename to vendor/github.com/godbus/dbus/v5/variant.go
index 0ca123b01..5b51828c8 100644
--- a/vendor/github.com/godbus/dbus/variant.go
+++ b/vendor/github.com/godbus/dbus/v5/variant.go
@@ -26,7 +26,7 @@ func MakeVariantWithSignature(v interface{}, s Signature) Variant {
}
// ParseVariant parses the given string as a variant as described at
-// https://developer.gnome.org/glib/unstable/gvariant-text.html. If sig is not
+// https://developer.gnome.org/glib/stable/gvariant-text.html. If sig is not
// empty, it is taken to be the expected signature for the variant.
func ParseVariant(s string, sig Signature) (Variant, error) {
tokens := varLex(s)
@@ -129,7 +129,7 @@ func (v Variant) Signature() Signature {
}
// String returns the string representation of the underlying value of v as
-// described at https://developer.gnome.org/glib/unstable/gvariant-text.html.
+// described at https://developer.gnome.org/glib/stable/gvariant-text.html.
func (v Variant) String() string {
s, unamb := v.format()
if !unamb {
diff --git a/vendor/github.com/godbus/dbus/variant_lexer.go b/vendor/github.com/godbus/dbus/v5/variant_lexer.go
similarity index 95%
rename from vendor/github.com/godbus/dbus/variant_lexer.go
rename to vendor/github.com/godbus/dbus/v5/variant_lexer.go
index 332007d6f..bf1398c8f 100644
--- a/vendor/github.com/godbus/dbus/variant_lexer.go
+++ b/vendor/github.com/godbus/dbus/v5/variant_lexer.go
@@ -51,7 +51,7 @@ func varLex(s string) []varToken {
}
func (l *varLexer) accept(valid string) bool {
- if strings.IndexRune(valid, l.next()) >= 0 {
+ if strings.ContainsRune(valid, l.next()) {
return true
}
l.backup()
@@ -214,17 +214,17 @@ func varLexNumber(l *varLexer) lexState {
digits = "01234567"
}
}
- for strings.IndexRune(digits, l.next()) >= 0 {
+ for strings.ContainsRune(digits, l.next()) {
}
l.backup()
if l.accept(".") {
- for strings.IndexRune(digits, l.next()) >= 0 {
+ for strings.ContainsRune(digits, l.next()) {
}
l.backup()
}
if l.accept("eE") {
l.accept("+-")
- for strings.IndexRune("0123456789", l.next()) >= 0 {
+ for strings.ContainsRune("0123456789", l.next()) {
}
l.backup()
}
diff --git a/vendor/github.com/godbus/dbus/variant_parser.go b/vendor/github.com/godbus/dbus/v5/variant_parser.go
similarity index 100%
rename from vendor/github.com/godbus/dbus/variant_parser.go
rename to vendor/github.com/godbus/dbus/v5/variant_parser.go
diff --git a/vendor/github.com/hashicorp/nomad/api/nodes.go b/vendor/github.com/hashicorp/nomad/api/nodes.go
index 8ec6f8d0a..94b660d6d 100644
--- a/vendor/github.com/hashicorp/nomad/api/nodes.go
+++ b/vendor/github.com/hashicorp/nomad/api/nodes.go
@@ -14,7 +14,7 @@ const (
NodeStatusDown = "down"
// NodeSchedulingEligible and Ineligible marks the node as eligible or not,
- // respectively, for receiving allocations. This is orthoginal to the node
+ // respectively, for receiving allocations. This is orthogonal to the node
// status being ready.
NodeSchedulingEligible = "eligible"
NodeSchedulingIneligible = "ineligible"
@@ -435,6 +435,25 @@ func (n *Nodes) GcAlloc(allocID string, q *QueryOptions) error {
return err
}
+// Purge removes a node from the system. Nodes can still re-join the cluster if
+// they are alive.
+func (n *Nodes) Purge(nodeID string, q *QueryOptions) (*NodePurgeResponse, *QueryMeta, error) {
+ var resp NodePurgeResponse
+ path := fmt.Sprintf("/v1/node/%s/purge", nodeID)
+ qm, err := n.client.putQuery(path, nil, &resp, q)
+ if err != nil {
+ return nil, nil, err
+ }
+ return &resp, qm, nil
+}
+
+// NodePurgeResponse is used to deserialize a Purge response.
+type NodePurgeResponse struct {
+ EvalIDs []string
+ EvalCreateIndex uint64
+ NodeModifyIndex uint64
+}
+
// DriverInfo is used to deserialize a DriverInfo entry
type DriverInfo struct {
Attributes map[string]string
diff --git a/vendor/github.com/moby/sys/mountinfo/LICENSE b/vendor/github.com/moby/sys/mountinfo/LICENSE
new file mode 100644
index 000000000..d64569567
--- /dev/null
+++ b/vendor/github.com/moby/sys/mountinfo/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/vendor/github.com/moby/sys/mountinfo/go.mod b/vendor/github.com/moby/sys/mountinfo/go.mod
new file mode 100644
index 000000000..10d9a15a6
--- /dev/null
+++ b/vendor/github.com/moby/sys/mountinfo/go.mod
@@ -0,0 +1,3 @@
+module github.com/moby/sys/mountinfo
+
+go 1.14
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/mount/mountinfo.go b/vendor/github.com/moby/sys/mountinfo/mountinfo.go
similarity index 54%
rename from vendor/github.com/opencontainers/runc/libcontainer/mount/mountinfo.go
rename to vendor/github.com/moby/sys/mountinfo/mountinfo.go
index e3fc3535e..136b14167 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/mount/mountinfo.go
+++ b/vendor/github.com/moby/sys/mountinfo/mountinfo.go
@@ -1,4 +1,31 @@
-package mount
+package mountinfo
+
+import "io"
+
+// GetMounts retrieves a list of mounts for the current running process,
+// with an optional filter applied (use nil for no filter).
+func GetMounts(f FilterFunc) ([]*Info, error) {
+ return parseMountTable(f)
+}
+
+// GetMountsFromReader retrieves a list of mounts from the
+// reader provided, with an optional filter applied (use nil
+// for no filter). This can be useful in tests or benchmarks
+// that provide a fake mountinfo data.
+func GetMountsFromReader(reader io.Reader, f FilterFunc) ([]*Info, error) {
+ return parseInfoFile(reader, f)
+}
+
+// Mounted determines if a specified mountpoint has been mounted.
+// On Linux it looks at /proc/self/mountinfo.
+func Mounted(mountpoint string) (bool, error) {
+ entries, err := GetMounts(SingleEntryFilter(mountpoint))
+ if err != nil {
+ return false, err
+ }
+
+ return len(entries) > 0, nil
+}
// Info reveals information about a particular mounted filesystem. This
// struct is populated from the content in the /proc//mountinfo file.
diff --git a/vendor/github.com/moby/sys/mountinfo/mountinfo_filters.go b/vendor/github.com/moby/sys/mountinfo/mountinfo_filters.go
new file mode 100644
index 000000000..795026465
--- /dev/null
+++ b/vendor/github.com/moby/sys/mountinfo/mountinfo_filters.go
@@ -0,0 +1,58 @@
+package mountinfo
+
+import "strings"
+
+// FilterFunc is a type defining a callback function for GetMount(),
+// used to filter out mountinfo entries we're not interested in,
+// and/or stop further processing if we found what we wanted.
+//
+// It takes a pointer to the Info struct (not fully populated,
+// currently only Mountpoint, Fstype, Source, and (on Linux)
+// VfsOpts are filled in), and returns two booleans:
+//
+// - skip: true if the entry should be skipped
+// - stop: true if parsing should be stopped after the entry
+type FilterFunc func(*Info) (skip, stop bool)
+
+// PrefixFilter discards all entries whose mount points
+// do not start with a specific prefix
+func PrefixFilter(prefix string) FilterFunc {
+ return func(m *Info) (bool, bool) {
+ skip := !strings.HasPrefix(m.Mountpoint, prefix)
+ return skip, false
+ }
+}
+
+// SingleEntryFilter looks for a specific entry
+func SingleEntryFilter(mp string) FilterFunc {
+ return func(m *Info) (bool, bool) {
+ if m.Mountpoint == mp {
+ return false, true // don't skip, stop now
+ }
+ return true, false // skip, keep going
+ }
+}
+
+// ParentsFilter returns all entries whose mount points
+// can be parents of a path specified, discarding others.
+//
+// For example, given `/var/lib/docker/something`, entries
+// like `/var/lib/docker`, `/var` and `/` are returned.
+func ParentsFilter(path string) FilterFunc {
+ return func(m *Info) (bool, bool) {
+ skip := !strings.HasPrefix(path, m.Mountpoint)
+ return skip, false
+ }
+}
+
+// FstypeFilter returns all entries that match provided fstype(s).
+func FstypeFilter(fstype ...string) FilterFunc {
+ return func(m *Info) (bool, bool) {
+ for _, t := range fstype {
+ if m.Fstype == t {
+ return false, false // don't skeep, keep going
+ }
+ }
+ return true, false // skip, keep going
+ }
+}
diff --git a/vendor/github.com/moby/sys/mountinfo/mountinfo_freebsd.go b/vendor/github.com/moby/sys/mountinfo/mountinfo_freebsd.go
new file mode 100644
index 000000000..a7dbb1b46
--- /dev/null
+++ b/vendor/github.com/moby/sys/mountinfo/mountinfo_freebsd.go
@@ -0,0 +1,53 @@
+package mountinfo
+
+/*
+#include
+#include
+#include
+*/
+import "C"
+
+import (
+ "fmt"
+ "reflect"
+ "unsafe"
+)
+
+// parseMountTable returns information about mounted filesystems
+func parseMountTable(filter FilterFunc) ([]*Info, error) {
+ var rawEntries *C.struct_statfs
+
+ count := int(C.getmntinfo(&rawEntries, C.MNT_WAIT))
+ if count == 0 {
+ return nil, fmt.Errorf("Failed to call getmntinfo")
+ }
+
+ var entries []C.struct_statfs
+ header := (*reflect.SliceHeader)(unsafe.Pointer(&entries))
+ header.Cap = count
+ header.Len = count
+ header.Data = uintptr(unsafe.Pointer(rawEntries))
+
+ var out []*Info
+ for _, entry := range entries {
+ var mountinfo Info
+ var skip, stop bool
+ mountinfo.Mountpoint = C.GoString(&entry.f_mntonname[0])
+ mountinfo.Fstype = C.GoString(&entry.f_fstypename[0])
+ mountinfo.Source = C.GoString(&entry.f_mntfromname[0])
+
+ if filter != nil {
+ // filter out entries we're not interested in
+ skip, stop = filter(&mountinfo)
+ if skip {
+ continue
+ }
+ }
+
+ out = append(out, &mountinfo)
+ if stop {
+ break
+ }
+ }
+ return out, nil
+}
diff --git a/vendor/github.com/moby/sys/mountinfo/mountinfo_linux.go b/vendor/github.com/moby/sys/mountinfo/mountinfo_linux.go
new file mode 100644
index 000000000..2d630c8dc
--- /dev/null
+++ b/vendor/github.com/moby/sys/mountinfo/mountinfo_linux.go
@@ -0,0 +1,152 @@
+// +build go1.13
+
+package mountinfo
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "os"
+ "strconv"
+ "strings"
+)
+
+func parseInfoFile(r io.Reader, filter FilterFunc) ([]*Info, error) {
+ s := bufio.NewScanner(r)
+ out := []*Info{}
+ var err error
+ for s.Scan() {
+ if err = s.Err(); err != nil {
+ return nil, err
+ }
+ /*
+ See http://man7.org/linux/man-pages/man5/proc.5.html
+
+ 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
+ (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
+
+ (1) mount ID: unique identifier of the mount (may be reused after umount)
+ (2) parent ID: ID of parent (or of self for the top of the mount tree)
+ (3) major:minor: value of st_dev for files on filesystem
+ (4) root: root of the mount within the filesystem
+ (5) mount point: mount point relative to the process's root
+ (6) mount options: per mount options
+ (7) optional fields: zero or more fields of the form "tag[:value]"
+ (8) separator: marks the end of the optional fields
+ (9) filesystem type: name of filesystem of the form "type[.subtype]"
+ (10) mount source: filesystem specific information or "none"
+ (11) super options: per super block options
+
+ In other words, we have:
+ * 6 mandatory fields (1)..(6)
+ * 0 or more optional fields (7)
+ * a separator field (8)
+ * 3 mandatory fields (9)..(11)
+ */
+
+ text := s.Text()
+ fields := strings.Split(text, " ")
+ numFields := len(fields)
+ if numFields < 10 {
+ // should be at least 10 fields
+ return nil, fmt.Errorf("Parsing '%s' failed: not enough fields (%d)", text, numFields)
+ }
+
+ // separator field
+ sepIdx := numFields - 4
+ // In Linux <= 3.9 mounting a cifs with spaces in a share
+ // name (like "//srv/My Docs") _may_ end up having a space
+ // in the last field of mountinfo (like "unc=//serv/My Docs").
+ // Since kernel 3.10-rc1, cifs option "unc=" is ignored,
+ // so spaces should not appear.
+ //
+ // Check for a separator, and work around the spaces bug
+ for fields[sepIdx] != "-" {
+ sepIdx--
+ if sepIdx == 5 {
+ return nil, fmt.Errorf("Parsing '%s' failed: missing - separator", text)
+ }
+ }
+
+ p := &Info{}
+
+ // Fill in the fields that a filter might check
+ p.Mountpoint, err = strconv.Unquote(`"` + fields[4] + `"`)
+ if err != nil {
+ return nil, fmt.Errorf("Parsing '%s' failed: unable to unquote mount point field: %w", fields[4], err)
+ }
+ p.Fstype = fields[sepIdx+1]
+ p.Source = fields[sepIdx+2]
+ p.VfsOpts = fields[sepIdx+3]
+
+ // Run a filter soon so we can skip parsing/adding entries
+ // the caller is not interested in
+ var skip, stop bool
+ if filter != nil {
+ skip, stop = filter(p)
+ if skip {
+ continue
+ }
+ }
+
+ // Fill in the rest of the fields
+
+ // ignore any numbers parsing errors, as there should not be any
+ p.ID, _ = strconv.Atoi(fields[0])
+ p.Parent, _ = strconv.Atoi(fields[1])
+ mm := strings.Split(fields[2], ":")
+ if len(mm) != 2 {
+ return nil, fmt.Errorf("Parsing '%s' failed: unexpected minor:major pair %s", text, mm)
+ }
+ p.Major, _ = strconv.Atoi(mm[0])
+ p.Minor, _ = strconv.Atoi(mm[1])
+
+ p.Root, err = strconv.Unquote(`"` + fields[3] + `"`)
+ if err != nil {
+ return nil, fmt.Errorf("Parsing '%s' failed: unable to unquote root field: %w", fields[3], err)
+ }
+
+ p.Opts = fields[5]
+
+ // zero or more optional fields
+ switch {
+ case sepIdx == 6:
+ // zero, do nothing
+ case sepIdx == 7:
+ p.Optional = fields[6]
+ default:
+ p.Optional = strings.Join(fields[6:sepIdx-1], " ")
+ }
+
+ out = append(out, p)
+ if stop {
+ break
+ }
+ }
+ return out, nil
+}
+
+// Parse /proc/self/mountinfo because comparing Dev and ino does not work from
+// bind mounts
+func parseMountTable(filter FilterFunc) ([]*Info, error) {
+ f, err := os.Open("/proc/self/mountinfo")
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ return parseInfoFile(f, filter)
+}
+
+// PidMountInfo collects the mounts for a specific process ID. If the process
+// ID is unknown, it is better to use `GetMounts` which will inspect
+// "/proc/self/mountinfo" instead.
+func PidMountInfo(pid int) ([]*Info, error) {
+ f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid))
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ return parseInfoFile(f, nil)
+}
diff --git a/vendor/github.com/moby/sys/mountinfo/mountinfo_unsupported.go b/vendor/github.com/moby/sys/mountinfo/mountinfo_unsupported.go
new file mode 100644
index 000000000..dc1869211
--- /dev/null
+++ b/vendor/github.com/moby/sys/mountinfo/mountinfo_unsupported.go
@@ -0,0 +1,17 @@
+// +build !windows,!linux,!freebsd freebsd,!cgo
+
+package mountinfo
+
+import (
+ "fmt"
+ "io"
+ "runtime"
+)
+
+func parseMountTable(_ FilterFunc) ([]*Info, error) {
+ return nil, fmt.Errorf("mount.parseMountTable is not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
+}
+
+func parseInfoFile(_ io.Reader, f FilterFunc) ([]*Info, error) {
+ return parseMountTable(f)
+}
diff --git a/vendor/github.com/moby/sys/mountinfo/mountinfo_windows.go b/vendor/github.com/moby/sys/mountinfo/mountinfo_windows.go
new file mode 100644
index 000000000..69ffdc52b
--- /dev/null
+++ b/vendor/github.com/moby/sys/mountinfo/mountinfo_windows.go
@@ -0,0 +1,12 @@
+package mountinfo
+
+import "io"
+
+func parseMountTable(_ FilterFunc) ([]*Info, error) {
+ // Do NOT return an error!
+ return nil, nil
+}
+
+func parseInfoFile(_ io.Reader, f FilterFunc) ([]*Info, error) {
+ return parseMountTable(f)
+}
diff --git a/vendor/github.com/mrunalp/fileutils/fileutils.go b/vendor/github.com/mrunalp/fileutils/fileutils.go
index 5a9818a24..136bbd9fb 100644
--- a/vendor/github.com/mrunalp/fileutils/fileutils.go
+++ b/vendor/github.com/mrunalp/fileutils/fileutils.go
@@ -22,9 +22,10 @@ func CopyFile(source string, dest string) error {
uid := int(st.Uid)
gid := int(st.Gid)
+ modeType := si.Mode()&os.ModeType
// Handle symlinks
- if si.Mode()&os.ModeSymlink != 0 {
+ if modeType == os.ModeSymlink {
target, err := os.Readlink(source)
if err != nil {
return err
@@ -35,15 +36,14 @@ func CopyFile(source string, dest string) error {
}
// Handle device files
- if st.Mode&syscall.S_IFMT == syscall.S_IFBLK || st.Mode&syscall.S_IFMT == syscall.S_IFCHR {
+ if modeType == os.ModeDevice {
devMajor := int64(major(uint64(st.Rdev)))
devMinor := int64(minor(uint64(st.Rdev)))
- mode := uint32(si.Mode() & 07777)
- if st.Mode&syscall.S_IFMT == syscall.S_IFBLK {
- mode |= syscall.S_IFBLK
- }
- if st.Mode&syscall.S_IFMT == syscall.S_IFCHR {
+ mode := uint32(si.Mode() & os.ModePerm)
+ if si.Mode()&os.ModeCharDevice != 0 {
mode |= syscall.S_IFCHR
+ } else {
+ mode |= syscall.S_IFBLK
}
if err := syscall.Mknod(dest, mode, int(mkdev(devMajor, devMinor))); err != nil {
return err
@@ -76,7 +76,7 @@ func CopyFile(source string, dest string) error {
}
// Chmod the file
- if !(si.Mode()&os.ModeSymlink == os.ModeSymlink) {
+ if !(modeType == os.ModeSymlink) {
if err := os.Chmod(dest, si.Mode()); err != nil {
return err
}
diff --git a/vendor/github.com/mrunalp/fileutils/idtools.go b/vendor/github.com/mrunalp/fileutils/idtools.go
index 161aec8f5..bad6539df 100644
--- a/vendor/github.com/mrunalp/fileutils/idtools.go
+++ b/vendor/github.com/mrunalp/fileutils/idtools.go
@@ -3,6 +3,7 @@ package fileutils
import (
"os"
"path/filepath"
+ "syscall"
)
// MkdirAllNewAs creates a directory (include any along the path) and then modifies
@@ -14,9 +15,13 @@ func MkdirAllNewAs(path string, mode os.FileMode, ownerUID, ownerGID int) error
// so that we can chown all of them properly at the end. If chownExisting is false, we won't
// chown the full directory path if it exists
var paths []string
- if _, err := os.Stat(path); err != nil && os.IsNotExist(err) {
+ st, err := os.Stat(path)
+ if err != nil && os.IsNotExist(err) {
paths = []string{path}
} else if err == nil {
+ if !st.IsDir() {
+ return &os.PathError{Op: "mkdir", Path: path, Err: syscall.ENOTDIR}
+ }
// nothing to do; directory path fully exists already
return nil
}
@@ -34,7 +39,7 @@ func MkdirAllNewAs(path string, mode os.FileMode, ownerUID, ownerGID int) error
}
}
- if err := os.MkdirAll(path, mode); err != nil && !os.IsExist(err) {
+ if err := os.MkdirAll(path, mode); err != nil {
return err
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/README.md b/vendor/github.com/opencontainers/runc/libcontainer/README.md
index a791ca2d2..6803ef56c 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/README.md
+++ b/vendor/github.com/opencontainers/runc/libcontainer/README.md
@@ -155,8 +155,7 @@ config := &configs.Config{
Parent: "system",
Resources: &configs.Resources{
MemorySwappiness: nil,
- AllowAllDevices: nil,
- AllowedDevices: configs.DefaultAllowedDevices,
+ Devices: specconv.AllowedDevices,
},
},
MaskPaths: []string{
@@ -166,7 +165,7 @@ config := &configs.Config{
ReadonlyPaths: []string{
"/proc/sys", "/proc/sysrq-trigger", "/proc/irq", "/proc/bus",
},
- Devices: configs.DefaultAutoCreatedDevices,
+ Devices: specconv.AllowedDevices,
Hostname: "testing",
Mounts: []*configs.Mount{
{
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go
index c0a965923..a16a68e97 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/cgroups.go
@@ -3,8 +3,6 @@
package cgroups
import (
- "fmt"
-
"github.com/opencontainers/runc/libcontainer/configs"
)
@@ -27,48 +25,27 @@ type Manager interface {
// Destroys the cgroup set
Destroy() error
- // The option func SystemdCgroups() and Cgroupfs() require following attributes:
- // Paths map[string]string
- // Cgroups *configs.Cgroup
- // Paths maps cgroup subsystem to path at which it is mounted.
- // Cgroups specifies specific cgroup settings for the various subsystems
-
- // Returns cgroup paths to save in a state file and to be able to
- // restore the object later.
- GetPaths() map[string]string
-
- // GetUnifiedPath returns the unified path when running in unified mode.
- // The value corresponds to the all values of GetPaths() map.
- //
- // GetUnifiedPath returns error when running in hybrid mode as well as
- // in legacy mode.
- GetUnifiedPath() (string, error)
+ // Path returns a cgroup path to the specified controller/subsystem.
+ // For cgroupv2, the argument is unused and can be empty.
+ Path(string) string
// Sets the cgroup as configured.
Set(container *configs.Config) error
- // Gets the cgroup as configured.
+ // GetPaths returns cgroup path(s) to save in a state file in order to restore later.
+ //
+ // For cgroup v1, a key is cgroup subsystem name, and the value is the path
+ // to the cgroup for this subsystem.
+ //
+ // For cgroup v2 unified hierarchy, a key is "", and the value is the unified path.
+ GetPaths() map[string]string
+
+ // GetCgroups returns the cgroup data as configured.
GetCgroups() (*configs.Cgroup, error)
-}
-type NotFoundError struct {
- Subsystem string
-}
+ // GetFreezerState retrieves the current FreezerState of the cgroup.
+ GetFreezerState() (configs.FreezerState, error)
-func (e *NotFoundError) Error() string {
- return fmt.Sprintf("mountpoint for %s not found", e.Subsystem)
-}
-
-func NewNotFoundError(sub string) error {
- return &NotFoundError{
- Subsystem: sub,
- }
-}
-
-func IsNotFound(err error) bool {
- if err == nil {
- return false
- }
- _, ok := err.(*NotFoundError)
- return ok
+ // Whether the cgroup path exists or not
+ Exists() bool
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/devices/devices_emulator.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/devices/devices_emulator.go
new file mode 100644
index 000000000..6afedbc6e
--- /dev/null
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/devices/devices_emulator.go
@@ -0,0 +1,373 @@
+// +build linux
+
+// SPDX-License-Identifier: Apache-2.0
+/*
+ * Copyright (C) 2020 Aleksa Sarai
+ * Copyright (C) 2020 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.
+ */
+
+package devices
+
+import (
+ "bufio"
+ "io"
+ "regexp"
+ "sort"
+ "strconv"
+
+ "github.com/opencontainers/runc/libcontainer/configs"
+
+ "github.com/pkg/errors"
+)
+
+// deviceMeta is a DeviceRule without the Allow or Permissions fields, and no
+// wildcard-type support. It's effectively the "match" portion of a metadata
+// rule, for the purposes of our emulation.
+type deviceMeta struct {
+ node configs.DeviceType
+ major int64
+ minor int64
+}
+
+// deviceRule is effectively the tuple (deviceMeta, DevicePermissions).
+type deviceRule struct {
+ meta deviceMeta
+ perms configs.DevicePermissions
+}
+
+// deviceRules is a mapping of device metadata rules to the associated
+// permissions in the ruleset.
+type deviceRules map[deviceMeta]configs.DevicePermissions
+
+func (r deviceRules) orderedEntries() []deviceRule {
+ var rules []deviceRule
+ for meta, perms := range r {
+ rules = append(rules, deviceRule{meta: meta, perms: perms})
+ }
+ sort.Slice(rules, func(i, j int) bool {
+ // Sort by (major, minor, type).
+ a, b := rules[i].meta, rules[j].meta
+ return a.major < b.major ||
+ (a.major == b.major && a.minor < b.minor) ||
+ (a.major == b.major && a.minor == b.minor && a.node < b.node)
+ })
+ return rules
+}
+
+type Emulator struct {
+ defaultAllow bool
+ rules deviceRules
+}
+
+func (e *Emulator) IsBlacklist() bool {
+ return e.defaultAllow
+}
+
+func (e *Emulator) IsAllowAll() bool {
+ return e.IsBlacklist() && len(e.rules) == 0
+}
+
+var devicesListRegexp = regexp.MustCompile(`^([abc])\s+(\d+|\*):(\d+|\*)\s+([rwm]+)$`)
+
+func parseLine(line string) (*deviceRule, error) {
+ matches := devicesListRegexp.FindStringSubmatch(line)
+ if matches == nil {
+ return nil, errors.Errorf("line doesn't match devices.list format")
+ }
+ var (
+ rule deviceRule
+ node = matches[1]
+ major = matches[2]
+ minor = matches[3]
+ perms = matches[4]
+ )
+
+ // Parse the node type.
+ switch node {
+ case "a":
+ // Super-special case -- "a" always means every device with every
+ // access mode. In fact, for devices.list this actually indicates that
+ // the cgroup is in black-list mode.
+ // TODO: Double-check that the entire file is "a *:* rwm".
+ return nil, nil
+ case "b":
+ rule.meta.node = configs.BlockDevice
+ case "c":
+ rule.meta.node = configs.CharDevice
+ default:
+ // Should never happen!
+ return nil, errors.Errorf("unknown device type %q", node)
+ }
+
+ // Parse the major number.
+ if major == "*" {
+ rule.meta.major = configs.Wildcard
+ } else {
+ val, err := strconv.ParseUint(major, 10, 32)
+ if err != nil {
+ return nil, errors.Wrap(err, "parse major number")
+ }
+ rule.meta.major = int64(val)
+ }
+
+ // Parse the minor number.
+ if minor == "*" {
+ rule.meta.minor = configs.Wildcard
+ } else {
+ val, err := strconv.ParseUint(minor, 10, 32)
+ if err != nil {
+ return nil, errors.Wrap(err, "parse minor number")
+ }
+ rule.meta.minor = int64(val)
+ }
+
+ // Parse the access permissions.
+ rule.perms = configs.DevicePermissions(perms)
+ if !rule.perms.IsValid() || rule.perms.IsEmpty() {
+ // Should never happen!
+ return nil, errors.Errorf("parse access mode: contained unknown modes or is empty: %q", perms)
+ }
+ return &rule, nil
+}
+
+func (e *Emulator) addRule(rule deviceRule) error {
+ if e.rules == nil {
+ e.rules = make(map[deviceMeta]configs.DevicePermissions)
+ }
+
+ // Merge with any pre-existing permissions.
+ oldPerms := e.rules[rule.meta]
+ newPerms := rule.perms.Union(oldPerms)
+ e.rules[rule.meta] = newPerms
+ return nil
+}
+
+func (e *Emulator) rmRule(rule deviceRule) error {
+ // Give an error if any of the permissions requested to be removed are
+ // present in a partially-matching wildcard rule, because such rules will
+ // be ignored by cgroupv1.
+ //
+ // This is a diversion from cgroupv1, but is necessary to avoid leading
+ // users into a false sense of security. cgroupv1 will silently(!) ignore
+ // requests to remove partial exceptions, but we really shouldn't do that.
+ //
+ // It may seem like we could just "split" wildcard rules which hit this
+ // issue, but unfortunately there are 2^32 possible major and minor
+ // numbers, which would exhaust kernel memory quickly if we did this. Not
+ // to mention it'd be really slow (the kernel side is implemented as a
+ // linked-list of exceptions).
+ for _, partialMeta := range []deviceMeta{
+ {node: rule.meta.node, major: configs.Wildcard, minor: rule.meta.minor},
+ {node: rule.meta.node, major: rule.meta.major, minor: configs.Wildcard},
+ {node: rule.meta.node, major: configs.Wildcard, minor: configs.Wildcard},
+ } {
+ // This wildcard rule is equivalent to the requested rule, so skip it.
+ if rule.meta == partialMeta {
+ continue
+ }
+ // Only give an error if the set of permissions overlap.
+ partialPerms := e.rules[partialMeta]
+ if !partialPerms.Intersection(rule.perms).IsEmpty() {
+ return errors.Errorf("requested rule [%v %v] not supported by devices cgroupv1 (cannot punch hole in existing wildcard rule [%v %v])", rule.meta, rule.perms, partialMeta, partialPerms)
+ }
+ }
+
+ // Subtract all of the permissions listed from the full match rule. If the
+ // rule didn't exist, all of this is a no-op.
+ newPerms := e.rules[rule.meta].Difference(rule.perms)
+ if newPerms.IsEmpty() {
+ delete(e.rules, rule.meta)
+ } else {
+ e.rules[rule.meta] = newPerms
+ }
+ // TODO: The actual cgroup code doesn't care if an exception didn't exist
+ // during removal, so not erroring out here is /accurate/ but quite
+ // worrying. Maybe we should do additional validation, but again we
+ // have to worry about backwards-compatibility.
+ return nil
+}
+
+func (e *Emulator) allow(rule *deviceRule) error {
+ // This cgroup is configured as a black-list. Reset the entire emulator,
+ // and put is into black-list mode.
+ if rule == nil || rule.meta.node == configs.WildcardDevice {
+ *e = Emulator{
+ defaultAllow: true,
+ rules: nil,
+ }
+ return nil
+ }
+
+ var err error
+ if e.defaultAllow {
+ err = errors.Wrap(e.rmRule(*rule), "remove 'deny' exception")
+ } else {
+ err = errors.Wrap(e.addRule(*rule), "add 'allow' exception")
+ }
+ return err
+}
+
+func (e *Emulator) deny(rule *deviceRule) error {
+ // This cgroup is configured as a white-list. Reset the entire emulator,
+ // and put is into white-list mode.
+ if rule == nil || rule.meta.node == configs.WildcardDevice {
+ *e = Emulator{
+ defaultAllow: false,
+ rules: nil,
+ }
+ return nil
+ }
+
+ var err error
+ if e.defaultAllow {
+ err = errors.Wrap(e.addRule(*rule), "add 'deny' exception")
+ } else {
+ err = errors.Wrap(e.rmRule(*rule), "remove 'allow' exception")
+ }
+ return err
+}
+
+func (e *Emulator) Apply(rule configs.DeviceRule) error {
+ if !rule.Type.CanCgroup() {
+ return errors.Errorf("cannot add rule [%#v] with non-cgroup type %q", rule, rule.Type)
+ }
+
+ innerRule := &deviceRule{
+ meta: deviceMeta{
+ node: rule.Type,
+ major: rule.Major,
+ minor: rule.Minor,
+ },
+ perms: rule.Permissions,
+ }
+ if innerRule.meta.node == configs.WildcardDevice {
+ innerRule = nil
+ }
+
+ if rule.Allow {
+ return e.allow(innerRule)
+ } else {
+ return e.deny(innerRule)
+ }
+}
+
+// EmulatorFromList takes a reader to a "devices.list"-like source, and returns
+// a new Emulator that represents the state of the devices cgroup. Note that
+// black-list devices cgroups cannot be fully reconstructed, due to limitations
+// in the devices cgroup API. Instead, such cgroups are always treated as
+// "allow all" cgroups.
+func EmulatorFromList(list io.Reader) (*Emulator, error) {
+ // Normally cgroups are in black-list mode by default, but the way we
+ // figure out the current mode is whether or not devices.list has an
+ // allow-all rule. So we default to a white-list, and the existence of an
+ // "a *:* rwm" entry will tell us otherwise.
+ e := &Emulator{
+ defaultAllow: false,
+ }
+
+ // Parse the "devices.list".
+ s := bufio.NewScanner(list)
+ for s.Scan() {
+ line := s.Text()
+ deviceRule, err := parseLine(line)
+ if err != nil {
+ return nil, errors.Wrapf(err, "parsing line %q", line)
+ }
+ // "devices.list" is an allow list. Note that this means that in
+ // black-list mode, we have no idea what rules are in play. As a
+ // result, we need to be very careful in Transition().
+ if err := e.allow(deviceRule); err != nil {
+ return nil, errors.Wrapf(err, "adding devices.list rule")
+ }
+ }
+ if err := s.Err(); err != nil {
+ return nil, errors.Wrap(err, "reading devices.list lines")
+ }
+ return e, nil
+}
+
+// Transition calculates what is the minimally-disruptive set of rules need to
+// be applied to a devices cgroup in order to transition to the given target.
+// This means that any already-existing rules will not be applied, and
+// disruptive rules (like denying all device access) will only be applied if
+// necessary.
+//
+// This function is the sole reason for all of Emulator -- to allow us
+// to figure out how to update a containers' cgroups without causing spurrious
+// device errors (if possible).
+func (source *Emulator) Transition(target *Emulator) ([]*configs.DeviceRule, error) {
+ var transitionRules []*configs.DeviceRule
+ oldRules := source.rules
+
+ // If the default policy doesn't match, we need to include a "disruptive"
+ // rule (either allow-all or deny-all) in order to switch the cgroup to the
+ // correct default policy.
+ //
+ // However, due to a limitation in "devices.list" we cannot be sure what
+ // deny rules are in place in a black-list cgroup. Thus if the source is a
+ // black-list we also have to include a disruptive rule.
+ if source.IsBlacklist() || source.defaultAllow != target.defaultAllow {
+ transitionRules = append(transitionRules, &configs.DeviceRule{
+ Type: 'a',
+ Major: -1,
+ Minor: -1,
+ Permissions: configs.DevicePermissions("rwm"),
+ Allow: target.defaultAllow,
+ })
+ // The old rules are only relevant if we aren't starting out with a
+ // disruptive rule.
+ oldRules = nil
+ }
+
+ // NOTE: We traverse through the rules in a sorted order so we always write
+ // the same set of rules (this is to aid testing).
+
+ // First, we create inverse rules for any old rules not in the new set.
+ // This includes partial-inverse rules for specific permissions. This is a
+ // no-op if we added a disruptive rule, since oldRules will be empty.
+ for _, rule := range oldRules.orderedEntries() {
+ meta, oldPerms := rule.meta, rule.perms
+ newPerms := target.rules[meta]
+ droppedPerms := oldPerms.Difference(newPerms)
+ if !droppedPerms.IsEmpty() {
+ transitionRules = append(transitionRules, &configs.DeviceRule{
+ Type: meta.node,
+ Major: meta.major,
+ Minor: meta.minor,
+ Permissions: droppedPerms,
+ Allow: target.defaultAllow,
+ })
+ }
+ }
+
+ // Add any additional rules which weren't in the old set. We happen to
+ // filter out rules which are present in both sets, though this isn't
+ // strictly necessary.
+ for _, rule := range target.rules.orderedEntries() {
+ meta, newPerms := rule.meta, rule.perms
+ oldPerms := oldRules[meta]
+ gainedPerms := newPerms.Difference(oldPerms)
+ if !gainedPerms.IsEmpty() {
+ transitionRules = append(transitionRules, &configs.DeviceRule{
+ Type: meta.node,
+ Major: meta.major,
+ Minor: meta.minor,
+ Permissions: gainedPerms,
+ Allow: !target.defaultAllow,
+ })
+ }
+ }
+ return transitionRules, nil
+}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/ebpf/devicefilter/devicefilter.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/ebpf/devicefilter/devicefilter.go
index 847ce8ef1..b593eb43e 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/ebpf/devicefilter/devicefilter.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/ebpf/devicefilter/devicefilter.go
@@ -22,7 +22,7 @@ const (
)
// DeviceFilter returns eBPF device filter program and its license string
-func DeviceFilter(devices []*configs.Device) (asm.Instructions, string, error) {
+func DeviceFilter(devices []*configs.DeviceRule) (asm.Instructions, string, error) {
p := &program{}
p.init()
for i := len(devices) - 1; i >= 0; i-- {
@@ -49,7 +49,8 @@ func (p *program) init() {
*/
// R2 <- type (lower 16 bit of u32 access_type at R1[0])
p.insts = append(p.insts,
- asm.LoadMem(asm.R2, asm.R1, 0, asm.Half))
+ asm.LoadMem(asm.R2, asm.R1, 0, asm.Word),
+ asm.And.Imm32(asm.R2, 0xFFFF))
// R3 <- access (upper 16 bit of u32 access_type at R1[0])
p.insts = append(p.insts,
@@ -67,7 +68,7 @@ func (p *program) init() {
}
// appendDevice needs to be called from the last element of OCI linux.resources.devices to the head element.
-func (p *program) appendDevice(dev *configs.Device) error {
+func (p *program) appendDevice(dev *configs.DeviceRule) error {
if p.blockID < 0 {
return errors.New("the program is finalized")
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go
deleted file mode 100644
index ec148b489..000000000
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/apply_raw.go
+++ /dev/null
@@ -1,411 +0,0 @@
-// +build linux
-
-package fs
-
-import (
- "fmt"
- "io"
- "os"
- "path/filepath"
- "sync"
-
- "github.com/opencontainers/runc/libcontainer/cgroups"
- "github.com/opencontainers/runc/libcontainer/configs"
- libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils"
- "github.com/pkg/errors"
- "golang.org/x/sys/unix"
-)
-
-var (
- subsystemsLegacy = subsystemSet{
- &CpusetGroup{},
- &DevicesGroup{},
- &MemoryGroup{},
- &CpuGroup{},
- &CpuacctGroup{},
- &PidsGroup{},
- &BlkioGroup{},
- &HugetlbGroup{},
- &NetClsGroup{},
- &NetPrioGroup{},
- &PerfEventGroup{},
- &FreezerGroup{},
- &NameGroup{GroupName: "name=systemd", Join: true},
- }
- HugePageSizes, _ = cgroups.GetHugePageSize()
-)
-
-var errSubsystemDoesNotExist = fmt.Errorf("cgroup: subsystem does not exist")
-
-type subsystemSet []subsystem
-
-func (s subsystemSet) Get(name string) (subsystem, error) {
- for _, ss := range s {
- if ss.Name() == name {
- return ss, nil
- }
- }
- return nil, errSubsystemDoesNotExist
-}
-
-type subsystem interface {
- // Name returns the name of the subsystem.
- Name() string
- // Returns the stats, as 'stats', corresponding to the cgroup under 'path'.
- GetStats(path string, stats *cgroups.Stats) error
- // Removes the cgroup represented by 'cgroupData'.
- Remove(*cgroupData) error
- // Creates and joins the cgroup represented by 'cgroupData'.
- Apply(*cgroupData) error
- // Set the cgroup represented by cgroup.
- Set(path string, cgroup *configs.Cgroup) error
-}
-
-type Manager struct {
- mu sync.Mutex
- Cgroups *configs.Cgroup
- Rootless bool // ignore permission-related errors
- Paths map[string]string
-}
-
-// The absolute path to the root of the cgroup hierarchies.
-var cgroupRootLock sync.Mutex
-var cgroupRoot string
-
-// Gets the cgroupRoot.
-func getCgroupRoot() (string, error) {
- cgroupRootLock.Lock()
- defer cgroupRootLock.Unlock()
-
- if cgroupRoot != "" {
- return cgroupRoot, nil
- }
-
- root, err := cgroups.FindCgroupMountpointDir()
- if err != nil {
- return "", err
- }
-
- if _, err := os.Stat(root); err != nil {
- return "", err
- }
-
- cgroupRoot = root
- return cgroupRoot, nil
-}
-
-type cgroupData struct {
- root string
- innerPath string
- config *configs.Cgroup
- pid int
-}
-
-// isIgnorableError returns whether err is a permission error (in the loose
-// sense of the word). This includes EROFS (which for an unprivileged user is
-// basically a permission error) and EACCES (for similar reasons) as well as
-// the normal EPERM.
-func isIgnorableError(rootless bool, err error) bool {
- // We do not ignore errors if we are root.
- if !rootless {
- return false
- }
- // Is it an ordinary EPERM?
- if os.IsPermission(errors.Cause(err)) {
- return true
- }
-
- // Try to handle other errnos.
- var errno error
- switch err := errors.Cause(err).(type) {
- case *os.PathError:
- errno = err.Err
- case *os.LinkError:
- errno = err.Err
- case *os.SyscallError:
- errno = err.Err
- }
- return errno == unix.EROFS || errno == unix.EPERM || errno == unix.EACCES
-}
-
-func (m *Manager) getSubsystems() subsystemSet {
- return subsystemsLegacy
-}
-
-func (m *Manager) Apply(pid int) (err error) {
- if m.Cgroups == nil {
- return nil
- }
- m.mu.Lock()
- defer m.mu.Unlock()
-
- var c = m.Cgroups
-
- d, err := getCgroupData(m.Cgroups, pid)
- if err != nil {
- return err
- }
-
- m.Paths = make(map[string]string)
- if c.Paths != nil {
- for name, path := range c.Paths {
- _, err := d.path(name)
- if err != nil {
- if cgroups.IsNotFound(err) {
- continue
- }
- return err
- }
- m.Paths[name] = path
- }
- return cgroups.EnterPid(m.Paths, pid)
- }
-
- for _, sys := range m.getSubsystems() {
- // TODO: Apply should, ideally, be reentrant or be broken up into a separate
- // create and join phase so that the cgroup hierarchy for a container can be
- // created then join consists of writing the process pids to cgroup.procs
- p, err := d.path(sys.Name())
- if err != nil {
- // The non-presence of the devices subsystem is
- // considered fatal for security reasons.
- if cgroups.IsNotFound(err) && sys.Name() != "devices" {
- continue
- }
- return err
- }
- m.Paths[sys.Name()] = p
-
- if err := sys.Apply(d); err != nil {
- // In the case of rootless (including euid=0 in userns), where an explicit cgroup path hasn't
- // been set, we don't bail on error in case of permission problems.
- // Cases where limits have been set (and we couldn't create our own
- // cgroup) are handled by Set.
- if isIgnorableError(m.Rootless, err) && m.Cgroups.Path == "" {
- delete(m.Paths, sys.Name())
- continue
- }
- return err
- }
-
- }
- return nil
-}
-
-func (m *Manager) Destroy() error {
- if m.Cgroups == nil || m.Cgroups.Paths != nil {
- return nil
- }
- m.mu.Lock()
- defer m.mu.Unlock()
- if err := cgroups.RemovePaths(m.Paths); err != nil {
- return err
- }
- m.Paths = make(map[string]string)
- return nil
-}
-
-func (m *Manager) GetPaths() map[string]string {
- m.mu.Lock()
- paths := m.Paths
- m.mu.Unlock()
- return paths
-}
-
-func (m *Manager) GetUnifiedPath() (string, error) {
- return "", errors.New("unified path is only supported when running in unified mode")
-}
-
-func (m *Manager) GetStats() (*cgroups.Stats, error) {
- m.mu.Lock()
- defer m.mu.Unlock()
- stats := cgroups.NewStats()
- for name, path := range m.Paths {
- sys, err := m.getSubsystems().Get(name)
- if err == errSubsystemDoesNotExist || !cgroups.PathExists(path) {
- continue
- }
- if err := sys.GetStats(path, stats); err != nil {
- return nil, err
- }
- }
- return stats, nil
-}
-
-func (m *Manager) Set(container *configs.Config) error {
- if container.Cgroups == nil {
- return nil
- }
-
- // If Paths are set, then we are just joining cgroups paths
- // and there is no need to set any values.
- if m.Cgroups != nil && m.Cgroups.Paths != nil {
- return nil
- }
-
- paths := m.GetPaths()
- for _, sys := range m.getSubsystems() {
- path := paths[sys.Name()]
- if err := sys.Set(path, container.Cgroups); err != nil {
- if m.Rootless && sys.Name() == "devices" {
- continue
- }
- // When m.Rootless is true, errors from the device subsystem are ignored because it is really not expected to work.
- // However, errors from other subsystems are not ignored.
- // see @test "runc create (rootless + limits + no cgrouppath + no permission) fails with informative error"
- if path == "" {
- // We never created a path for this cgroup, so we cannot set
- // limits for it (though we have already tried at this point).
- return fmt.Errorf("cannot set %s limit: container could not join or create cgroup", sys.Name())
- }
- return err
- }
- }
-
- if m.Paths["cpu"] != "" {
- if err := CheckCpushares(m.Paths["cpu"], container.Cgroups.Resources.CpuShares); err != nil {
- return err
- }
- }
- return nil
-}
-
-// Freeze toggles the container's freezer cgroup depending on the state
-// provided
-func (m *Manager) Freeze(state configs.FreezerState) error {
- if m.Cgroups == nil {
- return errors.New("cannot toggle freezer: cgroups not configured for container")
- }
-
- paths := m.GetPaths()
- dir := paths["freezer"]
- prevState := m.Cgroups.Resources.Freezer
- m.Cgroups.Resources.Freezer = state
- freezer, err := m.getSubsystems().Get("freezer")
- if err != nil {
- return err
- }
- err = freezer.Set(dir, m.Cgroups)
- if err != nil {
- m.Cgroups.Resources.Freezer = prevState
- return err
- }
- return nil
-}
-
-func (m *Manager) GetPids() ([]int, error) {
- paths := m.GetPaths()
- return cgroups.GetPids(paths["devices"])
-}
-
-func (m *Manager) GetAllPids() ([]int, error) {
- paths := m.GetPaths()
- return cgroups.GetAllPids(paths["devices"])
-}
-
-func getCgroupData(c *configs.Cgroup, pid int) (*cgroupData, error) {
- root, err := getCgroupRoot()
- if err != nil {
- return nil, err
- }
-
- if (c.Name != "" || c.Parent != "") && c.Path != "" {
- return nil, fmt.Errorf("cgroup: either Path or Name and Parent should be used")
- }
-
- // XXX: Do not remove this code. Path safety is important! -- cyphar
- cgPath := libcontainerUtils.CleanPath(c.Path)
- cgParent := libcontainerUtils.CleanPath(c.Parent)
- cgName := libcontainerUtils.CleanPath(c.Name)
-
- innerPath := cgPath
- if innerPath == "" {
- innerPath = filepath.Join(cgParent, cgName)
- }
-
- return &cgroupData{
- root: root,
- innerPath: innerPath,
- config: c,
- pid: pid,
- }, nil
-}
-
-func (raw *cgroupData) path(subsystem string) (string, error) {
- mnt, err := cgroups.FindCgroupMountpoint(raw.root, subsystem)
- // If we didn't mount the subsystem, there is no point we make the path.
- if err != nil {
- return "", err
- }
-
- // If the cgroup name/path is absolute do not look relative to the cgroup of the init process.
- if filepath.IsAbs(raw.innerPath) {
- // Sometimes subsystems can be mounted together as 'cpu,cpuacct'.
- return filepath.Join(raw.root, filepath.Base(mnt), raw.innerPath), nil
- }
-
- // Use GetOwnCgroupPath instead of GetInitCgroupPath, because the creating
- // process could in container and shared pid namespace with host, and
- // /proc/1/cgroup could point to whole other world of cgroups.
- parentPath, err := cgroups.GetOwnCgroupPath(subsystem)
- if err != nil {
- return "", err
- }
-
- return filepath.Join(parentPath, raw.innerPath), nil
-}
-
-func (raw *cgroupData) join(subsystem string) (string, error) {
- path, err := raw.path(subsystem)
- if err != nil {
- return "", err
- }
- if err := os.MkdirAll(path, 0755); err != nil {
- return "", err
- }
- if err := cgroups.WriteCgroupProc(path, raw.pid); err != nil {
- return "", err
- }
- return path, nil
-}
-
-func removePath(p string, err error) error {
- if err != nil {
- return err
- }
- if p != "" {
- return os.RemoveAll(p)
- }
- return nil
-}
-
-func CheckCpushares(path string, c uint64) error {
- var cpuShares uint64
-
- if c == 0 {
- return nil
- }
-
- fd, err := os.Open(filepath.Join(path, "cpu.shares"))
- if err != nil {
- return err
- }
- defer fd.Close()
-
- _, err = fmt.Fscanf(fd, "%d", &cpuShares)
- if err != nil && err != io.EOF {
- return err
- }
-
- if c > cpuShares {
- return fmt.Errorf("The maximum allowed cpu-shares is %d", cpuShares)
- } else if c < cpuShares {
- return fmt.Errorf("The minimum allowed cpu-shares is %d", cpuShares)
- }
-
- return nil
-}
-
-func (m *Manager) GetCgroups() (*configs.Cgroup, error) {
- return m.Cgroups, nil
-}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/blkio.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/blkio.go
index 52c118d68..031a6bbda 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/blkio.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/blkio.go
@@ -22,12 +22,8 @@ func (s *BlkioGroup) Name() string {
return "blkio"
}
-func (s *BlkioGroup) Apply(d *cgroupData) error {
- _, err := d.join("blkio")
- if err != nil && !cgroups.IsNotFound(err) {
- return err
- }
- return nil
+func (s *BlkioGroup) Apply(path string, d *cgroupData) error {
+ return join(path, d.pid)
}
func (s *BlkioGroup) Set(path string, cgroup *configs.Cgroup) error {
@@ -74,10 +70,6 @@ func (s *BlkioGroup) Set(path string, cgroup *configs.Cgroup) error {
return nil
}
-func (s *BlkioGroup) Remove(d *cgroupData) error {
- return removePath(d.path("blkio"))
-}
-
/*
examples:
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu.go
index 4db7b647c..6fb1c2078 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpu.go
@@ -4,6 +4,7 @@ package fs
import (
"bufio"
+ "fmt"
"os"
"path/filepath"
"strconv"
@@ -20,17 +21,7 @@ func (s *CpuGroup) Name() string {
return "cpu"
}
-func (s *CpuGroup) Apply(d *cgroupData) error {
- // We always want to join the cpu group, to allow fair cpu scheduling
- // on a container basis
- path, err := d.path("cpu")
- if err != nil && !cgroups.IsNotFound(err) {
- return err
- }
- return s.ApplyDir(path, d.config, d.pid)
-}
-
-func (s *CpuGroup) ApplyDir(path string, cgroup *configs.Cgroup, pid int) error {
+func (s *CpuGroup) Apply(path string, d *cgroupData) error {
// This might happen if we have no cpu cgroup mounted.
// Just do nothing and don't fail.
if path == "" {
@@ -42,12 +33,12 @@ func (s *CpuGroup) ApplyDir(path string, cgroup *configs.Cgroup, pid int) error
// We should set the real-Time group scheduling settings before moving
// in the process because if the process is already in SCHED_RR mode
// and no RT bandwidth is set, adding it will fail.
- if err := s.SetRtSched(path, cgroup); err != nil {
+ if err := s.SetRtSched(path, d.config); err != nil {
return err
}
- // because we are not using d.join we need to place the pid into the procs file
- // unlike the other subsystems
- return cgroups.WriteCgroupProc(path, pid)
+ // Since we are not using join(), we need to place the pid
+ // into the procs file unlike other subsystems.
+ return cgroups.WriteCgroupProc(path, d.pid)
}
func (s *CpuGroup) SetRtSched(path string, cgroup *configs.Cgroup) error {
@@ -66,9 +57,21 @@ func (s *CpuGroup) SetRtSched(path string, cgroup *configs.Cgroup) error {
func (s *CpuGroup) Set(path string, cgroup *configs.Cgroup) error {
if cgroup.Resources.CpuShares != 0 {
- if err := fscommon.WriteFile(path, "cpu.shares", strconv.FormatUint(cgroup.Resources.CpuShares, 10)); err != nil {
+ shares := cgroup.Resources.CpuShares
+ if err := fscommon.WriteFile(path, "cpu.shares", strconv.FormatUint(shares, 10)); err != nil {
return err
}
+ // read it back
+ sharesRead, err := fscommon.GetCgroupParamUint(path, "cpu.shares")
+ if err != nil {
+ return err
+ }
+ // ... and check
+ if shares > sharesRead {
+ return fmt.Errorf("the maximum allowed cpu-shares is %d", sharesRead)
+ } else if shares < sharesRead {
+ return fmt.Errorf("the minimum allowed cpu-shares is %d", sharesRead)
+ }
}
if cgroup.Resources.CpuPeriod != 0 {
if err := fscommon.WriteFile(path, "cpu.cfs_period_us", strconv.FormatUint(cgroup.Resources.CpuPeriod, 10)); err != nil {
@@ -83,10 +86,6 @@ func (s *CpuGroup) Set(path string, cgroup *configs.Cgroup) error {
return s.SetRtSched(path, cgroup)
}
-func (s *CpuGroup) Remove(d *cgroupData) error {
- return removePath(d.path("cpu"))
-}
-
func (s *CpuGroup) GetStats(path string, stats *cgroups.Stats) error {
f, err := os.Open(filepath.Join(path, "cpu.stat"))
if err != nil {
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuacct.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuacct.go
index 95dc9a1ec..1a18971bc 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuacct.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuacct.go
@@ -3,8 +3,10 @@
package fs
import (
+ "bufio"
"fmt"
"io/ioutil"
+ "os"
"path/filepath"
"strconv"
"strings"
@@ -12,15 +14,24 @@ import (
"github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
"github.com/opencontainers/runc/libcontainer/configs"
- "github.com/opencontainers/runc/libcontainer/system"
)
const (
- cgroupCpuacctStat = "cpuacct.stat"
- nanosecondsInSecond = 1000000000
-)
+ cgroupCpuacctStat = "cpuacct.stat"
+ cgroupCpuacctUsageAll = "cpuacct.usage_all"
-var clockTicks = uint64(system.GetClockTicks())
+ nanosecondsInSecond = 1000000000
+
+ userModeColumn = 1
+ kernelModeColumn = 2
+ cuacctUsageAllColumnsNumber = 3
+
+ // The value comes from `C.sysconf(C._SC_CLK_TCK)`, and
+ // on Linux it's a constant which is safe to be hard coded,
+ // so we can avoid using cgo here. For details, see:
+ // https://github.com/containerd/cgroups/pull/12
+ clockTicks uint64 = 100
+)
type CpuacctGroup struct {
}
@@ -29,24 +40,18 @@ func (s *CpuacctGroup) Name() string {
return "cpuacct"
}
-func (s *CpuacctGroup) Apply(d *cgroupData) error {
- // we just want to join this group even though we don't set anything
- if _, err := d.join("cpuacct"); err != nil && !cgroups.IsNotFound(err) {
- return err
- }
-
- return nil
+func (s *CpuacctGroup) Apply(path string, d *cgroupData) error {
+ return join(path, d.pid)
}
func (s *CpuacctGroup) Set(path string, cgroup *configs.Cgroup) error {
return nil
}
-func (s *CpuacctGroup) Remove(d *cgroupData) error {
- return removePath(d.path("cpuacct"))
-}
-
func (s *CpuacctGroup) GetStats(path string, stats *cgroups.Stats) error {
+ if !cgroups.PathExists(path) {
+ return nil
+ }
userModeUsage, kernelModeUsage, err := getCpuUsageBreakdown(path)
if err != nil {
return err
@@ -62,8 +67,15 @@ func (s *CpuacctGroup) GetStats(path string, stats *cgroups.Stats) error {
return err
}
+ percpuUsageInKernelmode, percpuUsageInUsermode, err := getPercpuUsageInModes(path)
+ if err != nil {
+ return err
+ }
+
stats.CpuStats.CpuUsage.TotalUsage = totalUsage
stats.CpuStats.CpuUsage.PercpuUsage = percpuUsage
+ stats.CpuStats.CpuUsage.PercpuUsageInKernelmode = percpuUsageInKernelmode
+ stats.CpuStats.CpuUsage.PercpuUsageInUsermode = percpuUsageInUsermode
stats.CpuStats.CpuUsage.UsageInUsermode = userModeUsage
stats.CpuStats.CpuUsage.UsageInKernelmode = kernelModeUsage
return nil
@@ -120,3 +132,44 @@ func getPercpuUsage(path string) ([]uint64, error) {
}
return percpuUsage, nil
}
+
+func getPercpuUsageInModes(path string) ([]uint64, []uint64, error) {
+ usageKernelMode := []uint64{}
+ usageUserMode := []uint64{}
+
+ file, err := os.Open(filepath.Join(path, cgroupCpuacctUsageAll))
+ if os.IsNotExist(err) {
+ return usageKernelMode, usageUserMode, nil
+ } else if err != nil {
+ return nil, nil, err
+ }
+ defer file.Close()
+
+ scanner := bufio.NewScanner(file)
+ scanner.Scan() //skipping header line
+
+ for scanner.Scan() {
+ lineFields := strings.SplitN(scanner.Text(), " ", cuacctUsageAllColumnsNumber+1)
+ if len(lineFields) != cuacctUsageAllColumnsNumber {
+ continue
+ }
+
+ usageInKernelMode, err := strconv.ParseUint(lineFields[kernelModeColumn], 10, 64)
+ if err != nil {
+ return nil, nil, fmt.Errorf("Unable to convert CPU usage in kernel mode to uint64: %s", err)
+ }
+ usageKernelMode = append(usageKernelMode, usageInKernelMode)
+
+ usageInUserMode, err := strconv.ParseUint(lineFields[userModeColumn], 10, 64)
+ if err != nil {
+ return nil, nil, fmt.Errorf("Unable to convert CPU usage in user mode to uint64: %s", err)
+ }
+ usageUserMode = append(usageUserMode, usageInUserMode)
+ }
+
+ if err := scanner.Err(); err != nil {
+ return nil, nil, fmt.Errorf("Problem in reading %s line by line, %s", cgroupCpuacctUsageAll, err)
+ }
+
+ return usageKernelMode, usageUserMode, nil
+}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go
index bfc900e3f..ba17519ba 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/cpuset.go
@@ -4,15 +4,16 @@ package fs
import (
"bytes"
- "fmt"
"io/ioutil"
"os"
"path/filepath"
+ "github.com/moby/sys/mountinfo"
"github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
"github.com/opencontainers/runc/libcontainer/configs"
libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils"
+ "github.com/pkg/errors"
)
type CpusetGroup struct {
@@ -22,12 +23,8 @@ func (s *CpusetGroup) Name() string {
return "cpuset"
}
-func (s *CpusetGroup) Apply(d *cgroupData) error {
- dir, err := d.path("cpuset")
- if err != nil && !cgroups.IsNotFound(err) {
- return err
- }
- return s.ApplyDir(dir, d.config, d.pid)
+func (s *CpusetGroup) Apply(path string, d *cgroupData) error {
+ return s.ApplyDir(path, d.config, d.pid)
}
func (s *CpusetGroup) Set(path string, cgroup *configs.Cgroup) error {
@@ -44,25 +41,43 @@ func (s *CpusetGroup) Set(path string, cgroup *configs.Cgroup) error {
return nil
}
-func (s *CpusetGroup) Remove(d *cgroupData) error {
- return removePath(d.path("cpuset"))
-}
-
func (s *CpusetGroup) GetStats(path string, stats *cgroups.Stats) error {
return nil
}
+// Get the source mount point of directory passed in as argument.
+func getMount(dir string) (string, error) {
+ mi, err := mountinfo.GetMounts(mountinfo.ParentsFilter(dir))
+ if err != nil {
+ return "", err
+ }
+ if len(mi) < 1 {
+ return "", errors.Errorf("Can't find mount point of %s", dir)
+ }
+
+ // find the longest mount point
+ var idx, maxlen int
+ for i := range mi {
+ if len(mi[i].Mountpoint) > maxlen {
+ maxlen = len(mi[i].Mountpoint)
+ idx = i
+ }
+ }
+
+ return mi[idx].Mountpoint, nil
+}
+
func (s *CpusetGroup) ApplyDir(dir string, cgroup *configs.Cgroup, pid int) error {
// This might happen if we have no cpuset cgroup mounted.
// Just do nothing and don't fail.
if dir == "" {
return nil
}
- mountInfo, err := ioutil.ReadFile("/proc/self/mountinfo")
+ root, err := getMount(dir)
if err != nil {
return err
}
- root := filepath.Dir(cgroups.GetClosestMountpointAncestor(dir, string(mountInfo)))
+ root = filepath.Dir(root)
// 'ensureParent' start with parent because we don't want to
// explicitly inherit from parent, it could conflict with
// 'cpuset.cpu_exclusive'.
@@ -108,7 +123,7 @@ func (s *CpusetGroup) ensureParent(current, root string) error {
}
// Avoid infinite recursion.
if parent == current {
- return fmt.Errorf("cpuset: cgroup parent path outside cgroup root")
+ return errors.New("cpuset: cgroup parent path outside cgroup root")
}
if err := s.ensureParent(parent, root); err != nil {
return err
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices.go
index 036c8db77..fd8f00d5b 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/devices.go
@@ -3,79 +3,108 @@
package fs
import (
+ "bytes"
+ "errors"
+ "reflect"
+
"github.com/opencontainers/runc/libcontainer/cgroups"
+ "github.com/opencontainers/runc/libcontainer/cgroups/devices"
"github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runc/libcontainer/system"
)
type DevicesGroup struct {
+ testingSkipFinalCheck bool
}
func (s *DevicesGroup) Name() string {
return "devices"
}
-func (s *DevicesGroup) Apply(d *cgroupData) error {
- _, err := d.join("devices")
- if err != nil {
- // We will return error even it's `not found` error, devices
- // cgroup is hard requirement for container's security.
- return err
+func (s *DevicesGroup) Apply(path string, d *cgroupData) error {
+ if d.config.SkipDevices {
+ return nil
}
- return nil
+ if path == "" {
+ // Return error here, since devices cgroup
+ // is a hard requirement for container's security.
+ return errSubsystemDoesNotExist
+ }
+ return join(path, d.pid)
+}
+
+func loadEmulator(path string) (*devices.Emulator, error) {
+ list, err := fscommon.ReadFile(path, "devices.list")
+ if err != nil {
+ return nil, err
+ }
+ return devices.EmulatorFromList(bytes.NewBufferString(list))
+}
+
+func buildEmulator(rules []*configs.DeviceRule) (*devices.Emulator, error) {
+ // This defaults to a white-list -- which is what we want!
+ emu := &devices.Emulator{}
+ for _, rule := range rules {
+ if err := emu.Apply(*rule); err != nil {
+ return nil, err
+ }
+ }
+ return emu, nil
}
func (s *DevicesGroup) Set(path string, cgroup *configs.Cgroup) error {
- if system.RunningInUserNS() {
+ if system.RunningInUserNS() || cgroup.SkipDevices {
return nil
}
- devices := cgroup.Resources.Devices
- if len(devices) > 0 {
- for _, dev := range devices {
- file := "devices.deny"
- if dev.Allow {
- file = "devices.allow"
- }
- if err := fscommon.WriteFile(path, file, dev.CgroupString()); err != nil {
- return err
- }
- }
- return nil
+ // Generate two emulators, one for the current state of the cgroup and one
+ // for the requested state by the user.
+ current, err := loadEmulator(path)
+ if err != nil {
+ return err
+ }
+ target, err := buildEmulator(cgroup.Resources.Devices)
+ if err != nil {
+ return err
}
- if cgroup.Resources.AllowAllDevices != nil {
- if *cgroup.Resources.AllowAllDevices == false {
- if err := fscommon.WriteFile(path, "devices.deny", "a"); err != nil {
- return err
- }
- for _, dev := range cgroup.Resources.AllowedDevices {
- if err := fscommon.WriteFile(path, "devices.allow", dev.CgroupString()); err != nil {
- return err
- }
- }
- return nil
+ // Compute the minimal set of transition rules needed to achieve the
+ // requested state.
+ transitionRules, err := current.Transition(target)
+ if err != nil {
+ return err
+ }
+ for _, rule := range transitionRules {
+ file := "devices.deny"
+ if rule.Allow {
+ file = "devices.allow"
}
-
- if err := fscommon.WriteFile(path, "devices.allow", "a"); err != nil {
+ if err := fscommon.WriteFile(path, file, rule.CgroupString()); err != nil {
return err
}
}
- for _, dev := range cgroup.Resources.DeniedDevices {
- if err := fscommon.WriteFile(path, "devices.deny", dev.CgroupString()); err != nil {
+ // Final safety check -- ensure that the resulting state is what was
+ // requested. This is only really correct for white-lists, but for
+ // black-lists we can at least check that the cgroup is in the right mode.
+ //
+ // This safety-check is skipped for the unit tests because we cannot
+ // currently mock devices.list correctly.
+ if !s.testingSkipFinalCheck {
+ currentAfter, err := loadEmulator(path)
+ if err != nil {
return err
}
+ if !target.IsBlacklist() && !reflect.DeepEqual(currentAfter, target) {
+ return errors.New("resulting devices cgroup doesn't precisely match target")
+ } else if target.IsBlacklist() != currentAfter.IsBlacklist() {
+ return errors.New("resulting devices cgroup doesn't match target mode")
+ }
}
-
return nil
}
-func (s *DevicesGroup) Remove(d *cgroupData) error {
- return removePath(d.path("devices"))
-}
-
func (s *DevicesGroup) GetStats(path string, stats *cgroups.Stats) error {
return nil
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/freezer.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/freezer.go
index 9dc81bdb8..11cb1646f 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/freezer.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/freezer.go
@@ -3,13 +3,16 @@
package fs
import (
+ "errors"
"fmt"
+ "os"
"strings"
"time"
"github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
"github.com/opencontainers/runc/libcontainer/configs"
+ "golang.org/x/sys/unix"
)
type FreezerGroup struct {
@@ -19,12 +22,8 @@ func (s *FreezerGroup) Name() string {
return "freezer"
}
-func (s *FreezerGroup) Apply(d *cgroupData) error {
- _, err := d.join("freezer")
- if err != nil && !cgroups.IsNotFound(err) {
- return err
- }
- return nil
+func (s *FreezerGroup) Apply(path string, d *cgroupData) error {
+ return join(path, d.pid)
}
func (s *FreezerGroup) Set(path string, cgroup *configs.Cgroup) error {
@@ -39,11 +38,11 @@ func (s *FreezerGroup) Set(path string, cgroup *configs.Cgroup) error {
return err
}
- state, err := fscommon.ReadFile(path, "freezer.state")
+ state, err := s.GetState(path)
if err != nil {
return err
}
- if strings.TrimSpace(state) == string(cgroup.Resources.Freezer) {
+ if state == cgroup.Resources.Freezer {
break
}
@@ -58,10 +57,33 @@ func (s *FreezerGroup) Set(path string, cgroup *configs.Cgroup) error {
return nil
}
-func (s *FreezerGroup) Remove(d *cgroupData) error {
- return removePath(d.path("freezer"))
-}
-
func (s *FreezerGroup) GetStats(path string, stats *cgroups.Stats) error {
return nil
}
+
+func (s *FreezerGroup) GetState(path string) (configs.FreezerState, error) {
+ for {
+ state, err := fscommon.ReadFile(path, "freezer.state")
+ if err != nil {
+ // If the kernel is too old, then we just treat the freezer as
+ // being in an "undefined" state.
+ if os.IsNotExist(err) || errors.Is(err, unix.ENODEV) {
+ err = nil
+ }
+ return configs.Undefined, err
+ }
+ switch strings.TrimSpace(state) {
+ case "THAWED":
+ return configs.Thawed, nil
+ case "FROZEN":
+ return configs.Frozen, nil
+ case "FREEZING":
+ // Make sure we get a stable freezer state, so retry if the cgroup
+ // is still undergoing freezing. This should be a temporary delay.
+ time.Sleep(1 * time.Millisecond)
+ continue
+ default:
+ return configs.Undefined, fmt.Errorf("unknown freezer.state %q", state)
+ }
+ }
+}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/fs.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/fs.go
new file mode 100644
index 000000000..3ccf3a3c6
--- /dev/null
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/fs.go
@@ -0,0 +1,460 @@
+// +build linux
+
+package fs
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "path/filepath"
+ "strings"
+ "sync"
+
+ "github.com/opencontainers/runc/libcontainer/cgroups"
+ "github.com/opencontainers/runc/libcontainer/configs"
+ libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils"
+ "github.com/pkg/errors"
+ "golang.org/x/sys/unix"
+)
+
+var (
+ subsystems = []subsystem{
+ &CpusetGroup{},
+ &DevicesGroup{},
+ &MemoryGroup{},
+ &CpuGroup{},
+ &CpuacctGroup{},
+ &PidsGroup{},
+ &BlkioGroup{},
+ &HugetlbGroup{},
+ &NetClsGroup{},
+ &NetPrioGroup{},
+ &PerfEventGroup{},
+ &FreezerGroup{},
+ &NameGroup{GroupName: "name=systemd", Join: true},
+ }
+ HugePageSizes, _ = cgroups.GetHugePageSize()
+)
+
+var errSubsystemDoesNotExist = errors.New("cgroup: subsystem does not exist")
+
+type subsystem interface {
+ // Name returns the name of the subsystem.
+ Name() string
+ // Returns the stats, as 'stats', corresponding to the cgroup under 'path'.
+ GetStats(path string, stats *cgroups.Stats) error
+ // Creates and joins the cgroup represented by 'cgroupData'.
+ Apply(path string, c *cgroupData) error
+ // Set the cgroup represented by cgroup.
+ Set(path string, cgroup *configs.Cgroup) error
+}
+
+type manager struct {
+ mu sync.Mutex
+ cgroups *configs.Cgroup
+ rootless bool // ignore permission-related errors
+ paths map[string]string
+}
+
+func NewManager(cg *configs.Cgroup, paths map[string]string, rootless bool) cgroups.Manager {
+ return &manager{
+ cgroups: cg,
+ paths: paths,
+ rootless: rootless,
+ }
+}
+
+// The absolute path to the root of the cgroup hierarchies.
+var cgroupRootLock sync.Mutex
+var cgroupRoot string
+
+const defaultCgroupRoot = "/sys/fs/cgroup"
+
+func tryDefaultCgroupRoot() string {
+ var st, pst unix.Stat_t
+
+ // (1) it should be a directory...
+ err := unix.Lstat(defaultCgroupRoot, &st)
+ if err != nil || st.Mode&unix.S_IFDIR == 0 {
+ return ""
+ }
+
+ // (2) ... and a mount point ...
+ err = unix.Lstat(filepath.Dir(defaultCgroupRoot), &pst)
+ if err != nil {
+ return ""
+ }
+
+ if st.Dev == pst.Dev {
+ // parent dir has the same dev -- not a mount point
+ return ""
+ }
+
+ // (3) ... of 'tmpfs' fs type.
+ var fst unix.Statfs_t
+ err = unix.Statfs(defaultCgroupRoot, &fst)
+ if err != nil || fst.Type != unix.TMPFS_MAGIC {
+ return ""
+ }
+
+ // (4) it should have at least 1 entry ...
+ dir, err := os.Open(defaultCgroupRoot)
+ if err != nil {
+ return ""
+ }
+ names, err := dir.Readdirnames(1)
+ if err != nil {
+ return ""
+ }
+ if len(names) < 1 {
+ return ""
+ }
+ // ... which is a cgroup mount point.
+ err = unix.Statfs(filepath.Join(defaultCgroupRoot, names[0]), &fst)
+ if err != nil || fst.Type != unix.CGROUP_SUPER_MAGIC {
+ return ""
+ }
+
+ return defaultCgroupRoot
+}
+
+// Gets the cgroupRoot.
+func getCgroupRoot() (string, error) {
+ cgroupRootLock.Lock()
+ defer cgroupRootLock.Unlock()
+
+ if cgroupRoot != "" {
+ return cgroupRoot, nil
+ }
+
+ // fast path
+ cgroupRoot = tryDefaultCgroupRoot()
+ if cgroupRoot != "" {
+ return cgroupRoot, nil
+ }
+
+ // slow path: parse mountinfo, find the first mount where fs=cgroup
+ // (e.g. "/sys/fs/cgroup/memory"), use its parent.
+ f, err := os.Open("/proc/self/mountinfo")
+ if err != nil {
+ return "", err
+ }
+ defer f.Close()
+
+ var root string
+ scanner := bufio.NewScanner(f)
+ for scanner.Scan() {
+ text := scanner.Text()
+ fields := strings.Split(text, " ")
+ // Safe as mountinfo encodes mountpoints with spaces as \040.
+ index := strings.Index(text, " - ")
+ postSeparatorFields := strings.Fields(text[index+3:])
+ numPostFields := len(postSeparatorFields)
+
+ // This is an error as we can't detect if the mount is for "cgroup"
+ if numPostFields == 0 {
+ return "", fmt.Errorf("mountinfo: found no fields post '-' in %q", text)
+ }
+
+ if postSeparatorFields[0] == "cgroup" {
+ // Check that the mount is properly formatted.
+ if numPostFields < 3 {
+ return "", fmt.Errorf("Error found less than 3 fields post '-' in %q", text)
+ }
+
+ root = filepath.Dir(fields[4])
+ break
+ }
+ }
+ if err := scanner.Err(); err != nil {
+ return "", err
+ }
+ if root == "" {
+ return "", errors.New("no cgroup mount found in mountinfo")
+ }
+
+ if _, err := os.Stat(root); err != nil {
+ return "", err
+ }
+
+ cgroupRoot = root
+ return cgroupRoot, nil
+}
+
+type cgroupData struct {
+ root string
+ innerPath string
+ config *configs.Cgroup
+ pid int
+}
+
+// isIgnorableError returns whether err is a permission error (in the loose
+// sense of the word). This includes EROFS (which for an unprivileged user is
+// basically a permission error) and EACCES (for similar reasons) as well as
+// the normal EPERM.
+func isIgnorableError(rootless bool, err error) bool {
+ // We do not ignore errors if we are root.
+ if !rootless {
+ return false
+ }
+ // TODO: rm errors.Cause once we switch to %w everywhere
+ err = errors.Cause(err)
+ // Is it an ordinary EPERM?
+ if errors.Is(err, os.ErrPermission) {
+ return true
+ }
+ // Handle some specific syscall errors.
+ var errno unix.Errno
+ if errors.As(err, &errno) {
+ return errno == unix.EROFS || errno == unix.EPERM || errno == unix.EACCES
+ }
+ return false
+}
+
+func (m *manager) Apply(pid int) (err error) {
+ if m.cgroups == nil {
+ return nil
+ }
+ m.mu.Lock()
+ defer m.mu.Unlock()
+
+ var c = m.cgroups
+
+ d, err := getCgroupData(m.cgroups, pid)
+ if err != nil {
+ return err
+ }
+
+ m.paths = make(map[string]string)
+ if c.Paths != nil {
+ for name, path := range c.Paths {
+ _, err := d.path(name)
+ if err != nil {
+ if cgroups.IsNotFound(err) {
+ continue
+ }
+ return err
+ }
+ m.paths[name] = path
+ }
+ return cgroups.EnterPid(m.paths, pid)
+ }
+
+ for _, sys := range subsystems {
+ p, err := d.path(sys.Name())
+ if err != nil {
+ // The non-presence of the devices subsystem is
+ // considered fatal for security reasons.
+ if cgroups.IsNotFound(err) && (c.SkipDevices || sys.Name() != "devices") {
+ continue
+ }
+ return err
+ }
+ m.paths[sys.Name()] = p
+
+ if err := sys.Apply(p, d); err != nil {
+ // In the case of rootless (including euid=0 in userns), where an
+ // explicit cgroup path hasn't been set, we don't bail on error in
+ // case of permission problems. Cases where limits have been set
+ // (and we couldn't create our own cgroup) are handled by Set.
+ if isIgnorableError(m.rootless, err) && m.cgroups.Path == "" {
+ delete(m.paths, sys.Name())
+ continue
+ }
+ return err
+ }
+
+ }
+ return nil
+}
+
+func (m *manager) Destroy() error {
+ if m.cgroups == nil || m.cgroups.Paths != nil {
+ return nil
+ }
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if err := cgroups.RemovePaths(m.paths); err != nil {
+ return err
+ }
+ m.paths = make(map[string]string)
+ return nil
+}
+
+func (m *manager) Path(subsys string) string {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ return m.paths[subsys]
+}
+
+func (m *manager) GetStats() (*cgroups.Stats, error) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ stats := cgroups.NewStats()
+ for _, sys := range subsystems {
+ path := m.paths[sys.Name()]
+ if path == "" {
+ continue
+ }
+ if err := sys.GetStats(path, stats); err != nil {
+ return nil, err
+ }
+ }
+ return stats, nil
+}
+
+func (m *manager) Set(container *configs.Config) error {
+ if container.Cgroups == nil {
+ return nil
+ }
+
+ // If Paths are set, then we are just joining cgroups paths
+ // and there is no need to set any values.
+ if m.cgroups != nil && m.cgroups.Paths != nil {
+ return nil
+ }
+
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ for _, sys := range subsystems {
+ path := m.paths[sys.Name()]
+ if err := sys.Set(path, container.Cgroups); err != nil {
+ if m.rootless && sys.Name() == "devices" {
+ continue
+ }
+ // When m.Rootless is true, errors from the device subsystem are ignored because it is really not expected to work.
+ // However, errors from other subsystems are not ignored.
+ // see @test "runc create (rootless + limits + no cgrouppath + no permission) fails with informative error"
+ if path == "" {
+ // We never created a path for this cgroup, so we cannot set
+ // limits for it (though we have already tried at this point).
+ return fmt.Errorf("cannot set %s limit: container could not join or create cgroup", sys.Name())
+ }
+ return err
+ }
+ }
+
+ return nil
+}
+
+// Freeze toggles the container's freezer cgroup depending on the state
+// provided
+func (m *manager) Freeze(state configs.FreezerState) error {
+ path := m.Path("freezer")
+ if m.cgroups == nil || path == "" {
+ return errors.New("cannot toggle freezer: cgroups not configured for container")
+ }
+
+ prevState := m.cgroups.Resources.Freezer
+ m.cgroups.Resources.Freezer = state
+ freezer := &FreezerGroup{}
+ if err := freezer.Set(path, m.cgroups); err != nil {
+ m.cgroups.Resources.Freezer = prevState
+ return err
+ }
+ return nil
+}
+
+func (m *manager) GetPids() ([]int, error) {
+ return cgroups.GetPids(m.Path("devices"))
+}
+
+func (m *manager) GetAllPids() ([]int, error) {
+ return cgroups.GetAllPids(m.Path("devices"))
+}
+
+func getCgroupData(c *configs.Cgroup, pid int) (*cgroupData, error) {
+ root, err := getCgroupRoot()
+ if err != nil {
+ return nil, err
+ }
+
+ if (c.Name != "" || c.Parent != "") && c.Path != "" {
+ return nil, errors.New("cgroup: either Path or Name and Parent should be used")
+ }
+
+ // XXX: Do not remove this code. Path safety is important! -- cyphar
+ cgPath := libcontainerUtils.CleanPath(c.Path)
+ cgParent := libcontainerUtils.CleanPath(c.Parent)
+ cgName := libcontainerUtils.CleanPath(c.Name)
+
+ innerPath := cgPath
+ if innerPath == "" {
+ innerPath = filepath.Join(cgParent, cgName)
+ }
+
+ return &cgroupData{
+ root: root,
+ innerPath: innerPath,
+ config: c,
+ pid: pid,
+ }, nil
+}
+
+func (raw *cgroupData) path(subsystem string) (string, error) {
+ // If the cgroup name/path is absolute do not look relative to the cgroup of the init process.
+ if filepath.IsAbs(raw.innerPath) {
+ mnt, err := cgroups.FindCgroupMountpoint(raw.root, subsystem)
+ // If we didn't mount the subsystem, there is no point we make the path.
+ if err != nil {
+ return "", err
+ }
+
+ // Sometimes subsystems can be mounted together as 'cpu,cpuacct'.
+ return filepath.Join(raw.root, filepath.Base(mnt), raw.innerPath), nil
+ }
+
+ // Use GetOwnCgroupPath instead of GetInitCgroupPath, because the creating
+ // process could in container and shared pid namespace with host, and
+ // /proc/1/cgroup could point to whole other world of cgroups.
+ parentPath, err := cgroups.GetOwnCgroupPath(subsystem)
+ if err != nil {
+ return "", err
+ }
+
+ return filepath.Join(parentPath, raw.innerPath), nil
+}
+
+func join(path string, pid int) error {
+ if path == "" {
+ return nil
+ }
+ if err := os.MkdirAll(path, 0755); err != nil {
+ return err
+ }
+ return cgroups.WriteCgroupProc(path, pid)
+}
+
+func removePath(p string, err error) error {
+ if err != nil {
+ return err
+ }
+ if p != "" {
+ return os.RemoveAll(p)
+ }
+ return nil
+}
+
+func (m *manager) GetPaths() map[string]string {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ return m.paths
+}
+
+func (m *manager) GetCgroups() (*configs.Cgroup, error) {
+ return m.cgroups, nil
+}
+
+func (m *manager) GetFreezerState() (configs.FreezerState, error) {
+ dir := m.Path("freezer")
+ // If the container doesn't have the freezer cgroup, say it's undefined.
+ if dir == "" {
+ return configs.Undefined, nil
+ }
+ freezer := &FreezerGroup{}
+ return freezer.GetState(dir)
+}
+
+func (m *manager) Exists() bool {
+ return cgroups.PathExists(m.Path("devices"))
+}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/hugetlb.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/hugetlb.go
index 68719c2e6..d32d02da1 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/hugetlb.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/hugetlb.go
@@ -19,12 +19,8 @@ func (s *HugetlbGroup) Name() string {
return "hugetlb"
}
-func (s *HugetlbGroup) Apply(d *cgroupData) error {
- _, err := d.join("hugetlb")
- if err != nil && !cgroups.IsNotFound(err) {
- return err
- }
- return nil
+func (s *HugetlbGroup) Apply(path string, d *cgroupData) error {
+ return join(path, d.pid)
}
func (s *HugetlbGroup) Set(path string, cgroup *configs.Cgroup) error {
@@ -37,12 +33,11 @@ func (s *HugetlbGroup) Set(path string, cgroup *configs.Cgroup) error {
return nil
}
-func (s *HugetlbGroup) Remove(d *cgroupData) error {
- return removePath(d.path("hugetlb"))
-}
-
func (s *HugetlbGroup) GetStats(path string, stats *cgroups.Stats) error {
hugetlbStats := cgroups.HugetlbStats{}
+ if !cgroups.PathExists(path) {
+ return nil
+ }
for _, pageSize := range HugePageSizes {
usage := strings.Join([]string{"hugetlb", pageSize, "usage_in_bytes"}, ".")
value, err := fscommon.GetCgroupParamUint(path, usage)
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/kmem.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/kmem.go
index 69b5a1946..8d97a6791 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/kmem.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/kmem.go
@@ -6,10 +6,8 @@ import (
"errors"
"fmt"
"io/ioutil"
- "os"
"path/filepath"
"strconv"
- "syscall" // for Errno type only
"github.com/opencontainers/runc/libcontainer/cgroups"
"golang.org/x/sys/unix"
@@ -49,12 +47,8 @@ func setKernelMemory(path string, kernelMemoryLimit int64) error {
// The EBUSY signal is returned on attempts to write to the
// memory.kmem.limit_in_bytes file if the cgroup has children or
// once tasks have been attached to the cgroup
- if pathErr, ok := err.(*os.PathError); ok {
- if errNo, ok := pathErr.Err.(syscall.Errno); ok {
- if errNo == unix.EBUSY {
- return fmt.Errorf("failed to set %s, because either tasks have already joined this cgroup or it has children", cgroupKernelMemoryLimit)
- }
- }
+ if errors.Is(err, unix.EBUSY) {
+ return fmt.Errorf("failed to set %s, because either tasks have already joined this cgroup or it has children", cgroupKernelMemoryLimit)
}
return fmt.Errorf("failed to write %v to %v: %v", kernelMemoryLimit, cgroupKernelMemoryLimit, err)
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go
index f81ed050b..41adcd38f 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go
@@ -5,7 +5,9 @@ package fs
import (
"bufio"
"fmt"
+ "math"
"os"
+ "path"
"path/filepath"
"strconv"
"strings"
@@ -16,8 +18,16 @@ import (
)
const (
- cgroupMemorySwapLimit = "memory.memsw.limit_in_bytes"
- cgroupMemoryLimit = "memory.limit_in_bytes"
+ numaNodeSymbol = "N"
+ numaStatColumnSeparator = " "
+ numaStatKeyValueSeparator = "="
+ numaStatMaxColumns = math.MaxUint8 + 1
+ numaStatValueIndex = 1
+ numaStatTypeIndex = 0
+ numaStatColumnSliceLength = 2
+ cgroupMemorySwapLimit = "memory.memsw.limit_in_bytes"
+ cgroupMemoryLimit = "memory.limit_in_bytes"
+ cgroupMemoryPagesByNuma = "memory.numa_stat"
)
type MemoryGroup struct {
@@ -27,11 +37,8 @@ func (s *MemoryGroup) Name() string {
return "memory"
}
-func (s *MemoryGroup) Apply(d *cgroupData) (err error) {
- path, err := d.path("memory")
- if err != nil && !cgroups.IsNotFound(err) {
- return err
- } else if path == "" {
+func (s *MemoryGroup) Apply(path string, d *cgroupData) (err error) {
+ if path == "" {
return nil
}
if memoryAssigned(d.config) {
@@ -56,17 +63,13 @@ func (s *MemoryGroup) Apply(d *cgroupData) (err error) {
// We need to join memory cgroup after set memory limits, because
// kmem.limit_in_bytes can only be set when the cgroup is empty.
- _, err = d.join("memory")
- if err != nil && !cgroups.IsNotFound(err) {
- return err
- }
- return nil
+ return join(path, d.pid)
}
func setMemoryAndSwap(path string, cgroup *configs.Cgroup) error {
- // If the memory update is set to -1 we should also
- // set swap to -1, it means unlimited memory.
- if cgroup.Resources.Memory == -1 {
+ // If the memory update is set to -1 and the swap is not explicitly
+ // set, we should also set swap to -1, it means unlimited memory.
+ if cgroup.Resources.Memory == -1 && cgroup.Resources.MemorySwap == 0 {
// Only set swap if it's enabled in kernel
if cgroups.PathExists(filepath.Join(path, cgroupMemorySwapLimit)) {
cgroup.Resources.MemorySwap = -1
@@ -155,10 +158,6 @@ func (s *MemoryGroup) Set(path string, cgroup *configs.Cgroup) error {
return nil
}
-func (s *MemoryGroup) Remove(d *cgroupData) error {
- return removePath(d.path("memory"))
-}
-
func (s *MemoryGroup) GetStats(path string, stats *cgroups.Stats) error {
// Set stats from memory.stat.
statsFile, err := os.Open(filepath.Join(path, "memory.stat"))
@@ -209,6 +208,13 @@ func (s *MemoryGroup) GetStats(path string, stats *cgroups.Stats) error {
if value == 1 {
stats.MemoryStats.UseHierarchy = true
}
+
+ pagesByNUMA, err := getPageUsageByNUMA(path)
+ if err != nil {
+ return err
+ }
+ stats.MemoryStats.PageUsageByNUMA = pagesByNUMA
+
return nil
}
@@ -269,3 +275,79 @@ func getMemoryData(path, name string) (cgroups.MemoryData, error) {
return memoryData, nil
}
+
+func getPageUsageByNUMA(cgroupPath string) (cgroups.PageUsageByNUMA, error) {
+ stats := cgroups.PageUsageByNUMA{}
+
+ file, err := os.Open(path.Join(cgroupPath, cgroupMemoryPagesByNuma))
+ if os.IsNotExist(err) {
+ return stats, nil
+ } else if err != nil {
+ return stats, err
+ }
+
+ scanner := bufio.NewScanner(file)
+ for scanner.Scan() {
+ var statsType string
+ statsByType := cgroups.PageStats{Nodes: map[uint8]uint64{}}
+ columns := strings.SplitN(scanner.Text(), numaStatColumnSeparator, numaStatMaxColumns)
+
+ for _, column := range columns {
+ pagesByNode := strings.SplitN(column, numaStatKeyValueSeparator, numaStatColumnSliceLength)
+
+ if strings.HasPrefix(pagesByNode[numaStatTypeIndex], numaNodeSymbol) {
+ nodeID, err := strconv.ParseUint(pagesByNode[numaStatTypeIndex][1:], 10, 8)
+ if err != nil {
+ return cgroups.PageUsageByNUMA{}, err
+ }
+
+ statsByType.Nodes[uint8(nodeID)], err = strconv.ParseUint(pagesByNode[numaStatValueIndex], 0, 64)
+ if err != nil {
+ return cgroups.PageUsageByNUMA{}, err
+ }
+ } else {
+ statsByType.Total, err = strconv.ParseUint(pagesByNode[numaStatValueIndex], 0, 64)
+ if err != nil {
+ return cgroups.PageUsageByNUMA{}, err
+ }
+
+ statsType = pagesByNode[numaStatTypeIndex]
+ }
+
+ err := addNUMAStatsByType(&stats, statsByType, statsType)
+ if err != nil {
+ return cgroups.PageUsageByNUMA{}, err
+ }
+ }
+ }
+ err = scanner.Err()
+ if err != nil {
+ return cgroups.PageUsageByNUMA{}, err
+ }
+
+ return stats, nil
+}
+
+func addNUMAStatsByType(stats *cgroups.PageUsageByNUMA, byTypeStats cgroups.PageStats, statsType string) error {
+ switch statsType {
+ case "total":
+ stats.Total = byTypeStats
+ case "file":
+ stats.File = byTypeStats
+ case "anon":
+ stats.Anon = byTypeStats
+ case "unevictable":
+ stats.Unevictable = byTypeStats
+ case "hierarchical_total":
+ stats.Hierarchical.Total = byTypeStats
+ case "hierarchical_file":
+ stats.Hierarchical.File = byTypeStats
+ case "hierarchical_anon":
+ stats.Hierarchical.Anon = byTypeStats
+ case "hierarchical_unevictable":
+ stats.Hierarchical.Unevictable = byTypeStats
+ default:
+ return fmt.Errorf("unsupported NUMA page type found: %s", statsType)
+ }
+ return nil
+}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/name.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/name.go
index d8cf1d87c..9a5af709d 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/name.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/name.go
@@ -16,10 +16,10 @@ func (s *NameGroup) Name() string {
return s.GroupName
}
-func (s *NameGroup) Apply(d *cgroupData) error {
+func (s *NameGroup) Apply(path string, d *cgroupData) error {
if s.Join {
// ignore errors if the named cgroup does not exist
- d.join(s.GroupName)
+ join(path, d.pid)
}
return nil
}
@@ -28,13 +28,6 @@ func (s *NameGroup) Set(path string, cgroup *configs.Cgroup) error {
return nil
}
-func (s *NameGroup) Remove(d *cgroupData) error {
- if s.Join {
- removePath(d.path(s.GroupName))
- }
- return nil
-}
-
func (s *NameGroup) GetStats(path string, stats *cgroups.Stats) error {
return nil
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_cls.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_cls.go
index 021201525..901e95544 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_cls.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_cls.go
@@ -17,12 +17,8 @@ func (s *NetClsGroup) Name() string {
return "net_cls"
}
-func (s *NetClsGroup) Apply(d *cgroupData) error {
- _, err := d.join("net_cls")
- if err != nil && !cgroups.IsNotFound(err) {
- return err
- }
- return nil
+func (s *NetClsGroup) Apply(path string, d *cgroupData) error {
+ return join(path, d.pid)
}
func (s *NetClsGroup) Set(path string, cgroup *configs.Cgroup) error {
@@ -35,10 +31,6 @@ func (s *NetClsGroup) Set(path string, cgroup *configs.Cgroup) error {
return nil
}
-func (s *NetClsGroup) Remove(d *cgroupData) error {
- return removePath(d.path("net_cls"))
-}
-
func (s *NetClsGroup) GetStats(path string, stats *cgroups.Stats) error {
return nil
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_prio.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_prio.go
index 2bdeedf80..a9645de26 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_prio.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/net_prio.go
@@ -15,12 +15,8 @@ func (s *NetPrioGroup) Name() string {
return "net_prio"
}
-func (s *NetPrioGroup) Apply(d *cgroupData) error {
- _, err := d.join("net_prio")
- if err != nil && !cgroups.IsNotFound(err) {
- return err
- }
- return nil
+func (s *NetPrioGroup) Apply(path string, d *cgroupData) error {
+ return join(path, d.pid)
}
func (s *NetPrioGroup) Set(path string, cgroup *configs.Cgroup) error {
@@ -33,10 +29,6 @@ func (s *NetPrioGroup) Set(path string, cgroup *configs.Cgroup) error {
return nil
}
-func (s *NetPrioGroup) Remove(d *cgroupData) error {
- return removePath(d.path("net_prio"))
-}
-
func (s *NetPrioGroup) GetStats(path string, stats *cgroups.Stats) error {
return nil
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/perf_event.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/perf_event.go
index 5693676d3..dd1e98d0a 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/perf_event.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/perf_event.go
@@ -14,22 +14,14 @@ func (s *PerfEventGroup) Name() string {
return "perf_event"
}
-func (s *PerfEventGroup) Apply(d *cgroupData) error {
- // we just want to join this group even though we don't set anything
- if _, err := d.join("perf_event"); err != nil && !cgroups.IsNotFound(err) {
- return err
- }
- return nil
+func (s *PerfEventGroup) Apply(path string, d *cgroupData) error {
+ return join(path, d.pid)
}
func (s *PerfEventGroup) Set(path string, cgroup *configs.Cgroup) error {
return nil
}
-func (s *PerfEventGroup) Remove(d *cgroupData) error {
- return removePath(d.path("perf_event"))
-}
-
func (s *PerfEventGroup) GetStats(path string, stats *cgroups.Stats) error {
return nil
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/pids.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/pids.go
index 7bf680135..6614df88a 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/pids.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/pids.go
@@ -19,12 +19,8 @@ func (s *PidsGroup) Name() string {
return "pids"
}
-func (s *PidsGroup) Apply(d *cgroupData) error {
- _, err := d.join("pids")
- if err != nil && !cgroups.IsNotFound(err) {
- return err
- }
- return nil
+func (s *PidsGroup) Apply(path string, d *cgroupData) error {
+ return join(path, d.pid)
}
func (s *PidsGroup) Set(path string, cgroup *configs.Cgroup) error {
@@ -44,11 +40,10 @@ func (s *PidsGroup) Set(path string, cgroup *configs.Cgroup) error {
return nil
}
-func (s *PidsGroup) Remove(d *cgroupData) error {
- return removePath(d.path("pids"))
-}
-
func (s *PidsGroup) GetStats(path string, stats *cgroups.Stats) error {
+ if !cgroups.PathExists(path) {
+ return nil
+ }
current, err := fscommon.GetCgroupParamUint(path, "pids.current")
if err != nil {
return fmt.Errorf("failed to parse pids.current - %s", err)
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/fs_unsupported.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/unsupported.go
similarity index 100%
rename from vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/fs_unsupported.go
rename to vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/unsupported.go
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/cpu.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/cpu.go
index f0f5df09a..edf1060ec 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/cpu.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/cpu.go
@@ -13,15 +13,36 @@ import (
"github.com/opencontainers/runc/libcontainer/configs"
)
+func isCpuSet(cgroup *configs.Cgroup) bool {
+ return cgroup.Resources.CpuWeight != 0 || cgroup.Resources.CpuQuota != 0 || cgroup.Resources.CpuPeriod != 0
+}
+
func setCpu(dirPath string, cgroup *configs.Cgroup) error {
- if cgroup.Resources.CpuWeight != 0 {
- if err := fscommon.WriteFile(dirPath, "cpu.weight", strconv.FormatUint(cgroup.Resources.CpuWeight, 10)); err != nil {
+ if !isCpuSet(cgroup) {
+ return nil
+ }
+ r := cgroup.Resources
+
+ // NOTE: .CpuShares is not used here. Conversion is the caller's responsibility.
+ if r.CpuWeight != 0 {
+ if err := fscommon.WriteFile(dirPath, "cpu.weight", strconv.FormatUint(r.CpuWeight, 10)); err != nil {
return err
}
}
- if cgroup.Resources.CpuMax != "" {
- if err := fscommon.WriteFile(dirPath, "cpu.max", cgroup.Resources.CpuMax); err != nil {
+ if r.CpuQuota != 0 || r.CpuPeriod != 0 {
+ str := "max"
+ if r.CpuQuota > 0 {
+ str = strconv.FormatInt(r.CpuQuota, 10)
+ }
+ period := r.CpuPeriod
+ if period == 0 {
+ // This default value is documented in
+ // https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html
+ period = 100000
+ }
+ str += " " + strconv.FormatUint(period, 10)
+ if err := fscommon.WriteFile(dirPath, "cpu.max", str); err != nil {
return err
}
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/cpuset.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/cpuset.go
index 6492ac93c..fb4456b43 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/cpuset.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/cpuset.go
@@ -7,7 +7,15 @@ import (
"github.com/opencontainers/runc/libcontainer/configs"
)
+func isCpusetSet(cgroup *configs.Cgroup) bool {
+ return cgroup.Resources.CpusetCpus != "" || cgroup.Resources.CpusetMems != ""
+}
+
func setCpuset(dirPath string, cgroup *configs.Cgroup) error {
+ if !isCpusetSet(cgroup) {
+ return nil
+ }
+
if cgroup.Resources.CpusetCpus != "" {
if err := fscommon.WriteFile(dirPath, "cpuset.cpus", cgroup.Resources.CpusetCpus); err != nil {
return err
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/create.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/create.go
new file mode 100644
index 000000000..7be9ece0b
--- /dev/null
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/create.go
@@ -0,0 +1,151 @@
+package fs2
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/opencontainers/runc/libcontainer/configs"
+)
+
+func supportedControllers(cgroup *configs.Cgroup) ([]byte, error) {
+ const file = UnifiedMountpoint + "/cgroup.controllers"
+ return ioutil.ReadFile(file)
+}
+
+// needAnyControllers returns whether we enable some supported controllers or not,
+// based on (1) controllers available and (2) resources that are being set.
+// We don't check "pseudo" controllers such as
+// "freezer" and "devices".
+func needAnyControllers(cgroup *configs.Cgroup) (bool, error) {
+ if cgroup == nil {
+ return false, nil
+ }
+
+ // list of all available controllers
+ content, err := supportedControllers(cgroup)
+ if err != nil {
+ return false, err
+ }
+ avail := make(map[string]struct{})
+ for _, ctr := range strings.Fields(string(content)) {
+ avail[ctr] = struct{}{}
+ }
+
+ // check whether the controller if available or not
+ have := func(controller string) bool {
+ _, ok := avail[controller]
+ return ok
+ }
+
+ if isPidsSet(cgroup) && have("pids") {
+ return true, nil
+ }
+ if isMemorySet(cgroup) && have("memory") {
+ return true, nil
+ }
+ if isIoSet(cgroup) && have("io") {
+ return true, nil
+ }
+ if isCpuSet(cgroup) && have("cpu") {
+ return true, nil
+ }
+ if isCpusetSet(cgroup) && have("cpuset") {
+ return true, nil
+ }
+ if isHugeTlbSet(cgroup) && have("hugetlb") {
+ return true, nil
+ }
+
+ return false, nil
+}
+
+// containsDomainController returns whether the current config contains domain controller or not.
+// Refer to: http://man7.org/linux/man-pages/man7/cgroups.7.html
+// As at Linux 4.19, the following controllers are threaded: cpu, perf_event, and pids.
+func containsDomainController(cg *configs.Cgroup) bool {
+ return isMemorySet(cg) || isIoSet(cg) || isCpuSet(cg) || isHugeTlbSet(cg)
+}
+
+// CreateCgroupPath creates cgroupv2 path, enabling all the supported controllers.
+func CreateCgroupPath(path string, c *configs.Cgroup) (Err error) {
+ if !strings.HasPrefix(path, UnifiedMountpoint) {
+ return fmt.Errorf("invalid cgroup path %s", path)
+ }
+
+ content, err := supportedControllers(c)
+ if err != nil {
+ return err
+ }
+
+ ctrs := bytes.Fields(content)
+ res := append([]byte("+"), bytes.Join(ctrs, []byte(" +"))...)
+
+ elements := strings.Split(path, "/")
+ elements = elements[3:]
+ current := "/sys/fs"
+ for i, e := range elements {
+ current = filepath.Join(current, e)
+ if i > 0 {
+ if err := os.Mkdir(current, 0755); err != nil {
+ if !os.IsExist(err) {
+ return err
+ }
+ } else {
+ // If the directory was created, be sure it is not left around on errors.
+ current := current
+ defer func() {
+ if Err != nil {
+ os.Remove(current)
+ }
+ }()
+ }
+ cgTypeFile := filepath.Join(current, "cgroup.type")
+ cgType, _ := ioutil.ReadFile(cgTypeFile)
+ switch strings.TrimSpace(string(cgType)) {
+ // If the cgroup is in an invalid mode (usually this means there's an internal
+ // process in the cgroup tree, because we created a cgroup under an
+ // already-populated-by-other-processes cgroup), then we have to error out if
+ // the user requested controllers which are not thread-aware. However, if all
+ // the controllers requested are thread-aware we can simply put the cgroup into
+ // threaded mode.
+ case "domain invalid":
+ if containsDomainController(c) {
+ return fmt.Errorf("cannot enter cgroupv2 %q with domain controllers -- it is in an invalid state", current)
+ } else {
+ // Not entirely correct (in theory we'd always want to be a domain --
+ // since that means we're a properly delegated cgroup subtree) but in
+ // this case there's not much we can do and it's better than giving an
+ // error.
+ _ = ioutil.WriteFile(cgTypeFile, []byte("threaded"), 0644)
+ }
+ // If the cgroup is in (threaded) or (domain threaded) mode, we can only use thread-aware controllers
+ // (and you cannot usually take a cgroup out of threaded mode).
+ case "domain threaded":
+ fallthrough
+ case "threaded":
+ if containsDomainController(c) {
+ return fmt.Errorf("cannot enter cgroupv2 %q with domain controllers -- it is in %s mode", current, strings.TrimSpace(string(cgType)))
+ }
+ }
+ }
+ // enable all supported controllers
+ if i < len(elements)-1 {
+ file := filepath.Join(current, "cgroup.subtree_control")
+ if err := ioutil.WriteFile(file, res, 0644); err != nil {
+ // try write one by one
+ allCtrs := bytes.Split(res, []byte(" "))
+ for _, ctr := range allCtrs {
+ _ = ioutil.WriteFile(file, ctr, 0644)
+ }
+ }
+ // Some controllers might not be enabled when rootless or containerized,
+ // but we don't catch the error here. (Caught in setXXX() functions.)
+ }
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/defaultpath.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/defaultpath.go
index e84b33f2c..009126453 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/defaultpath.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/defaultpath.go
@@ -44,14 +44,10 @@ func defaultDirPath(c *configs.Cgroup) (string, error) {
cgParent := libcontainerUtils.CleanPath(c.Parent)
cgName := libcontainerUtils.CleanPath(c.Name)
- ownCgroup, err := parseCgroupFile("/proc/self/cgroup")
- if err != nil {
- return "", err
- }
- return _defaultDirPath(UnifiedMountpoint, cgPath, cgParent, cgName, ownCgroup)
+ return _defaultDirPath(UnifiedMountpoint, cgPath, cgParent, cgName)
}
-func _defaultDirPath(root, cgPath, cgParent, cgName, ownCgroup string) (string, error) {
+func _defaultDirPath(root, cgPath, cgParent, cgName string) (string, error) {
if (cgName != "" || cgParent != "") && cgPath != "" {
return "", errors.New("cgroup: either Path or Name and Parent should be used")
}
@@ -62,6 +58,16 @@ func _defaultDirPath(root, cgPath, cgParent, cgName, ownCgroup string) (string,
if filepath.IsAbs(innerPath) {
return filepath.Join(root, innerPath), nil
}
+
+ ownCgroup, err := parseCgroupFile("/proc/self/cgroup")
+ if err != nil {
+ return "", err
+ }
+ // The current user scope most probably has tasks in it already,
+ // making it impossible to enable controllers for its sub-cgroup.
+ // A parent cgroup (with no tasks in it) is what we need.
+ ownCgroup = filepath.Dir(ownCgroup)
+
return filepath.Join(root, ownCgroup, innerPath), nil
}
@@ -80,9 +86,6 @@ func parseCgroupFromReader(r io.Reader) (string, error) {
s = bufio.NewScanner(r)
)
for s.Scan() {
- if err := s.Err(); err != nil {
- return "", err
- }
var (
text = s.Text()
parts = strings.SplitN(text, ":", 3)
@@ -95,5 +98,8 @@ func parseCgroupFromReader(r io.Reader) (string, error) {
return parts[2], nil
}
}
+ if err := s.Err(); err != nil {
+ return "", err
+ }
return "", errors.New("cgroup path not found")
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/devices.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/devices.go
index e0fd68540..053ec33e0 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/devices.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/devices.go
@@ -10,12 +10,10 @@ import (
"golang.org/x/sys/unix"
)
-func isRWM(cgroupPermissions string) bool {
- r := false
- w := false
- m := false
- for _, rn := range cgroupPermissions {
- switch rn {
+func isRWM(perms configs.DevicePermissions) bool {
+ var r, w, m bool
+ for _, perm := range perms {
+ switch perm {
case 'r':
r = true
case 'w':
@@ -39,22 +37,13 @@ func canSkipEBPFError(cgroup *configs.Cgroup) bool {
}
func setDevices(dirPath string, cgroup *configs.Cgroup) error {
+ if cgroup.SkipDevices {
+ return nil
+ }
+ // XXX: This is currently a white-list (but all callers pass a blacklist of
+ // devices). This is bad for a whole variety of reasons, but will need
+ // to be fixed with co-ordinated effort with downstreams.
devices := cgroup.Devices
- if allowAllDevices := cgroup.Resources.AllowAllDevices; allowAllDevices != nil {
- // never set by OCI specconv, but *allowAllDevices=false is still used by the integration test
- if *allowAllDevices == true {
- return errors.New("libcontainer AllowAllDevices is not supported, use Devices")
- }
- for _, ad := range cgroup.Resources.AllowedDevices {
- d := *ad
- d.Allow = true
- devices = append(devices, &d)
- }
- }
- if len(cgroup.Resources.DeniedDevices) != 0 {
- // never set by OCI specconv
- return errors.New("libcontainer DeniedDevices is not supported, use Devices")
- }
insts, license, err := devicefilter.DeviceFilter(devices)
if err != nil {
return err
@@ -64,6 +53,17 @@ func setDevices(dirPath string, cgroup *configs.Cgroup) error {
return errors.Errorf("cannot get dir FD for %s", dirPath)
}
defer unix.Close(dirFD)
+ // XXX: This code is currently incorrect when it comes to updating an
+ // existing cgroup with new rules (new rulesets are just appended to
+ // the program list because this uses BPF_F_ALLOW_MULTI). If we didn't
+ // use BPF_F_ALLOW_MULTI we could actually atomically swap the
+ // programs.
+ //
+ // The real issue is that BPF_F_ALLOW_MULTI makes it hard to have a
+ // race-free blacklist because it acts as a whitelist by default, and
+ // having a deny-everything program cannot be overriden by other
+ // programs. You could temporarily insert a deny-everything program
+ // but that would result in spurrious failures during updates.
if _, err := ebpf.LoadAttachCgroupDeviceFilter(insts, license, dirFD); err != nil {
if !canSkipEBPFError(cgroup) {
return err
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/freezer.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/freezer.go
index 130c63f3e..213ff65a1 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/freezer.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/freezer.go
@@ -3,32 +3,49 @@
package fs2
import (
- "strconv"
+ stdErrors "errors"
+ "os"
"strings"
"github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/pkg/errors"
+ "golang.org/x/sys/unix"
)
func setFreezer(dirPath string, state configs.FreezerState) error {
- var desired int
+ if err := supportsFreezer(dirPath); err != nil {
+ // We can ignore this request as long as the user didn't ask us to
+ // freeze the container (since without the freezer cgroup, that's a
+ // no-op).
+ if state == configs.Undefined || state == configs.Thawed {
+ err = nil
+ }
+ return errors.Wrap(err, "freezer not supported")
+ }
+
+ var stateStr string
switch state {
case configs.Undefined:
return nil
case configs.Frozen:
- desired = 1
+ stateStr = "1"
case configs.Thawed:
- desired = 0
+ stateStr = "0"
default:
- return errors.Errorf("unknown freezer state %+v", state)
+ return errors.Errorf("invalid freezer state %q requested", state)
}
- supportedErr := supportsFreezer(dirPath)
- if supportedErr != nil && desired != 0 {
- // can ignore error if desired == 1
- return errors.Wrap(supportedErr, "freezer not supported")
+
+ if err := fscommon.WriteFile(dirPath, "cgroup.freeze", stateStr); err != nil {
+ return err
}
- return freezeWithInt(dirPath, desired)
+ // Confirm that the cgroup did actually change states.
+ if actualState, err := getFreezer(dirPath); err != nil {
+ return err
+ } else if actualState != state {
+ return errors.Errorf(`expected "cgroup.freeze" to be in state %q but was in %q`, state, actualState)
+ }
+ return nil
}
func supportsFreezer(dirPath string) error {
@@ -36,18 +53,22 @@ func supportsFreezer(dirPath string) error {
return err
}
-// freeze writes desired int to "cgroup.freeze".
-func freezeWithInt(dirPath string, desired int) error {
- desiredS := strconv.Itoa(desired)
- if err := fscommon.WriteFile(dirPath, "cgroup.freeze", desiredS); err != nil {
- return err
- }
- got, err := fscommon.ReadFile(dirPath, "cgroup.freeze")
+func getFreezer(dirPath string) (configs.FreezerState, error) {
+ state, err := fscommon.ReadFile(dirPath, "cgroup.freeze")
if err != nil {
- return err
+ // If the kernel is too old, then we just treat the freezer as being in
+ // an "undefined" state.
+ if os.IsNotExist(err) || stdErrors.Is(err, unix.ENODEV) {
+ err = nil
+ }
+ return configs.Undefined, err
}
- if gotS := strings.TrimSpace(string(got)); gotS != desiredS {
- return errors.Errorf("expected \"cgroup.freeze\" in %q to be %q, got %q", dirPath, desiredS, gotS)
+ switch strings.TrimSpace(state) {
+ case "0":
+ return configs.Thawed, nil
+ case "1":
+ return configs.Frozen, nil
+ default:
+ return configs.Undefined, errors.Errorf(`unknown "cgroup.freeze" state: %q`, state)
}
- return nil
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/fs2.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/fs2.go
index 4bb7091a1..7be26211a 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/fs2.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/fs2.go
@@ -8,64 +8,12 @@ import (
"path/filepath"
"strings"
- securejoin "github.com/cyphar/filepath-securejoin"
"github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/pkg/errors"
+ "golang.org/x/sys/unix"
)
-// NewManager creates a manager for cgroup v2 unified hierarchy.
-// dirPath is like "/sys/fs/cgroup/user.slice/user-1001.slice/session-1.scope".
-// If dirPath is empty, it is automatically set using config.
-func NewManager(config *configs.Cgroup, dirPath string, rootless bool) (cgroups.Manager, error) {
- if config == nil {
- config = &configs.Cgroup{}
- }
- if dirPath != "" {
- if filepath.Clean(dirPath) != dirPath || !filepath.IsAbs(dirPath) {
- return nil, errors.Errorf("invalid dir path %q", dirPath)
- }
- } else {
- var err error
- dirPath, err = defaultDirPath(config)
- if err != nil {
- return nil, err
- }
- }
- controllers, err := detectControllers(dirPath)
- if err != nil && !rootless {
- return nil, err
- }
-
- m := &manager{
- config: config,
- dirPath: dirPath,
- controllers: controllers,
- rootless: rootless,
- }
- return m, nil
-}
-
-func detectControllers(dirPath string) (map[string]struct{}, error) {
- if err := os.MkdirAll(dirPath, 0755); err != nil {
- return nil, err
- }
- controllersPath, err := securejoin.SecureJoin(dirPath, "cgroup.controllers")
- if err != nil {
- return nil, err
- }
- controllersData, err := ioutil.ReadFile(controllersPath)
- if err != nil {
- return nil, err
- }
- controllersFields := strings.Fields(string(controllersData))
- controllers := make(map[string]struct{}, len(controllersFields))
- for _, c := range controllersFields {
- controllers[c] = struct{}{}
- }
- return controllers, nil
-}
-
type manager struct {
config *configs.Cgroup
// dirPath is like "/sys/fs/cgroup/user.slice/user-1001.slice/session-1.scope"
@@ -76,8 +24,68 @@ type manager struct {
rootless bool
}
+// NewManager creates a manager for cgroup v2 unified hierarchy.
+// dirPath is like "/sys/fs/cgroup/user.slice/user-1001.slice/session-1.scope".
+// If dirPath is empty, it is automatically set using config.
+func NewManager(config *configs.Cgroup, dirPath string, rootless bool) (cgroups.Manager, error) {
+ if config == nil {
+ config = &configs.Cgroup{}
+ }
+ if dirPath == "" {
+ var err error
+ dirPath, err = defaultDirPath(config)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ m := &manager{
+ config: config,
+ dirPath: dirPath,
+ rootless: rootless,
+ }
+ return m, nil
+}
+
+func (m *manager) getControllers() error {
+ if m.controllers != nil {
+ return nil
+ }
+
+ file := filepath.Join(m.dirPath, "cgroup.controllers")
+ data, err := ioutil.ReadFile(file)
+ if err != nil {
+ if m.rootless && m.config.Path == "" {
+ return nil
+ }
+ return err
+ }
+ fields := strings.Fields(string(data))
+ m.controllers = make(map[string]struct{}, len(fields))
+ for _, c := range fields {
+ m.controllers[c] = struct{}{}
+ }
+
+ return nil
+}
+
func (m *manager) Apply(pid int) error {
- if err := cgroups.WriteCgroupProc(m.dirPath, pid); err != nil && !m.rootless {
+ if err := CreateCgroupPath(m.dirPath, m.config); err != nil {
+ // Related tests:
+ // - "runc create (no limits + no cgrouppath + no permission) succeeds"
+ // - "runc create (rootless + no limits + cgrouppath + no permission) fails with permission error"
+ // - "runc create (rootless + limits + no cgrouppath + no permission) fails with informative error"
+ if m.rootless {
+ if m.config.Path == "" {
+ if blNeed, nErr := needAnyControllers(m.config); nErr == nil && !blNeed {
+ return nil
+ }
+ return errors.Wrap(err, "rootless needs no limits + no cgrouppath when no permission is granted for cgroups")
+ }
+ }
+ return err
+ }
+ if err := cgroups.WriteCgroupProc(m.dirPath, pid); err != nil {
return err
}
return nil
@@ -93,41 +101,52 @@ func (m *manager) GetAllPids() ([]int, error) {
func (m *manager) GetStats() (*cgroups.Stats, error) {
var (
- st cgroups.Stats
errs []error
)
+
+ st := cgroups.NewStats()
+ if err := m.getControllers(); err != nil {
+ return st, err
+ }
+
// pids (since kernel 4.5)
if _, ok := m.controllers["pids"]; ok {
- if err := statPids(m.dirPath, &st); err != nil {
+ if err := statPids(m.dirPath, st); err != nil {
errs = append(errs, err)
}
} else {
- if err := statPidsWithoutController(m.dirPath, &st); err != nil {
+ if err := statPidsWithoutController(m.dirPath, st); err != nil {
errs = append(errs, err)
}
}
- // memory (since kenrel 4.5)
+ // memory (since kernel 4.5)
if _, ok := m.controllers["memory"]; ok {
- if err := statMemory(m.dirPath, &st); err != nil {
+ if err := statMemory(m.dirPath, st); err != nil {
errs = append(errs, err)
}
}
// io (since kernel 4.5)
if _, ok := m.controllers["io"]; ok {
- if err := statIo(m.dirPath, &st); err != nil {
+ if err := statIo(m.dirPath, st); err != nil {
errs = append(errs, err)
}
}
// cpu (since kernel 4.15)
if _, ok := m.controllers["cpu"]; ok {
- if err := statCpu(m.dirPath, &st); err != nil {
+ if err := statCpu(m.dirPath, st); err != nil {
+ errs = append(errs, err)
+ }
+ }
+ // hugetlb (since kernel 5.6)
+ if _, ok := m.controllers["hugetlb"]; ok {
+ if err := statHugeTlb(m.dirPath, st); err != nil {
errs = append(errs, err)
}
}
if len(errs) > 0 && !m.rootless {
- return &st, errors.Errorf("error while statting cgroup v2: %+v", errs)
+ return st, errors.Errorf("error while statting cgroup v2: %+v", errs)
}
- return &st, nil
+ return st, nil
}
func (m *manager) Freeze(state configs.FreezerState) error {
@@ -138,77 +157,112 @@ func (m *manager) Freeze(state configs.FreezerState) error {
return nil
}
+func rmdir(path string) error {
+ err := unix.Rmdir(path)
+ if err == nil || err == unix.ENOENT {
+ return nil
+ }
+ return &os.PathError{Op: "rmdir", Path: path, Err: err}
+}
+
+// removeCgroupPath aims to remove cgroup path recursively
+// Because there may be subcgroups in it.
+func removeCgroupPath(path string) error {
+ // try the fast path first
+ if err := rmdir(path); err == nil {
+ return nil
+ }
+
+ infos, err := ioutil.ReadDir(path)
+ if err != nil {
+ if os.IsNotExist(err) {
+ err = nil
+ }
+ return err
+ }
+ for _, info := range infos {
+ if info.IsDir() {
+ // We should remove subcgroups dir first
+ if err = removeCgroupPath(filepath.Join(path, info.Name())); err != nil {
+ break
+ }
+ }
+ }
+ if err == nil {
+ err = rmdir(path)
+ }
+ return err
+}
+
func (m *manager) Destroy() error {
- return os.RemoveAll(m.dirPath)
+ return removeCgroupPath(m.dirPath)
}
-// GetPaths is for compatibility purpose and should be removed in future
-func (m *manager) GetPaths() map[string]string {
- paths := map[string]string{
- // pseudo-controller for compatibility
- "devices": m.dirPath,
- "freezer": m.dirPath,
- }
- for c := range m.controllers {
- paths[c] = m.dirPath
- }
- return paths
-}
-
-func (m *manager) GetUnifiedPath() (string, error) {
- return m.dirPath, nil
+func (m *manager) Path(_ string) string {
+ return m.dirPath
}
func (m *manager) Set(container *configs.Config) error {
if container == nil || container.Cgroups == nil {
return nil
}
- var errs []error
+ if err := m.getControllers(); err != nil {
+ return err
+ }
// pids (since kernel 4.5)
- if _, ok := m.controllers["pids"]; ok {
- if err := setPids(m.dirPath, container.Cgroups); err != nil {
- errs = append(errs, err)
- }
+ if err := setPids(m.dirPath, container.Cgroups); err != nil {
+ return err
}
// memory (since kernel 4.5)
- if _, ok := m.controllers["memory"]; ok {
- if err := setMemory(m.dirPath, container.Cgroups); err != nil {
- errs = append(errs, err)
- }
+ if err := setMemory(m.dirPath, container.Cgroups); err != nil {
+ return err
}
// io (since kernel 4.5)
- if _, ok := m.controllers["io"]; ok {
- if err := setIo(m.dirPath, container.Cgroups); err != nil {
- errs = append(errs, err)
- }
+ if err := setIo(m.dirPath, container.Cgroups); err != nil {
+ return err
}
// cpu (since kernel 4.15)
- if _, ok := m.controllers["cpu"]; ok {
- if err := setCpu(m.dirPath, container.Cgroups); err != nil {
- errs = append(errs, err)
- }
+ if err := setCpu(m.dirPath, container.Cgroups); err != nil {
+ return err
}
// devices (since kernel 4.15, pseudo-controller)
- if err := setDevices(m.dirPath, container.Cgroups); err != nil {
- errs = append(errs, err)
+ //
+ // When m.Rootless is true, errors from the device subsystem are ignored because it is really not expected to work.
+ // However, errors from other subsystems are not ignored.
+ // see @test "runc create (rootless + limits + no cgrouppath + no permission) fails with informative error"
+ if err := setDevices(m.dirPath, container.Cgroups); err != nil && !m.rootless {
+ return err
}
// cpuset (since kernel 5.0)
- if _, ok := m.controllers["cpuset"]; ok {
- if err := setCpuset(m.dirPath, container.Cgroups); err != nil {
- errs = append(errs, err)
- }
+ if err := setCpuset(m.dirPath, container.Cgroups); err != nil {
+ return err
+ }
+ // hugetlb (since kernel 5.6)
+ if err := setHugeTlb(m.dirPath, container.Cgroups); err != nil {
+ return err
}
// freezer (since kernel 5.2, pseudo-controller)
if err := setFreezer(m.dirPath, container.Cgroups.Freezer); err != nil {
- errs = append(errs, err)
- }
- if len(errs) > 0 && !m.rootless {
- return errors.Errorf("error while setting cgroup v2: %+v", errs)
+ return err
}
m.config = container.Cgroups
return nil
}
+func (m *manager) GetPaths() map[string]string {
+ paths := make(map[string]string, 1)
+ paths[""] = m.dirPath
+ return paths
+}
+
func (m *manager) GetCgroups() (*configs.Cgroup, error) {
return m.config, nil
}
+
+func (m *manager) GetFreezerState() (configs.FreezerState, error) {
+ return getFreezer(m.dirPath)
+}
+
+func (m *manager) Exists() bool {
+ return cgroups.PathExists(m.dirPath)
+}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/hugetlb.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/hugetlb.go
new file mode 100644
index 000000000..4a399aaec
--- /dev/null
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/hugetlb.go
@@ -0,0 +1,66 @@
+// +build linux
+
+package fs2
+
+import (
+ "io/ioutil"
+ "path/filepath"
+ "strconv"
+ "strings"
+
+ "github.com/pkg/errors"
+
+ "github.com/opencontainers/runc/libcontainer/cgroups"
+ "github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
+ "github.com/opencontainers/runc/libcontainer/configs"
+)
+
+func isHugeTlbSet(cgroup *configs.Cgroup) bool {
+ return len(cgroup.Resources.HugetlbLimit) > 0
+}
+
+func setHugeTlb(dirPath string, cgroup *configs.Cgroup) error {
+ if !isHugeTlbSet(cgroup) {
+ return nil
+ }
+ for _, hugetlb := range cgroup.Resources.HugetlbLimit {
+ if err := fscommon.WriteFile(dirPath, strings.Join([]string{"hugetlb", hugetlb.Pagesize, "max"}, "."), strconv.FormatUint(hugetlb.Limit, 10)); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func statHugeTlb(dirPath string, stats *cgroups.Stats) error {
+ hugePageSizes, err := cgroups.GetHugePageSize()
+ if err != nil {
+ return errors.Wrap(err, "failed to fetch hugetlb info")
+ }
+ hugetlbStats := cgroups.HugetlbStats{}
+
+ for _, pagesize := range hugePageSizes {
+ usage := strings.Join([]string{"hugetlb", pagesize, "current"}, ".")
+ value, err := fscommon.GetCgroupParamUint(dirPath, usage)
+ if err != nil {
+ return errors.Wrapf(err, "failed to parse hugetlb.%s.current file", pagesize)
+ }
+ hugetlbStats.Usage = value
+
+ fileName := strings.Join([]string{"hugetlb", pagesize, "events"}, ".")
+ filePath := filepath.Join(dirPath, fileName)
+ contents, err := ioutil.ReadFile(filePath)
+ if err != nil {
+ return errors.Wrapf(err, "failed to parse hugetlb.%s.events file", pagesize)
+ }
+ _, value, err = fscommon.GetCgroupParamKeyValue(string(contents))
+ if err != nil {
+ return errors.Wrapf(err, "failed to parse hugetlb.%s.events file", pagesize)
+ }
+ hugetlbStats.Failcnt = value
+
+ stats.HugetlbStats[pagesize] = hugetlbStats
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/io.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/io.go
index 9a0730880..bbe3ac064 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/io.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/io.go
@@ -14,14 +14,26 @@ import (
"github.com/opencontainers/runc/libcontainer/configs"
)
+func isIoSet(cgroup *configs.Cgroup) bool {
+ return cgroup.Resources.BlkioWeight != 0 ||
+ len(cgroup.Resources.BlkioThrottleReadBpsDevice) > 0 ||
+ len(cgroup.Resources.BlkioThrottleWriteBpsDevice) > 0 ||
+ len(cgroup.Resources.BlkioThrottleReadIOPSDevice) > 0 ||
+ len(cgroup.Resources.BlkioThrottleWriteIOPSDevice) > 0
+}
+
func setIo(dirPath string, cgroup *configs.Cgroup) error {
+ if !isIoSet(cgroup) {
+ return nil
+ }
+
if cgroup.Resources.BlkioWeight != 0 {
filename := "io.bfq.weight"
- if err := fscommon.WriteFile(dirPath, filename, strconv.FormatUint(uint64(cgroup.Resources.BlkioWeight), 10)); err != nil {
+ if err := fscommon.WriteFile(dirPath, filename,
+ strconv.FormatUint(cgroups.ConvertBlkIOToCgroupV2Value(cgroup.Resources.BlkioWeight), 10)); err != nil {
return err
}
}
-
for _, td := range cgroup.Resources.BlkioThrottleReadBpsDevice {
if err := fscommon.WriteFile(dirPath, "io.max", td.StringName("rbps")); err != nil {
return err
@@ -81,11 +93,11 @@ func statIo(dirPath string, stats *cgroups.Stats) error {
if len(d) != 2 {
continue
}
- minor, err := strconv.ParseUint(d[0], 10, 0)
+ major, err := strconv.ParseUint(d[0], 10, 0)
if err != nil {
return err
}
- major, err := strconv.ParseUint(d[1], 10, 0)
+ minor, err := strconv.ParseUint(d[1], 10, 0)
if err != nil {
return err
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/memory.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/memory.go
index 23eccbec4..51d12c086 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/memory.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/memory.go
@@ -15,22 +15,58 @@ import (
"github.com/pkg/errors"
)
+// numToStr converts an int64 value to a string for writing to a
+// cgroupv2 files with .min, .max, .low, or .high suffix.
+// The value of -1 is converted to "max" for cgroupv1 compatibility
+// (which used to write -1 to remove the limit).
+func numToStr(value int64) (ret string) {
+ switch {
+ case value == 0:
+ ret = ""
+ case value == -1:
+ ret = "max"
+ default:
+ ret = strconv.FormatInt(value, 10)
+ }
+
+ return ret
+}
+
+func isMemorySet(cgroup *configs.Cgroup) bool {
+ return cgroup.Resources.MemoryReservation != 0 ||
+ cgroup.Resources.Memory != 0 || cgroup.Resources.MemorySwap != 0
+}
+
func setMemory(dirPath string, cgroup *configs.Cgroup) error {
- if cgroup.Resources.MemorySwap != 0 {
- if err := fscommon.WriteFile(dirPath, "memory.swap.max", strconv.FormatInt(cgroup.Resources.MemorySwap, 10)); err != nil {
+ if !isMemorySet(cgroup) {
+ return nil
+ }
+ swap, err := cgroups.ConvertMemorySwapToCgroupV2Value(cgroup.Resources.MemorySwap, cgroup.Resources.Memory)
+ if err != nil {
+ return err
+ }
+ swapStr := numToStr(swap)
+ if swapStr == "" && swap == 0 && cgroup.Resources.MemorySwap > 0 {
+ // memory and memorySwap set to the same value -- disable swap
+ swapStr = "0"
+ }
+ // never write empty string to `memory.swap.max`, it means set to 0.
+ if swapStr != "" {
+ if err := fscommon.WriteFile(dirPath, "memory.swap.max", swapStr); err != nil {
return err
}
}
- if cgroup.Resources.Memory != 0 {
- if err := fscommon.WriteFile(dirPath, "memory.max", strconv.FormatInt(cgroup.Resources.Memory, 10)); err != nil {
+
+ if val := numToStr(cgroup.Resources.Memory); val != "" {
+ if err := fscommon.WriteFile(dirPath, "memory.max", val); err != nil {
return err
}
}
// cgroup.Resources.KernelMemory is ignored
- if cgroup.Resources.MemoryReservation != 0 {
- if err := fscommon.WriteFile(dirPath, "memory.low", strconv.FormatInt(cgroup.Resources.MemoryReservation, 10)); err != nil {
+ if val := numToStr(cgroup.Resources.MemoryReservation); val != "" {
+ if err := fscommon.WriteFile(dirPath, "memory.low", val); err != nil {
return err
}
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/pids.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/pids.go
index db2d7ac90..b8153d283 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/pids.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs2/pids.go
@@ -4,9 +4,7 @@ package fs2
import (
"io/ioutil"
- "os"
"path/filepath"
- "strconv"
"strings"
"github.com/opencontainers/runc/libcontainer/cgroups"
@@ -16,16 +14,16 @@ import (
"golang.org/x/sys/unix"
)
+func isPidsSet(cgroup *configs.Cgroup) bool {
+ return cgroup.Resources.PidsLimit != 0
+}
+
func setPids(dirPath string, cgroup *configs.Cgroup) error {
- if cgroup.Resources.PidsLimit != 0 {
- // "max" is the fallback value.
- limit := "max"
-
- if cgroup.Resources.PidsLimit > 0 {
- limit = strconv.FormatInt(cgroup.Resources.PidsLimit, 10)
- }
-
- if err := fscommon.WriteFile(dirPath, "pids.max", limit); err != nil {
+ if !isPidsSet(cgroup) {
+ return nil
+ }
+ if val := numToStr(cgroup.Resources.PidsLimit); val != "" {
+ if err := fscommon.WriteFile(dirPath, "pids.max", val); err != nil {
return err
}
}
@@ -33,20 +31,11 @@ func setPids(dirPath string, cgroup *configs.Cgroup) error {
return nil
}
-func isNOTSUP(err error) bool {
- switch err := err.(type) {
- case *os.PathError:
- return err.Err == unix.ENOTSUP
- default:
- return false
- }
-}
-
func statPidsWithoutController(dirPath string, stats *cgroups.Stats) error {
// if the controller is not enabled, let's read PIDS from cgroups.procs
// (or threads if cgroup.threads is enabled)
contents, err := ioutil.ReadFile(filepath.Join(dirPath, "cgroup.procs"))
- if err != nil && isNOTSUP(err) {
+ if errors.Is(err, unix.ENOTSUP) {
contents, err = ioutil.ReadFile(filepath.Join(dirPath, "cgroup.threads"))
}
if err != nil {
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fscommon/fscommon.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fscommon/fscommon.go
index dd92e8c8c..46e06dc62 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fscommon/fscommon.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fscommon/fscommon.go
@@ -4,9 +4,12 @@ package fscommon
import (
"io/ioutil"
+ "os"
securejoin "github.com/cyphar/filepath-securejoin"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ "golang.org/x/sys/unix"
)
func WriteFile(dir, file, data string) error {
@@ -17,7 +20,7 @@ func WriteFile(dir, file, data string) error {
if err != nil {
return err
}
- if err := ioutil.WriteFile(path, []byte(data), 0700); err != nil {
+ if err := retryingWriteFile(path, []byte(data), 0700); err != nil {
return errors.Wrapf(err, "failed to write %q to %q", data, path)
}
return nil
@@ -34,3 +37,14 @@ func ReadFile(dir, file string) (string, error) {
data, err := ioutil.ReadFile(path)
return string(data), err
}
+
+func retryingWriteFile(filename string, data []byte, perm os.FileMode) error {
+ for {
+ err := ioutil.WriteFile(filename, data, perm)
+ if errors.Is(err, unix.EINTR) {
+ logrus.Infof("interrupted while writing %s to %s", string(data), filename)
+ continue
+ }
+ return err
+ }
+}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go
index 8eeedc55b..7ac816605 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/stats.go
@@ -20,6 +20,12 @@ type CpuUsage struct {
// Total CPU time consumed per core.
// Units: nanoseconds.
PercpuUsage []uint64 `json:"percpu_usage,omitempty"`
+ // CPU time consumed per core in kernel mode
+ // Units: nanoseconds.
+ PercpuUsageInKernelmode []uint64 `json:"percpu_usage_in_kernelmode"`
+ // CPU time consumed per core in user mode
+ // Units: nanoseconds.
+ PercpuUsageInUsermode []uint64 `json:"percpu_usage_in_usermode"`
// Time spent by tasks of the cgroup in kernel mode.
// Units: nanoseconds.
UsageInKernelmode uint64 `json:"usage_in_kernelmode"`
@@ -51,12 +57,33 @@ type MemoryStats struct {
KernelUsage MemoryData `json:"kernel_usage,omitempty"`
// usage of kernel TCP memory
KernelTCPUsage MemoryData `json:"kernel_tcp_usage,omitempty"`
+ // usage of memory pages by NUMA node
+ // see chapter 5.6 of memory controller documentation
+ PageUsageByNUMA PageUsageByNUMA `json:"page_usage_by_numa,omitempty"`
// if true, memory usage is accounted for throughout a hierarchy of cgroups.
UseHierarchy bool `json:"use_hierarchy"`
Stats map[string]uint64 `json:"stats,omitempty"`
}
+type PageUsageByNUMA struct {
+ // Embedding is used as types can't be recursive.
+ PageUsageByNUMAInner
+ Hierarchical PageUsageByNUMAInner `json:"hierarchical,omitempty"`
+}
+
+type PageUsageByNUMAInner struct {
+ Total PageStats `json:"total,omitempty"`
+ File PageStats `json:"file,omitempty"`
+ Anon PageStats `json:"anon,omitempty"`
+ Unevictable PageStats `json:"unevictable,omitempty"`
+}
+
+type PageStats struct {
+ Total uint64 `json:"total,omitempty"`
+ Nodes map[uint8]uint64 `json:"nodes,omitempty"`
+}
+
type PidsStats struct {
// number of pids in the cgroup
Current uint64 `json:"current,omitempty"`
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_systemd.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_systemd.go
deleted file mode 100644
index c4b19b3e6..000000000
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_systemd.go
+++ /dev/null
@@ -1,534 +0,0 @@
-// +build linux
-
-package systemd
-
-import (
- "errors"
- "fmt"
- "io/ioutil"
- "math"
- "os"
- "path/filepath"
- "strings"
- "sync"
- "time"
-
- systemdDbus "github.com/coreos/go-systemd/dbus"
- "github.com/godbus/dbus"
- "github.com/opencontainers/runc/libcontainer/cgroups"
- "github.com/opencontainers/runc/libcontainer/cgroups/fs"
- "github.com/opencontainers/runc/libcontainer/configs"
- "github.com/sirupsen/logrus"
-)
-
-type LegacyManager struct {
- mu sync.Mutex
- Cgroups *configs.Cgroup
- Paths map[string]string
-}
-
-type subsystem interface {
- // Name returns the name of the subsystem.
- Name() string
- // Returns the stats, as 'stats', corresponding to the cgroup under 'path'.
- GetStats(path string, stats *cgroups.Stats) error
- // Set the cgroup represented by cgroup.
- Set(path string, cgroup *configs.Cgroup) error
-}
-
-var errSubsystemDoesNotExist = errors.New("cgroup: subsystem does not exist")
-
-type subsystemSet []subsystem
-
-func (s subsystemSet) Get(name string) (subsystem, error) {
- for _, ss := range s {
- if ss.Name() == name {
- return ss, nil
- }
- }
- return nil, errSubsystemDoesNotExist
-}
-
-var legacySubsystems = subsystemSet{
- &fs.CpusetGroup{},
- &fs.DevicesGroup{},
- &fs.MemoryGroup{},
- &fs.CpuGroup{},
- &fs.CpuacctGroup{},
- &fs.PidsGroup{},
- &fs.BlkioGroup{},
- &fs.HugetlbGroup{},
- &fs.PerfEventGroup{},
- &fs.FreezerGroup{},
- &fs.NetPrioGroup{},
- &fs.NetClsGroup{},
- &fs.NameGroup{GroupName: "name=systemd"},
-}
-
-const (
- testScopeWait = 4
- testSliceWait = 4
-)
-
-var (
- connLock sync.Mutex
- theConn *systemdDbus.Conn
-)
-
-func newProp(name string, units interface{}) systemdDbus.Property {
- return systemdDbus.Property{
- Name: name,
- Value: dbus.MakeVariant(units),
- }
-}
-
-// NOTE: This function comes from package github.com/coreos/go-systemd/util
-// It was borrowed here to avoid a dependency on cgo.
-//
-// IsRunningSystemd checks whether the host was booted with systemd as its init
-// system. This functions similarly to systemd's `sd_booted(3)`: internally, it
-// checks whether /run/systemd/system/ exists and is a directory.
-// http://www.freedesktop.org/software/systemd/man/sd_booted.html
-func isRunningSystemd() bool {
- fi, err := os.Lstat("/run/systemd/system")
- if err != nil {
- return false
- }
- return fi.IsDir()
-}
-
-func UseSystemd() bool {
- if !isRunningSystemd() {
- return false
- }
-
- connLock.Lock()
- defer connLock.Unlock()
-
- if theConn == nil {
- var err error
- theConn, err = systemdDbus.New()
- if err != nil {
- return false
- }
- }
- return true
-}
-
-func NewSystemdCgroupsManager() (func(config *configs.Cgroup, paths map[string]string) cgroups.Manager, error) {
- if !isRunningSystemd() {
- return nil, fmt.Errorf("systemd not running on this host, can't use systemd as a cgroups.Manager")
- }
- if cgroups.IsCgroup2UnifiedMode() {
- return func(config *configs.Cgroup, paths map[string]string) cgroups.Manager {
- return &UnifiedManager{
- Cgroups: config,
- Paths: paths,
- }
- }, nil
- }
- return func(config *configs.Cgroup, paths map[string]string) cgroups.Manager {
- return &LegacyManager{
- Cgroups: config,
- Paths: paths,
- }
- }, nil
-}
-
-func (m *LegacyManager) Apply(pid int) error {
- var (
- c = m.Cgroups
- unitName = getUnitName(c)
- slice = "system.slice"
- properties []systemdDbus.Property
- )
-
- if c.Paths != nil {
- paths := make(map[string]string)
- for name, path := range c.Paths {
- _, err := getSubsystemPath(m.Cgroups, name)
- if err != nil {
- // Don't fail if a cgroup hierarchy was not found, just skip this subsystem
- if cgroups.IsNotFound(err) {
- continue
- }
- return err
- }
- paths[name] = path
- }
- m.Paths = paths
- return cgroups.EnterPid(m.Paths, pid)
- }
-
- if c.Parent != "" {
- slice = c.Parent
- }
-
- properties = append(properties, systemdDbus.PropDescription("libcontainer container "+c.Name))
-
- // if we create a slice, the parent is defined via a Wants=
- if strings.HasSuffix(unitName, ".slice") {
- properties = append(properties, systemdDbus.PropWants(slice))
- } else {
- // otherwise, we use Slice=
- properties = append(properties, systemdDbus.PropSlice(slice))
- }
-
- // only add pid if its valid, -1 is used w/ general slice creation.
- if pid != -1 {
- properties = append(properties, newProp("PIDs", []uint32{uint32(pid)}))
- }
-
- // Check if we can delegate. This is only supported on systemd versions 218 and above.
- if !strings.HasSuffix(unitName, ".slice") {
- // Assume scopes always support delegation.
- properties = append(properties, newProp("Delegate", true))
- }
-
- // Always enable accounting, this gets us the same behaviour as the fs implementation,
- // plus the kernel has some problems with joining the memory cgroup at a later time.
- properties = append(properties,
- newProp("MemoryAccounting", true),
- newProp("CPUAccounting", true),
- newProp("BlockIOAccounting", true))
-
- // Assume DefaultDependencies= will always work (the check for it was previously broken.)
- properties = append(properties,
- newProp("DefaultDependencies", false))
-
- if c.Resources.Memory != 0 {
- properties = append(properties,
- newProp("MemoryLimit", uint64(c.Resources.Memory)))
- }
-
- if c.Resources.CpuShares != 0 {
- properties = append(properties,
- newProp("CPUShares", c.Resources.CpuShares))
- }
-
- // cpu.cfs_quota_us and cpu.cfs_period_us are controlled by systemd.
- if c.Resources.CpuQuota != 0 && c.Resources.CpuPeriod != 0 {
- // corresponds to USEC_INFINITY in systemd
- // if USEC_INFINITY is provided, CPUQuota is left unbound by systemd
- // always setting a property value ensures we can apply a quota and remove it later
- cpuQuotaPerSecUSec := uint64(math.MaxUint64)
- if c.Resources.CpuQuota > 0 {
- // systemd converts CPUQuotaPerSecUSec (microseconds per CPU second) to CPUQuota
- // (integer percentage of CPU) internally. This means that if a fractional percent of
- // CPU is indicated by Resources.CpuQuota, we need to round up to the nearest
- // 10ms (1% of a second) such that child cgroups can set the cpu.cfs_quota_us they expect.
- cpuQuotaPerSecUSec = uint64(c.Resources.CpuQuota*1000000) / c.Resources.CpuPeriod
- if cpuQuotaPerSecUSec%10000 != 0 {
- cpuQuotaPerSecUSec = ((cpuQuotaPerSecUSec / 10000) + 1) * 10000
- }
- }
- properties = append(properties,
- newProp("CPUQuotaPerSecUSec", cpuQuotaPerSecUSec))
- }
-
- if c.Resources.BlkioWeight != 0 {
- properties = append(properties,
- newProp("BlockIOWeight", uint64(c.Resources.BlkioWeight)))
- }
-
- if c.Resources.PidsLimit > 0 {
- properties = append(properties,
- newProp("TasksAccounting", true),
- newProp("TasksMax", uint64(c.Resources.PidsLimit)))
- }
-
- // We have to set kernel memory here, as we can't change it once
- // processes have been attached to the cgroup.
- if c.Resources.KernelMemory != 0 {
- if err := setKernelMemory(c); err != nil {
- return err
- }
- }
-
- statusChan := make(chan string, 1)
- if _, err := theConn.StartTransientUnit(unitName, "replace", properties, statusChan); err == nil {
- select {
- case <-statusChan:
- case <-time.After(time.Second):
- logrus.Warnf("Timed out while waiting for StartTransientUnit(%s) completion signal from dbus. Continuing...", unitName)
- }
- } else if !isUnitExists(err) {
- return err
- }
-
- if err := joinCgroups(c, pid); err != nil {
- return err
- }
-
- paths := make(map[string]string)
- for _, s := range legacySubsystems {
- subsystemPath, err := getSubsystemPath(m.Cgroups, s.Name())
- if err != nil {
- // Don't fail if a cgroup hierarchy was not found, just skip this subsystem
- if cgroups.IsNotFound(err) {
- continue
- }
- return err
- }
- paths[s.Name()] = subsystemPath
- }
- m.Paths = paths
- return nil
-}
-
-func (m *LegacyManager) Destroy() error {
- if m.Cgroups.Paths != nil {
- return nil
- }
- m.mu.Lock()
- defer m.mu.Unlock()
- theConn.StopUnit(getUnitName(m.Cgroups), "replace", nil)
- if err := cgroups.RemovePaths(m.Paths); err != nil {
- return err
- }
- m.Paths = make(map[string]string)
- return nil
-}
-
-func (m *LegacyManager) GetPaths() map[string]string {
- m.mu.Lock()
- paths := m.Paths
- m.mu.Unlock()
- return paths
-}
-
-func (m *LegacyManager) GetUnifiedPath() (string, error) {
- return "", errors.New("unified path is only supported when running in unified mode")
-}
-
-func join(c *configs.Cgroup, subsystem string, pid int) (string, error) {
- path, err := getSubsystemPath(c, subsystem)
- if err != nil {
- return "", err
- }
-
- if err := os.MkdirAll(path, 0755); err != nil {
- return "", err
- }
- if err := cgroups.WriteCgroupProc(path, pid); err != nil {
- return "", err
- }
- return path, nil
-}
-
-func joinCgroups(c *configs.Cgroup, pid int) error {
- for _, sys := range legacySubsystems {
- name := sys.Name()
- switch name {
- case "name=systemd":
- // let systemd handle this
- case "cpuset":
- path, err := getSubsystemPath(c, name)
- if err != nil && !cgroups.IsNotFound(err) {
- return err
- }
- s := &fs.CpusetGroup{}
- if err := s.ApplyDir(path, c, pid); err != nil {
- return err
- }
- default:
- _, err := join(c, name, pid)
- if err != nil {
- // Even if it's `not found` error, we'll return err
- // because devices cgroup is hard requirement for
- // container security.
- if name == "devices" {
- return err
- }
- // For other subsystems, omit the `not found` error
- // because they are optional.
- if !cgroups.IsNotFound(err) {
- return err
- }
- }
- }
- }
-
- return nil
-}
-
-// systemd represents slice hierarchy using `-`, so we need to follow suit when
-// generating the path of slice. Essentially, test-a-b.slice becomes
-// /test.slice/test-a.slice/test-a-b.slice.
-func ExpandSlice(slice string) (string, error) {
- suffix := ".slice"
- // Name has to end with ".slice", but can't be just ".slice".
- if len(slice) < len(suffix) || !strings.HasSuffix(slice, suffix) {
- return "", fmt.Errorf("invalid slice name: %s", slice)
- }
-
- // Path-separators are not allowed.
- if strings.Contains(slice, "/") {
- return "", fmt.Errorf("invalid slice name: %s", slice)
- }
-
- var path, prefix string
- sliceName := strings.TrimSuffix(slice, suffix)
- // if input was -.slice, we should just return root now
- if sliceName == "-" {
- return "/", nil
- }
- for _, component := range strings.Split(sliceName, "-") {
- // test--a.slice isn't permitted, nor is -test.slice.
- if component == "" {
- return "", fmt.Errorf("invalid slice name: %s", slice)
- }
-
- // Append the component to the path and to the prefix.
- path += "/" + prefix + component + suffix
- prefix += component + "-"
- }
- return path, nil
-}
-
-func getSubsystemPath(c *configs.Cgroup, subsystem string) (string, error) {
- mountpoint, err := cgroups.FindCgroupMountpoint(c.Path, subsystem)
- if err != nil {
- return "", err
- }
-
- initPath, err := cgroups.GetInitCgroup(subsystem)
- if err != nil {
- return "", err
- }
- // if pid 1 is systemd 226 or later, it will be in init.scope, not the root
- initPath = strings.TrimSuffix(filepath.Clean(initPath), "init.scope")
-
- slice := "system.slice"
- if c.Parent != "" {
- slice = c.Parent
- }
-
- slice, err = ExpandSlice(slice)
- if err != nil {
- return "", err
- }
-
- return filepath.Join(mountpoint, initPath, slice, getUnitName(c)), nil
-}
-
-func (m *LegacyManager) Freeze(state configs.FreezerState) error {
- path, err := getSubsystemPath(m.Cgroups, "freezer")
- if err != nil {
- return err
- }
- prevState := m.Cgroups.Resources.Freezer
- m.Cgroups.Resources.Freezer = state
- freezer, err := legacySubsystems.Get("freezer")
- if err != nil {
- return err
- }
- err = freezer.Set(path, m.Cgroups)
- if err != nil {
- m.Cgroups.Resources.Freezer = prevState
- return err
- }
- return nil
-}
-
-func (m *LegacyManager) GetPids() ([]int, error) {
- path, err := getSubsystemPath(m.Cgroups, "devices")
- if err != nil {
- return nil, err
- }
- return cgroups.GetPids(path)
-}
-
-func (m *LegacyManager) GetAllPids() ([]int, error) {
- path, err := getSubsystemPath(m.Cgroups, "devices")
- if err != nil {
- return nil, err
- }
- return cgroups.GetAllPids(path)
-}
-
-func (m *LegacyManager) GetStats() (*cgroups.Stats, error) {
- m.mu.Lock()
- defer m.mu.Unlock()
- stats := cgroups.NewStats()
- for name, path := range m.Paths {
- sys, err := legacySubsystems.Get(name)
- if err == errSubsystemDoesNotExist || !cgroups.PathExists(path) {
- continue
- }
- if err := sys.GetStats(path, stats); err != nil {
- return nil, err
- }
- }
-
- return stats, nil
-}
-
-func (m *LegacyManager) Set(container *configs.Config) error {
- // If Paths are set, then we are just joining cgroups paths
- // and there is no need to set any values.
- if m.Cgroups.Paths != nil {
- return nil
- }
- for _, sys := range legacySubsystems {
- // Get the subsystem path, but don't error out for not found cgroups.
- path, err := getSubsystemPath(container.Cgroups, sys.Name())
- if err != nil && !cgroups.IsNotFound(err) {
- return err
- }
-
- if err := sys.Set(path, container.Cgroups); err != nil {
- return err
- }
- }
-
- if m.Paths["cpu"] != "" {
- if err := fs.CheckCpushares(m.Paths["cpu"], container.Cgroups.Resources.CpuShares); err != nil {
- return err
- }
- }
- return nil
-}
-
-func getUnitName(c *configs.Cgroup) string {
- // by default, we create a scope unless the user explicitly asks for a slice.
- if !strings.HasSuffix(c.Name, ".slice") {
- return fmt.Sprintf("%s-%s.scope", c.ScopePrefix, c.Name)
- }
- return c.Name
-}
-
-func setKernelMemory(c *configs.Cgroup) error {
- path, err := getSubsystemPath(c, "memory")
- if err != nil && !cgroups.IsNotFound(err) {
- return err
- }
-
- if err := os.MkdirAll(path, 0755); err != nil {
- return err
- }
- // do not try to enable the kernel memory if we already have
- // tasks in the cgroup.
- content, err := ioutil.ReadFile(filepath.Join(path, "tasks"))
- if err != nil {
- return err
- }
- if len(content) > 0 {
- return nil
- }
- return fs.EnableKernelMemoryAccounting(path)
-}
-
-// isUnitExists returns true if the error is that a systemd unit already exists.
-func isUnitExists(err error) bool {
- if err != nil {
- if dbusError, ok := err.(dbus.Error); ok {
- return strings.Contains(dbusError.Name, "org.freedesktop.systemd1.UnitExists")
- }
- }
- return false
-}
-
-func (m *LegacyManager) GetCgroups() (*configs.Cgroup, error) {
- return m.Cgroups, nil
-}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/common.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/common.go
new file mode 100644
index 000000000..b567f3e1f
--- /dev/null
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/common.go
@@ -0,0 +1,427 @@
+package systemd
+
+import (
+ "bufio"
+ "fmt"
+ "math"
+ "os"
+ "regexp"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ systemdDbus "github.com/coreos/go-systemd/v22/dbus"
+ dbus "github.com/godbus/dbus/v5"
+ "github.com/opencontainers/runc/libcontainer/cgroups/devices"
+ "github.com/opencontainers/runc/libcontainer/configs"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+var (
+ connOnce sync.Once
+ connDbus *systemdDbus.Conn
+ connErr error
+
+ versionOnce sync.Once
+ version int
+ versionErr error
+
+ isRunningSystemdOnce sync.Once
+ isRunningSystemd bool
+)
+
+// NOTE: This function comes from package github.com/coreos/go-systemd/util
+// It was borrowed here to avoid a dependency on cgo.
+//
+// IsRunningSystemd checks whether the host was booted with systemd as its init
+// system. This functions similarly to systemd's `sd_booted(3)`: internally, it
+// checks whether /run/systemd/system/ exists and is a directory.
+// http://www.freedesktop.org/software/systemd/man/sd_booted.html
+func IsRunningSystemd() bool {
+ isRunningSystemdOnce.Do(func() {
+ fi, err := os.Lstat("/run/systemd/system")
+ isRunningSystemd = err == nil && fi.IsDir()
+ })
+ return isRunningSystemd
+}
+
+// systemd represents slice hierarchy using `-`, so we need to follow suit when
+// generating the path of slice. Essentially, test-a-b.slice becomes
+// /test.slice/test-a.slice/test-a-b.slice.
+func ExpandSlice(slice string) (string, error) {
+ suffix := ".slice"
+ // Name has to end with ".slice", but can't be just ".slice".
+ if len(slice) < len(suffix) || !strings.HasSuffix(slice, suffix) {
+ return "", fmt.Errorf("invalid slice name: %s", slice)
+ }
+
+ // Path-separators are not allowed.
+ if strings.Contains(slice, "/") {
+ return "", fmt.Errorf("invalid slice name: %s", slice)
+ }
+
+ var path, prefix string
+ sliceName := strings.TrimSuffix(slice, suffix)
+ // if input was -.slice, we should just return root now
+ if sliceName == "-" {
+ return "/", nil
+ }
+ for _, component := range strings.Split(sliceName, "-") {
+ // test--a.slice isn't permitted, nor is -test.slice.
+ if component == "" {
+ return "", fmt.Errorf("invalid slice name: %s", slice)
+ }
+
+ // Append the component to the path and to the prefix.
+ path += "/" + prefix + component + suffix
+ prefix += component + "-"
+ }
+ return path, nil
+}
+
+func groupPrefix(ruleType configs.DeviceType) (string, error) {
+ switch ruleType {
+ case configs.BlockDevice:
+ return "block-", nil
+ case configs.CharDevice:
+ return "char-", nil
+ default:
+ return "", errors.Errorf("device type %v has no group prefix", ruleType)
+ }
+}
+
+// findDeviceGroup tries to find the device group name (as listed in
+// /proc/devices) with the type prefixed as requried for DeviceAllow, for a
+// given (type, major) combination. If more than one device group exists, an
+// arbitrary one is chosen.
+func findDeviceGroup(ruleType configs.DeviceType, ruleMajor int64) (string, error) {
+ fh, err := os.Open("/proc/devices")
+ if err != nil {
+ return "", err
+ }
+ defer fh.Close()
+
+ prefix, err := groupPrefix(ruleType)
+ if err != nil {
+ return "", err
+ }
+
+ scanner := bufio.NewScanner(fh)
+ var currentType configs.DeviceType
+ for scanner.Scan() {
+ // We need to strip spaces because the first number is column-aligned.
+ line := strings.TrimSpace(scanner.Text())
+
+ // Handle the "header" lines.
+ switch line {
+ case "Block devices:":
+ currentType = configs.BlockDevice
+ continue
+ case "Character devices:":
+ currentType = configs.CharDevice
+ continue
+ case "":
+ continue
+ }
+
+ // Skip lines unrelated to our type.
+ if currentType != ruleType {
+ continue
+ }
+
+ // Parse out the (major, name).
+ var (
+ currMajor int64
+ currName string
+ )
+ if n, err := fmt.Sscanf(line, "%d %s", &currMajor, &currName); err != nil || n != 2 {
+ if err == nil {
+ err = errors.Errorf("wrong number of fields")
+ }
+ return "", errors.Wrapf(err, "scan /proc/devices line %q", line)
+ }
+
+ if currMajor == ruleMajor {
+ return prefix + currName, nil
+ }
+ }
+ if err := scanner.Err(); err != nil {
+ return "", errors.Wrap(err, "reading /proc/devices")
+ }
+ // Couldn't find the device group.
+ return "", nil
+}
+
+// generateDeviceProperties takes the configured device rules and generates a
+// corresponding set of systemd properties to configure the devices correctly.
+func generateDeviceProperties(rules []*configs.DeviceRule) ([]systemdDbus.Property, error) {
+ // DeviceAllow is the type "a(ss)" which means we need a temporary struct
+ // to represent it in Go.
+ type deviceAllowEntry struct {
+ Path string
+ Perms string
+ }
+
+ properties := []systemdDbus.Property{
+ // Always run in the strictest white-list mode.
+ newProp("DevicePolicy", "strict"),
+ // Empty the DeviceAllow array before filling it.
+ newProp("DeviceAllow", []deviceAllowEntry{}),
+ }
+
+ // Figure out the set of rules.
+ configEmu := &devices.Emulator{}
+ for _, rule := range rules {
+ if err := configEmu.Apply(*rule); err != nil {
+ return nil, errors.Wrap(err, "apply rule for systemd")
+ }
+ }
+ // systemd doesn't support blacklists. So we log a warning, and tell
+ // systemd to act as a deny-all whitelist. This ruleset will be replaced
+ // with our normal fallback code. This may result in spurrious errors, but
+ // the only other option is to error out here.
+ if configEmu.IsBlacklist() {
+ // However, if we're dealing with an allow-all rule then we can do it.
+ if configEmu.IsAllowAll() {
+ return []systemdDbus.Property{
+ // Run in white-list mode by setting to "auto" and removing all
+ // DeviceAllow rules.
+ newProp("DevicePolicy", "auto"),
+ newProp("DeviceAllow", []deviceAllowEntry{}),
+ }, nil
+ }
+ logrus.Warn("systemd doesn't support blacklist device rules -- applying temporary deny-all rule")
+ return properties, nil
+ }
+
+ // Now generate the set of rules we actually need to apply. Unlike the
+ // normal devices cgroup, in "strict" mode systemd defaults to a deny-all
+ // whitelist which is the default for devices.Emulator.
+ baseEmu := &devices.Emulator{}
+ finalRules, err := baseEmu.Transition(configEmu)
+ if err != nil {
+ return nil, errors.Wrap(err, "get simplified rules for systemd")
+ }
+ var deviceAllowList []deviceAllowEntry
+ for _, rule := range finalRules {
+ if !rule.Allow {
+ // Should never happen.
+ return nil, errors.Errorf("[internal error] cannot add deny rule to systemd DeviceAllow list: %v", *rule)
+ }
+ switch rule.Type {
+ case configs.BlockDevice, configs.CharDevice:
+ default:
+ // Should never happen.
+ return nil, errors.Errorf("invalid device type for DeviceAllow: %v", rule.Type)
+ }
+
+ entry := deviceAllowEntry{
+ Perms: string(rule.Permissions),
+ }
+
+ // systemd has a fairly odd (though understandable) syntax here, and
+ // because of the OCI configuration format we have to do quite a bit of
+ // trickery to convert things:
+ //
+ // * Concrete rules with non-wildcard major/minor numbers have to use
+ // /dev/{block,char} paths. This is slightly odd because it means
+ // that we cannot add whitelist rules for devices that don't exist,
+ // but there's not too much we can do about that.
+ //
+ // However, path globbing is not support for path-based rules so we
+ // need to handle wildcards in some other manner.
+ //
+ // * Wildcard-minor rules have to specify a "device group name" (the
+ // second column in /proc/devices).
+ //
+ // * Wildcard (major and minor) rules can just specify a glob with the
+ // type ("char-*" or "block-*").
+ //
+ // The only type of rule we can't handle is wildcard-major rules, and
+ // so we'll give a warning in that case (note that the fallback code
+ // will insert any rules systemd couldn't handle). What amazing fun.
+
+ if rule.Major == configs.Wildcard {
+ // "_ *:n _" rules aren't supported by systemd.
+ if rule.Minor != configs.Wildcard {
+ logrus.Warnf("systemd doesn't support '*:n' device rules -- temporarily ignoring rule: %v", *rule)
+ continue
+ }
+
+ // "_ *:* _" rules just wildcard everything.
+ prefix, err := groupPrefix(rule.Type)
+ if err != nil {
+ return nil, err
+ }
+ entry.Path = prefix + "*"
+ } else if rule.Minor == configs.Wildcard {
+ // "_ n:* _" rules require a device group from /proc/devices.
+ group, err := findDeviceGroup(rule.Type, rule.Major)
+ if err != nil {
+ return nil, errors.Wrapf(err, "find device '%v/%d'", rule.Type, rule.Major)
+ }
+ if group == "" {
+ // Couldn't find a group.
+ logrus.Warnf("could not find device group for '%v/%d' in /proc/devices -- temporarily ignoring rule: %v", rule.Type, rule.Major, *rule)
+ continue
+ }
+ entry.Path = group
+ } else {
+ // "_ n:m _" rules are just a path in /dev/{block,char}/.
+ switch rule.Type {
+ case configs.BlockDevice:
+ entry.Path = fmt.Sprintf("/dev/block/%d:%d", rule.Major, rule.Minor)
+ case configs.CharDevice:
+ entry.Path = fmt.Sprintf("/dev/char/%d:%d", rule.Major, rule.Minor)
+ }
+ }
+ deviceAllowList = append(deviceAllowList, entry)
+ }
+
+ properties = append(properties, newProp("DeviceAllow", deviceAllowList))
+ return properties, nil
+}
+
+// getDbusConnection lazy initializes systemd dbus connection
+// and returns it
+func getDbusConnection(rootless bool) (*systemdDbus.Conn, error) {
+ connOnce.Do(func() {
+ if rootless {
+ connDbus, connErr = NewUserSystemdDbus()
+ } else {
+ connDbus, connErr = systemdDbus.New()
+ }
+ })
+ return connDbus, connErr
+}
+
+func newProp(name string, units interface{}) systemdDbus.Property {
+ return systemdDbus.Property{
+ Name: name,
+ Value: dbus.MakeVariant(units),
+ }
+}
+
+func getUnitName(c *configs.Cgroup) string {
+ // by default, we create a scope unless the user explicitly asks for a slice.
+ if !strings.HasSuffix(c.Name, ".slice") {
+ return fmt.Sprintf("%s-%s.scope", c.ScopePrefix, c.Name)
+ }
+ return c.Name
+}
+
+// isUnitExists returns true if the error is that a systemd unit already exists.
+func isUnitExists(err error) bool {
+ if err != nil {
+ if dbusError, ok := err.(dbus.Error); ok {
+ return strings.Contains(dbusError.Name, "org.freedesktop.systemd1.UnitExists")
+ }
+ }
+ return false
+}
+
+func startUnit(dbusConnection *systemdDbus.Conn, unitName string, properties []systemdDbus.Property) error {
+ statusChan := make(chan string, 1)
+ if _, err := dbusConnection.StartTransientUnit(unitName, "replace", properties, statusChan); err == nil {
+ select {
+ case s := <-statusChan:
+ close(statusChan)
+ // Please refer to https://godoc.org/github.com/coreos/go-systemd/dbus#Conn.StartUnit
+ if s != "done" {
+ dbusConnection.ResetFailedUnit(unitName)
+ return errors.Errorf("error creating systemd unit `%s`: got `%s`", unitName, s)
+ }
+ case <-time.After(time.Second):
+ logrus.Warnf("Timed out while waiting for StartTransientUnit(%s) completion signal from dbus. Continuing...", unitName)
+ }
+ } else if !isUnitExists(err) {
+ return err
+ }
+
+ return nil
+}
+
+func stopUnit(dbusConnection *systemdDbus.Conn, unitName string) error {
+ statusChan := make(chan string, 1)
+ if _, err := dbusConnection.StopUnit(unitName, "replace", statusChan); err == nil {
+ select {
+ case s := <-statusChan:
+ close(statusChan)
+ // Please refer to https://godoc.org/github.com/coreos/go-systemd/dbus#Conn.StartUnit
+ if s != "done" {
+ logrus.Warnf("error removing unit `%s`: got `%s`. Continuing...", unitName, s)
+ }
+ case <-time.After(time.Second):
+ logrus.Warnf("Timed out while waiting for StopUnit(%s) completion signal from dbus. Continuing...", unitName)
+ }
+ }
+ return nil
+}
+
+func systemdVersion(conn *systemdDbus.Conn) (int, error) {
+ versionOnce.Do(func() {
+ version = -1
+ verStr, err := conn.GetManagerProperty("Version")
+ if err != nil {
+ versionErr = err
+ return
+ }
+
+ version, versionErr = systemdVersionAtoi(verStr)
+ return
+ })
+
+ return version, versionErr
+}
+
+func systemdVersionAtoi(verStr string) (int, error) {
+ // verStr should be of the form:
+ // "v245.4-1.fc32", "245", "v245-1.fc32", "245-1.fc32"
+ // all the input strings include quotes, and the output int should be 245
+ // thus, we unconditionally remove the `"v`
+ // and then match on the first integer we can grab
+ re := regexp.MustCompile(`"?v?([0-9]+)`)
+ matches := re.FindStringSubmatch(verStr)
+ if len(matches) < 2 {
+ return 0, errors.Errorf("can't parse version %s: incorrect number of matches %v", verStr, matches)
+ }
+ ver, err := strconv.Atoi(matches[1])
+ return ver, errors.Wrapf(err, "can't parse version %s", verStr)
+}
+
+func addCpuQuota(conn *systemdDbus.Conn, properties *[]systemdDbus.Property, quota int64, period uint64) {
+ if period != 0 {
+ // systemd only supports CPUQuotaPeriodUSec since v242
+ sdVer, err := systemdVersion(conn)
+ if err != nil {
+ logrus.Warnf("systemdVersion: %s", err)
+ } else if sdVer >= 242 {
+ *properties = append(*properties,
+ newProp("CPUQuotaPeriodUSec", period))
+ }
+ }
+ if quota != 0 || period != 0 {
+ // corresponds to USEC_INFINITY in systemd
+ cpuQuotaPerSecUSec := uint64(math.MaxUint64)
+ if quota > 0 {
+ if period == 0 {
+ // assume the default kernel value of 100000 us (100 ms), same for v1 and v2.
+ // v1: https://www.kernel.org/doc/html/latest/scheduler/sched-bwc.html and
+ // v2: https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html
+ period = 100000
+ }
+ // systemd converts CPUQuotaPerSecUSec (microseconds per CPU second) to CPUQuota
+ // (integer percentage of CPU) internally. This means that if a fractional percent of
+ // CPU is indicated by Resources.CpuQuota, we need to round up to the nearest
+ // 10ms (1% of a second) such that child cgroups can set the cpu.cfs_quota_us they expect.
+ cpuQuotaPerSecUSec = uint64(quota*1000000) / period
+ if cpuQuotaPerSecUSec%10000 != 0 {
+ cpuQuotaPerSecUSec = ((cpuQuotaPerSecUSec / 10000) + 1) * 10000
+ }
+ }
+ *properties = append(*properties,
+ newProp("CPUQuotaPerSecUSec", cpuQuotaPerSecUSec))
+ }
+}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/unified_hierarchy.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/unified_hierarchy.go
deleted file mode 100644
index 660509919..000000000
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/unified_hierarchy.go
+++ /dev/null
@@ -1,312 +0,0 @@
-// +build linux
-
-package systemd
-
-import (
- "fmt"
- "io/ioutil"
- "math"
- "os"
- "path/filepath"
- "strings"
- "sync"
- "time"
-
- systemdDbus "github.com/coreos/go-systemd/dbus"
- "github.com/opencontainers/runc/libcontainer/cgroups"
- "github.com/opencontainers/runc/libcontainer/cgroups/fs2"
- "github.com/opencontainers/runc/libcontainer/configs"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-)
-
-type UnifiedManager struct {
- mu sync.Mutex
- Cgroups *configs.Cgroup
- Paths map[string]string
-}
-
-func (m *UnifiedManager) Apply(pid int) error {
- var (
- c = m.Cgroups
- unitName = getUnitName(c)
- slice = "system.slice"
- properties []systemdDbus.Property
- )
-
- if c.Paths != nil {
- paths := make(map[string]string)
- for name, path := range c.Paths {
- _, err := getSubsystemPath(m.Cgroups, name)
- if err != nil {
- // Don't fail if a cgroup hierarchy was not found, just skip this subsystem
- if cgroups.IsNotFound(err) {
- continue
- }
- return err
- }
- paths[name] = path
- }
- m.Paths = paths
- return cgroups.EnterPid(m.Paths, pid)
- }
-
- if c.Parent != "" {
- slice = c.Parent
- }
-
- properties = append(properties, systemdDbus.PropDescription("libcontainer container "+c.Name))
-
- // if we create a slice, the parent is defined via a Wants=
- if strings.HasSuffix(unitName, ".slice") {
- properties = append(properties, systemdDbus.PropWants(slice))
- } else {
- // otherwise, we use Slice=
- properties = append(properties, systemdDbus.PropSlice(slice))
- }
-
- // only add pid if its valid, -1 is used w/ general slice creation.
- if pid != -1 {
- properties = append(properties, newProp("PIDs", []uint32{uint32(pid)}))
- }
-
- // Check if we can delegate. This is only supported on systemd versions 218 and above.
- if !strings.HasSuffix(unitName, ".slice") {
- // Assume scopes always support delegation.
- properties = append(properties, newProp("Delegate", true))
- }
-
- // Always enable accounting, this gets us the same behaviour as the fs implementation,
- // plus the kernel has some problems with joining the memory cgroup at a later time.
- properties = append(properties,
- newProp("MemoryAccounting", true),
- newProp("CPUAccounting", true),
- newProp("BlockIOAccounting", true))
-
- // Assume DefaultDependencies= will always work (the check for it was previously broken.)
- properties = append(properties,
- newProp("DefaultDependencies", false))
-
- if c.Resources.Memory != 0 {
- properties = append(properties,
- newProp("MemoryLimit", uint64(c.Resources.Memory)))
- }
-
- if c.Resources.CpuShares != 0 {
- properties = append(properties,
- newProp("CPUShares", c.Resources.CpuShares))
- }
-
- // cpu.cfs_quota_us and cpu.cfs_period_us are controlled by systemd.
- if c.Resources.CpuQuota != 0 && c.Resources.CpuPeriod != 0 {
- // corresponds to USEC_INFINITY in systemd
- // if USEC_INFINITY is provided, CPUQuota is left unbound by systemd
- // always setting a property value ensures we can apply a quota and remove it later
- cpuQuotaPerSecUSec := uint64(math.MaxUint64)
- if c.Resources.CpuQuota > 0 {
- // systemd converts CPUQuotaPerSecUSec (microseconds per CPU second) to CPUQuota
- // (integer percentage of CPU) internally. This means that if a fractional percent of
- // CPU is indicated by Resources.CpuQuota, we need to round up to the nearest
- // 10ms (1% of a second) such that child cgroups can set the cpu.cfs_quota_us they expect.
- cpuQuotaPerSecUSec = uint64(c.Resources.CpuQuota*1000000) / c.Resources.CpuPeriod
- if cpuQuotaPerSecUSec%10000 != 0 {
- cpuQuotaPerSecUSec = ((cpuQuotaPerSecUSec / 10000) + 1) * 10000
- }
- }
- properties = append(properties,
- newProp("CPUQuotaPerSecUSec", cpuQuotaPerSecUSec))
- }
-
- if c.Resources.BlkioWeight != 0 {
- properties = append(properties,
- newProp("BlockIOWeight", uint64(c.Resources.BlkioWeight)))
- }
-
- if c.Resources.PidsLimit > 0 {
- properties = append(properties,
- newProp("TasksAccounting", true),
- newProp("TasksMax", uint64(c.Resources.PidsLimit)))
- }
-
- // We have to set kernel memory here, as we can't change it once
- // processes have been attached to the cgroup.
- if c.Resources.KernelMemory != 0 {
- if err := setKernelMemory(c); err != nil {
- return err
- }
- }
-
- statusChan := make(chan string, 1)
- if _, err := theConn.StartTransientUnit(unitName, "replace", properties, statusChan); err == nil {
- select {
- case <-statusChan:
- case <-time.After(time.Second):
- logrus.Warnf("Timed out while waiting for StartTransientUnit(%s) completion signal from dbus. Continuing...", unitName)
- }
- } else if !isUnitExists(err) {
- return err
- }
-
- if err := joinCgroupsV2(c, pid); err != nil {
- return err
- }
-
- path, err := getSubsystemPath(m.Cgroups, "")
- if err != nil {
- return err
- }
- m.Paths = map[string]string{
- "pids": path,
- "memory": path,
- "io": path,
- "cpu": path,
- "devices": path,
- "cpuset": path,
- "freezer": path,
- }
- return nil
-}
-
-func (m *UnifiedManager) Destroy() error {
- if m.Cgroups.Paths != nil {
- return nil
- }
- m.mu.Lock()
- defer m.mu.Unlock()
- theConn.StopUnit(getUnitName(m.Cgroups), "replace", nil)
- if err := cgroups.RemovePaths(m.Paths); err != nil {
- return err
- }
- m.Paths = make(map[string]string)
- return nil
-}
-
-func (m *UnifiedManager) GetPaths() map[string]string {
- m.mu.Lock()
- paths := m.Paths
- m.mu.Unlock()
- return paths
-}
-func (m *UnifiedManager) GetUnifiedPath() (string, error) {
- unifiedPath := ""
- m.mu.Lock()
- defer m.mu.Unlock()
- for k, v := range m.Paths {
- if unifiedPath == "" {
- unifiedPath = v
- } else if v != unifiedPath {
- return unifiedPath,
- errors.Errorf("expected %q path to be unified path %q, got %q", k, unifiedPath, v)
- }
- }
- if unifiedPath == "" {
- // FIXME: unified path could be detected even when no controller is available
- return unifiedPath, errors.New("cannot detect unified path")
- }
- return unifiedPath, nil
-}
-func createCgroupsv2Path(path string) (Err error) {
- content, err := ioutil.ReadFile("/sys/fs/cgroup/cgroup.controllers")
- if err != nil {
- return err
- }
- if !filepath.HasPrefix(path, "/sys/fs/cgroup") {
- return fmt.Errorf("invalid cgroup path %s", path)
- }
-
- res := ""
- for i, c := range strings.Split(strings.TrimSpace(string(content)), " ") {
- if i == 0 {
- res = fmt.Sprintf("+%s", c)
- } else {
- res = res + fmt.Sprintf(" +%s", c)
- }
- }
- resByte := []byte(res)
-
- current := "/sys/fs"
- elements := strings.Split(path, "/")
- for i, e := range elements[3:] {
- current = filepath.Join(current, e)
- if i > 0 {
- if err := os.Mkdir(current, 0755); err != nil {
- if !os.IsExist(err) {
- return err
- }
- } else {
- // If the directory was created, be sure it is not left around on errors.
- defer func() {
- if Err != nil {
- os.Remove(current)
- }
- }()
- }
- }
- if i < len(elements[3:])-1 {
- if err := ioutil.WriteFile(filepath.Join(current, "cgroup.subtree_control"), resByte, 0755); err != nil {
- return err
- }
- }
- }
- return nil
-}
-
-func joinCgroupsV2(c *configs.Cgroup, pid int) error {
- path, err := getSubsystemPath(c, "memory")
- if err != nil {
- return err
- }
- return createCgroupsv2Path(path)
-}
-
-func (m *UnifiedManager) fsManager() (cgroups.Manager, error) {
- path, err := m.GetUnifiedPath()
- if err != nil {
- return nil, err
- }
- return fs2.NewManager(m.Cgroups, path, false)
-}
-
-func (m *UnifiedManager) Freeze(state configs.FreezerState) error {
- fsMgr, err := m.fsManager()
- if err != nil {
- return err
- }
- return fsMgr.Freeze(state)
-}
-
-func (m *UnifiedManager) GetPids() ([]int, error) {
- path, err := m.GetUnifiedPath()
- if err != nil {
- return nil, err
- }
- return cgroups.GetPids(path)
-}
-
-func (m *UnifiedManager) GetAllPids() ([]int, error) {
- path, err := m.GetUnifiedPath()
- if err != nil {
- return nil, err
- }
- return cgroups.GetAllPids(path)
-}
-
-func (m *UnifiedManager) GetStats() (*cgroups.Stats, error) {
- fsMgr, err := m.fsManager()
- if err != nil {
- return nil, err
- }
- return fsMgr.GetStats()
-}
-
-func (m *UnifiedManager) Set(container *configs.Config) error {
- fsMgr, err := m.fsManager()
- if err != nil {
- return err
- }
- return fsMgr.Set(container)
-}
-
-func (m *UnifiedManager) GetCgroups() (*configs.Cgroup, error) {
- return m.Cgroups, nil
-}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_nosystemd.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/unsupported.go
similarity index 60%
rename from vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_nosystemd.go
rename to vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/unsupported.go
index ef0db5aeb..cb4d00c88 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/apply_nosystemd.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/unsupported.go
@@ -3,7 +3,7 @@
package systemd
import (
- "fmt"
+ "errors"
"github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/configs"
@@ -14,54 +14,58 @@ type Manager struct {
Paths map[string]string
}
-func UseSystemd() bool {
+func IsRunningSystemd() bool {
return false
}
func NewSystemdCgroupsManager() (func(config *configs.Cgroup, paths map[string]string) cgroups.Manager, error) {
- return nil, fmt.Errorf("Systemd not supported")
+ return nil, errors.New("Systemd not supported")
}
func (m *Manager) Apply(pid int) error {
- return fmt.Errorf("Systemd not supported")
+ return errors.New("Systemd not supported")
}
func (m *Manager) GetPids() ([]int, error) {
- return nil, fmt.Errorf("Systemd not supported")
+ return nil, errors.New("Systemd not supported")
}
func (m *Manager) GetAllPids() ([]int, error) {
- return nil, fmt.Errorf("Systemd not supported")
+ return nil, errors.New("Systemd not supported")
}
func (m *Manager) Destroy() error {
- return fmt.Errorf("Systemd not supported")
+ return errors.New("Systemd not supported")
}
func (m *Manager) GetPaths() map[string]string {
return nil
}
-func (m *Manager) GetUnifiedPath() (string, error) {
- return "", fmt.Errorf("Systemd not supported")
+func (m *Manager) Path(_ string) string {
+ return ""
}
func (m *Manager) GetStats() (*cgroups.Stats, error) {
- return nil, fmt.Errorf("Systemd not supported")
+ return nil, errors.New("Systemd not supported")
}
func (m *Manager) Set(container *configs.Config) error {
- return fmt.Errorf("Systemd not supported")
+ return errors.New("Systemd not supported")
}
func (m *Manager) Freeze(state configs.FreezerState) error {
- return fmt.Errorf("Systemd not supported")
+ return errors.New("Systemd not supported")
}
func Freeze(c *configs.Cgroup, state configs.FreezerState) error {
- return fmt.Errorf("Systemd not supported")
+ return errors.New("Systemd not supported")
}
func (m *Manager) GetCgroups() (*configs.Cgroup, error) {
- return nil, fmt.Errorf("Systemd not supported")
+ return nil, errors.New("Systemd not supported")
+}
+
+func (m *Manager) Exists() bool {
+ return false
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/user.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/user.go
new file mode 100644
index 000000000..cb070cec8
--- /dev/null
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/user.go
@@ -0,0 +1,106 @@
+// +build linux
+
+package systemd
+
+import (
+ "bufio"
+ "bytes"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strconv"
+ "strings"
+
+ systemdDbus "github.com/coreos/go-systemd/v22/dbus"
+ dbus "github.com/godbus/dbus/v5"
+ "github.com/opencontainers/runc/libcontainer/system"
+ "github.com/pkg/errors"
+)
+
+// NewUserSystemdDbus creates a connection for systemd user-instance.
+func NewUserSystemdDbus() (*systemdDbus.Conn, error) {
+ addr, err := DetectUserDbusSessionBusAddress()
+ if err != nil {
+ return nil, err
+ }
+ uid, err := DetectUID()
+ if err != nil {
+ return nil, err
+ }
+
+ return systemdDbus.NewConnection(func() (*dbus.Conn, error) {
+ conn, err := dbus.Dial(addr)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error while dialing %q", addr)
+ }
+ methods := []dbus.Auth{dbus.AuthExternal(strconv.Itoa(uid))}
+ err = conn.Auth(methods)
+ if err != nil {
+ conn.Close()
+ return nil, errors.Wrapf(err, "error while authenticating connection, address=%q, UID=%d", addr, uid)
+ }
+ if err = conn.Hello(); err != nil {
+ conn.Close()
+ return nil, errors.Wrapf(err, "error while sending Hello message, address=%q, UID=%d", addr, uid)
+ }
+ return conn, nil
+ })
+}
+
+// DetectUID detects UID from the OwnerUID field of `busctl --user status`
+// if running in userNS. The value corresponds to sd_bus_creds_get_owner_uid(3) .
+//
+// Otherwise returns os.Getuid() .
+func DetectUID() (int, error) {
+ if !system.RunningInUserNS() {
+ return os.Getuid(), nil
+ }
+ b, err := exec.Command("busctl", "--user", "--no-pager", "status").CombinedOutput()
+ if err != nil {
+ return -1, errors.Wrap(err, "could not execute `busctl --user --no-pager status`")
+ }
+ scanner := bufio.NewScanner(bytes.NewReader(b))
+ for scanner.Scan() {
+ s := strings.TrimSpace(scanner.Text())
+ if strings.HasPrefix(s, "OwnerUID=") {
+ uidStr := strings.TrimPrefix(s, "OwnerUID=")
+ i, err := strconv.Atoi(uidStr)
+ if err != nil {
+ return -1, errors.Wrapf(err, "could not detect the OwnerUID: %s", s)
+ }
+ return i, nil
+ }
+ }
+ if err := scanner.Err(); err != nil {
+ return -1, err
+ }
+ return -1, errors.New("could not detect the OwnerUID")
+}
+
+// DetectUserDbusSessionBusAddress returns $DBUS_SESSION_BUS_ADDRESS if set.
+// Otherwise returns "unix:path=$XDG_RUNTIME_DIR/bus" if $XDG_RUNTIME_DIR/bus exists.
+// Otherwise parses the value from `systemctl --user show-environment` .
+func DetectUserDbusSessionBusAddress() (string, error) {
+ if env := os.Getenv("DBUS_SESSION_BUS_ADDRESS"); env != "" {
+ return env, nil
+ }
+ if xdr := os.Getenv("XDG_RUNTIME_DIR"); xdr != "" {
+ busPath := filepath.Join(xdr, "bus")
+ if _, err := os.Stat(busPath); err == nil {
+ busAddress := "unix:path=" + busPath
+ return busAddress, nil
+ }
+ }
+ b, err := exec.Command("systemctl", "--user", "--no-pager", "show-environment").CombinedOutput()
+ if err != nil {
+ return "", errors.Wrapf(err, "could not execute `systemctl --user --no-pager show-environment`, output=%q", string(b))
+ }
+ scanner := bufio.NewScanner(bytes.NewReader(b))
+ for scanner.Scan() {
+ s := strings.TrimSpace(scanner.Text())
+ if strings.HasPrefix(s, "DBUS_SESSION_BUS_ADDRESS=") {
+ return strings.TrimPrefix(s, "DBUS_SESSION_BUS_ADDRESS="), nil
+ }
+ }
+ return "", errors.New("could not detect DBUS_SESSION_BUS_ADDRESS from `systemctl --user --no-pager show-environment`")
+}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/v1.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/v1.go
new file mode 100644
index 000000000..7217b0af7
--- /dev/null
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/v1.go
@@ -0,0 +1,463 @@
+// +build linux
+
+package systemd
+
+import (
+ "errors"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+ "sync"
+
+ systemdDbus "github.com/coreos/go-systemd/v22/dbus"
+ "github.com/opencontainers/runc/libcontainer/cgroups"
+ "github.com/opencontainers/runc/libcontainer/cgroups/fs"
+ "github.com/opencontainers/runc/libcontainer/configs"
+ "github.com/sirupsen/logrus"
+)
+
+type legacyManager struct {
+ mu sync.Mutex
+ cgroups *configs.Cgroup
+ paths map[string]string
+}
+
+func NewLegacyManager(cg *configs.Cgroup, paths map[string]string) cgroups.Manager {
+ return &legacyManager{
+ cgroups: cg,
+ paths: paths,
+ }
+}
+
+type subsystem interface {
+ // Name returns the name of the subsystem.
+ Name() string
+ // Returns the stats, as 'stats', corresponding to the cgroup under 'path'.
+ GetStats(path string, stats *cgroups.Stats) error
+ // Set the cgroup represented by cgroup.
+ Set(path string, cgroup *configs.Cgroup) error
+}
+
+var errSubsystemDoesNotExist = errors.New("cgroup: subsystem does not exist")
+
+var legacySubsystems = []subsystem{
+ &fs.CpusetGroup{},
+ &fs.DevicesGroup{},
+ &fs.MemoryGroup{},
+ &fs.CpuGroup{},
+ &fs.CpuacctGroup{},
+ &fs.PidsGroup{},
+ &fs.BlkioGroup{},
+ &fs.HugetlbGroup{},
+ &fs.PerfEventGroup{},
+ &fs.FreezerGroup{},
+ &fs.NetPrioGroup{},
+ &fs.NetClsGroup{},
+ &fs.NameGroup{GroupName: "name=systemd"},
+}
+
+func genV1ResourcesProperties(c *configs.Cgroup, conn *systemdDbus.Conn) ([]systemdDbus.Property, error) {
+ var properties []systemdDbus.Property
+ r := c.Resources
+
+ deviceProperties, err := generateDeviceProperties(r.Devices)
+ if err != nil {
+ return nil, err
+ }
+ properties = append(properties, deviceProperties...)
+
+ if r.Memory != 0 {
+ properties = append(properties,
+ newProp("MemoryLimit", uint64(r.Memory)))
+ }
+
+ if r.CpuShares != 0 {
+ properties = append(properties,
+ newProp("CPUShares", r.CpuShares))
+ }
+
+ addCpuQuota(conn, &properties, r.CpuQuota, r.CpuPeriod)
+
+ if r.BlkioWeight != 0 {
+ properties = append(properties,
+ newProp("BlockIOWeight", uint64(r.BlkioWeight)))
+ }
+
+ if r.PidsLimit > 0 || r.PidsLimit == -1 {
+ properties = append(properties,
+ newProp("TasksAccounting", true),
+ newProp("TasksMax", uint64(r.PidsLimit)))
+ }
+
+ return properties, nil
+}
+
+func (m *legacyManager) Apply(pid int) error {
+ var (
+ c = m.cgroups
+ unitName = getUnitName(c)
+ slice = "system.slice"
+ properties []systemdDbus.Property
+ )
+
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if c.Paths != nil {
+ paths := make(map[string]string)
+ for name, path := range c.Paths {
+ _, err := getSubsystemPath(m.cgroups, name)
+ if err != nil {
+ // Don't fail if a cgroup hierarchy was not found, just skip this subsystem
+ if cgroups.IsNotFound(err) {
+ continue
+ }
+ return err
+ }
+ paths[name] = path
+ }
+ m.paths = paths
+ return cgroups.EnterPid(m.paths, pid)
+ }
+
+ if c.Parent != "" {
+ slice = c.Parent
+ }
+
+ properties = append(properties, systemdDbus.PropDescription("libcontainer container "+c.Name))
+
+ // if we create a slice, the parent is defined via a Wants=
+ if strings.HasSuffix(unitName, ".slice") {
+ properties = append(properties, systemdDbus.PropWants(slice))
+ } else {
+ // otherwise, we use Slice=
+ properties = append(properties, systemdDbus.PropSlice(slice))
+ }
+
+ // only add pid if its valid, -1 is used w/ general slice creation.
+ if pid != -1 {
+ properties = append(properties, newProp("PIDs", []uint32{uint32(pid)}))
+ }
+
+ // Check if we can delegate. This is only supported on systemd versions 218 and above.
+ if !strings.HasSuffix(unitName, ".slice") {
+ // Assume scopes always support delegation.
+ properties = append(properties, newProp("Delegate", true))
+ }
+
+ // Always enable accounting, this gets us the same behaviour as the fs implementation,
+ // plus the kernel has some problems with joining the memory cgroup at a later time.
+ properties = append(properties,
+ newProp("MemoryAccounting", true),
+ newProp("CPUAccounting", true),
+ newProp("BlockIOAccounting", true))
+
+ // Assume DefaultDependencies= will always work (the check for it was previously broken.)
+ properties = append(properties,
+ newProp("DefaultDependencies", false))
+
+ dbusConnection, err := getDbusConnection(false)
+ if err != nil {
+ return err
+ }
+ resourcesProperties, err := genV1ResourcesProperties(c, dbusConnection)
+ if err != nil {
+ return err
+ }
+ properties = append(properties, resourcesProperties...)
+ properties = append(properties, c.SystemdProps...)
+
+ // We have to set kernel memory here, as we can't change it once
+ // processes have been attached to the cgroup.
+ if c.Resources.KernelMemory != 0 {
+ if err := enableKmem(c); err != nil {
+ return err
+ }
+ }
+
+ if err := startUnit(dbusConnection, unitName, properties); err != nil {
+ return err
+ }
+
+ if err := joinCgroups(c, pid); err != nil {
+ return err
+ }
+
+ paths := make(map[string]string)
+ for _, s := range legacySubsystems {
+ subsystemPath, err := getSubsystemPath(m.cgroups, s.Name())
+ if err != nil {
+ // Don't fail if a cgroup hierarchy was not found, just skip this subsystem
+ if cgroups.IsNotFound(err) {
+ continue
+ }
+ return err
+ }
+ paths[s.Name()] = subsystemPath
+ }
+ m.paths = paths
+ return nil
+}
+
+func (m *legacyManager) Destroy() error {
+ if m.cgroups.Paths != nil {
+ return nil
+ }
+ m.mu.Lock()
+ defer m.mu.Unlock()
+
+ dbusConnection, err := getDbusConnection(false)
+ if err != nil {
+ return err
+ }
+ unitName := getUnitName(m.cgroups)
+
+ err = stopUnit(dbusConnection, unitName)
+ // Both on success and on error, cleanup all the cgroups we are aware of.
+ // Some of them were created directly by Apply() and are not managed by systemd.
+ if err := cgroups.RemovePaths(m.paths); err != nil {
+ return err
+ }
+ if err != nil {
+ return err
+ }
+ m.paths = make(map[string]string)
+ return nil
+}
+
+func (m *legacyManager) Path(subsys string) string {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ return m.paths[subsys]
+}
+
+func join(c *configs.Cgroup, subsystem string, pid int) (string, error) {
+ path, err := getSubsystemPath(c, subsystem)
+ if err != nil {
+ return "", err
+ }
+
+ if err := os.MkdirAll(path, 0755); err != nil {
+ return "", err
+ }
+ if err := cgroups.WriteCgroupProc(path, pid); err != nil {
+ return "", err
+ }
+ return path, nil
+}
+
+func joinCgroups(c *configs.Cgroup, pid int) error {
+ for _, sys := range legacySubsystems {
+ name := sys.Name()
+ switch name {
+ case "name=systemd":
+ // let systemd handle this
+ case "cpuset":
+ path, err := getSubsystemPath(c, name)
+ if err != nil && !cgroups.IsNotFound(err) {
+ return err
+ }
+ s := &fs.CpusetGroup{}
+ if err := s.ApplyDir(path, c, pid); err != nil {
+ return err
+ }
+ default:
+ _, err := join(c, name, pid)
+ if err != nil {
+ // Even if it's `not found` error, we'll return err
+ // because devices cgroup is hard requirement for
+ // container security.
+ if name == "devices" {
+ return err
+ }
+ // For other subsystems, omit the `not found` error
+ // because they are optional.
+ if !cgroups.IsNotFound(err) {
+ return err
+ }
+ }
+ }
+ }
+
+ return nil
+}
+
+func getSubsystemPath(c *configs.Cgroup, subsystem string) (string, error) {
+ mountpoint, err := cgroups.FindCgroupMountpoint(c.Path, subsystem)
+ if err != nil {
+ return "", err
+ }
+
+ initPath, err := cgroups.GetInitCgroup(subsystem)
+ if err != nil {
+ return "", err
+ }
+ // if pid 1 is systemd 226 or later, it will be in init.scope, not the root
+ initPath = strings.TrimSuffix(filepath.Clean(initPath), "init.scope")
+
+ slice := "system.slice"
+ if c.Parent != "" {
+ slice = c.Parent
+ }
+
+ slice, err = ExpandSlice(slice)
+ if err != nil {
+ return "", err
+ }
+
+ return filepath.Join(mountpoint, initPath, slice, getUnitName(c)), nil
+}
+
+func (m *legacyManager) Freeze(state configs.FreezerState) error {
+ path, err := getSubsystemPath(m.cgroups, "freezer")
+ if err != nil {
+ return err
+ }
+ prevState := m.cgroups.Resources.Freezer
+ m.cgroups.Resources.Freezer = state
+ freezer := &fs.FreezerGroup{}
+ err = freezer.Set(path, m.cgroups)
+ if err != nil {
+ m.cgroups.Resources.Freezer = prevState
+ return err
+ }
+ return nil
+}
+
+func (m *legacyManager) GetPids() ([]int, error) {
+ path, err := getSubsystemPath(m.cgroups, "devices")
+ if err != nil {
+ return nil, err
+ }
+ return cgroups.GetPids(path)
+}
+
+func (m *legacyManager) GetAllPids() ([]int, error) {
+ path, err := getSubsystemPath(m.cgroups, "devices")
+ if err != nil {
+ return nil, err
+ }
+ return cgroups.GetAllPids(path)
+}
+
+func (m *legacyManager) GetStats() (*cgroups.Stats, error) {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ stats := cgroups.NewStats()
+ for _, sys := range legacySubsystems {
+ path := m.paths[sys.Name()]
+ if path == "" {
+ continue
+ }
+ if err := sys.GetStats(path, stats); err != nil {
+ return nil, err
+ }
+ }
+
+ return stats, nil
+}
+
+func (m *legacyManager) Set(container *configs.Config) error {
+ // If Paths are set, then we are just joining cgroups paths
+ // and there is no need to set any values.
+ if m.cgroups.Paths != nil {
+ return nil
+ }
+ dbusConnection, err := getDbusConnection(false)
+ if err != nil {
+ return err
+ }
+ properties, err := genV1ResourcesProperties(container.Cgroups, dbusConnection)
+ if err != nil {
+ return err
+ }
+
+ // We have to freeze the container while systemd sets the cgroup settings.
+ // The reason for this is that systemd's application of DeviceAllow rules
+ // is done disruptively, resulting in spurrious errors to common devices
+ // (unlike our fs driver, they will happily write deny-all rules to running
+ // containers). So we freeze the container to avoid them hitting the cgroup
+ // error. But if the freezer cgroup isn't supported, we just warn about it.
+ targetFreezerState := configs.Undefined
+ if !m.cgroups.SkipDevices {
+ // Figure out the current freezer state, so we can revert to it after we
+ // temporarily freeze the container.
+ targetFreezerState, err = m.GetFreezerState()
+ if err != nil {
+ return err
+ }
+ if targetFreezerState == configs.Undefined {
+ targetFreezerState = configs.Thawed
+ }
+
+ if err := m.Freeze(configs.Frozen); err != nil {
+ logrus.Infof("freeze container before SetUnitProperties failed: %v", err)
+ }
+ }
+
+ if err := dbusConnection.SetUnitProperties(getUnitName(container.Cgroups), true, properties...); err != nil {
+ _ = m.Freeze(targetFreezerState)
+ return err
+ }
+
+ // Reset freezer state before we apply the configuration, to avoid clashing
+ // with the freezer setting in the configuration.
+ _ = m.Freeze(targetFreezerState)
+
+ for _, sys := range legacySubsystems {
+ // Get the subsystem path, but don't error out for not found cgroups.
+ path, err := getSubsystemPath(container.Cgroups, sys.Name())
+ if err != nil && !cgroups.IsNotFound(err) {
+ return err
+ }
+ if err := sys.Set(path, container.Cgroups); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func enableKmem(c *configs.Cgroup) error {
+ path, err := getSubsystemPath(c, "memory")
+ if err != nil && !cgroups.IsNotFound(err) {
+ return err
+ }
+
+ if err := os.MkdirAll(path, 0755); err != nil {
+ return err
+ }
+ // do not try to enable the kernel memory if we already have
+ // tasks in the cgroup.
+ content, err := ioutil.ReadFile(filepath.Join(path, "tasks"))
+ if err != nil {
+ return err
+ }
+ if len(content) > 0 {
+ return nil
+ }
+ return fs.EnableKernelMemoryAccounting(path)
+}
+
+func (m *legacyManager) GetPaths() map[string]string {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ return m.paths
+}
+
+func (m *legacyManager) GetCgroups() (*configs.Cgroup, error) {
+ return m.cgroups, nil
+}
+
+func (m *legacyManager) GetFreezerState() (configs.FreezerState, error) {
+ path, err := getSubsystemPath(m.cgroups, "freezer")
+ if err != nil && !cgroups.IsNotFound(err) {
+ return configs.Undefined, err
+ }
+ freezer := &fs.FreezerGroup{}
+ return freezer.GetState(path)
+}
+
+func (m *legacyManager) Exists() bool {
+ return cgroups.PathExists(m.Path("devices"))
+}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/v2.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/v2.go
new file mode 100644
index 000000000..e1a6622a0
--- /dev/null
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd/v2.go
@@ -0,0 +1,360 @@
+// +build linux
+
+package systemd
+
+import (
+ "os"
+ "path/filepath"
+ "strconv"
+ "strings"
+ "sync"
+
+ systemdDbus "github.com/coreos/go-systemd/v22/dbus"
+ securejoin "github.com/cyphar/filepath-securejoin"
+ "github.com/opencontainers/runc/libcontainer/cgroups"
+ "github.com/opencontainers/runc/libcontainer/cgroups/fs2"
+ "github.com/opencontainers/runc/libcontainer/configs"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+type unifiedManager struct {
+ mu sync.Mutex
+ cgroups *configs.Cgroup
+ // path is like "/sys/fs/cgroup/user.slice/user-1001.slice/session-1.scope"
+ path string
+ rootless bool
+}
+
+func NewUnifiedManager(config *configs.Cgroup, path string, rootless bool) cgroups.Manager {
+ return &unifiedManager{
+ cgroups: config,
+ path: path,
+ rootless: rootless,
+ }
+}
+
+func genV2ResourcesProperties(c *configs.Cgroup, conn *systemdDbus.Conn) ([]systemdDbus.Property, error) {
+ var properties []systemdDbus.Property
+ r := c.Resources
+
+ // NOTE: This is of questionable correctness because we insert our own
+ // devices eBPF program later. Two programs with identical rules
+ // aren't the end of the world, but it is a bit concerning. However
+ // it's unclear if systemd removes all eBPF programs attached when
+ // doing SetUnitProperties...
+ deviceProperties, err := generateDeviceProperties(r.Devices)
+ if err != nil {
+ return nil, err
+ }
+ properties = append(properties, deviceProperties...)
+
+ if r.Memory != 0 {
+ properties = append(properties,
+ newProp("MemoryMax", uint64(r.Memory)))
+ }
+ if r.MemoryReservation != 0 {
+ properties = append(properties,
+ newProp("MemoryLow", uint64(r.MemoryReservation)))
+ }
+
+ swap, err := cgroups.ConvertMemorySwapToCgroupV2Value(r.MemorySwap, r.Memory)
+ if err != nil {
+ return nil, err
+ }
+ if swap != 0 {
+ properties = append(properties,
+ newProp("MemorySwapMax", uint64(swap)))
+ }
+
+ if r.CpuWeight != 0 {
+ properties = append(properties,
+ newProp("CPUWeight", r.CpuWeight))
+ }
+
+ addCpuQuota(conn, &properties, r.CpuQuota, r.CpuPeriod)
+
+ if r.PidsLimit > 0 || r.PidsLimit == -1 {
+ properties = append(properties,
+ newProp("TasksAccounting", true),
+ newProp("TasksMax", uint64(r.PidsLimit)))
+ }
+
+ // ignore r.KernelMemory
+
+ return properties, nil
+}
+
+func (m *unifiedManager) Apply(pid int) error {
+ var (
+ c = m.cgroups
+ unitName = getUnitName(c)
+ properties []systemdDbus.Property
+ )
+
+ if c.Paths != nil {
+ return cgroups.WriteCgroupProc(m.path, pid)
+ }
+
+ slice := "system.slice"
+ if m.rootless {
+ slice = "user.slice"
+ }
+ if c.Parent != "" {
+ slice = c.Parent
+ }
+
+ properties = append(properties, systemdDbus.PropDescription("libcontainer container "+c.Name))
+
+ // if we create a slice, the parent is defined via a Wants=
+ if strings.HasSuffix(unitName, ".slice") {
+ properties = append(properties, systemdDbus.PropWants(slice))
+ } else {
+ // otherwise, we use Slice=
+ properties = append(properties, systemdDbus.PropSlice(slice))
+ }
+
+ // only add pid if its valid, -1 is used w/ general slice creation.
+ if pid != -1 {
+ properties = append(properties, newProp("PIDs", []uint32{uint32(pid)}))
+ }
+
+ // Check if we can delegate. This is only supported on systemd versions 218 and above.
+ if !strings.HasSuffix(unitName, ".slice") {
+ // Assume scopes always support delegation.
+ properties = append(properties, newProp("Delegate", true))
+ }
+
+ // Always enable accounting, this gets us the same behaviour as the fs implementation,
+ // plus the kernel has some problems with joining the memory cgroup at a later time.
+ properties = append(properties,
+ newProp("MemoryAccounting", true),
+ newProp("CPUAccounting", true),
+ newProp("IOAccounting", true))
+
+ // Assume DefaultDependencies= will always work (the check for it was previously broken.)
+ properties = append(properties,
+ newProp("DefaultDependencies", false))
+
+ dbusConnection, err := getDbusConnection(m.rootless)
+ if err != nil {
+ return err
+ }
+ resourcesProperties, err := genV2ResourcesProperties(c, dbusConnection)
+ if err != nil {
+ return err
+ }
+ properties = append(properties, resourcesProperties...)
+ properties = append(properties, c.SystemdProps...)
+
+ if err := startUnit(dbusConnection, unitName, properties); err != nil {
+ return errors.Wrapf(err, "error while starting unit %q with properties %+v", unitName, properties)
+ }
+
+ if err = m.initPath(); err != nil {
+ return err
+ }
+ if err := fs2.CreateCgroupPath(m.path, m.cgroups); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (m *unifiedManager) Destroy() error {
+ if m.cgroups.Paths != nil {
+ return nil
+ }
+ m.mu.Lock()
+ defer m.mu.Unlock()
+
+ dbusConnection, err := getDbusConnection(m.rootless)
+ if err != nil {
+ return err
+ }
+ unitName := getUnitName(m.cgroups)
+ if err := stopUnit(dbusConnection, unitName); err != nil {
+ return err
+ }
+
+ // XXX this is probably not needed, systemd should handle it
+ err = os.Remove(m.path)
+ if err != nil && !os.IsNotExist(err) {
+ return err
+ }
+
+ return nil
+}
+
+func (m *unifiedManager) Path(_ string) string {
+ return m.path
+}
+
+// getSliceFull value is used in initPath.
+// The value is incompatible with systemdDbus.PropSlice.
+func (m *unifiedManager) getSliceFull() (string, error) {
+ c := m.cgroups
+ slice := "system.slice"
+ if m.rootless {
+ slice = "user.slice"
+ }
+ if c.Parent != "" {
+ var err error
+ slice, err = ExpandSlice(c.Parent)
+ if err != nil {
+ return "", err
+ }
+ }
+
+ if m.rootless {
+ dbusConnection, err := getDbusConnection(m.rootless)
+ if err != nil {
+ return "", err
+ }
+ // managerCGQuoted is typically "/user.slice/user-${uid}.slice/user@${uid}.service" including the quote symbols
+ managerCGQuoted, err := dbusConnection.GetManagerProperty("ControlGroup")
+ if err != nil {
+ return "", err
+ }
+ managerCG, err := strconv.Unquote(managerCGQuoted)
+ if err != nil {
+ return "", err
+ }
+ slice = filepath.Join(managerCG, slice)
+ }
+
+ // an example of the final slice in rootless: "/user.slice/user-1001.slice/user@1001.service/user.slice"
+ // NOTE: systemdDbus.PropSlice requires the "/user.slice/user-1001.slice/user@1001.service/" prefix NOT to be specified.
+ return slice, nil
+}
+
+func (m *unifiedManager) initPath() error {
+ if m.path != "" {
+ return nil
+ }
+
+ sliceFull, err := m.getSliceFull()
+ if err != nil {
+ return err
+ }
+
+ c := m.cgroups
+ path := filepath.Join(sliceFull, getUnitName(c))
+ path, err = securejoin.SecureJoin(fs2.UnifiedMountpoint, path)
+ if err != nil {
+ return err
+ }
+
+ // an example of the final path in rootless:
+ // "/sys/fs/cgroup/user.slice/user-1001.slice/user@1001.service/user.slice/libpod-132ff0d72245e6f13a3bbc6cdc5376886897b60ac59eaa8dea1df7ab959cbf1c.scope"
+ m.path = path
+
+ return nil
+}
+
+func (m *unifiedManager) fsManager() (cgroups.Manager, error) {
+ if err := m.initPath(); err != nil {
+ return nil, err
+ }
+ return fs2.NewManager(m.cgroups, m.path, m.rootless)
+}
+
+func (m *unifiedManager) Freeze(state configs.FreezerState) error {
+ fsMgr, err := m.fsManager()
+ if err != nil {
+ return err
+ }
+ return fsMgr.Freeze(state)
+}
+
+func (m *unifiedManager) GetPids() ([]int, error) {
+ if err := m.initPath(); err != nil {
+ return nil, err
+ }
+ return cgroups.GetPids(m.path)
+}
+
+func (m *unifiedManager) GetAllPids() ([]int, error) {
+ if err := m.initPath(); err != nil {
+ return nil, err
+ }
+ return cgroups.GetAllPids(m.path)
+}
+
+func (m *unifiedManager) GetStats() (*cgroups.Stats, error) {
+ fsMgr, err := m.fsManager()
+ if err != nil {
+ return nil, err
+ }
+ return fsMgr.GetStats()
+}
+
+func (m *unifiedManager) Set(container *configs.Config) error {
+ dbusConnection, err := getDbusConnection(m.rootless)
+ if err != nil {
+ return err
+ }
+ properties, err := genV2ResourcesProperties(m.cgroups, dbusConnection)
+ if err != nil {
+ return err
+ }
+
+ // We have to freeze the container while systemd sets the cgroup settings.
+ // The reason for this is that systemd's application of DeviceAllow rules
+ // is done disruptively, resulting in spurrious errors to common devices
+ // (unlike our fs driver, they will happily write deny-all rules to running
+ // containers). So we freeze the container to avoid them hitting the cgroup
+ // error. But if the freezer cgroup isn't supported, we just warn about it.
+ targetFreezerState := configs.Undefined
+ if !m.cgroups.SkipDevices {
+ // Figure out the current freezer state, so we can revert to it after we
+ // temporarily freeze the container.
+ targetFreezerState, err = m.GetFreezerState()
+ if err != nil {
+ return err
+ }
+ if targetFreezerState == configs.Undefined {
+ targetFreezerState = configs.Thawed
+ }
+
+ if err := m.Freeze(configs.Frozen); err != nil {
+ logrus.Infof("freeze container before SetUnitProperties failed: %v", err)
+ }
+ }
+
+ if err := dbusConnection.SetUnitProperties(getUnitName(m.cgroups), true, properties...); err != nil {
+ _ = m.Freeze(targetFreezerState)
+ return errors.Wrap(err, "error while setting unit properties")
+ }
+
+ // Reset freezer state before we apply the configuration, to avoid clashing
+ // with the freezer setting in the configuration.
+ _ = m.Freeze(targetFreezerState)
+
+ fsMgr, err := m.fsManager()
+ if err != nil {
+ return err
+ }
+ return fsMgr.Set(container)
+}
+
+func (m *unifiedManager) GetPaths() map[string]string {
+ paths := make(map[string]string, 1)
+ paths[""] = m.path
+ return paths
+}
+
+func (m *unifiedManager) GetCgroups() (*configs.Cgroup, error) {
+ return m.cgroups, nil
+}
+
+func (m *unifiedManager) GetFreezerState() (configs.FreezerState, error) {
+ fsMgr, err := m.fsManager()
+ if err != nil {
+ return configs.Undefined, err
+ }
+ return fsMgr.GetFreezerState()
+}
+
+func (m *unifiedManager) Exists() bool {
+ return cgroups.PathExists(m.path)
+}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go
index dbcc58f5b..6e88b5dff 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/utils.go
@@ -4,6 +4,7 @@ package cgroups
import (
"bufio"
+ "errors"
"fmt"
"io"
"io/ioutil"
@@ -12,7 +13,6 @@ import (
"strconv"
"strings"
"sync"
- "syscall"
"time"
units "github.com/docker/go-units"
@@ -20,7 +20,6 @@ import (
)
const (
- CgroupNamePrefix = "name="
CgroupProcesses = "cgroup.procs"
unifiedMountpoint = "/sys/fs/cgroup"
)
@@ -40,8 +39,8 @@ var HugePageSizeUnitList = []string{"B", "KB", "MB", "GB", "TB", "PB"}
// IsCgroup2UnifiedMode returns whether we are running in cgroup v2 unified mode.
func IsCgroup2UnifiedMode() bool {
isUnifiedOnce.Do(func() {
- var st syscall.Statfs_t
- if err := syscall.Statfs(unifiedMountpoint, &st); err != nil {
+ var st unix.Statfs_t
+ if err := unix.Statfs(unifiedMountpoint, &st); err != nil {
panic("cannot statfs cgroup root")
}
isUnified = st.Type == unix.CGROUP2_SUPER_MAGIC
@@ -49,191 +48,19 @@ func IsCgroup2UnifiedMode() bool {
return isUnified
}
-// https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt
-func FindCgroupMountpoint(cgroupPath, subsystem string) (string, error) {
- if IsCgroup2UnifiedMode() {
- return unifiedMountpoint, nil
- }
- mnt, _, err := FindCgroupMountpointAndRoot(cgroupPath, subsystem)
- return mnt, err
-}
-
-func FindCgroupMountpointAndRoot(cgroupPath, subsystem string) (string, string, error) {
- // We are not using mount.GetMounts() because it's super-inefficient,
- // parsing it directly sped up x10 times because of not using Sscanf.
- // It was one of two major performance drawbacks in container start.
- if !isSubsystemAvailable(subsystem) {
- return "", "", NewNotFoundError(subsystem)
- }
-
- f, err := os.Open("/proc/self/mountinfo")
- if err != nil {
- return "", "", err
- }
- defer f.Close()
-
- if IsCgroup2UnifiedMode() {
- subsystem = ""
- }
-
- return findCgroupMountpointAndRootFromReader(f, cgroupPath, subsystem)
-}
-
-func findCgroupMountpointAndRootFromReader(reader io.Reader, cgroupPath, subsystem string) (string, string, error) {
- scanner := bufio.NewScanner(reader)
- for scanner.Scan() {
- txt := scanner.Text()
- fields := strings.Fields(txt)
- if len(fields) < 9 {
- continue
- }
- if strings.HasPrefix(fields[4], cgroupPath) {
- for _, opt := range strings.Split(fields[len(fields)-1], ",") {
- if (subsystem == "" && fields[9] == "cgroup2") || opt == subsystem {
- return fields[4], fields[3], nil
- }
- }
- }
- }
- if err := scanner.Err(); err != nil {
- return "", "", err
- }
-
- return "", "", NewNotFoundError(subsystem)
-}
-
-func isSubsystemAvailable(subsystem string) bool {
- if IsCgroup2UnifiedMode() {
- controllers, err := GetAllSubsystems()
- if err != nil {
- return false
- }
- for _, c := range controllers {
- if c == subsystem {
- return true
- }
- }
- return false
- }
-
- cgroups, err := ParseCgroupFile("/proc/self/cgroup")
- if err != nil {
- return false
- }
- _, avail := cgroups[subsystem]
- return avail
-}
-
-func GetClosestMountpointAncestor(dir, mountinfo string) string {
- deepestMountPoint := ""
- for _, mountInfoEntry := range strings.Split(mountinfo, "\n") {
- mountInfoParts := strings.Fields(mountInfoEntry)
- if len(mountInfoParts) < 5 {
- continue
- }
- mountPoint := mountInfoParts[4]
- if strings.HasPrefix(mountPoint, deepestMountPoint) && strings.HasPrefix(dir, mountPoint) {
- deepestMountPoint = mountPoint
- }
- }
- return deepestMountPoint
-}
-
-func FindCgroupMountpointDir() (string, error) {
- f, err := os.Open("/proc/self/mountinfo")
- if err != nil {
- return "", err
- }
- defer f.Close()
-
- scanner := bufio.NewScanner(f)
- for scanner.Scan() {
- text := scanner.Text()
- fields := strings.Split(text, " ")
- // Safe as mountinfo encodes mountpoints with spaces as \040.
- index := strings.Index(text, " - ")
- postSeparatorFields := strings.Fields(text[index+3:])
- numPostFields := len(postSeparatorFields)
-
- // This is an error as we can't detect if the mount is for "cgroup"
- if numPostFields == 0 {
- return "", fmt.Errorf("Found no fields post '-' in %q", text)
- }
-
- if postSeparatorFields[0] == "cgroup" || postSeparatorFields[0] == "cgroup2" {
- // Check that the mount is properly formatted.
- if numPostFields < 3 {
- return "", fmt.Errorf("Error found less than 3 fields post '-' in %q", text)
- }
-
- return filepath.Dir(fields[4]), nil
- }
- }
- if err := scanner.Err(); err != nil {
- return "", err
- }
-
- return "", NewNotFoundError("cgroup")
-}
-
type Mount struct {
Mountpoint string
Root string
Subsystems []string
}
-func (m Mount) GetOwnCgroup(cgroups map[string]string) (string, error) {
- if len(m.Subsystems) == 0 {
- return "", fmt.Errorf("no subsystem for mount")
- }
-
- return getControllerPath(m.Subsystems[0], cgroups)
-}
-
-func getCgroupMountsHelper(ss map[string]bool, mi io.Reader, all bool) ([]Mount, error) {
- res := make([]Mount, 0, len(ss))
- scanner := bufio.NewScanner(mi)
- numFound := 0
- for scanner.Scan() && numFound < len(ss) {
- txt := scanner.Text()
- sepIdx := strings.Index(txt, " - ")
- if sepIdx == -1 {
- return nil, fmt.Errorf("invalid mountinfo format")
- }
- if txt[sepIdx+3:sepIdx+10] == "cgroup2" || txt[sepIdx+3:sepIdx+9] != "cgroup" {
- continue
- }
- fields := strings.Split(txt, " ")
- m := Mount{
- Mountpoint: fields[4],
- Root: fields[3],
- }
- for _, opt := range strings.Split(fields[len(fields)-1], ",") {
- seen, known := ss[opt]
- if !known || (!all && seen) {
- continue
- }
- ss[opt] = true
- if strings.HasPrefix(opt, CgroupNamePrefix) {
- opt = opt[len(CgroupNamePrefix):]
- }
- m.Subsystems = append(m.Subsystems, opt)
- numFound++
- }
- if len(m.Subsystems) > 0 || all {
- res = append(res, m)
- }
- }
- if err := scanner.Err(); err != nil {
- return nil, err
- }
- return res, nil
-}
-
// GetCgroupMounts returns the mounts for the cgroup subsystems.
// all indicates whether to return just the first instance or all the mounts.
+// This function should not be used from cgroupv2 code, as in this case
+// all the controllers are available under the constant unifiedMountpoint.
func GetCgroupMounts(all bool) ([]Mount, error) {
if IsCgroup2UnifiedMode() {
+ // TODO: remove cgroupv2 case once all external users are converted
availableControllers, err := GetAllSubsystems()
if err != nil {
return nil, err
@@ -246,22 +73,7 @@ func GetCgroupMounts(all bool) ([]Mount, error) {
return []Mount{m}, nil
}
- f, err := os.Open("/proc/self/mountinfo")
- if err != nil {
- return nil, err
- }
- defer f.Close()
-
- allSubsystems, err := ParseCgroupFile("/proc/self/cgroup")
- if err != nil {
- return nil, err
- }
-
- allMap := make(map[string]bool)
- for s := range allSubsystems {
- allMap[s] = false
- }
- return getCgroupMountsHelper(allMap, f, all)
+ return getCgroupMountsV1(all)
}
// GetAllSubsystems returns all the cgroup subsystems supported by the kernel
@@ -305,61 +117,8 @@ func GetAllSubsystems() ([]string, error) {
return subsystems, nil
}
-// GetOwnCgroup returns the relative path to the cgroup docker is running in.
-func GetOwnCgroup(subsystem string) (string, error) {
- cgroups, err := ParseCgroupFile("/proc/self/cgroup")
- if err != nil {
- return "", err
- }
-
- return getControllerPath(subsystem, cgroups)
-}
-
-func GetOwnCgroupPath(subsystem string) (string, error) {
- cgroup, err := GetOwnCgroup(subsystem)
- if err != nil {
- return "", err
- }
-
- return getCgroupPathHelper(subsystem, cgroup)
-}
-
-func GetInitCgroup(subsystem string) (string, error) {
- cgroups, err := ParseCgroupFile("/proc/1/cgroup")
- if err != nil {
- return "", err
- }
-
- return getControllerPath(subsystem, cgroups)
-}
-
-func GetInitCgroupPath(subsystem string) (string, error) {
- cgroup, err := GetInitCgroup(subsystem)
- if err != nil {
- return "", err
- }
-
- return getCgroupPathHelper(subsystem, cgroup)
-}
-
-func getCgroupPathHelper(subsystem, cgroup string) (string, error) {
- mnt, root, err := FindCgroupMountpointAndRoot("", subsystem)
- if err != nil {
- return "", err
- }
-
- // This is needed for nested containers, because in /proc/self/cgroup we
- // see paths from host, which don't exist in container.
- relCgroup, err := filepath.Rel(root, cgroup)
- if err != nil {
- return "", err
- }
-
- return filepath.Join(mnt, relCgroup), nil
-}
-
-func readProcsFile(dir string) ([]int, error) {
- f, err := os.Open(filepath.Join(dir, CgroupProcesses))
+func readProcsFile(file string) ([]int, error) {
+ f, err := os.Open(file)
if err != nil {
return nil, err
}
@@ -379,11 +138,18 @@ func readProcsFile(dir string) ([]int, error) {
out = append(out, pid)
}
}
- return out, nil
+ return out, s.Err()
}
-// ParseCgroupFile parses the given cgroup file, typically from
-// /proc//cgroup, into a map of subgroups to cgroup names.
+// ParseCgroupFile parses the given cgroup file, typically /proc/self/cgroup
+// or /proc//cgroup, into a map of subsystems to cgroup paths, e.g.
+// "cpu": "/user.slice/user-1000.slice"
+// "pids": "/user.slice/user-1000.slice"
+// etc.
+//
+// Note that for cgroup v2 unified hierarchy, there are no per-controller
+// cgroup paths, so the resulting map will have a single element where the key
+// is empty string ("") and the value is the cgroup path the is in.
func ParseCgroupFile(path string) (map[string]string, error) {
f, err := os.Open(path)
if err != nil {
@@ -423,22 +189,6 @@ func parseCgroupFromReader(r io.Reader) (map[string]string, error) {
return cgroups, nil
}
-func getControllerPath(subsystem string, cgroups map[string]string) (string, error) {
- if IsCgroup2UnifiedMode() {
- return "/", nil
- }
-
- if p, ok := cgroups[subsystem]; ok {
- return p, nil
- }
-
- if p, ok := cgroups[CgroupNamePrefix+subsystem]; ok {
- return p, nil
- }
-
- return "", NewNotFoundError(subsystem)
-}
-
func PathExists(path string) bool {
if _, err := os.Stat(path); err != nil {
return false
@@ -514,8 +264,8 @@ func getHugePageSizeFromFilenames(fileNames []string) ([]string, error) {
}
// GetPids returns all pids, that were added to cgroup at path.
-func GetPids(path string) ([]int, error) {
- return readProcsFile(path)
+func GetPids(dir string) ([]int, error) {
+ return readProcsFile(filepath.Join(dir, CgroupProcesses))
}
// GetAllPids returns all pids, that were added to cgroup at path and to all its
@@ -524,14 +274,13 @@ func GetAllPids(path string) ([]int, error) {
var pids []int
// collect pids from all sub-cgroups
err := filepath.Walk(path, func(p string, info os.FileInfo, iErr error) error {
- dir, file := filepath.Split(p)
- if file != CgroupProcesses {
- return nil
- }
if iErr != nil {
return iErr
}
- cPids, err := readProcsFile(dir)
+ if info.IsDir() || info.Name() != CgroupProcesses {
+ return nil
+ }
+ cPids, err := readProcsFile(p)
if err != nil {
return err
}
@@ -568,7 +317,7 @@ func WriteCgroupProc(dir string, pid int) error {
// EINVAL might mean that the task being added to cgroup.procs is in state
// TASK_NEW. We should attempt to do so again.
- if isEINVAL(err) {
+ if errors.Is(err, unix.EINVAL) {
time.Sleep(30 * time.Millisecond)
continue
}
@@ -578,11 +327,53 @@ func WriteCgroupProc(dir string, pid int) error {
return err
}
-func isEINVAL(err error) bool {
- switch err := err.(type) {
- case *os.PathError:
- return err.Err == unix.EINVAL
- default:
- return false
+// Since the OCI spec is designed for cgroup v1, in some cases
+// there is need to convert from the cgroup v1 configuration to cgroup v2
+// the formula for BlkIOWeight is y = (1 + (x - 10) * 9999 / 990)
+// convert linearly from [10-1000] to [1-10000]
+func ConvertBlkIOToCgroupV2Value(blkIoWeight uint16) uint64 {
+ if blkIoWeight == 0 {
+ return 0
}
+ return uint64(1 + (uint64(blkIoWeight)-10)*9999/990)
+}
+
+// Since the OCI spec is designed for cgroup v1, in some cases
+// there is need to convert from the cgroup v1 configuration to cgroup v2
+// the formula for cpuShares is y = (1 + ((x - 2) * 9999) / 262142)
+// convert from [2-262144] to [1-10000]
+// 262144 comes from Linux kernel definition "#define MAX_SHARES (1UL << 18)"
+func ConvertCPUSharesToCgroupV2Value(cpuShares uint64) uint64 {
+ if cpuShares == 0 {
+ return 0
+ }
+ return (1 + ((cpuShares-2)*9999)/262142)
+}
+
+// ConvertMemorySwapToCgroupV2Value converts MemorySwap value from OCI spec
+// for use by cgroup v2 drivers. A conversion is needed since Resources.MemorySwap
+// is defined as memory+swap combined, while in cgroup v2 swap is a separate value.
+func ConvertMemorySwapToCgroupV2Value(memorySwap, memory int64) (int64, error) {
+ // for compatibility with cgroup1 controller, set swap to unlimited in
+ // case the memory is set to unlimited, and swap is not explicitly set,
+ // treating the request as "set both memory and swap to unlimited".
+ if memory == -1 && memorySwap == 0 {
+ return -1, nil
+ }
+ if memorySwap == -1 || memorySwap == 0 {
+ // -1 is "max", 0 is "unset", so treat as is
+ return memorySwap, nil
+ }
+ // sanity checks
+ if memory == 0 || memory == -1 {
+ return 0, errors.New("unable to set swap limit without memory limit")
+ }
+ if memory < 0 {
+ return 0, fmt.Errorf("invalid memory value: %d", memory)
+ }
+ if memorySwap < memory {
+ return 0, errors.New("memory+swap limit should be >= memory limit")
+ }
+
+ return memorySwap - memory, nil
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/cgroups/v1_utils.go b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/v1_utils.go
new file mode 100644
index 000000000..a94f20861
--- /dev/null
+++ b/vendor/github.com/opencontainers/runc/libcontainer/cgroups/v1_utils.go
@@ -0,0 +1,301 @@
+package cgroups
+
+import (
+ "bufio"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "strings"
+ "syscall"
+
+ securejoin "github.com/cyphar/filepath-securejoin"
+ "golang.org/x/sys/unix"
+)
+
+// Code in this source file are specific to cgroup v1,
+// and must not be used from any cgroup v2 code.
+
+const (
+ CgroupNamePrefix = "name="
+ defaultPrefix = "/sys/fs/cgroup"
+)
+
+var (
+ errUnified = errors.New("not implemented for cgroup v2 unified hierarchy")
+)
+
+type NotFoundError struct {
+ Subsystem string
+}
+
+func (e *NotFoundError) Error() string {
+ return fmt.Sprintf("mountpoint for %s not found", e.Subsystem)
+}
+
+func NewNotFoundError(sub string) error {
+ return &NotFoundError{
+ Subsystem: sub,
+ }
+}
+
+func IsNotFound(err error) bool {
+ if err == nil {
+ return false
+ }
+ _, ok := err.(*NotFoundError)
+ return ok
+}
+
+func tryDefaultPath(cgroupPath, subsystem string) string {
+ if !strings.HasPrefix(defaultPrefix, cgroupPath) {
+ return ""
+ }
+
+ // remove possible prefix
+ subsystem = strings.TrimPrefix(subsystem, CgroupNamePrefix)
+
+ // Make sure we're still under defaultPrefix, and resolve
+ // a possible symlink (like cpu -> cpu,cpuacct).
+ path, err := securejoin.SecureJoin(defaultPrefix, subsystem)
+ if err != nil {
+ return ""
+ }
+
+ // (1) path should be a directory.
+ st, err := os.Lstat(path)
+ if err != nil || !st.IsDir() {
+ return ""
+ }
+
+ // (2) path should be a mount point.
+ pst, err := os.Lstat(filepath.Dir(path))
+ if err != nil {
+ return ""
+ }
+
+ if st.Sys().(*syscall.Stat_t).Dev == pst.Sys().(*syscall.Stat_t).Dev {
+ // parent dir has the same dev -- path is not a mount point
+ return ""
+ }
+
+ // (3) path should have 'cgroup' fs type.
+ fst := unix.Statfs_t{}
+ err = unix.Statfs(path, &fst)
+ if err != nil || fst.Type != unix.CGROUP_SUPER_MAGIC {
+ return ""
+ }
+
+ return path
+}
+
+// https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt
+func FindCgroupMountpoint(cgroupPath, subsystem string) (string, error) {
+ if IsCgroup2UnifiedMode() {
+ return "", errUnified
+ }
+
+ // Avoid parsing mountinfo by trying the default path first, if possible.
+ if path := tryDefaultPath(cgroupPath, subsystem); path != "" {
+ return path, nil
+ }
+
+ mnt, _, err := FindCgroupMountpointAndRoot(cgroupPath, subsystem)
+ return mnt, err
+}
+
+func FindCgroupMountpointAndRoot(cgroupPath, subsystem string) (string, string, error) {
+ if IsCgroup2UnifiedMode() {
+ return "", "", errUnified
+ }
+
+ // Avoid parsing mountinfo by checking if subsystem is valid/available.
+ if !isSubsystemAvailable(subsystem) {
+ return "", "", NewNotFoundError(subsystem)
+ }
+
+ f, err := os.Open("/proc/self/mountinfo")
+ if err != nil {
+ return "", "", err
+ }
+ defer f.Close()
+
+ return findCgroupMountpointAndRootFromReader(f, cgroupPath, subsystem)
+}
+
+func findCgroupMountpointAndRootFromReader(reader io.Reader, cgroupPath, subsystem string) (string, string, error) {
+ scanner := bufio.NewScanner(reader)
+ for scanner.Scan() {
+ txt := scanner.Text()
+ fields := strings.Fields(txt)
+ if len(fields) < 9 {
+ continue
+ }
+ if strings.HasPrefix(fields[4], cgroupPath) {
+ 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 "", "", NewNotFoundError(subsystem)
+}
+
+func isSubsystemAvailable(subsystem string) bool {
+ if IsCgroup2UnifiedMode() {
+ panic("don't call isSubsystemAvailable from cgroupv2 code")
+ }
+
+ cgroups, err := ParseCgroupFile("/proc/self/cgroup")
+ if err != nil {
+ return false
+ }
+ _, avail := cgroups[subsystem]
+ return avail
+}
+
+func (m Mount) GetOwnCgroup(cgroups map[string]string) (string, error) {
+ if len(m.Subsystems) == 0 {
+ return "", fmt.Errorf("no subsystem for mount")
+ }
+
+ return getControllerPath(m.Subsystems[0], cgroups)
+}
+
+func getCgroupMountsHelper(ss map[string]bool, mi io.Reader, all bool) ([]Mount, error) {
+ res := make([]Mount, 0, len(ss))
+ scanner := bufio.NewScanner(mi)
+ numFound := 0
+ for scanner.Scan() && numFound < len(ss) {
+ txt := scanner.Text()
+ sepIdx := strings.Index(txt, " - ")
+ if sepIdx == -1 {
+ return nil, fmt.Errorf("invalid mountinfo format")
+ }
+ if txt[sepIdx+3:sepIdx+10] == "cgroup2" || txt[sepIdx+3:sepIdx+9] != "cgroup" {
+ continue
+ }
+ fields := strings.Split(txt, " ")
+ m := Mount{
+ Mountpoint: fields[4],
+ Root: fields[3],
+ }
+ for _, opt := range strings.Split(fields[len(fields)-1], ",") {
+ seen, known := ss[opt]
+ if !known || (!all && seen) {
+ continue
+ }
+ ss[opt] = true
+ opt = strings.TrimPrefix(opt, CgroupNamePrefix)
+ m.Subsystems = append(m.Subsystems, opt)
+ numFound++
+ }
+ if len(m.Subsystems) > 0 || all {
+ res = append(res, m)
+ }
+ }
+ if err := scanner.Err(); err != nil {
+ return nil, err
+ }
+ return res, nil
+}
+
+func getCgroupMountsV1(all bool) ([]Mount, error) {
+ f, err := os.Open("/proc/self/mountinfo")
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ allSubsystems, err := ParseCgroupFile("/proc/self/cgroup")
+ if err != nil {
+ return nil, err
+ }
+
+ allMap := make(map[string]bool)
+ for s := range allSubsystems {
+ allMap[s] = false
+ }
+ return getCgroupMountsHelper(allMap, f, all)
+}
+
+// GetOwnCgroup returns the relative path to the cgroup docker is running in.
+func GetOwnCgroup(subsystem string) (string, error) {
+ if IsCgroup2UnifiedMode() {
+ return "", errUnified
+ }
+ cgroups, err := ParseCgroupFile("/proc/self/cgroup")
+ if err != nil {
+ return "", err
+ }
+
+ return getControllerPath(subsystem, cgroups)
+}
+
+func GetOwnCgroupPath(subsystem string) (string, error) {
+ cgroup, err := GetOwnCgroup(subsystem)
+ if err != nil {
+ return "", err
+ }
+
+ return getCgroupPathHelper(subsystem, cgroup)
+}
+
+func GetInitCgroup(subsystem string) (string, error) {
+ if IsCgroup2UnifiedMode() {
+ return "", errUnified
+ }
+ cgroups, err := ParseCgroupFile("/proc/1/cgroup")
+ if err != nil {
+ return "", err
+ }
+
+ return getControllerPath(subsystem, cgroups)
+}
+
+func GetInitCgroupPath(subsystem string) (string, error) {
+ cgroup, err := GetInitCgroup(subsystem)
+ if err != nil {
+ return "", err
+ }
+
+ return getCgroupPathHelper(subsystem, cgroup)
+}
+
+func getCgroupPathHelper(subsystem, cgroup string) (string, error) {
+ mnt, root, err := FindCgroupMountpointAndRoot("", subsystem)
+ if err != nil {
+ return "", err
+ }
+
+ // This is needed for nested containers, because in /proc/self/cgroup we
+ // see paths from host, which don't exist in container.
+ relCgroup, err := filepath.Rel(root, cgroup)
+ if err != nil {
+ return "", err
+ }
+
+ return filepath.Join(mnt, relCgroup), nil
+}
+
+func getControllerPath(subsystem string, cgroups map[string]string) (string, error) {
+ if IsCgroup2UnifiedMode() {
+ return "", errUnified
+ }
+
+ if p, ok := cgroups[subsystem]; ok {
+ return p, nil
+ }
+
+ if p, ok := cgroups[CgroupNamePrefix+subsystem]; ok {
+ return p, nil
+ }
+
+ return "", NewNotFoundError(subsystem)
+}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_linux.go
index 58ed19c9e..6e90ae16b 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_linux.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_linux.go
@@ -1,5 +1,9 @@
package configs
+import (
+ systemdDbus "github.com/coreos/go-systemd/v22/dbus"
+)
+
type FreezerState string
const (
@@ -29,18 +33,16 @@ type Cgroup struct {
// Resources contains various cgroups settings to apply
*Resources
+
+ // SystemdProps are any additional properties for systemd,
+ // derived from org.systemd.property.xxx annotations.
+ // Ignored unless systemd is used for managing cgroups.
+ SystemdProps []systemdDbus.Property `json:"-"`
}
type Resources struct {
- // If this is true allow access to any kind of device within the container. If false, allow access only to devices explicitly listed in the allowed_devices list.
- // Deprecated
- AllowAllDevices *bool `json:"allow_all_devices,omitempty"`
- // Deprecated
- AllowedDevices []*Device `json:"allowed_devices,omitempty"`
- // Deprecated
- DeniedDevices []*Device `json:"denied_devices,omitempty"`
-
- Devices []*Device `json:"devices"`
+ // Devices is the set of access rules for devices in the container.
+ Devices []*DeviceRule `json:"devices"`
// Memory limit (in bytes)
Memory int64 `json:"memory"`
@@ -125,6 +127,10 @@ type Resources struct {
// CpuWeight sets a proportional bandwidth limit.
CpuWeight uint64 `json:"cpu_weight"`
- // CpuMax sets she maximum bandwidth limit (format: max period).
- CpuMax string `json:"cpu_max"`
+ // SkipDevices allows to skip configuring device permissions.
+ // Used by e.g. kubelet while creating a parent cgroup (kubepods)
+ // common for many containers.
+ //
+ // NOTE it is impossible to start a container which has this flag set.
+ SkipDevices bool `json:"skip_devices"`
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go
index 24989e9f5..540f0f85d 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/config.go
@@ -8,7 +8,7 @@ import (
"time"
"github.com/opencontainers/runtime-spec/specs-go"
-
+ "github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -70,9 +70,10 @@ type Arg struct {
// Syscall is a rule to match a syscall in Seccomp
type Syscall struct {
- Name string `json:"name"`
- Action Action `json:"action"`
- Args []*Arg `json:"args"`
+ Name string `json:"name"`
+ Action Action `json:"action"`
+ ErrnoRet *uint `json:"errnoRet"`
+ Args []*Arg `json:"args"`
}
// TODO Windows. Many of these fields should be factored out into those parts
@@ -175,7 +176,7 @@ type Config struct {
// Hooks are a collection of actions to perform at various container lifecycle events.
// CommandHooks are serialized to JSON, but other hooks are not.
- Hooks *Hooks
+ Hooks Hooks
// Version is the version of opencontainer specification that is supported.
Version string `json:"version"`
@@ -202,17 +203,41 @@ type Config struct {
RootlessCgroups bool `json:"rootless_cgroups,omitempty"`
}
-type Hooks struct {
+type HookName string
+type HookList []Hook
+type Hooks map[HookName]HookList
+
+const (
// Prestart commands are executed after the container namespaces are created,
// but before the user supplied command is executed from init.
- Prestart []Hook
+ // Note: This hook is now deprecated
+ // Prestart commands are called in the Runtime namespace.
+ Prestart HookName = "prestart"
+
+ // CreateRuntime commands MUST be called as part of the create operation after
+ // the runtime environment has been created but before the pivot_root has been executed.
+ // CreateRuntime is called immediately after the deprecated Prestart hook.
+ // CreateRuntime commands are called in the Runtime Namespace.
+ CreateRuntime = "createRuntime"
+
+ // CreateContainer commands MUST be called as part of the create operation after
+ // the runtime environment has been created but before the pivot_root has been executed.
+ // CreateContainer commands are called in the Container namespace.
+ CreateContainer = "createContainer"
+
+ // StartContainer commands MUST be called as part of the start operation and before
+ // the container process is started.
+ // StartContainer commands are called in the Container namespace.
+ StartContainer = "startContainer"
// Poststart commands are executed after the container init process starts.
- Poststart []Hook
+ // Poststart commands are called in the Runtime Namespace.
+ Poststart = "poststart"
// Poststop commands are executed after the container init process exits.
- Poststop []Hook
-}
+ // Poststop commands are called in the Runtime Namespace.
+ Poststop = "poststop"
+)
type Capabilities struct {
// Bounding is the set of capabilities checked by the kernel.
@@ -227,32 +252,39 @@ type Capabilities struct {
Ambient []string
}
-func (hooks *Hooks) UnmarshalJSON(b []byte) error {
- var state struct {
- Prestart []CommandHook
- Poststart []CommandHook
- Poststop []CommandHook
+func (hooks HookList) RunHooks(state *specs.State) error {
+ for i, h := range hooks {
+ if err := h.Run(state); err != nil {
+ return errors.Wrapf(err, "Running hook #%d:", i)
+ }
}
+ return nil
+}
+
+func (hooks *Hooks) UnmarshalJSON(b []byte) error {
+ var state map[HookName][]CommandHook
+
if err := json.Unmarshal(b, &state); err != nil {
return err
}
- deserialize := func(shooks []CommandHook) (hooks []Hook) {
- for _, shook := range shooks {
- hooks = append(hooks, shook)
+ *hooks = Hooks{}
+ for n, commandHooks := range state {
+ if len(commandHooks) == 0 {
+ continue
}
- return hooks
+ (*hooks)[n] = HookList{}
+ for _, h := range commandHooks {
+ (*hooks)[n] = append((*hooks)[n], h)
+ }
}
- hooks.Prestart = deserialize(state.Prestart)
- hooks.Poststart = deserialize(state.Poststart)
- hooks.Poststop = deserialize(state.Poststop)
return nil
}
-func (hooks Hooks) MarshalJSON() ([]byte, error) {
+func (hooks *Hooks) MarshalJSON() ([]byte, error) {
serialize := func(hooks []Hook) (serializableHooks []CommandHook) {
for _, hook := range hooks {
switch chook := hook.(type) {
@@ -267,9 +299,12 @@ func (hooks Hooks) MarshalJSON() ([]byte, error) {
}
return json.Marshal(map[string]interface{}{
- "prestart": serialize(hooks.Prestart),
- "poststart": serialize(hooks.Poststart),
- "poststop": serialize(hooks.Poststop),
+ "prestart": serialize((*hooks)[Prestart]),
+ "createRuntime": serialize((*hooks)[CreateRuntime]),
+ "createContainer": serialize((*hooks)[CreateContainer]),
+ "startContainer": serialize((*hooks)[StartContainer]),
+ "poststart": serialize((*hooks)[Poststart]),
+ "poststop": serialize((*hooks)[Poststop]),
})
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/device.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/device.go
index 8701bb212..632bf6ac4 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/configs/device.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/device.go
@@ -3,30 +3,19 @@ package configs
import (
"fmt"
"os"
+ "strconv"
)
const (
Wildcard = -1
)
-// TODO Windows: This can be factored out in the future
-
type Device struct {
- // Device type, block, char, etc.
- Type rune `json:"type"`
+ DeviceRule
// Path to the device.
Path string `json:"path"`
- // Major is the device's major number.
- Major int64 `json:"major"`
-
- // Minor is the device's minor number.
- Minor int64 `json:"minor"`
-
- // Cgroup permissions format, rwm.
- Permissions string `json:"permissions"`
-
// FileMode permission bits for the device.
FileMode os.FileMode `json:"file_mode"`
@@ -35,23 +24,147 @@ type Device struct {
// Gid of the device.
Gid uint32 `json:"gid"`
+}
- // Write the file to the allowed list
+// DevicePermissions is a cgroupv1-style string to represent device access. It
+// has to be a string for backward compatibility reasons, hence why it has
+// methods to do set operations.
+type DevicePermissions string
+
+const (
+ deviceRead uint = (1 << iota)
+ deviceWrite
+ deviceMknod
+)
+
+func (p DevicePermissions) toSet() uint {
+ var set uint
+ for _, perm := range p {
+ switch perm {
+ case 'r':
+ set |= deviceRead
+ case 'w':
+ set |= deviceWrite
+ case 'm':
+ set |= deviceMknod
+ }
+ }
+ return set
+}
+
+func fromSet(set uint) DevicePermissions {
+ var perm string
+ if set&deviceRead == deviceRead {
+ perm += "r"
+ }
+ if set&deviceWrite == deviceWrite {
+ perm += "w"
+ }
+ if set&deviceMknod == deviceMknod {
+ perm += "m"
+ }
+ return DevicePermissions(perm)
+}
+
+// Union returns the union of the two sets of DevicePermissions.
+func (p DevicePermissions) Union(o DevicePermissions) DevicePermissions {
+ lhs := p.toSet()
+ rhs := o.toSet()
+ return fromSet(lhs | rhs)
+}
+
+// Difference returns the set difference of the two sets of DevicePermissions.
+// In set notation, A.Difference(B) gives you A\B.
+func (p DevicePermissions) Difference(o DevicePermissions) DevicePermissions {
+ lhs := p.toSet()
+ rhs := o.toSet()
+ return fromSet(lhs &^ rhs)
+}
+
+// Intersection computes the intersection of the two sets of DevicePermissions.
+func (p DevicePermissions) Intersection(o DevicePermissions) DevicePermissions {
+ lhs := p.toSet()
+ rhs := o.toSet()
+ return fromSet(lhs & rhs)
+}
+
+// IsEmpty returns whether the set of permissions in a DevicePermissions is
+// empty.
+func (p DevicePermissions) IsEmpty() bool {
+ return p == DevicePermissions("")
+}
+
+// IsValid returns whether the set of permissions is a subset of valid
+// permissions (namely, {r,w,m}).
+func (p DevicePermissions) IsValid() bool {
+ return p == fromSet(p.toSet())
+}
+
+type DeviceType rune
+
+const (
+ WildcardDevice DeviceType = 'a'
+ BlockDevice DeviceType = 'b'
+ CharDevice DeviceType = 'c' // or 'u'
+ FifoDevice DeviceType = 'p'
+)
+
+func (t DeviceType) IsValid() bool {
+ switch t {
+ case WildcardDevice, BlockDevice, CharDevice, FifoDevice:
+ return true
+ default:
+ return false
+ }
+}
+
+func (t DeviceType) CanMknod() bool {
+ switch t {
+ case BlockDevice, CharDevice, FifoDevice:
+ return true
+ default:
+ return false
+ }
+}
+
+func (t DeviceType) CanCgroup() bool {
+ switch t {
+ case WildcardDevice, BlockDevice, CharDevice:
+ return true
+ default:
+ return false
+ }
+}
+
+type DeviceRule struct {
+ // Type of device ('c' for char, 'b' for block). If set to 'a', this rule
+ // acts as a wildcard and all fields other than Allow are ignored.
+ Type DeviceType `json:"type"`
+
+ // Major is the device's major number.
+ Major int64 `json:"major"`
+
+ // Minor is the device's minor number.
+ Minor int64 `json:"minor"`
+
+ // Permissions is the set of permissions that this rule applies to (in the
+ // cgroupv1 format -- any combination of "rwm").
+ Permissions DevicePermissions `json:"permissions"`
+
+ // Allow specifies whether this rule is allowed.
Allow bool `json:"allow"`
}
-func (d *Device) CgroupString() string {
- return fmt.Sprintf("%c %s:%s %s", d.Type, deviceNumberString(d.Major), deviceNumberString(d.Minor), d.Permissions)
-}
-
-func (d *Device) Mkdev() int {
- return int((d.Major << 8) | (d.Minor & 0xff) | ((d.Minor & 0xfff00) << 12))
-}
-
-// deviceNumberString converts the device number to a string return result.
-func deviceNumberString(number int64) string {
- if number == Wildcard {
- return "*"
+func (d *DeviceRule) CgroupString() string {
+ var (
+ major = strconv.FormatInt(d.Major, 10)
+ minor = strconv.FormatInt(d.Minor, 10)
+ )
+ if d.Major == Wildcard {
+ major = "*"
}
- return fmt.Sprint(number)
+ if d.Minor == Wildcard {
+ minor = "*"
+ }
+ return fmt.Sprintf("%c %s:%s %s", d.Type, major, minor, d.Permissions)
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/device_defaults.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/device_defaults.go
deleted file mode 100644
index e4f423c52..000000000
--- a/vendor/github.com/opencontainers/runc/libcontainer/configs/device_defaults.go
+++ /dev/null
@@ -1,111 +0,0 @@
-// +build linux
-
-package configs
-
-var (
- // DefaultSimpleDevices are devices that are to be both allowed and created.
- DefaultSimpleDevices = []*Device{
- // /dev/null and zero
- {
- Path: "/dev/null",
- Type: 'c',
- Major: 1,
- Minor: 3,
- Permissions: "rwm",
- FileMode: 0666,
- },
- {
- Path: "/dev/zero",
- Type: 'c',
- Major: 1,
- Minor: 5,
- Permissions: "rwm",
- FileMode: 0666,
- },
-
- {
- Path: "/dev/full",
- Type: 'c',
- Major: 1,
- Minor: 7,
- Permissions: "rwm",
- FileMode: 0666,
- },
-
- // consoles and ttys
- {
- Path: "/dev/tty",
- Type: 'c',
- Major: 5,
- Minor: 0,
- Permissions: "rwm",
- FileMode: 0666,
- },
-
- // /dev/urandom,/dev/random
- {
- Path: "/dev/urandom",
- Type: 'c',
- Major: 1,
- Minor: 9,
- Permissions: "rwm",
- FileMode: 0666,
- },
- {
- Path: "/dev/random",
- Type: 'c',
- Major: 1,
- Minor: 8,
- Permissions: "rwm",
- FileMode: 0666,
- },
- }
- DefaultAllowedDevices = append([]*Device{
- // allow mknod for any device
- {
- Type: 'c',
- Major: Wildcard,
- Minor: Wildcard,
- Permissions: "m",
- },
- {
- Type: 'b',
- Major: Wildcard,
- Minor: Wildcard,
- Permissions: "m",
- },
-
- {
- Path: "/dev/console",
- Type: 'c',
- Major: 5,
- Minor: 1,
- Permissions: "rwm",
- },
- // /dev/pts/ - pts namespaces are "coming soon"
- {
- Path: "",
- Type: 'c',
- Major: 136,
- Minor: Wildcard,
- Permissions: "rwm",
- },
- {
- Path: "",
- Type: 'c',
- Major: 5,
- Minor: 2,
- Permissions: "rwm",
- },
-
- // tuntap
- {
- Path: "",
- Type: 'c',
- Major: 10,
- Minor: 200,
- Permissions: "rwm",
- },
- }, DefaultSimpleDevices...)
- DefaultAutoCreatedDevices = append([]*Device{}, DefaultSimpleDevices...)
-)
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/device_unix.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/device_unix.go
new file mode 100644
index 000000000..650c46848
--- /dev/null
+++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/device_unix.go
@@ -0,0 +1,16 @@
+// +build !windows
+
+package configs
+
+import (
+ "errors"
+
+ "golang.org/x/sys/unix"
+)
+
+func (d *DeviceRule) Mkdev() (uint64, error) {
+ if d.Major == Wildcard || d.Minor == Wildcard {
+ return 0, errors.New("cannot mkdev() device with wildcards")
+ }
+ return unix.Mkdev(uint32(d.Major), uint32(d.Minor)), nil
+}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/device_windows.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/device_windows.go
new file mode 100644
index 000000000..729289393
--- /dev/null
+++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/device_windows.go
@@ -0,0 +1,5 @@
+package configs
+
+func (d *DeviceRule) Mkdev() (uint64, error) {
+ return 0, nil
+}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go
index 393d9e81e..717d0f00a 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go
@@ -1,6 +1,7 @@
package validate
import (
+ "errors"
"fmt"
"strings"
@@ -35,14 +36,14 @@ func hasIDMapping(id int, mappings []configs.IDMap) bool {
func rootlessEUIDMappings(config *configs.Config) error {
if !config.Namespaces.Contains(configs.NEWUSER) {
- return fmt.Errorf("rootless container requires user namespaces")
+ return errors.New("rootless container requires user namespaces")
}
if len(config.UidMappings) == 0 {
- return fmt.Errorf("rootless containers requires at least one UID mapping")
+ return errors.New("rootless containers requires at least one UID mapping")
}
if len(config.GidMappings) == 0 {
- return fmt.Errorf("rootless containers requires at least one GID mapping")
+ return errors.New("rootless containers requires at least one GID mapping")
}
return nil
}
@@ -67,7 +68,7 @@ func rootlessEUIDMount(config *configs.Config) error {
continue
}
if !hasIDMapping(uid, config.UidMappings) {
- return fmt.Errorf("cannot specify uid= mount options for unmapped uid in rootless containers")
+ return errors.New("cannot specify uid= mount options for unmapped uid in rootless containers")
}
}
@@ -79,7 +80,7 @@ func rootlessEUIDMount(config *configs.Config) error {
continue
}
if !hasIDMapping(gid, config.GidMappings) {
- return fmt.Errorf("cannot specify gid= mount options for unmapped gid in rootless containers")
+ return errors.New("cannot specify gid= mount options for unmapped gid in rootless containers")
}
}
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go b/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go
index 3b42f3010..49b5f4c69 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go
@@ -1,6 +1,7 @@
package validate
import (
+ "errors"
"fmt"
"os"
"path/filepath"
@@ -80,7 +81,7 @@ func (v *ConfigValidator) rootfs(config *configs.Config) error {
func (v *ConfigValidator) network(config *configs.Config) error {
if !config.Namespaces.Contains(configs.NEWNET) {
if len(config.Networks) > 0 || len(config.Routes) > 0 {
- return fmt.Errorf("unable to apply network settings without a private NET namespace")
+ return errors.New("unable to apply network settings without a private NET namespace")
}
}
return nil
@@ -88,7 +89,7 @@ func (v *ConfigValidator) network(config *configs.Config) error {
func (v *ConfigValidator) hostname(config *configs.Config) error {
if config.Hostname != "" && !config.Namespaces.Contains(configs.NEWUTS) {
- return fmt.Errorf("unable to set hostname without a private UTS namespace")
+ return errors.New("unable to set hostname without a private UTS namespace")
}
return nil
}
@@ -97,10 +98,10 @@ func (v *ConfigValidator) security(config *configs.Config) error {
// restrict sys without mount namespace
if (len(config.MaskPaths) > 0 || len(config.ReadonlyPaths) > 0) &&
!config.Namespaces.Contains(configs.NEWNS) {
- return fmt.Errorf("unable to restrict sys entries without a private MNT namespace")
+ return errors.New("unable to restrict sys entries without a private MNT namespace")
}
if config.ProcessLabel != "" && !selinux.GetEnabled() {
- return fmt.Errorf("selinux label is specified in config, but selinux is disabled or not supported")
+ return errors.New("selinux label is specified in config, but selinux is disabled or not supported")
}
return nil
@@ -109,11 +110,11 @@ func (v *ConfigValidator) security(config *configs.Config) error {
func (v *ConfigValidator) usernamespace(config *configs.Config) error {
if config.Namespaces.Contains(configs.NEWUSER) {
if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) {
- return fmt.Errorf("USER namespaces aren't enabled in the kernel")
+ return errors.New("USER namespaces aren't enabled in the kernel")
}
} else {
if config.UidMappings != nil || config.GidMappings != nil {
- return fmt.Errorf("User namespace mappings specified, but USER namespace isn't enabled in the config")
+ return errors.New("User namespace mappings specified, but USER namespace isn't enabled in the config")
}
}
return nil
@@ -122,7 +123,7 @@ func (v *ConfigValidator) usernamespace(config *configs.Config) error {
func (v *ConfigValidator) cgroupnamespace(config *configs.Config) error {
if config.Namespaces.Contains(configs.NEWCGROUP) {
if _, err := os.Stat("/proc/self/ns/cgroup"); os.IsNotExist(err) {
- return fmt.Errorf("cgroup namespaces aren't enabled in the kernel")
+ return errors.New("cgroup namespaces aren't enabled in the kernel")
}
}
return nil
@@ -182,21 +183,21 @@ func (v *ConfigValidator) sysctl(config *configs.Config) error {
func (v *ConfigValidator) intelrdt(config *configs.Config) error {
if config.IntelRdt != nil {
if !intelrdt.IsCatEnabled() && !intelrdt.IsMbaEnabled() {
- return fmt.Errorf("intelRdt is specified in config, but Intel RDT is not supported or enabled")
+ return errors.New("intelRdt is specified in config, but Intel RDT is not supported or enabled")
}
if !intelrdt.IsCatEnabled() && config.IntelRdt.L3CacheSchema != "" {
- return fmt.Errorf("intelRdt.l3CacheSchema is specified in config, but Intel RDT/CAT is not enabled")
+ return errors.New("intelRdt.l3CacheSchema is specified in config, but Intel RDT/CAT is not enabled")
}
if !intelrdt.IsMbaEnabled() && config.IntelRdt.MemBwSchema != "" {
- return fmt.Errorf("intelRdt.memBwSchema is specified in config, but Intel RDT/MBA is not enabled")
+ return errors.New("intelRdt.memBwSchema is specified in config, but Intel RDT/MBA is not enabled")
}
if intelrdt.IsCatEnabled() && config.IntelRdt.L3CacheSchema == "" {
- return fmt.Errorf("Intel RDT/CAT is enabled and intelRdt is specified in config, but intelRdt.l3CacheSchema is empty")
+ return errors.New("Intel RDT/CAT is enabled and intelRdt is specified in config, but intelRdt.l3CacheSchema is empty")
}
if intelrdt.IsMbaEnabled() && config.IntelRdt.MemBwSchema == "" {
- return fmt.Errorf("Intel RDT/MBA is enabled and intelRdt is specified in config, but intelRdt.memBwSchema is empty")
+ return errors.New("Intel RDT/MBA is enabled and intelRdt is specified in config, but intelRdt.memBwSchema is empty")
}
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go
index fe70c937a..e2f64fcb9 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/container_linux.go
@@ -16,7 +16,6 @@ import (
"reflect"
"strings"
"sync"
- "syscall" // only for SysProcAttr and Signal
"time"
securejoin "github.com/cyphar/filepath-securejoin"
@@ -27,8 +26,10 @@ import (
"github.com/opencontainers/runc/libcontainer/utils"
"github.com/opencontainers/runtime-spec/specs-go"
- criurpc "github.com/checkpoint-restore/go-criu/rpc"
+ "github.com/checkpoint-restore/go-criu/v4"
+ criurpc "github.com/checkpoint-restore/go-criu/v4/rpc"
"github.com/golang/protobuf/proto"
+ errorsf "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
@@ -65,8 +66,12 @@ type State struct {
// Set to true if BaseState.Config.RootlessEUID && BaseState.Config.RootlessCgroups
Rootless bool `json:"rootless"`
- // Path to all the cgroups setup for a container. Key is cgroup subsystem name
- // with the value as the path.
+ // Paths to all the container's cgroups, as returned by (*cgroups.Manager).GetPaths
+ //
+ // For cgroup v1, a key is cgroup subsystem name, and the value is the path
+ // to the cgroup for this subsystem.
+ //
+ // For cgroup v2 unified hierarchy, a key is "", and the value is the unified path.
CgroupPaths map[string]string `json:"cgroup_paths"`
// NamespacePaths are filepaths to the container's namespaces. Key is the namespace type
@@ -165,7 +170,17 @@ func (c *linuxContainer) OCIState() (*specs.State, error) {
}
func (c *linuxContainer) Processes() ([]int, error) {
- pids, err := c.cgroupManager.GetAllPids()
+ var pids []int
+ status, err := c.currentStatus()
+ if err != nil {
+ return pids, err
+ }
+ // for systemd cgroup, the unit's cgroup path will be auto removed if container's all processes exited
+ if status == Stopped && !c.cgroupManager.Exists() {
+ return pids, nil
+ }
+
+ pids, err = c.cgroupManager.GetAllPids()
if err != nil {
return nil, newSystemErrorWithCause(err, "getting all container pids from cgroups")
}
@@ -206,7 +221,7 @@ func (c *linuxContainer) Set(config configs.Config) error {
return err
}
if status == Stopped {
- return newGenericError(fmt.Errorf("container not running"), ContainerNotRunning)
+ return newGenericError(errors.New("container not running"), ContainerNotRunning)
}
if err := c.cgroupManager.Set(&config); err != nil {
// Set configs back
@@ -218,6 +233,9 @@ func (c *linuxContainer) Set(config configs.Config) error {
if c.intelRdtManager != nil {
if err := c.intelRdtManager.Set(&config); err != nil {
// Set configs back
+ if err2 := c.cgroupManager.Set(c.config); err2 != nil {
+ logrus.Warnf("Setting back cgroup configs failed due to error: %v, your state.json and actual configs might be inconsistent.", err2)
+ }
if err2 := c.intelRdtManager.Set(c.config); err2 != nil {
logrus.Warnf("Setting back intelrdt configs failed due to error: %v, your state.json and actual configs might be inconsistent.", err2)
}
@@ -233,6 +251,9 @@ func (c *linuxContainer) Set(config configs.Config) error {
func (c *linuxContainer) Start(process *Process) error {
c.m.Lock()
defer c.m.Unlock()
+ if c.config.Cgroups.Resources.SkipDevices {
+ return newGenericError(errors.New("can't start container with SkipDevices set"), ConfigInvalid)
+ }
if process.Init {
if err := c.createExecFifo(); err != nil {
return err
@@ -292,7 +313,7 @@ func readFromExecFifo(execFifo io.Reader) error {
return err
}
if len(data) <= 0 {
- return fmt.Errorf("cannot start an already running container")
+ return errors.New("cannot start an already running container")
}
return nil
}
@@ -309,7 +330,7 @@ func awaitFifoOpen(path string) <-chan openResult {
func fifoOpen(path string, block bool) openResult {
flags := os.O_RDONLY
if !block {
- flags |= syscall.O_NONBLOCK
+ flags |= unix.O_NONBLOCK
}
f, err := os.OpenFile(path, flags, 0)
if err != nil {
@@ -365,13 +386,12 @@ func (c *linuxContainer) start(process *Process) error {
if err != nil {
return err
}
- for i, hook := range c.config.Hooks.Poststart {
- if err := hook.Run(s); err != nil {
- if err := ignoreTerminateErrors(parent.terminate()); err != nil {
- logrus.Warn(err)
- }
- return newSystemErrorWithCausef(err, "running poststart hook %d", i)
+
+ if err := c.config.Hooks[configs.Poststart].RunHooks(s); err != nil {
+ if err := ignoreTerminateErrors(parent.terminate()); err != nil {
+ logrus.Warn(errorsf.Wrapf(err, "Running Poststart hook"))
}
+ return err
}
}
}
@@ -379,13 +399,19 @@ func (c *linuxContainer) start(process *Process) error {
}
func (c *linuxContainer) Signal(s os.Signal, all bool) error {
- if all {
- return signalAllProcesses(c.cgroupManager, s)
- }
+ c.m.Lock()
+ defer c.m.Unlock()
status, err := c.currentStatus()
if err != nil {
return err
}
+ if all {
+ // for systemd cgroup, the unit's cgroup path will be auto removed if container's all processes exited
+ if status == Stopped && !c.cgroupManager.Exists() {
+ return nil
+ }
+ return signalAllProcesses(c.cgroupManager, s)
+ }
// to avoid a PID reuse attack
if status == Running || status == Created || status == Paused {
if err := c.initProcess.signal(s); err != nil {
@@ -393,7 +419,7 @@ func (c *linuxContainer) Signal(s os.Signal, all bool) error {
}
return nil
}
- return newGenericError(fmt.Errorf("container not running"), ContainerNotRunning)
+ return newGenericError(errors.New("container not running"), ContainerNotRunning)
}
func (c *linuxContainer) createExecFifo() error {
@@ -454,10 +480,7 @@ func (c *linuxContainer) newParentProcess(p *Process) (parentProcess, error) {
}
logFilePair := filePair{parentLogPipe, childLogPipe}
- cmd, err := c.commandTemplate(p, childInitPipe, childLogPipe)
- if err != nil {
- return nil, newSystemErrorWithCause(err, "creating new command template")
- }
+ cmd := c.commandTemplate(p, childInitPipe, childLogPipe)
if !p.Init {
return c.newSetnsProcess(p, cmd, messageSockPair, logFilePair)
}
@@ -473,7 +496,7 @@ func (c *linuxContainer) newParentProcess(p *Process) (parentProcess, error) {
return c.newInitProcess(p, cmd, messageSockPair, logFilePair)
}
-func (c *linuxContainer) commandTemplate(p *Process, childInitPipe *os.File, childLogPipe *os.File) (*exec.Cmd, error) {
+func (c *linuxContainer) commandTemplate(p *Process, childInitPipe *os.File, childLogPipe *os.File) *exec.Cmd {
cmd := exec.Command(c.initPath, c.initArgs[1:]...)
cmd.Args[0] = c.initArgs[0]
cmd.Stdin = p.Stdin
@@ -481,7 +504,7 @@ func (c *linuxContainer) commandTemplate(p *Process, childInitPipe *os.File, chi
cmd.Stderr = p.Stderr
cmd.Dir = c.config.Rootfs
if cmd.SysProcAttr == nil {
- cmd.SysProcAttr = &syscall.SysProcAttr{}
+ cmd.SysProcAttr = &unix.SysProcAttr{}
}
cmd.Env = append(cmd.Env, fmt.Sprintf("GOMAXPROCS=%s", os.Getenv("GOMAXPROCS")))
cmd.ExtraFiles = append(cmd.ExtraFiles, p.ExtraFiles...)
@@ -507,9 +530,9 @@ func (c *linuxContainer) commandTemplate(p *Process, childInitPipe *os.File, chi
// PID1 the pdeathsig is being delivered to the container's init process by the kernel for some reason
// even with the parent still running.
if c.config.ParentDeathSignal > 0 {
- cmd.SysProcAttr.Pdeathsig = syscall.Signal(c.config.ParentDeathSignal)
+ cmd.SysProcAttr.Pdeathsig = unix.Signal(c.config.ParentDeathSignal)
}
- return cmd, nil
+ return cmd
}
func (c *linuxContainer) newInitProcess(p *Process, cmd *exec.Cmd, messageSockPair, logFilePair filePair) (*initProcess, error) {
@@ -555,7 +578,7 @@ func (c *linuxContainer) newSetnsProcess(p *Process, cmd *exec.Cmd, messageSockP
}
return &setnsProcess{
cmd: cmd,
- cgroupPaths: c.cgroupManager.GetPaths(),
+ cgroupPaths: state.CgroupPaths,
rootlessCgroups: c.config.RootlessCgroups,
intelRdtPath: state.IntelRdtPath,
messageSockPair: messageSockPair,
@@ -563,6 +586,7 @@ func (c *linuxContainer) newSetnsProcess(p *Process, cmd *exec.Cmd, messageSockP
config: c.newInitConfig(p),
process: p,
bootstrapData: data,
+ initProcessPid: state.InitProcessPid,
}, nil
}
@@ -650,7 +674,11 @@ func (c *linuxContainer) NotifyOOM() (<-chan struct{}, error) {
if c.config.RootlessCgroups {
logrus.Warn("getting OOM notifications may fail if you don't have the full access to cgroups")
}
- return notifyOnOOM(c.cgroupManager.GetPaths())
+ path := c.cgroupManager.Path("memory")
+ if cgroups.IsCgroup2UnifiedMode() {
+ return notifyOnOOMV2(path)
+ }
+ return notifyOnOOM(path)
}
func (c *linuxContainer) NotifyMemoryPressure(level PressureLevel) (<-chan struct{}, error) {
@@ -658,7 +686,7 @@ func (c *linuxContainer) NotifyMemoryPressure(level PressureLevel) (<-chan struc
if c.config.RootlessCgroups {
logrus.Warn("getting memory pressure notifications may fail if you don't have the full access to cgroups")
}
- return notifyMemoryPressure(c.cgroupManager.GetPaths(), level)
+ return notifyMemoryPressure(c.cgroupManager.Path("memory"), level)
}
var criuFeatures *criurpc.CriuFeatures
@@ -668,16 +696,6 @@ func (c *linuxContainer) checkCriuFeatures(criuOpts *CriuOpts, rpcOpts *criurpc.
var t criurpc.CriuReqType
t = criurpc.CriuReqType_FEATURE_CHECK
- // criu 1.8 => 10800
- if err := c.checkCriuVersion(10800); err != nil {
- // Feature checking was introduced with CRIU 1.8.
- // Ignore the feature check if an older CRIU version is used
- // and just act as before.
- // As all automated PR testing is done using CRIU 1.7 this
- // code will not be tested by automated PR testing.
- return nil
- }
-
// make sure the features we are looking for are really not from
// some previous check
criuFeatures = nil
@@ -691,10 +709,10 @@ func (c *linuxContainer) checkCriuFeatures(criuOpts *CriuOpts, rpcOpts *criurpc.
Features: criuFeat,
}
- err := c.criuSwrk(nil, req, criuOpts, false, nil)
+ err := c.criuSwrk(nil, req, criuOpts, nil)
if err != nil {
logrus.Debugf("%s", err)
- return fmt.Errorf("CRIU feature check failed")
+ return errors.New("CRIU feature check failed")
}
logrus.Debugf("Feature check says: %s", criuFeatures)
@@ -721,56 +739,12 @@ func (c *linuxContainer) checkCriuFeatures(criuOpts *CriuOpts, rpcOpts *criurpc.
}
if missingFeatures {
- return fmt.Errorf("CRIU is missing features")
+ return errors.New("CRIU is missing features")
}
return nil
}
-func parseCriuVersion(path string) (int, error) {
- var x, y, z int
-
- out, err := exec.Command(path, "-V").Output()
- if err != nil {
- return 0, fmt.Errorf("Unable to execute CRIU command: %s", path)
- }
-
- x = 0
- y = 0
- z = 0
- if ep := strings.Index(string(out), "-"); ep >= 0 {
- // criu Git version format
- var version string
- if sp := strings.Index(string(out), "GitID"); sp > 0 {
- version = string(out)[sp:ep]
- } else {
- return 0, fmt.Errorf("Unable to parse the CRIU version: %s", path)
- }
-
- n, err := fmt.Sscanf(version, "GitID: v%d.%d.%d", &x, &y, &z) // 1.5.2
- if err != nil {
- n, err = fmt.Sscanf(version, "GitID: v%d.%d", &x, &y) // 1.6
- y++
- } else {
- z++
- }
- if n < 2 || err != nil {
- return 0, fmt.Errorf("Unable to parse the CRIU version: %s %d %s", version, n, err)
- }
- } else {
- // criu release version format
- n, err := fmt.Sscanf(string(out), "Version: %d.%d.%d\n", &x, &y, &z) // 1.5.2
- if err != nil {
- n, err = fmt.Sscanf(string(out), "Version: %d.%d\n", &x, &y) // 1.6
- }
- if n < 2 || err != nil {
- return 0, fmt.Errorf("Unable to parse the CRIU version: %s %d %s", out, n, err)
- }
- }
-
- return x*10000 + y*100 + z, nil
-}
-
func compareCriuVersion(criuVersion int, minVersion int) error {
// simple function to perform the actual version compare
if criuVersion < minVersion {
@@ -780,9 +754,6 @@ func compareCriuVersion(criuVersion int, minVersion int) error {
return nil
}
-// This is used to store the result of criu version RPC
-var criuVersionRPC *criurpc.CriuVersion
-
// checkCriuVersion checks Criu version greater than or equal to minVersion
func (c *linuxContainer) checkCriuVersion(minVersion int) error {
@@ -792,50 +763,14 @@ func (c *linuxContainer) checkCriuVersion(minVersion int) error {
return compareCriuVersion(c.criuVersion, minVersion)
}
- // First try if this version of CRIU support the version RPC.
- // The CRIU version RPC was introduced with CRIU 3.0.
-
- // First, reset the variable for the RPC answer to nil
- criuVersionRPC = nil
-
- var t criurpc.CriuReqType
- t = criurpc.CriuReqType_VERSION
- req := &criurpc.CriuReq{
- Type: &t,
- }
-
- err := c.criuSwrk(nil, req, nil, false, nil)
+ criu := criu.MakeCriu()
+ criu.SetCriuPath(c.criuPath)
+ var err error
+ c.criuVersion, err = criu.GetCriuVersion()
if err != nil {
return fmt.Errorf("CRIU version check failed: %s", err)
}
- if criuVersionRPC != nil {
- logrus.Debugf("CRIU version: %s", criuVersionRPC)
- // major and minor are always set
- c.criuVersion = int(*criuVersionRPC.Major) * 10000
- c.criuVersion += int(*criuVersionRPC.Minor) * 100
- if criuVersionRPC.Sublevel != nil {
- c.criuVersion += int(*criuVersionRPC.Sublevel)
- }
- if criuVersionRPC.Gitid != nil {
- // runc's convention is that a CRIU git release is
- // always the same as increasing the minor by 1
- c.criuVersion -= (c.criuVersion % 100)
- c.criuVersion += 100
- }
- return compareCriuVersion(c.criuVersion, minVersion)
- }
-
- // This is CRIU without the version RPC and therefore
- // older than 3.0. Parsing the output is required.
-
- // This can be remove once runc does not work with criu older than 3.0
-
- c.criuVersion, err = parseCriuVersion(c.criuPath)
- if err != nil {
- return err
- }
-
return compareCriuVersion(c.criuVersion, minVersion)
}
@@ -876,26 +811,6 @@ func (c *linuxContainer) addMaskPaths(req *criurpc.CriuReq) error {
return nil
}
-func waitForCriuLazyServer(r *os.File, status string) error {
-
- data := make([]byte, 1)
- _, err := r.Read(data)
- if err != nil {
- return err
- }
- fd, err := os.OpenFile(status, os.O_TRUNC|os.O_WRONLY, os.ModeAppend)
- if err != nil {
- return err
- }
- _, err = fd.Write(data)
- if err != nil {
- return err
- }
- fd.Close()
-
- return nil
-}
-
func (c *linuxContainer) handleCriuConfigurationFile(rpcOpts *criurpc.CriuOpts) {
// CRIU will evaluate a configuration starting with release 3.11.
// Settings in the configuration file will overwrite RPC settings.
@@ -922,6 +837,78 @@ func (c *linuxContainer) handleCriuConfigurationFile(rpcOpts *criurpc.CriuOpts)
}
}
+func (c *linuxContainer) criuSupportsExtNS(t configs.NamespaceType) bool {
+ var minVersion int
+ switch t {
+ case configs.NEWNET:
+ // CRIU supports different external namespace with different released CRIU versions.
+ // For network namespaces to work we need at least criu 3.11.0 => 31100.
+ minVersion = 31100
+ case configs.NEWPID:
+ // For PID namespaces criu 31500 is needed.
+ minVersion = 31500
+ default:
+ return false
+ }
+ return c.checkCriuVersion(minVersion) == nil
+}
+
+func (c *linuxContainer) criuNsToKey(t configs.NamespaceType) string {
+ return "extRoot" + strings.Title(configs.NsName(t)) + "NS"
+}
+
+func (c *linuxContainer) handleCheckpointingExternalNamespaces(rpcOpts *criurpc.CriuOpts, t configs.NamespaceType) error {
+ if !c.criuSupportsExtNS(t) {
+ return nil
+ }
+
+ nsPath := c.config.Namespaces.PathOf(t)
+ if nsPath == "" {
+ return nil
+ }
+ // CRIU expects the information about an external namespace
+ // like this: --external []:
+ // This is always 'extRootNS'.
+ var ns unix.Stat_t
+ if err := unix.Stat(nsPath, &ns); err != nil {
+ return err
+ }
+ criuExternal := fmt.Sprintf("%s[%d]:%s", configs.NsName(t), ns.Ino, c.criuNsToKey(t))
+ rpcOpts.External = append(rpcOpts.External, criuExternal)
+
+ return nil
+}
+
+func (c *linuxContainer) handleRestoringExternalNamespaces(rpcOpts *criurpc.CriuOpts, extraFiles *[]*os.File, t configs.NamespaceType) error {
+ if !c.criuSupportsExtNS(t) {
+ return nil
+ }
+
+ nsPath := c.config.Namespaces.PathOf(t)
+ if nsPath == "" {
+ return nil
+ }
+ // CRIU wants the information about an existing namespace
+ // like this: --inherit-fd fd[]:
+ // The needs to be the same as during checkpointing.
+ // We are always using 'extRootNS' as the key in this.
+ nsFd, err := os.Open(nsPath)
+ if err != nil {
+ logrus.Errorf("If a specific network namespace is defined it must exist: %s", err)
+ return fmt.Errorf("Requested network namespace %v does not exist", nsPath)
+ }
+ inheritFd := new(criurpc.InheritFd)
+ inheritFd.Key = proto.String(c.criuNsToKey(t))
+ // The offset of four is necessary because 0, 1, 2 and 3 is already
+ // used by stdin, stdout, stderr, 'criu swrk' socket.
+ inheritFd.Fd = proto.Int32(int32(4 + len(*extraFiles)))
+ rpcOpts.InheritFd = append(rpcOpts.InheritFd, inheritFd)
+ // All open FDs need to be transferred to CRIU via extraFiles
+ *extraFiles = append(*extraFiles, nsFd)
+
+ return nil
+}
+
func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
c.m.Lock()
defer c.m.Unlock()
@@ -932,13 +919,13 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
// support for doing unprivileged dumps, but the setup of
// rootless containers might make this complicated.
- // criu 1.5.2 => 10502
- if err := c.checkCriuVersion(10502); err != nil {
+ // We are relying on the CRIU version RPC which was introduced with CRIU 3.0.0
+ if err := c.checkCriuVersion(30000); err != nil {
return err
}
if criuOpts.ImagesDirectory == "" {
- return fmt.Errorf("invalid directory to save checkpoint")
+ return errors.New("invalid directory to save checkpoint")
}
// Since a container can be C/R'ed multiple times,
@@ -995,30 +982,22 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
// will expect that the namespace exists during restore.
// This basically means that CRIU will ignore the namespace
// and expect to be setup correctly.
- nsPath := c.config.Namespaces.PathOf(configs.NEWNET)
- if nsPath != "" {
- // For this to work we need at least criu 3.11.0 => 31100.
- // As there was already a successful version check we will
- // not error out if it fails. runc will just behave as it used
- // to do and ignore external network namespaces.
- err := c.checkCriuVersion(31100)
- if err == nil {
- // CRIU expects the information about an external namespace
- // like this: --external net[]:
- // This is always 'extRootNetNS'.
- var netns syscall.Stat_t
- err = syscall.Stat(nsPath, &netns)
- if err != nil {
- return err
- }
- criuExternal := fmt.Sprintf("net[%d]:extRootNetNS", netns.Ino)
- rpcOpts.External = append(rpcOpts.External, criuExternal)
- }
+ if err := c.handleCheckpointingExternalNamespaces(&rpcOpts, configs.NEWNET); err != nil {
+ return err
}
- fcg := c.cgroupManager.GetPaths()["freezer"]
- if fcg != "" {
- rpcOpts.FreezeCgroup = proto.String(fcg)
+ // Same for possible external PID namespaces
+ if err := c.handleCheckpointingExternalNamespaces(&rpcOpts, configs.NEWPID); err != nil {
+ return err
+ }
+
+ // CRIU can use cgroup freezer; when rpcOpts.FreezeCgroup
+ // is not set, CRIU uses ptrace() to pause the processes.
+ // Note cgroup v2 freezer is only supported since CRIU release 3.14.
+ if !cgroups.IsCgroup2UnifiedMode() || c.checkCriuVersion(31400) == nil {
+ if fcg := c.cgroupManager.Path("freezer"); fcg != "" {
+ rpcOpts.FreezeCgroup = proto.String(fcg)
+ }
}
// append optional criu opts, e.g., page-server and port
@@ -1037,10 +1016,6 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
// append optional manage cgroups mode
if criuOpts.ManageCgroupsMode != 0 {
- // criu 1.7 => 10700
- if err := c.checkCriuVersion(10700); err != nil {
- return err
- }
mode := criurpc.CriuCgMode(criuOpts.ManageCgroupsMode)
rpcOpts.ManageCgroupsMode = &mode
}
@@ -1059,36 +1034,53 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
} else {
t = criurpc.CriuReqType_DUMP
}
- req := &criurpc.CriuReq{
- Type: &t,
- Opts: &rpcOpts,
- }
if criuOpts.LazyPages {
// lazy migration requested; check if criu supports it
feat := criurpc.CriuFeatures{
LazyPages: proto.Bool(true),
}
-
if err := c.checkCriuFeatures(criuOpts, &rpcOpts, &feat); err != nil {
return err
}
- statusRead, statusWrite, err := os.Pipe()
- if err != nil {
- return err
+ if fd := criuOpts.StatusFd; fd != -1 {
+ // check that the FD is valid
+ flags, err := unix.FcntlInt(uintptr(fd), unix.F_GETFL, 0)
+ if err != nil {
+ return fmt.Errorf("invalid --status-fd argument %d: %w", fd, err)
+ }
+ // and writable
+ if flags&unix.O_WRONLY == 0 {
+ return fmt.Errorf("invalid --status-fd argument %d: not writable", fd)
+ }
+
+ if c.checkCriuVersion(31500) != nil {
+ // For criu 3.15+, use notifications (see case "status-ready"
+ // in criuNotifications). Otherwise, rely on criu status fd.
+ rpcOpts.StatusFd = proto.Int32(int32(fd))
+ }
}
- rpcOpts.StatusFd = proto.Int32(int32(statusWrite.Fd()))
- go waitForCriuLazyServer(statusRead, criuOpts.StatusFd)
}
- //no need to dump these information in pre-dump
+ req := &criurpc.CriuReq{
+ Type: &t,
+ Opts: &rpcOpts,
+ }
+
+ // no need to dump all this in pre-dump
if !criuOpts.PreDump {
+ hasCgroupns := c.config.Namespaces.Contains(configs.NEWCGROUP)
for _, m := range c.config.Mounts {
switch m.Device {
case "bind":
c.addCriuDumpMount(req, m)
case "cgroup":
+ if cgroups.IsCgroup2UnifiedMode() || hasCgroupns {
+ // real mount(s)
+ continue
+ }
+ // a set of "external" bind mounts
binds, err := getCgroupMounts(m)
if err != nil {
return err
@@ -1120,7 +1112,7 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error {
}
}
- err = c.criuSwrk(nil, req, criuOpts, false, nil)
+ err = c.criuSwrk(nil, req, criuOpts, nil)
if err != nil {
return err
}
@@ -1166,7 +1158,14 @@ func (c *linuxContainer) restoreNetwork(req *criurpc.CriuReq, criuOpts *CriuOpts
func (c *linuxContainer) makeCriuRestoreMountpoints(m *configs.Mount) error {
switch m.Device {
case "cgroup":
- // Do nothing for cgroup, CRIU should handle it
+ // No mount point(s) need to be created:
+ //
+ // * for v1, mount points are saved by CRIU because
+ // /sys/fs/cgroup is a tmpfs mount
+ //
+ // * for v2, /sys/fs/cgroup is a real mount, but
+ // the mountpoint appears as soon as /sys is mounted
+ return nil
case "bind":
// The prepareBindMount() function checks if source
// exists. So it cannot be used for other filesystem types.
@@ -1174,7 +1173,7 @@ func (c *linuxContainer) makeCriuRestoreMountpoints(m *configs.Mount) error {
return err
}
default:
- // for all other file-systems just create the mountpoints
+ // for all other filesystems just create the mountpoints
dest, err := securejoin.SecureJoin(c.config.Rootfs, m.Destination)
if err != nil {
return err
@@ -1195,10 +1194,10 @@ func (c *linuxContainer) makeCriuRestoreMountpoints(m *configs.Mount) error {
func isPathInPrefixList(path string, prefix []string) bool {
for _, p := range prefix {
if strings.HasPrefix(path, p+"/") {
- return false
+ return true
}
}
- return true
+ return false
}
// prepareCriuRestoreMounts tries to set up the rootfs of the
@@ -1220,7 +1219,7 @@ func (c *linuxContainer) prepareCriuRestoreMounts(mounts []*configs.Mount) error
// if the mountpoints are not on a tmpfs, as CRIU will
// restore the complete tmpfs content from its checkpoint.
for _, m := range mounts {
- if isPathInPrefixList(m.Destination, tmpfs) {
+ if !isPathInPrefixList(m.Destination, tmpfs) {
if err := c.makeCriuRestoreMountpoints(m); err != nil {
return err
}
@@ -1240,8 +1239,8 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
// TODO(avagin): Figure out how to make this work nicely. CRIU doesn't have
// support for unprivileged restore at the moment.
- // criu 1.5.2 => 10502
- if err := c.checkCriuVersion(10502); err != nil {
+ // We are relying on the CRIU version RPC which was introduced with CRIU 3.0.0
+ if err := c.checkCriuVersion(30000); err != nil {
return err
}
if criuOpts.WorkDirectory == "" {
@@ -1258,7 +1257,7 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
}
defer workDir.Close()
if criuOpts.ImagesDirectory == "" {
- return fmt.Errorf("invalid directory to restore checkpoint")
+ return errors.New("invalid directory to restore checkpoint")
}
imageDir, err := os.Open(criuOpts.ImagesDirectory)
if err != nil {
@@ -1313,33 +1312,13 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
// Same as during checkpointing. If the container has a specific network namespace
// assigned to it, this now expects that the checkpoint will be restored in a
// already created network namespace.
- nsPath := c.config.Namespaces.PathOf(configs.NEWNET)
- if nsPath != "" {
- // For this to work we need at least criu 3.11.0 => 31100.
- // As there was already a successful version check we will
- // not error out if it fails. runc will just behave as it used
- // to do and ignore external network namespaces.
- err := c.checkCriuVersion(31100)
- if err == nil {
- // CRIU wants the information about an existing network namespace
- // like this: --inherit-fd fd[]:
- // The needs to be the same as during checkpointing.
- // We are always using 'extRootNetNS' as the key in this.
- netns, err := os.Open(nsPath)
- defer netns.Close()
- if err != nil {
- logrus.Errorf("If a specific network namespace is defined it must exist: %s", err)
- return fmt.Errorf("Requested network namespace %v does not exist", nsPath)
- }
- inheritFd := new(criurpc.InheritFd)
- inheritFd.Key = proto.String("extRootNetNS")
- // The offset of four is necessary because 0, 1, 2 and 3 is already
- // used by stdin, stdout, stderr, 'criu swrk' socket.
- inheritFd.Fd = proto.Int32(int32(4 + len(extraFiles)))
- req.Opts.InheritFd = append(req.Opts.InheritFd, inheritFd)
- // All open FDs need to be transferred to CRIU via extraFiles
- extraFiles = append(extraFiles, netns)
- }
+ if err := c.handleRestoringExternalNamespaces(req.Opts, &extraFiles, configs.NEWNET); err != nil {
+ return err
+ }
+
+ // Same for PID namespaces.
+ if err := c.handleRestoringExternalNamespaces(req.Opts, &extraFiles, configs.NEWPID); err != nil {
+ return err
}
// This will modify the rootfs of the container in the same way runc
@@ -1348,11 +1327,16 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
return err
}
+ hasCgroupns := c.config.Namespaces.Contains(configs.NEWCGROUP)
for _, m := range c.config.Mounts {
switch m.Device {
case "bind":
c.addCriuRestoreMount(req, m)
case "cgroup":
+ if cgroups.IsCgroup2UnifiedMode() || hasCgroupns {
+ continue
+ }
+ // cgroup v1 is a set of bind mounts, unless cgroupns is used
binds, err := getCgroupMounts(m)
if err != nil {
return err
@@ -1379,10 +1363,6 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
// append optional manage cgroups mode
if criuOpts.ManageCgroupsMode != 0 {
- // criu 1.7 => 10700
- if err := c.checkCriuVersion(10700); err != nil {
- return err
- }
mode := criurpc.CriuCgMode(criuOpts.ManageCgroupsMode)
req.Opts.ManageCgroupsMode = &mode
}
@@ -1406,10 +1386,22 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error {
req.Opts.InheritFd = append(req.Opts.InheritFd, inheritFd)
}
}
- return c.criuSwrk(process, req, criuOpts, true, extraFiles)
+ err = c.criuSwrk(process, req, criuOpts, extraFiles)
+
+ // Now that CRIU is done let's close all opened FDs CRIU needed.
+ for _, fd := range extraFiles {
+ fd.Close()
+ }
+
+ return err
}
func (c *linuxContainer) criuApplyCgroups(pid int, req *criurpc.CriuReq) error {
+ // need to apply cgroups only on restore
+ if req.GetType() != criurpc.CriuReqType_RESTORE {
+ return nil
+ }
+
// XXX: Do we need to deal with this case? AFAIK criu still requires root.
if err := c.cgroupManager.Apply(pid); err != nil {
return err
@@ -1419,6 +1411,11 @@ func (c *linuxContainer) criuApplyCgroups(pid int, req *criurpc.CriuReq) error {
return newSystemError(err)
}
+ if cgroups.IsCgroup2UnifiedMode() {
+ return nil
+ }
+ // the stuff below is cgroupv1-specific
+
path := fmt.Sprintf("/proc/%d/cgroup", pid)
cgroupsPaths, err := cgroups.ParseCgroupFile(path)
if err != nil {
@@ -1436,7 +1433,7 @@ func (c *linuxContainer) criuApplyCgroups(pid int, req *criurpc.CriuReq) error {
return nil
}
-func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts *CriuOpts, applyCgroups bool, extraFiles []*os.File) error {
+func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts *CriuOpts, extraFiles []*os.File) error {
fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_SEQPACKET|unix.SOCK_CLOEXEC, 0)
if err != nil {
return err
@@ -1484,26 +1481,29 @@ func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts *
if err := cmd.Start(); err != nil {
return err
}
+ // we close criuServer so that even if CRIU crashes or unexpectedly exits, runc will not hang.
criuServer.Close()
+ // cmd.Process will be replaced by a restored init.
+ criuProcess := cmd.Process
+ var criuProcessState *os.ProcessState
defer func() {
- criuClientCon.Close()
- _, err := cmd.Process.Wait()
- if err != nil {
- return
+ if criuProcessState == nil {
+ criuClientCon.Close()
+ _, err := criuProcess.Wait()
+ if err != nil {
+ logrus.Warnf("wait on criuProcess returned %v", err)
+ }
}
}()
- if applyCgroups {
- err := c.criuApplyCgroups(cmd.Process.Pid, req)
- if err != nil {
- return err
- }
+ if err := c.criuApplyCgroups(criuProcess.Pid, req); err != nil {
+ return err
}
var extFds []string
if process != nil {
- extFds, err = getPipeFds(cmd.Process.Pid)
+ extFds, err = getPipeFds(criuProcess.Pid)
if err != nil {
return err
}
@@ -1542,14 +1542,23 @@ func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts *
oob := make([]byte, 4096)
for true {
n, oobn, _, _, err := criuClientCon.ReadMsgUnix(buf, oob)
+ if req.Opts != nil && req.Opts.StatusFd != nil {
+ // Close status_fd as soon as we got something back from criu,
+ // assuming it has consumed (reopened) it by this time.
+ // Otherwise it will might be left open forever and whoever
+ // is waiting on it will wait forever.
+ fd := int(*req.Opts.StatusFd)
+ _ = unix.Close(fd)
+ req.Opts.StatusFd = nil
+ }
if err != nil {
return err
}
if n == 0 {
- return fmt.Errorf("unexpected EOF")
+ return errors.New("unexpected EOF")
}
if n == len(buf) {
- return fmt.Errorf("buffer is too small")
+ return errors.New("buffer is too small")
}
resp := new(criurpc.CriuResp)
@@ -1559,25 +1568,16 @@ func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts *
}
if !resp.GetSuccess() {
typeString := req.GetType().String()
- if typeString == "VERSION" {
- // If the VERSION RPC fails this probably means that the CRIU
- // version is too old for this RPC. Just return 'nil'.
- return nil
- }
return fmt.Errorf("criu failed: type %s errno %d\nlog file: %s", typeString, resp.GetCrErrno(), logPath)
}
t := resp.GetType()
switch {
- case t == criurpc.CriuReqType_VERSION:
- logrus.Debugf("CRIU version: %s", resp)
- criuVersionRPC = resp.GetVersion()
- break
case t == criurpc.CriuReqType_FEATURE_CHECK:
logrus.Debugf("Feature check says: %s", resp)
criuFeatures = resp.GetFeatures()
case t == criurpc.CriuReqType_NOTIFY:
- if err := c.criuNotifications(resp, process, opts, extFds, oob[:oobn]); err != nil {
+ if err := c.criuNotifications(resp, process, cmd, opts, extFds, oob[:oobn]); err != nil {
return err
}
t = criurpc.CriuReqType_NOTIFY
@@ -1607,7 +1607,7 @@ func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts *
criuClientCon.CloseWrite()
// cmd.Wait() waits cmd.goroutines which are used for proxying file descriptors.
// Here we want to wait only the CRIU process.
- st, err := cmd.Process.Wait()
+ criuProcessState, err = criuProcess.Wait()
if err != nil {
return err
}
@@ -1619,8 +1619,8 @@ func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts *
// and not the whole series of pre-dump, pre-dump, ...m, dump
// If we got the message CriuReqType_PRE_DUMP it means
// CRIU was successful and we need to forcefully stop CRIU
- if !st.Success() && *req.Type != criurpc.CriuReqType_PRE_DUMP {
- return fmt.Errorf("criu failed: %s\nlog file: %s", st.String(), logPath)
+ if !criuProcessState.Success() && *req.Type != criurpc.CriuReqType_PRE_DUMP {
+ return fmt.Errorf("criu failed: %s\nlog file: %s", criuProcessState.String(), logPath)
}
return nil
}
@@ -1653,43 +1653,53 @@ func unlockNetwork(config *configs.Config) error {
return nil
}
-func (c *linuxContainer) criuNotifications(resp *criurpc.CriuResp, process *Process, opts *CriuOpts, fds []string, oob []byte) error {
+func (c *linuxContainer) criuNotifications(resp *criurpc.CriuResp, process *Process, cmd *exec.Cmd, opts *CriuOpts, fds []string, oob []byte) error {
notify := resp.GetNotify()
if notify == nil {
return fmt.Errorf("invalid response: %s", resp.String())
}
- logrus.Debugf("notify: %s\n", notify.GetScript())
- switch {
- case notify.GetScript() == "post-dump":
+ script := notify.GetScript()
+ logrus.Debugf("notify: %s\n", script)
+ switch script {
+ case "post-dump":
f, err := os.Create(filepath.Join(c.root, "checkpoint"))
if err != nil {
return err
}
f.Close()
- case notify.GetScript() == "network-unlock":
+ case "network-unlock":
if err := unlockNetwork(c.config); err != nil {
return err
}
- case notify.GetScript() == "network-lock":
+ case "network-lock":
if err := lockNetwork(c.config); err != nil {
return err
}
- case notify.GetScript() == "setup-namespaces":
+ case "setup-namespaces":
if c.config.Hooks != nil {
s, err := c.currentOCIState()
if err != nil {
return nil
}
s.Pid = int(notify.GetPid())
- for i, hook := range c.config.Hooks.Prestart {
- if err := hook.Run(s); err != nil {
- return newSystemErrorWithCausef(err, "running prestart hook %d", i)
- }
+
+ if err := c.config.Hooks[configs.Prestart].RunHooks(s); err != nil {
+ return err
+ }
+ if err := c.config.Hooks[configs.CreateRuntime].RunHooks(s); err != nil {
+ return err
}
}
- case notify.GetScript() == "post-restore":
+ case "post-restore":
pid := notify.GetPid()
- r, err := newRestoredProcess(int(pid), fds)
+
+ p, err := os.FindProcess(int(pid))
+ if err != nil {
+ return err
+ }
+ cmd.Process = p
+
+ r, err := newRestoredProcess(cmd, fds)
if err != nil {
return err
}
@@ -1710,7 +1720,7 @@ func (c *linuxContainer) criuNotifications(resp *criurpc.CriuResp, process *Proc
logrus.Error(err)
}
}
- case notify.GetScript() == "orphan-pts-master":
+ case "orphan-pts-master":
scm, err := unix.ParseSocketControlMessage(oob)
if err != nil {
return err
@@ -1727,6 +1737,16 @@ func (c *linuxContainer) criuNotifications(resp *criurpc.CriuResp, process *Proc
if err := utils.SendFd(process.ConsoleSocket, master.Name(), master.Fd()); err != nil {
return err
}
+ case "status-ready":
+ if opts.StatusFd != -1 {
+ // write \0 to status fd to notify that lazy page server is ready
+ _, err := unix.Write(opts.StatusFd, []byte{0})
+ if err != nil {
+ logrus.Warnf("can't write \\0 to status fd: %v", err)
+ }
+ _ = unix.Close(opts.StatusFd)
+ opts.StatusFd = -1
+ }
}
return nil
}
@@ -1746,13 +1766,30 @@ func (c *linuxContainer) updateState(process parentProcess) (*State, error) {
return state, nil
}
-func (c *linuxContainer) saveState(s *State) error {
- f, err := os.Create(filepath.Join(c.root, stateFilename))
+func (c *linuxContainer) saveState(s *State) (retErr error) {
+ tmpFile, err := ioutil.TempFile(c.root, "state-")
if err != nil {
return err
}
- defer f.Close()
- return utils.WriteJSON(f, s)
+
+ defer func() {
+ if retErr != nil {
+ tmpFile.Close()
+ os.Remove(tmpFile.Name())
+ }
+ }()
+
+ err = utils.WriteJSON(tmpFile, s)
+ if err != nil {
+ return err
+ }
+ err = tmpFile.Close()
+ if err != nil {
+ return err
+ }
+
+ stateFilePath := filepath.Join(c.root, stateFilename)
+ return os.Rename(tmpFile.Name(), stateFilePath)
}
func (c *linuxContainer) deleteState() error {
@@ -1778,10 +1815,7 @@ func (c *linuxContainer) refreshState() error {
if paused {
return c.state.transition(&pausedState{c: c})
}
- t, err := c.runType()
- if err != nil {
- return err
- }
+ t := c.runType()
switch t {
case Created:
return c.state.transition(&createdState{c: c})
@@ -1791,48 +1825,32 @@ func (c *linuxContainer) refreshState() error {
return c.state.transition(&stoppedState{c: c})
}
-func (c *linuxContainer) runType() (Status, error) {
+func (c *linuxContainer) runType() Status {
if c.initProcess == nil {
- return Stopped, nil
+ return Stopped
}
pid := c.initProcess.pid()
stat, err := system.Stat(pid)
if err != nil {
- return Stopped, nil
+ return Stopped
}
if stat.StartTime != c.initProcessStartTime || stat.State == system.Zombie || stat.State == system.Dead {
- return Stopped, nil
+ return Stopped
}
// We'll create exec fifo and blocking on it after container is created,
// and delete it after start container.
if _, err := os.Stat(filepath.Join(c.root, execFifoFilename)); err == nil {
- return Created, nil
+ return Created
}
- return Running, nil
+ return Running
}
func (c *linuxContainer) isPaused() (bool, error) {
- fcg := c.cgroupManager.GetPaths()["freezer"]
- if fcg == "" {
- // A container doesn't have a freezer cgroup
- return false, nil
- }
- pausedState := "FROZEN"
- filename := "freezer.state"
- if cgroups.IsCgroup2UnifiedMode() {
- filename = "cgroup.freeze"
- pausedState = "1"
- }
-
- data, err := ioutil.ReadFile(filepath.Join(fcg, filename))
+ state, err := c.cgroupManager.GetFreezerState()
if err != nil {
- // If freezer cgroup is not mounted, the container would just be not paused.
- if os.IsNotExist(err) || err == syscall.ENODEV {
- return false, nil
- }
- return false, newSystemErrorWithCause(err, "checking if container is paused")
+ return false, err
}
- return bytes.Equal(bytes.TrimSpace(data), []byte(pausedState)), nil
+ return state == configs.Frozen, nil
}
func (c *linuxContainer) currentState() (*State, error) {
@@ -1893,7 +1911,7 @@ func (c *linuxContainer) currentOCIState() (*specs.State, error) {
if err != nil {
return nil, err
}
- state.Status = status.String()
+ state.Status = specs.ContainerState(status.String())
if status != Stopped {
if c.initProcess != nil {
state.Pid = c.initProcess.pid()
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/criu_opts_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/criu_opts_linux.go
index a2e344fc4..1d119246d 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/criu_opts_linux.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/criu_opts_linux.go
@@ -36,5 +36,5 @@ type CriuOpts struct {
EmptyNs uint32 // don't c/r properties for namespace from this mask
AutoDedup bool // auto deduplication for incremental dumps
LazyPages bool // restore memory pages lazily using userfaultfd
- StatusFd string // fd for feedback when lazy server is ready
+ StatusFd int // fd for feedback when lazy server is ready
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/devices/devices.go b/vendor/github.com/opencontainers/runc/libcontainer/devices/devices.go
index 5dabe06ce..79f89c2d7 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/devices/devices.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/devices/devices.go
@@ -31,33 +31,33 @@ func DeviceFromPath(path, permissions string) (*configs.Device, error) {
}
var (
+ devType configs.DeviceType
+ mode = stat.Mode
devNumber = uint64(stat.Rdev)
major = unix.Major(devNumber)
minor = unix.Minor(devNumber)
)
- if major == 0 {
+ switch mode & unix.S_IFMT {
+ case unix.S_IFBLK:
+ devType = configs.BlockDevice
+ case unix.S_IFCHR:
+ devType = configs.CharDevice
+ case unix.S_IFIFO:
+ devType = configs.FifoDevice
+ default:
return nil, ErrNotADevice
}
-
- var (
- devType rune
- mode = stat.Mode
- )
- switch {
- case mode&unix.S_IFBLK == unix.S_IFBLK:
- devType = 'b'
- case mode&unix.S_IFCHR == unix.S_IFCHR:
- devType = 'c'
- }
return &configs.Device{
- Type: devType,
- Path: path,
- Major: int64(major),
- Minor: int64(minor),
- Permissions: permissions,
- FileMode: os.FileMode(mode),
- Uid: stat.Uid,
- Gid: stat.Gid,
+ DeviceRule: configs.DeviceRule{
+ Type: devType,
+ Major: int64(major),
+ Minor: int64(minor),
+ Permissions: configs.DevicePermissions(permissions),
+ },
+ Path: path,
+ FileMode: os.FileMode(mode),
+ Uid: stat.Uid,
+ Gid: stat.Gid,
}, nil
}
@@ -104,6 +104,9 @@ func GetDevices(path string) ([]*configs.Device, error) {
}
return nil, err
}
+ if device.Type == configs.FifoDevice {
+ continue
+ }
out = append(out, device)
}
return out, nil
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/factory_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/factory_linux.go
index 437633c6e..59548ef88 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/factory_linux.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/factory_linux.go
@@ -11,7 +11,8 @@ import (
"runtime/debug"
"strconv"
- "github.com/cyphar/filepath-securejoin"
+ securejoin "github.com/cyphar/filepath-securejoin"
+ "github.com/moby/sys/mountinfo"
"github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/cgroups/fs"
"github.com/opencontainers/runc/libcontainer/cgroups/fs2"
@@ -19,7 +20,6 @@ import (
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runc/libcontainer/configs/validate"
"github.com/opencontainers/runc/libcontainer/intelrdt"
- "github.com/opencontainers/runc/libcontainer/mount"
"github.com/opencontainers/runc/libcontainer/utils"
"github.com/pkg/errors"
@@ -50,28 +50,60 @@ func InitArgs(args ...string) func(*LinuxFactory) error {
}
}
-// SystemdCgroups is an options func to configure a LinuxFactory to return
-// containers that use systemd to create and manage cgroups.
-func SystemdCgroups(l *LinuxFactory) error {
- systemdCgroupsManager, err := systemd.NewSystemdCgroupsManager()
- if err != nil {
- return err
- }
- l.NewCgroupsManager = systemdCgroupsManager
- return nil
-}
-
func getUnifiedPath(paths map[string]string) string {
- unifiedPath := ""
+ path := ""
for k, v := range paths {
- if unifiedPath == "" {
- unifiedPath = v
- } else if v != unifiedPath {
- panic(errors.Errorf("expected %q path to be unified path %q, got %q", k, unifiedPath, v))
+ if path == "" {
+ path = v
+ } else if v != path {
+ panic(errors.Errorf("expected %q path to be unified path %q, got %q", k, path, v))
}
}
// can be empty
- return unifiedPath
+ if path != "" {
+ if filepath.Clean(path) != path || !filepath.IsAbs(path) {
+ panic(errors.Errorf("invalid dir path %q", path))
+ }
+ }
+
+ return path
+}
+
+func systemdCgroupV2(l *LinuxFactory, rootless bool) error {
+ l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager {
+ return systemd.NewUnifiedManager(config, getUnifiedPath(paths), rootless)
+ }
+ return nil
+}
+
+// SystemdCgroups is an options func to configure a LinuxFactory to return
+// containers that use systemd to create and manage cgroups.
+func SystemdCgroups(l *LinuxFactory) error {
+ if !systemd.IsRunningSystemd() {
+ return fmt.Errorf("systemd not running on this host, can't use systemd as cgroups manager")
+ }
+
+ if cgroups.IsCgroup2UnifiedMode() {
+ return systemdCgroupV2(l, false)
+ }
+
+ l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager {
+ return systemd.NewLegacyManager(config, paths)
+ }
+
+ return nil
+}
+
+// RootlessSystemdCgroups is rootless version of SystemdCgroups.
+func RootlessSystemdCgroups(l *LinuxFactory) error {
+ if !systemd.IsRunningSystemd() {
+ return fmt.Errorf("systemd not running on this host, can't use systemd as cgroups manager")
+ }
+
+ if !cgroups.IsCgroup2UnifiedMode() {
+ return fmt.Errorf("cgroup v2 not enabled on this host, can't use systemd (rootless) as cgroups manager")
+ }
+ return systemdCgroupV2(l, true)
}
func cgroupfs2(l *LinuxFactory, rootless bool) error {
@@ -85,20 +117,21 @@ func cgroupfs2(l *LinuxFactory, rootless bool) error {
return nil
}
+func cgroupfs(l *LinuxFactory, rootless bool) error {
+ if cgroups.IsCgroup2UnifiedMode() {
+ return cgroupfs2(l, rootless)
+ }
+ l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager {
+ return fs.NewManager(config, paths, rootless)
+ }
+ return nil
+}
+
// Cgroupfs is an options func to configure a LinuxFactory to return containers
// that use the native cgroups filesystem implementation to create and manage
// cgroups.
func Cgroupfs(l *LinuxFactory) error {
- if cgroups.IsCgroup2UnifiedMode() {
- return cgroupfs2(l, false)
- }
- l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager {
- return &fs.Manager{
- Cgroups: config,
- Paths: paths,
- }
- }
- return nil
+ return cgroupfs(l, false)
}
// RootlessCgroupfs is an options func to configure a LinuxFactory to return
@@ -108,17 +141,7 @@ func Cgroupfs(l *LinuxFactory) error {
// during rootless container (including euid=0 in userns) setup (while still allowing cgroup usage if
// they've been set up properly).
func RootlessCgroupfs(l *LinuxFactory) error {
- if cgroups.IsCgroup2UnifiedMode() {
- return cgroupfs2(l, true)
- }
- l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager {
- return &fs.Manager{
- Cgroups: config,
- Rootless: true,
- Paths: paths,
- }
- }
- return nil
+ return cgroupfs(l, true)
}
// IntelRdtfs is an options func to configure a LinuxFactory to return
@@ -137,7 +160,7 @@ func IntelRdtFs(l *LinuxFactory) error {
// TmpfsRoot is an option func to mount LinuxFactory.Root to tmpfs.
func TmpfsRoot(l *LinuxFactory) error {
- mounted, err := mount.Mounted(l.Root)
+ mounted, err := mountinfo.Mounted(l.Root)
if err != nil {
return err
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/generic_error.go b/vendor/github.com/opencontainers/runc/libcontainer/generic_error.go
index 6e7de2fe7..d185ebd89 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/generic_error.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/generic_error.go
@@ -80,7 +80,7 @@ func (e *genericError) Error() string {
return e.Message
}
frame := e.Stack.Frames[0]
- return fmt.Sprintf("%s:%d: %s caused %q", frame.File, frame.Line, e.Cause, e.Message)
+ return fmt.Sprintf("%s:%d: %s caused: %s", frame.File, frame.Line, e.Cause, e.Message)
}
func (e *genericError) Code() ErrorCode {
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/init_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/init_linux.go
index c1b156002..f2dc17e00 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/init_linux.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/init_linux.go
@@ -10,7 +10,6 @@ import (
"net"
"os"
"strings"
- "syscall" // only for Errno
"unsafe"
"golang.org/x/sys/unix"
@@ -21,6 +20,7 @@ import (
"github.com/opencontainers/runc/libcontainer/system"
"github.com/opencontainers/runc/libcontainer/user"
"github.com/opencontainers/runc/libcontainer/utils"
+ "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"
@@ -68,6 +68,7 @@ type initConfig struct {
ConsoleHeight uint16 `json:"console_height"`
RootlessEUID bool `json:"rootless_euid,omitempty"`
RootlessCgroups bool `json:"rootless_cgroups,omitempty"`
+ SpecState *specs.State `json:"spec_state,omitempty"`
}
type initer interface {
@@ -183,6 +184,9 @@ func setupConsole(socket *os.File, config *initConfig, mount bool) error {
return err
}
+ // After we return from here, we don't need the console anymore.
+ defer pty.Close()
+
if config.ConsoleHeight != 0 && config.ConsoleWidth != 0 {
err = pty.Resize(console.WinSize{
Height: config.ConsoleHeight,
@@ -194,9 +198,6 @@ func setupConsole(socket *os.File, config *initConfig, mount bool) error {
}
}
- // After we return from here, we don't need the console anymore.
- defer pty.Close()
-
// Mount the console inside our rootfs.
if mount {
if err := mountConsole(slavePath); err != nil {
@@ -272,10 +273,10 @@ func setupUser(config *initConfig) error {
// Rather than just erroring out later in setuid(2) and setgid(2), check
// that the user is mapped here.
if _, err := config.Config.HostUID(execUser.Uid); err != nil {
- return fmt.Errorf("cannot set uid to unmapped user in user namespace")
+ return errors.New("cannot set uid to unmapped user in user namespace")
}
if _, err := config.Config.HostGID(execUser.Gid); err != nil {
- return fmt.Errorf("cannot set gid to unmapped user in user namespace")
+ return errors.New("cannot set gid to unmapped user in user namespace")
}
if config.RootlessEUID {
@@ -284,7 +285,7 @@ func setupUser(config *initConfig) error {
// this check earlier, but if libcontainer.Process.User was typesafe
// this might work.
if len(addGroups) > 0 {
- return fmt.Errorf("cannot set any additional groups in a rootless container")
+ return errors.New("cannot set any additional groups in a rootless container")
}
}
@@ -455,7 +456,7 @@ func isWaitable(pid int) (bool, error) {
// isNoChildren returns true if err represents a unix.ECHILD (formerly syscall.ECHILD) false otherwise
func isNoChildren(err error) bool {
switch err := err.(type) {
- case syscall.Errno:
+ case unix.Errno:
if err == unix.ECHILD {
return true
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/cmt.go b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/cmt.go
new file mode 100644
index 000000000..5c406e102
--- /dev/null
+++ b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/cmt.go
@@ -0,0 +1,22 @@
+package intelrdt
+
+var (
+ cmtEnabled bool
+)
+
+// Check if Intel RDT/CMT is enabled.
+func IsCMTEnabled() bool {
+ return cmtEnabled
+}
+
+func getCMTNumaNodeStats(numaPath string) (*CMTNumaNodeStats, error) {
+ stats := &CMTNumaNodeStats{}
+
+ llcOccupancy, err := getIntelRdtParamUint(numaPath, "llc_occupancy")
+ if err != nil {
+ return nil, err
+ }
+ stats.LLCOccupancy = llcOccupancy
+
+ return stats, nil
+}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt.go b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt.go
index 0071ce755..5b19d55a2 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt.go
@@ -55,6 +55,10 @@ import (
* | | |-- cbm_mask
* | | |-- min_cbm_bits
* | | |-- num_closids
+ * | |-- L3_MON
+ * | | |-- max_threshold_occupancy
+ * | | |-- mon_features
+ * | | |-- num_rmids
* | |-- MB
* | |-- bandwidth_gran
* | |-- delay_linear
@@ -191,8 +195,7 @@ type intelRdtData struct {
// Check if Intel RDT sub-features are enabled in init()
func init() {
// 1. Check if hardware and kernel support Intel RDT sub-features
- // "cat_l3" flag for CAT and "mba" flag for MBA
- isCatFlagSet, isMbaFlagSet, err := parseCpuInfoFile("/proc/cpuinfo")
+ flagsSet, err := parseCpuInfoFile("/proc/cpuinfo")
if err != nil {
return
}
@@ -207,7 +210,7 @@ func init() {
// "resource control" filesystem. Intel RDT sub-features can be
// selectively disabled or enabled by kernel command line
// (e.g., rdt=!l3cat,mba) in 4.14 and newer kernel
- if isCatFlagSet {
+ if flagsSet.CAT {
if _, err := os.Stat(filepath.Join(intelRdtRoot, "info", "L3")); err == nil {
isCatEnabled = true
}
@@ -217,11 +220,23 @@ func init() {
// MBA should be enabled because MBA Software Controller
// depends on MBA
isMbaEnabled = true
- } else if isMbaFlagSet {
+ } else if flagsSet.MBA {
if _, err := os.Stat(filepath.Join(intelRdtRoot, "info", "MB")); err == nil {
isMbaEnabled = true
}
}
+
+ if flagsSet.MBMTotal || flagsSet.MBMLocal {
+ if _, err := os.Stat(filepath.Join(intelRdtRoot, "info", "L3_MON")); err == nil {
+ mbmEnabled = true
+ cmtEnabled = true
+ }
+
+ enabledMonFeatures, err = getMonFeatures(intelRdtRoot)
+ if err != nil {
+ return
+ }
+ }
}
// Return the mount point path of Intel RDT "resource control" filesysem
@@ -298,40 +313,52 @@ func isIntelRdtMounted() bool {
return true
}
-func parseCpuInfoFile(path string) (bool, bool, error) {
- isCatFlagSet := false
- isMbaFlagSet := false
+type cpuInfoFlags struct {
+ CAT bool // Cache Allocation Technology
+ MBA bool // Memory Bandwidth Allocation
+
+ // Memory Bandwidth Monitoring related.
+ MBMTotal bool
+ MBMLocal bool
+}
+
+func parseCpuInfoFile(path string) (cpuInfoFlags, error) {
+ infoFlags := cpuInfoFlags{}
f, err := os.Open(path)
if err != nil {
- return false, false, err
+ return infoFlags, err
}
defer f.Close()
s := bufio.NewScanner(f)
for s.Scan() {
- if err := s.Err(); err != nil {
- return false, false, err
- }
-
line := s.Text()
// Search "cat_l3" and "mba" flags in first "flags" line
- if strings.Contains(line, "flags") {
+ if strings.HasPrefix(line, "flags") {
flags := strings.Split(line, " ")
// "cat_l3" flag for CAT and "mba" flag for MBA
for _, flag := range flags {
switch flag {
case "cat_l3":
- isCatFlagSet = true
+ infoFlags.CAT = true
case "mba":
- isMbaFlagSet = true
+ infoFlags.MBA = true
+ case "cqm_mbm_total":
+ infoFlags.MBMTotal = true
+ case "cqm_mbm_local":
+ infoFlags.MBMLocal = true
}
}
- return isCatFlagSet, isMbaFlagSet, nil
+ return infoFlags, nil
}
}
- return isCatFlagSet, isMbaFlagSet, nil
+ if err := s.Err(); err != nil {
+ return infoFlags, err
+ }
+
+ return infoFlags, nil
}
func parseUint(s string, base, bitSize int) (uint64, error) {
@@ -586,7 +613,8 @@ func (m *IntelRdtManager) GetStats() (*Stats, error) {
schemaRootStrings := strings.Split(tmpRootStrings, "\n")
// The L3 cache and memory bandwidth schemata in 'container_id' group
- tmpStrings, err := getIntelRdtParamString(m.GetPath(), "schemata")
+ containerPath := m.GetPath()
+ tmpStrings, err := getIntelRdtParamString(containerPath, "schemata")
if err != nil {
return nil, err
}
@@ -638,6 +666,11 @@ func (m *IntelRdtManager) GetStats() (*Stats, error) {
}
}
+ err = getMonitoringStats(containerPath, stats)
+ if err != nil {
+ return nil, err
+ }
+
return stats, nil
}
@@ -758,7 +791,7 @@ type LastCmdError struct {
}
func (e *LastCmdError) Error() string {
- return fmt.Sprintf(e.Err.Error() + ", last_cmd_status: " + e.LastCmdStatus)
+ return e.Err.Error() + ", last_cmd_status: " + e.LastCmdStatus
}
func NewLastCmdError(err error) error {
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/mbm.go b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/mbm.go
new file mode 100644
index 000000000..3730bab56
--- /dev/null
+++ b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/mbm.go
@@ -0,0 +1,34 @@
+// +build linux
+
+package intelrdt
+
+var (
+ // The flag to indicate if Intel RDT/MBM is enabled
+ mbmEnabled bool
+)
+
+// Check if Intel RDT/MBM is enabled.
+func IsMBMEnabled() bool {
+ return mbmEnabled
+}
+
+func getMBMNumaNodeStats(numaPath string) (*MBMNumaNodeStats, error) {
+ stats := &MBMNumaNodeStats{}
+ if enabledMonFeatures.mbmTotalBytes {
+ mbmTotalBytes, err := getIntelRdtParamUint(numaPath, "mbm_total_bytes")
+ if err != nil {
+ return nil, err
+ }
+ stats.MBMTotalBytes = mbmTotalBytes
+ }
+
+ if enabledMonFeatures.mbmLocalBytes {
+ mbmLocalBytes, err := getIntelRdtParamUint(numaPath, "mbm_local_bytes")
+ if err != nil {
+ return nil, err
+ }
+ stats.MBMLocalBytes = mbmLocalBytes
+ }
+
+ return stats, nil
+}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/monitoring.go b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/monitoring.go
new file mode 100644
index 000000000..4ccc8eae0
--- /dev/null
+++ b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/monitoring.go
@@ -0,0 +1,85 @@
+package intelrdt
+
+import (
+ "bufio"
+ "github.com/sirupsen/logrus"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+)
+
+var (
+ enabledMonFeatures monFeatures
+)
+
+type monFeatures struct {
+ mbmTotalBytes bool
+ mbmLocalBytes bool
+ llcOccupancy bool
+}
+
+func getMonFeatures(intelRdtRoot string) (monFeatures, error) {
+ file, err := os.Open(filepath.Join(intelRdtRoot, "info", "L3_MON", "mon_features"))
+ defer file.Close()
+ if err != nil {
+ return monFeatures{}, err
+ }
+ return parseMonFeatures(file)
+}
+
+func parseMonFeatures(reader io.Reader) (monFeatures, error) {
+ scanner := bufio.NewScanner(reader)
+
+ monFeatures := monFeatures{}
+
+ for scanner.Scan() {
+ switch feature := scanner.Text(); feature {
+ case "mbm_total_bytes":
+ monFeatures.mbmTotalBytes = true
+ case "mbm_local_bytes":
+ monFeatures.mbmLocalBytes = true
+ case "llc_occupancy":
+ monFeatures.llcOccupancy = true
+ default:
+ logrus.Warnf("Unsupported Intel RDT monitoring feature: %s", feature)
+ }
+ }
+
+ return monFeatures, scanner.Err()
+}
+
+func getMonitoringStats(containerPath string, stats *Stats) error {
+ numaFiles, err := ioutil.ReadDir(filepath.Join(containerPath, "mon_data"))
+ if err != nil {
+ return err
+ }
+
+ var mbmStats []MBMNumaNodeStats
+ var cmtStats []CMTNumaNodeStats
+
+ for _, file := range numaFiles {
+ if file.IsDir() {
+ numaPath := filepath.Join(containerPath, "mon_data", file.Name())
+ if IsMBMEnabled() {
+ numaMBMStats, err := getMBMNumaNodeStats(numaPath)
+ if err != nil {
+ return err
+ }
+ mbmStats = append(mbmStats, *numaMBMStats)
+ }
+ if IsCMTEnabled() {
+ numaCMTStats, err := getCMTNumaNodeStats(numaPath)
+ if err != nil {
+ return err
+ }
+ cmtStats = append(cmtStats, *numaCMTStats)
+ }
+ }
+ }
+
+ stats.MBMStats = &mbmStats
+ stats.CMTStats = &cmtStats
+
+ return err
+}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/stats.go b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/stats.go
index df5686f3b..eeb0ee9f0 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/stats.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/stats.go
@@ -15,6 +15,19 @@ type MemBwInfo struct {
NumClosids uint64 `json:"num_closids,omitempty"`
}
+type MBMNumaNodeStats struct {
+ // The 'mbm_total_bytes' in 'container_id' group.
+ MBMTotalBytes uint64 `json:"mbm_total_bytes,omitempty"`
+
+ // The 'mbm_local_bytes' in 'container_id' group.
+ MBMLocalBytes uint64 `json:"mbm_local_bytes,omitempty"`
+}
+
+type CMTNumaNodeStats struct {
+ // The 'llc_occupancy' in 'container_id' group.
+ LLCOccupancy uint64 `json:"llc_occupancy,omitempty"`
+}
+
type Stats struct {
// The read-only L3 cache information
L3CacheInfo *L3CacheInfo `json:"l3_cache_info,omitempty"`
@@ -33,6 +46,12 @@ type Stats struct {
// The memory bandwidth schema in 'container_id' group
MemBwSchema string `json:"mem_bw_schema,omitempty"`
+
+ // The memory bandwidth monitoring statistics from NUMA nodes in 'container_id' group
+ MBMStats *[]MBMNumaNodeStats `json:"mbm_stats,omitempty"`
+
+ // The cache monitoring technology statistics from NUMA nodes in 'container_id' group
+ CMTStats *[]CMTNumaNodeStats `json:"cmt_stats,omitempty"`
}
func NewStats() *Stats {
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/keys/keyctl.go b/vendor/github.com/opencontainers/runc/libcontainer/keys/keyctl.go
index 74dedd56c..e73af7ae2 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/keys/keyctl.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/keys/keyctl.go
@@ -3,7 +3,6 @@
package keys
import (
- "fmt"
"strconv"
"strings"
@@ -33,7 +32,7 @@ func ModKeyringPerm(ringId KeySerial, mask, setbits uint32) error {
res := strings.Split(dest, ";")
if len(res) < 5 {
- return fmt.Errorf("Destination buffer for key description is too small")
+ return errors.New("Destination buffer for key description is too small")
}
// parse permissions
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/mount/mount.go b/vendor/github.com/opencontainers/runc/libcontainer/mount/mount.go
deleted file mode 100644
index e8965e081..000000000
--- a/vendor/github.com/opencontainers/runc/libcontainer/mount/mount.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package mount
-
-// GetMounts retrieves a list of mounts for the current running process.
-func GetMounts() ([]*Info, error) {
- return parseMountTable()
-}
-
-// Mounted looks at /proc/self/mountinfo to determine of the specified
-// mountpoint has been mounted
-func Mounted(mountpoint string) (bool, error) {
- entries, err := parseMountTable()
- if err != nil {
- return false, err
- }
-
- // Search the table for the mountpoint
- for _, e := range entries {
- if e.Mountpoint == mountpoint {
- return true, nil
- }
- }
- return false, nil
-}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/mount/mount_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/mount/mount_linux.go
deleted file mode 100644
index 1e5191928..000000000
--- a/vendor/github.com/opencontainers/runc/libcontainer/mount/mount_linux.go
+++ /dev/null
@@ -1,82 +0,0 @@
-// +build linux
-
-package mount
-
-import (
- "bufio"
- "fmt"
- "io"
- "os"
- "strings"
-)
-
-const (
- /* 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
- (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
-
- (1) mount ID: unique identifier of the mount (may be reused after umount)
- (2) parent ID: ID of parent (or of self for the top of the mount tree)
- (3) major:minor: value of st_dev for files on filesystem
- (4) root: root of the mount within the filesystem
- (5) mount point: mount point relative to the process's root
- (6) mount options: per mount options
- (7) optional fields: zero or more fields of the form "tag[:value]"
- (8) separator: marks the end of the optional fields
- (9) filesystem type: name of filesystem of the form "type[.subtype]"
- (10) mount source: filesystem specific information or "none"
- (11) super options: per super block options*/
- mountinfoFormat = "%d %d %d:%d %s %s %s %s"
-)
-
-// Parse /proc/self/mountinfo because comparing Dev and ino does not work from
-// bind mounts
-func parseMountTable() ([]*Info, error) {
- f, err := os.Open("/proc/self/mountinfo")
- if err != nil {
- return nil, err
- }
- defer f.Close()
-
- return parseInfoFile(f)
-}
-
-func parseInfoFile(r io.Reader) ([]*Info, error) {
- var (
- s = bufio.NewScanner(r)
- out = []*Info{}
- )
-
- for s.Scan() {
- if err := s.Err(); err != nil {
- return nil, err
- }
-
- var (
- p = &Info{}
- text = s.Text()
- optionalFields string
- )
-
- if _, err := fmt.Sscanf(text, mountinfoFormat,
- &p.ID, &p.Parent, &p.Major, &p.Minor,
- &p.Root, &p.Mountpoint, &p.Opts, &optionalFields); err != nil {
- return nil, fmt.Errorf("Scanning '%s' failed: %s", text, err)
- }
- // Safe as mountinfo encodes mountpoints with spaces as \040.
- index := strings.Index(text, " - ")
- postSeparatorFields := strings.Fields(text[index+3:])
- if len(postSeparatorFields) < 3 {
- return nil, fmt.Errorf("Error found less than 3 fields post '-' in %q", text)
- }
-
- if optionalFields != "-" {
- p.Optional = optionalFields
- }
-
- p.Fstype = postSeparatorFields[0]
- p.Source = postSeparatorFields[1]
- p.VfsOpts = strings.Join(postSeparatorFields[2:], " ")
- out = append(out, p)
- }
- return out, nil
-}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/notify_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/notify_linux.go
index 47a06783d..d7d1de1ba 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/notify_linux.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/notify_linux.go
@@ -3,6 +3,7 @@
package libcontainer
import (
+ "errors"
"fmt"
"io/ioutil"
"os"
@@ -11,8 +12,6 @@ import (
"golang.org/x/sys/unix"
)
-const oomCgroupName = "memory"
-
type PressureLevel uint
const (
@@ -66,19 +65,17 @@ func registerMemoryEvent(cgDir string, evName string, arg string) (<-chan struct
// notifyOnOOM returns channel on which you can expect event about OOM,
// if process died without OOM this channel will be closed.
-func notifyOnOOM(paths map[string]string) (<-chan struct{}, error) {
- dir := paths[oomCgroupName]
+func notifyOnOOM(dir string) (<-chan struct{}, error) {
if dir == "" {
- return nil, fmt.Errorf("path %q missing", oomCgroupName)
+ return nil, errors.New("memory controller missing")
}
return registerMemoryEvent(dir, "memory.oom_control", "")
}
-func notifyMemoryPressure(paths map[string]string, level PressureLevel) (<-chan struct{}, error) {
- dir := paths[oomCgroupName]
+func notifyMemoryPressure(dir string, level PressureLevel) (<-chan struct{}, error) {
if dir == "" {
- return nil, fmt.Errorf("path %q missing", oomCgroupName)
+ return nil, errors.New("memory controller missing")
}
if level > CriticalPressure {
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/notify_linux_v2.go b/vendor/github.com/opencontainers/runc/libcontainer/notify_linux_v2.go
new file mode 100644
index 000000000..cdab10ed6
--- /dev/null
+++ b/vendor/github.com/opencontainers/runc/libcontainer/notify_linux_v2.go
@@ -0,0 +1,102 @@
+// +build linux
+
+package libcontainer
+
+import (
+ "io/ioutil"
+ "path/filepath"
+ "strconv"
+ "strings"
+ "unsafe"
+
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ "golang.org/x/sys/unix"
+)
+
+func getValueFromCgroup(path, key string) (int, error) {
+ content, err := ioutil.ReadFile(path)
+ if err != nil {
+ return 0, err
+ }
+
+ lines := strings.Split(string(content), "\n")
+ for _, line := range lines {
+ arr := strings.Split(line, " ")
+ if len(arr) == 2 && arr[0] == key {
+ return strconv.Atoi(arr[1])
+ }
+ }
+ return 0, nil
+}
+
+func registerMemoryEventV2(cgDir, evName, cgEvName string) (<-chan struct{}, error) {
+ eventControlPath := filepath.Join(cgDir, evName)
+ cgEvPath := filepath.Join(cgDir, cgEvName)
+ fd, err := unix.InotifyInit()
+ if err != nil {
+ return nil, errors.Wrap(err, "unable to init inotify")
+ }
+ // watching oom kill
+ evFd, err := unix.InotifyAddWatch(fd, eventControlPath, unix.IN_MODIFY)
+ if err != nil {
+ unix.Close(fd)
+ return nil, errors.Wrap(err, "unable to add inotify watch")
+ }
+ // Because no `unix.IN_DELETE|unix.IN_DELETE_SELF` event for cgroup file system, so watching all process exited
+ cgFd, err := unix.InotifyAddWatch(fd, cgEvPath, unix.IN_MODIFY)
+ if err != nil {
+ unix.Close(fd)
+ return nil, errors.Wrap(err, "unable to add inotify watch")
+ }
+ ch := make(chan struct{})
+ go func() {
+ var (
+ buffer [unix.SizeofInotifyEvent + unix.PathMax + 1]byte
+ offset uint32
+ )
+ defer func() {
+ unix.Close(fd)
+ close(ch)
+ }()
+
+ for {
+ n, err := unix.Read(fd, buffer[:])
+ if err != nil {
+ logrus.Warnf("unable to read event data from inotify, got error: %v", err)
+ return
+ }
+ if n < unix.SizeofInotifyEvent {
+ logrus.Warnf("we should read at least %d bytes from inotify, but got %d bytes.", unix.SizeofInotifyEvent, n)
+ return
+ }
+ offset = 0
+ for offset <= uint32(n-unix.SizeofInotifyEvent) {
+ rawEvent := (*unix.InotifyEvent)(unsafe.Pointer(&buffer[offset]))
+ offset += unix.SizeofInotifyEvent + uint32(rawEvent.Len)
+ if rawEvent.Mask&unix.IN_MODIFY != unix.IN_MODIFY {
+ continue
+ }
+ switch int(rawEvent.Wd) {
+ case evFd:
+ oom, err := getValueFromCgroup(eventControlPath, "oom_kill")
+ if err != nil || oom > 0 {
+ ch <- struct{}{}
+ }
+ case cgFd:
+ pids, err := getValueFromCgroup(cgEvPath, "populated")
+ if err != nil || pids == 0 {
+ return
+ }
+ }
+ }
+ }
+ }()
+ return ch, nil
+}
+
+// notifyOnOOMV2 returns channel on which you can expect event about OOM,
+// if process died without OOM this channel will be closed.
+func notifyOnOOMV2(path string) (<-chan struct{}, error) {
+ return registerMemoryEventV2(path, "memory.events", "cgroup.events")
+}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/nsenter/cloned_binary.c b/vendor/github.com/opencontainers/runc/libcontainer/nsenter/cloned_binary.c
index ad10f1406..24cc8c6e1 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/nsenter/cloned_binary.c
+++ b/vendor/github.com/opencontainers/runc/libcontainer/nsenter/cloned_binary.c
@@ -1,7 +1,14 @@
+// SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
/*
* Copyright (C) 2019 Aleksa Sarai
* Copyright (C) 2019 SUSE LLC
*
+ * This work is dual licensed under the following licenses. You may use,
+ * redistribute, and/or modify the work under the conditions of either (or
+ * both) licenses.
+ *
+ * === Apache-2.0 ===
+ *
* 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
@@ -13,6 +20,23 @@
* 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.
+ *
+ * === LGPL-2.1-or-later ===
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * .
+ *
*/
#define _GNU_SOURCE
@@ -95,8 +119,10 @@ static int is_self_cloned(void)
struct statfs fsbuf = {};
fd = open("/proc/self/exe", O_RDONLY|O_CLOEXEC);
- if (fd < 0)
+ if (fd < 0) {
+ fprintf(stderr, "you have no read access to runc binary file\n");
return -ENOTRECOVERABLE;
+ }
/*
* Is the binary a fully-sealed memfd? We don't need CLONED_BINARY_ENV for
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c b/vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c
index 072656831..a33f2fcc3 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c
+++ b/vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c
@@ -714,12 +714,12 @@ void nsexec(void)
* ready, so we can receive all possible error codes
* generated by children.
*/
+ syncfd = sync_child_pipe[1];
+ close(sync_child_pipe[0]);
+
while (!ready) {
enum sync_t s;
- syncfd = sync_child_pipe[1];
- close(sync_child_pipe[0]);
-
if (read(syncfd, &s, sizeof(s)) != sizeof(s))
bail("failed to sync with child: next state");
@@ -789,13 +789,13 @@ void nsexec(void)
/* Now sync with grandchild. */
+ syncfd = sync_grandchild_pipe[1];
+ close(sync_grandchild_pipe[0]);
+
ready = false;
while (!ready) {
enum sync_t s;
- syncfd = sync_grandchild_pipe[1];
- close(sync_grandchild_pipe[0]);
-
s = SYNC_GRANDCHILD;
if (write(syncfd, &s, sizeof(s)) != sizeof(s)) {
kill(child, SIGKILL);
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/process_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/process_linux.go
index de989b5bc..cb8c724a2 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/process_linux.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/process_linux.go
@@ -11,15 +11,16 @@ import (
"os/exec"
"path/filepath"
"strconv"
- "syscall" // only for Signal
"github.com/opencontainers/runc/libcontainer/cgroups"
+ "github.com/opencontainers/runc/libcontainer/cgroups/fs2"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runc/libcontainer/intelrdt"
"github.com/opencontainers/runc/libcontainer/logs"
"github.com/opencontainers/runc/libcontainer/system"
"github.com/opencontainers/runc/libcontainer/utils"
-
+ "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
@@ -68,6 +69,7 @@ type setnsProcess struct {
fds []string
process *Process
bootstrapData io.Reader
+ initProcessPid int
}
func (p *setnsProcess) startTime() (uint64, error) {
@@ -76,7 +78,7 @@ func (p *setnsProcess) startTime() (uint64, error) {
}
func (p *setnsProcess) signal(sig os.Signal) error {
- s, ok := sig.(syscall.Signal)
+ s, ok := sig.(unix.Signal)
if !ok {
return errors.New("os: unsupported signal type")
}
@@ -102,7 +104,25 @@ func (p *setnsProcess) start() (err error) {
}
if len(p.cgroupPaths) > 0 {
if err := cgroups.EnterPid(p.cgroupPaths, p.pid()); err != nil && !p.rootlessCgroups {
- return newSystemErrorWithCausef(err, "adding pid %d to cgroups", p.pid())
+ // On cgroup v2 + nesting + domain controllers, EnterPid may fail with EBUSY.
+ // https://github.com/opencontainers/runc/issues/2356#issuecomment-621277643
+ // Try to join the cgroup of InitProcessPid.
+ if cgroups.IsCgroup2UnifiedMode() {
+ initProcCgroupFile := fmt.Sprintf("/proc/%d/cgroup", p.initProcessPid)
+ initCg, initCgErr := cgroups.ParseCgroupFile(initProcCgroupFile)
+ if initCgErr == nil {
+ if initCgPath, ok := initCg[""]; ok {
+ initCgDirpath := filepath.Join(fs2.UnifiedMountpoint, initCgPath)
+ logrus.Debugf("adding pid %d to cgroups %v failed (%v), attempting to join %q (obtained from %s)",
+ p.pid(), p.cgroupPaths, err, initCg, initCgDirpath)
+ // NOTE: initCgDirPath is not guaranteed to exist because we didn't pause the container.
+ err = cgroups.WriteCgroupProc(initCgDirpath, p.pid())
+ }
+ }
+ }
+ if err != nil {
+ return newSystemErrorWithCausef(err, "adding pid %d to cgroups", p.pid())
+ }
}
}
if p.intelRdtPath != "" {
@@ -132,7 +152,7 @@ func (p *setnsProcess) start() (err error) {
// This shouldn't happen.
panic("unexpected procHooks in setns")
default:
- return newSystemError(fmt.Errorf("invalid JSON payload from child"))
+ return newSystemError(errors.New("invalid JSON payload from child"))
}
})
@@ -279,7 +299,7 @@ func (p *initProcess) waitForChildExit(childPid int) error {
return nil
}
-func (p *initProcess) start() error {
+func (p *initProcess) start() (retErr error) {
defer p.messageSockPair.parent.Close()
err := p.cmd.Start()
p.process.ops = p
@@ -290,6 +310,15 @@ func (p *initProcess) start() error {
p.process.ops = nil
return newSystemErrorWithCause(err, "starting init process command")
}
+ defer func() {
+ if retErr != nil {
+ p.manager.Destroy()
+ if p.intelRdtManager != nil {
+ p.intelRdtManager.Destroy()
+ }
+ }
+ }()
+
// Do this before syncing with child so that no children can escape the
// cgroup. We don't need to worry about not doing this and not being root
// because we'd be using the rootless cgroup manager in that case.
@@ -301,16 +330,6 @@ func (p *initProcess) start() error {
return newSystemErrorWithCause(err, "applying Intel RDT configuration for process")
}
}
- defer func() {
- if err != nil {
- // TODO: should not be the responsibility to call here
- p.manager.Destroy()
- if p.intelRdtManager != nil {
- p.intelRdtManager.Destroy()
- }
- }
- }()
-
if _, err := io.Copy(p.messageSockPair.parent, p.bootstrapData); err != nil {
return newSystemErrorWithCause(err, "copying bootstrap data to pipe")
}
@@ -327,16 +346,7 @@ func (p *initProcess) start() error {
return newSystemErrorWithCausef(err, "getting pipe fds for pid %d", childPid)
}
p.setExternalDescriptors(fds)
- // Do this before syncing with child so that no children
- // can escape the cgroup
- if err := p.manager.Apply(childPid); err != nil {
- return newSystemErrorWithCause(err, "applying cgroup configuration for process")
- }
- if p.intelRdtManager != nil {
- if err := p.intelRdtManager.Apply(childPid); err != nil {
- return newSystemErrorWithCause(err, "applying Intel RDT configuration for process")
- }
- }
+
// Now it's time to setup cgroup namesapce
if p.config.Config.Namespaces.Contains(configs.NEWCGROUP) && p.config.Config.Namespaces.PathOf(configs.NEWCGROUP) == "" {
if _, err := p.messageSockPair.parent.Write([]byte{createCgroupns}); err != nil {
@@ -349,18 +359,12 @@ func (p *initProcess) start() error {
return newSystemErrorWithCause(err, "waiting for our first child to exit")
}
- defer func() {
- if err != nil {
- // TODO: should not be the responsibility to call here
- p.manager.Destroy()
- if p.intelRdtManager != nil {
- p.intelRdtManager.Destroy()
- }
- }
- }()
if err := p.createNetworkInterfaces(); err != nil {
return newSystemErrorWithCause(err, "creating network interfaces")
}
+ if err := p.updateSpecState(); err != nil {
+ return newSystemErrorWithCause(err, "updating the spec state")
+ }
if err := p.sendConfig(); err != nil {
return newSystemErrorWithCause(err, "sending config to init process")
}
@@ -377,9 +381,9 @@ func (p *initProcess) start() error {
if err := setupRlimits(p.config.Rlimits, p.pid()); err != nil {
return newSystemErrorWithCause(err, "setting rlimits for ready process")
}
- // call prestart hooks
+ // call prestart and CreateRuntime hooks
if !p.config.Config.Namespaces.Contains(configs.NEWNS) {
- // Setup cgroup before prestart hook, so that the prestart hook could apply cgroup permissions.
+ // Setup cgroup before the hook, so that the prestart and CreateRuntime hook could apply cgroup permissions.
if err := p.manager.Set(p.config.Config); err != nil {
return newSystemErrorWithCause(err, "setting cgroup config for ready process")
}
@@ -396,11 +400,14 @@ func (p *initProcess) start() error {
}
// initProcessStartTime hasn't been set yet.
s.Pid = p.cmd.Process.Pid
- s.Status = "creating"
- for i, hook := range p.config.Config.Hooks.Prestart {
- if err := hook.Run(s); err != nil {
- return newSystemErrorWithCausef(err, "running prestart hook %d", i)
- }
+ s.Status = specs.StateCreating
+ hooks := p.config.Config.Hooks
+
+ if err := hooks[configs.Prestart].RunHooks(s); err != nil {
+ return err
+ }
+ if err := hooks[configs.CreateRuntime].RunHooks(s); err != nil {
+ return err
}
}
}
@@ -426,11 +433,14 @@ func (p *initProcess) start() error {
}
// initProcessStartTime hasn't been set yet.
s.Pid = p.cmd.Process.Pid
- s.Status = "creating"
- for i, hook := range p.config.Config.Hooks.Prestart {
- if err := hook.Run(s); err != nil {
- return newSystemErrorWithCausef(err, "running prestart hook %d", i)
- }
+ s.Status = specs.StateCreating
+ hooks := p.config.Config.Hooks
+
+ if err := hooks[configs.Prestart].RunHooks(s); err != nil {
+ return err
+ }
+ if err := hooks[configs.CreateRuntime].RunHooks(s); err != nil {
+ return err
}
}
// Sync with child.
@@ -439,7 +449,7 @@ func (p *initProcess) start() error {
}
sentResume = true
default:
- return newSystemError(fmt.Errorf("invalid JSON payload from child"))
+ return newSystemError(errors.New("invalid JSON payload from child"))
}
return nil
@@ -449,7 +459,7 @@ func (p *initProcess) start() error {
return newSystemErrorWithCause(ierr, "container init")
}
if p.config.Config.Namespaces.Contains(configs.NEWNS) && !sentResume {
- return newSystemError(fmt.Errorf("could not synchronise after executing prestart hooks with container process"))
+ return newSystemError(errors.New("could not synchronise after executing prestart and CreateRuntime hooks with container process"))
}
if err := unix.Shutdown(int(p.messageSockPair.parent.Fd()), unix.SHUT_WR); err != nil {
return newSystemErrorWithCause(err, "shutting down init pipe")
@@ -491,6 +501,16 @@ func (p *initProcess) startTime() (uint64, error) {
return stat.StartTime, err
}
+func (p *initProcess) updateSpecState() error {
+ s, err := p.container.currentOCIState()
+ if err != nil {
+ return err
+ }
+
+ p.config.SpecState = s
+ return nil
+}
+
func (p *initProcess) sendConfig() error {
// send the config to the container's init process, we don't use JSON Encode
// here because there might be a problem in JSON decoder in some cases, see:
@@ -516,7 +536,7 @@ func (p *initProcess) createNetworkInterfaces() error {
}
func (p *initProcess) signal(sig os.Signal) error {
- s, ok := sig.(syscall.Signal)
+ s, ok := sig.(unix.Signal)
if !ok {
return errors.New("os: unsupported signal type")
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/restored_process.go b/vendor/github.com/opencontainers/runc/libcontainer/restored_process.go
index 28d52ad06..f861e82d1 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/restored_process.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/restored_process.go
@@ -5,31 +5,29 @@ package libcontainer
import (
"fmt"
"os"
+ "os/exec"
"github.com/opencontainers/runc/libcontainer/system"
)
-func newRestoredProcess(pid int, fds []string) (*restoredProcess, error) {
+func newRestoredProcess(cmd *exec.Cmd, fds []string) (*restoredProcess, error) {
var (
err error
)
- proc, err := os.FindProcess(pid)
- if err != nil {
- return nil, err
- }
+ pid := cmd.Process.Pid
stat, err := system.Stat(pid)
if err != nil {
return nil, err
}
return &restoredProcess{
- proc: proc,
+ cmd: cmd,
processStartTime: stat.StartTime,
fds: fds,
}, nil
}
type restoredProcess struct {
- proc *os.Process
+ cmd *exec.Cmd
processStartTime uint64
fds []string
}
@@ -39,11 +37,11 @@ func (p *restoredProcess) start() error {
}
func (p *restoredProcess) pid() int {
- return p.proc.Pid
+ return p.cmd.Process.Pid
}
func (p *restoredProcess) terminate() error {
- err := p.proc.Kill()
+ err := p.cmd.Process.Kill()
if _, werr := p.wait(); err == nil {
err = werr
}
@@ -53,10 +51,13 @@ func (p *restoredProcess) terminate() error {
func (p *restoredProcess) wait() (*os.ProcessState, error) {
// TODO: how do we wait on the actual process?
// maybe use --exec-cmd in criu
- st, err := p.proc.Wait()
+ err := p.cmd.Wait()
if err != nil {
- return nil, err
+ if _, ok := err.(*exec.ExitError); !ok {
+ return nil, err
+ }
}
+ st := p.cmd.ProcessState
return st, nil
}
@@ -65,7 +66,7 @@ func (p *restoredProcess) startTime() (uint64, error) {
}
func (p *restoredProcess) signal(s os.Signal) error {
- return p.proc.Signal(s)
+ return p.cmd.Process.Signal(s)
}
func (p *restoredProcess) externalDescriptors() []string {
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go
index 106c4c2b9..e00df0a2c 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go
@@ -14,12 +14,13 @@ import (
"time"
securejoin "github.com/cyphar/filepath-securejoin"
+ "github.com/moby/sys/mountinfo"
"github.com/mrunalp/fileutils"
"github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/configs"
- "github.com/opencontainers/runc/libcontainer/mount"
"github.com/opencontainers/runc/libcontainer/system"
libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils"
+ "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/selinux/go-selinux/label"
"golang.org/x/sys/unix"
@@ -55,7 +56,7 @@ func prepareRootfs(pipe io.ReadWriter, iConfig *initConfig) (err error) {
}
}
if err := mountToRootfs(m, config.Rootfs, config.MountLabel, hasCgroupns); err != nil {
- return newSystemErrorWithCausef(err, "mounting %q to rootfs %q at %q", m.Source, config.Rootfs, m.Destination)
+ return newSystemErrorWithCausef(err, "mounting %q to rootfs at %q", m.Source, m.Destination)
}
for _, postcmd := range m.PostmountCmds {
@@ -98,12 +99,19 @@ func prepareRootfs(pipe io.ReadWriter, iConfig *initConfig) (err error) {
return newSystemErrorWithCausef(err, "changing dir to %q", config.Rootfs)
}
+ s := iConfig.SpecState
+ s.Pid = unix.Getpid()
+ s.Status = specs.StateCreating
+ if err := iConfig.Config.Hooks[configs.CreateContainer].RunHooks(s); err != nil {
+ return err
+ }
+
if config.NoPivotRoot {
err = msMoveRoot(config.Rootfs)
} else if config.Namespaces.Contains(configs.NEWNS) {
err = pivotRoot(config.Rootfs)
} else {
- err = chroot(config.Rootfs)
+ err = chroot()
}
if err != nil {
return newSystemErrorWithCause(err, "jailing process inside rootfs")
@@ -244,7 +252,7 @@ func mountCgroupV1(m *configs.Mount, rootfs, mountLabel string, enableCgroupns b
}
cgroupmount := &configs.Mount{
Source: "cgroup",
- Device: "cgroup",
+ Device: "cgroup", // this is actually fstype
Destination: subsystemPath,
Flags: flags,
Data: filepath.Base(subsystemPath),
@@ -402,27 +410,9 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string, enableCgroupns b
}
case "cgroup":
if cgroups.IsCgroup2UnifiedMode() {
- if err := mountCgroupV2(m, rootfs, mountLabel, enableCgroupns); err != nil {
- return err
- }
- } else {
-
- if err := mountCgroupV1(m, rootfs, mountLabel, enableCgroupns); err != nil {
- return err
- }
- }
- if m.Flags&unix.MS_RDONLY != 0 {
- // remount cgroup root as readonly
- mcgrouproot := &configs.Mount{
- Source: m.Destination,
- Device: "bind",
- Destination: m.Destination,
- Flags: defaultMountFlags | unix.MS_RDONLY | unix.MS_BIND,
- }
- if err := remount(mcgrouproot, rootfs); err != nil {
- return err
- }
+ return mountCgroupV2(m, rootfs, mountLabel, enableCgroupns)
}
+ return mountCgroupV1(m, rootfs, mountLabel, enableCgroupns)
default:
// ensure that the destination of the mount is resolved of symlinks at mount time because
// any previous mounts can invalidate the next mount's destination.
@@ -624,11 +614,14 @@ func bindMountDeviceNode(dest string, node *configs.Device) error {
// Creates the device node in the rootfs of the container.
func createDeviceNode(rootfs string, node *configs.Device, bind bool) error {
+ if node.Path == "" {
+ // The node only exists for cgroup reasons, ignore it here.
+ return nil
+ }
dest := filepath.Join(rootfs, node.Path)
if err := os.MkdirAll(filepath.Dir(dest), 0755); err != nil {
return err
}
-
if bind {
return bindMountDeviceNode(dest, node)
}
@@ -646,61 +639,45 @@ func createDeviceNode(rootfs string, node *configs.Device, bind bool) error {
func mknodDevice(dest string, node *configs.Device) error {
fileMode := node.FileMode
switch node.Type {
- case 'c', 'u':
- fileMode |= unix.S_IFCHR
- case 'b':
+ case configs.BlockDevice:
fileMode |= unix.S_IFBLK
- case 'p':
+ case configs.CharDevice:
+ fileMode |= unix.S_IFCHR
+ case configs.FifoDevice:
fileMode |= unix.S_IFIFO
default:
return fmt.Errorf("%c is not a valid device type for device %s", node.Type, node.Path)
}
- if err := unix.Mknod(dest, uint32(fileMode), node.Mkdev()); err != nil {
+ dev, err := node.Mkdev()
+ if err != nil {
+ return err
+ }
+ if err := unix.Mknod(dest, uint32(fileMode), int(dev)); err != nil {
return err
}
return unix.Chown(dest, int(node.Uid), int(node.Gid))
}
-func getMountInfo(mountinfo []*mount.Info, dir string) *mount.Info {
- for _, m := range mountinfo {
- if m.Mountpoint == dir {
- return m
- }
- }
- return nil
-}
-
// Get the parent mount point of directory passed in as argument. Also return
// optional fields.
func getParentMount(rootfs string) (string, string, error) {
- var path string
-
- mountinfos, err := mount.GetMounts()
+ mi, err := mountinfo.GetMounts(mountinfo.ParentsFilter(rootfs))
if err != nil {
return "", "", err
}
-
- mountinfo := getMountInfo(mountinfos, rootfs)
- if mountinfo != nil {
- return rootfs, mountinfo.Optional, nil
+ if len(mi) < 1 {
+ return "", "", fmt.Errorf("could not find parent mount of %s", rootfs)
}
- path = rootfs
- for {
- path = filepath.Dir(path)
-
- mountinfo = getMountInfo(mountinfos, path)
- if mountinfo != nil {
- return path, mountinfo.Optional, nil
- }
-
- if path == "/" {
- break
+ // find the longest mount point
+ var idx, maxlen int
+ for i := range mi {
+ if len(mi[i].Mountpoint) > maxlen {
+ maxlen = len(mi[i].Mountpoint)
+ idx = i
}
}
-
- // If we are here, we did not find parent mount. Something is wrong.
- return "", "", fmt.Errorf("Could not find parent mount of %s", rootfs)
+ return mi[idx].Mountpoint, mi[idx].Optional, nil
}
// Make parent mount private if it was shared
@@ -825,25 +802,22 @@ func pivotRoot(rootfs string) error {
}
func msMoveRoot(rootfs string) error {
- mountinfos, err := mount.GetMounts()
- if err != nil {
- return err
- }
-
- absRootfs, err := filepath.Abs(rootfs)
+ mountinfos, err := mountinfo.GetMounts(func(info *mountinfo.Info) (skip, stop bool) {
+ skip = false
+ stop = false
+ // Collect every sysfs and proc file systems, except those under the container rootfs
+ if (info.Fstype != "proc" && info.Fstype != "sysfs") || strings.HasPrefix(info.Mountpoint, rootfs) {
+ skip = true
+ return
+ }
+ return
+ })
if err != nil {
return err
}
for _, info := range mountinfos {
- p, err := filepath.Abs(info.Mountpoint)
- if err != nil {
- return err
- }
- // Umount every syfs and proc file systems, except those under the container rootfs
- if (info.Fstype != "proc" && info.Fstype != "sysfs") || filepath.HasPrefix(p, absRootfs) {
- continue
- }
+ p := info.Mountpoint
// Be sure umount events are not propagated to the host.
if err := unix.Mount("", p, "", unix.MS_SLAVE|unix.MS_REC, ""); err != nil {
return err
@@ -863,10 +837,10 @@ func msMoveRoot(rootfs string) error {
if err := unix.Mount(rootfs, "/", "", unix.MS_MOVE, ""); err != nil {
return err
}
- return chroot(rootfs)
+ return chroot()
}
-func chroot(rootfs string) error {
+func chroot() error {
if err := unix.Chroot("."); err != nil {
return err
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go
index 1b7a07118..73ddf3d18 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go
@@ -4,6 +4,7 @@ package seccomp
import (
"bufio"
+ "errors"
"fmt"
"os"
"strings"
@@ -34,12 +35,12 @@ const (
// of the init until they join the namespace
func InitSeccomp(config *configs.Seccomp) error {
if config == nil {
- return fmt.Errorf("cannot initialize Seccomp - nil config passed")
+ return errors.New("cannot initialize Seccomp - nil config passed")
}
- defaultAction, err := getAction(config.DefaultAction)
+ defaultAction, err := getAction(config.DefaultAction, nil)
if err != nil {
- return fmt.Errorf("error initializing seccomp - invalid default action")
+ return errors.New("error initializing seccomp - invalid default action")
}
filter, err := libseccomp.NewFilter(defaultAction)
@@ -67,7 +68,7 @@ func InitSeccomp(config *configs.Seccomp) error {
// Add a rule for each syscall
for _, call := range config.Syscalls {
if call == nil {
- return fmt.Errorf("encountered nil syscall while initializing Seccomp")
+ return errors.New("encountered nil syscall while initializing Seccomp")
}
if err = matchCall(filter, call); err != nil {
@@ -101,22 +102,28 @@ func IsEnabled() bool {
}
// Convert Libcontainer Action to Libseccomp ScmpAction
-func getAction(act configs.Action) (libseccomp.ScmpAction, error) {
+func getAction(act configs.Action, errnoRet *uint) (libseccomp.ScmpAction, error) {
switch act {
case configs.Kill:
return actKill, nil
case configs.Errno:
+ if errnoRet != nil {
+ return libseccomp.ActErrno.SetReturnCode(int16(*errnoRet)), nil
+ }
return actErrno, nil
case configs.Trap:
return actTrap, nil
case configs.Allow:
return actAllow, nil
case configs.Trace:
+ if errnoRet != nil {
+ return libseccomp.ActTrace.SetReturnCode(int16(*errnoRet)), nil
+ }
return actTrace, nil
case configs.Log:
return actLog, nil
default:
- return libseccomp.ActInvalid, fmt.Errorf("invalid action, cannot use in rule")
+ return libseccomp.ActInvalid, errors.New("invalid action, cannot use in rule")
}
}
@@ -138,7 +145,7 @@ func getOperator(op configs.Operator) (libseccomp.ScmpCompareOp, error) {
case configs.MaskEqualTo:
return libseccomp.CompareMaskedEqual, nil
default:
- return libseccomp.CompareInvalid, fmt.Errorf("invalid operator, cannot use in rule")
+ return libseccomp.CompareInvalid, errors.New("invalid operator, cannot use in rule")
}
}
@@ -147,7 +154,7 @@ func getCondition(arg *configs.Arg) (libseccomp.ScmpCondition, error) {
cond := libseccomp.ScmpCondition{}
if arg == nil {
- return cond, fmt.Errorf("cannot convert nil to syscall condition")
+ return cond, errors.New("cannot convert nil to syscall condition")
}
op, err := getOperator(arg.Op)
@@ -161,11 +168,11 @@ func getCondition(arg *configs.Arg) (libseccomp.ScmpCondition, error) {
// Add a rule to match a single syscall
func matchCall(filter *libseccomp.ScmpFilter, call *configs.Syscall) error {
if call == nil || filter == nil {
- return fmt.Errorf("cannot use nil as syscall to block")
+ return errors.New("cannot use nil as syscall to block")
}
if len(call.Name) == 0 {
- return fmt.Errorf("empty string is not a valid syscall")
+ return errors.New("empty string is not a valid syscall")
}
// If we can't resolve the syscall, assume it's not supported on this kernel
@@ -176,7 +183,7 @@ func matchCall(filter *libseccomp.ScmpFilter, call *configs.Syscall) error {
}
// Convert the call's action to the libseccomp equivalent
- callAct, err := getAction(call.Action)
+ callAct, err := getAction(call.Action, call.ErrnoRet)
if err != nil {
return fmt.Errorf("action in seccomp profile is invalid: %s", err)
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/setns_init_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/setns_init_linux.go
index 888981f52..0b9cd8852 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/setns_init_linux.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/setns_init_linux.go
@@ -11,9 +11,8 @@ import (
"github.com/opencontainers/runc/libcontainer/keys"
"github.com/opencontainers/runc/libcontainer/seccomp"
"github.com/opencontainers/runc/libcontainer/system"
- "github.com/opencontainers/selinux/go-selinux/label"
+ "github.com/opencontainers/selinux/go-selinux"
"github.com/pkg/errors"
-
"golang.org/x/sys/unix"
)
@@ -34,10 +33,10 @@ func (l *linuxSetnsInit) Init() error {
defer runtime.UnlockOSThread()
if !l.config.Config.NoNewKeyring {
- if err := label.SetKeyLabel(l.config.ProcessLabel); err != nil {
+ if err := selinux.SetKeyLabel(l.config.ProcessLabel); err != nil {
return err
}
- defer label.SetKeyLabel("")
+ defer selinux.SetKeyLabel("")
// Do not inherit the parent's session keyring.
if _, err := keys.JoinSessionKeyring(l.getSessionRingName()); err != nil {
// Same justification as in standart_init_linux.go as to why we
@@ -62,10 +61,10 @@ func (l *linuxSetnsInit) Init() error {
return err
}
}
- if err := label.SetProcessLabel(l.config.ProcessLabel); err != nil {
+ if err := selinux.SetExecLabel(l.config.ProcessLabel); err != nil {
return err
}
- defer label.SetProcessLabel("")
+ defer selinux.SetExecLabel("")
// Without NoNewPrivileges seccomp is a privileged operation, so we need to
// do this before dropping capabilities; otherwise do it as late as possible
// just before execve so as few syscalls take place after it as possible.
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/specconv/example.go b/vendor/github.com/opencontainers/runc/libcontainer/specconv/example.go
new file mode 100644
index 000000000..8a201bc78
--- /dev/null
+++ b/vendor/github.com/opencontainers/runc/libcontainer/specconv/example.go
@@ -0,0 +1,230 @@
+package specconv
+
+import (
+ "os"
+ "strings"
+
+ "github.com/opencontainers/runc/libcontainer/cgroups"
+ "github.com/opencontainers/runtime-spec/specs-go"
+)
+
+// Example returns an example spec file, with many options set so a user can
+// see what a standard spec file looks like.
+func Example() *specs.Spec {
+ spec := &specs.Spec{
+ Version: specs.Version,
+ Root: &specs.Root{
+ Path: "rootfs",
+ Readonly: true,
+ },
+ Process: &specs.Process{
+ Terminal: true,
+ User: specs.User{},
+ Args: []string{
+ "sh",
+ },
+ Env: []string{
+ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
+ "TERM=xterm",
+ },
+ Cwd: "/",
+ NoNewPrivileges: true,
+ Capabilities: &specs.LinuxCapabilities{
+ Bounding: []string{
+ "CAP_AUDIT_WRITE",
+ "CAP_KILL",
+ "CAP_NET_BIND_SERVICE",
+ },
+ Permitted: []string{
+ "CAP_AUDIT_WRITE",
+ "CAP_KILL",
+ "CAP_NET_BIND_SERVICE",
+ },
+ Inheritable: []string{
+ "CAP_AUDIT_WRITE",
+ "CAP_KILL",
+ "CAP_NET_BIND_SERVICE",
+ },
+ Ambient: []string{
+ "CAP_AUDIT_WRITE",
+ "CAP_KILL",
+ "CAP_NET_BIND_SERVICE",
+ },
+ Effective: []string{
+ "CAP_AUDIT_WRITE",
+ "CAP_KILL",
+ "CAP_NET_BIND_SERVICE",
+ },
+ },
+ Rlimits: []specs.POSIXRlimit{
+ {
+ Type: "RLIMIT_NOFILE",
+ Hard: uint64(1024),
+ Soft: uint64(1024),
+ },
+ },
+ },
+ Hostname: "runc",
+ Mounts: []specs.Mount{
+ {
+ Destination: "/proc",
+ Type: "proc",
+ Source: "proc",
+ Options: nil,
+ },
+ {
+ Destination: "/dev",
+ Type: "tmpfs",
+ Source: "tmpfs",
+ Options: []string{"nosuid", "strictatime", "mode=755", "size=65536k"},
+ },
+ {
+ Destination: "/dev/pts",
+ Type: "devpts",
+ Source: "devpts",
+ Options: []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"},
+ },
+ {
+ Destination: "/dev/shm",
+ Type: "tmpfs",
+ Source: "shm",
+ Options: []string{"nosuid", "noexec", "nodev", "mode=1777", "size=65536k"},
+ },
+ {
+ Destination: "/dev/mqueue",
+ Type: "mqueue",
+ Source: "mqueue",
+ Options: []string{"nosuid", "noexec", "nodev"},
+ },
+ {
+ Destination: "/sys",
+ Type: "sysfs",
+ Source: "sysfs",
+ Options: []string{"nosuid", "noexec", "nodev", "ro"},
+ },
+ {
+ Destination: "/sys/fs/cgroup",
+ Type: "cgroup",
+ Source: "cgroup",
+ Options: []string{"nosuid", "noexec", "nodev", "relatime", "ro"},
+ },
+ },
+ Linux: &specs.Linux{
+ MaskedPaths: []string{
+ "/proc/acpi",
+ "/proc/asound",
+ "/proc/kcore",
+ "/proc/keys",
+ "/proc/latency_stats",
+ "/proc/timer_list",
+ "/proc/timer_stats",
+ "/proc/sched_debug",
+ "/sys/firmware",
+ "/proc/scsi",
+ },
+ ReadonlyPaths: []string{
+ "/proc/bus",
+ "/proc/fs",
+ "/proc/irq",
+ "/proc/sys",
+ "/proc/sysrq-trigger",
+ },
+ Resources: &specs.LinuxResources{
+ Devices: []specs.LinuxDeviceCgroup{
+ {
+ Allow: false,
+ Access: "rwm",
+ },
+ },
+ },
+ Namespaces: []specs.LinuxNamespace{
+ {
+ Type: specs.PIDNamespace,
+ },
+ {
+ Type: specs.NetworkNamespace,
+ },
+ {
+ Type: specs.IPCNamespace,
+ },
+ {
+ Type: specs.UTSNamespace,
+ },
+ {
+ Type: specs.MountNamespace,
+ },
+ },
+ },
+ }
+ if cgroups.IsCgroup2UnifiedMode() {
+ spec.Linux.Namespaces = append(spec.Linux.Namespaces, specs.LinuxNamespace{
+ Type: specs.CgroupNamespace,
+ })
+ }
+ return spec
+}
+
+// ToRootless converts the given spec file into one that should work with
+// rootless containers (euid != 0), by removing incompatible options and adding others that
+// are needed.
+func ToRootless(spec *specs.Spec) {
+ var namespaces []specs.LinuxNamespace
+
+ // Remove networkns from the spec.
+ for _, ns := range spec.Linux.Namespaces {
+ switch ns.Type {
+ case specs.NetworkNamespace, specs.UserNamespace:
+ // Do nothing.
+ default:
+ namespaces = append(namespaces, ns)
+ }
+ }
+ // Add userns to the spec.
+ namespaces = append(namespaces, specs.LinuxNamespace{
+ Type: specs.UserNamespace,
+ })
+ spec.Linux.Namespaces = namespaces
+
+ // Add mappings for the current user.
+ spec.Linux.UIDMappings = []specs.LinuxIDMapping{{
+ HostID: uint32(os.Geteuid()),
+ ContainerID: 0,
+ Size: 1,
+ }}
+ spec.Linux.GIDMappings = []specs.LinuxIDMapping{{
+ HostID: uint32(os.Getegid()),
+ ContainerID: 0,
+ Size: 1,
+ }}
+
+ // Fix up mounts.
+ var mounts []specs.Mount
+ for _, mount := range spec.Mounts {
+ // Ignore all mounts that are under /sys.
+ if strings.HasPrefix(mount.Destination, "/sys") {
+ continue
+ }
+
+ // Remove all gid= and uid= mappings.
+ var options []string
+ for _, option := range mount.Options {
+ if !strings.HasPrefix(option, "gid=") && !strings.HasPrefix(option, "uid=") {
+ options = append(options, option)
+ }
+ }
+
+ mount.Options = options
+ mounts = append(mounts, mount)
+ }
+ // Add the sysfs mount as an rbind.
+ mounts = append(mounts, specs.Mount{
+ Source: "/sys",
+ Destination: "/sys",
+ Type: "none",
+ Options: []string{"rbind", "nosuid", "noexec", "nodev", "ro"},
+ })
+ spec.Mounts = mounts
+
+ // Remove cgroup settings.
+ spec.Linux.Resources = nil
+}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/specconv/spec_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/specconv/spec_linux.go
new file mode 100644
index 000000000..6fd98f027
--- /dev/null
+++ b/vendor/github.com/opencontainers/runc/libcontainer/specconv/spec_linux.go
@@ -0,0 +1,924 @@
+// +build linux
+
+// Package specconv implements conversion of specifications to libcontainer
+// configurations
+package specconv
+
+import (
+ "errors"
+ "fmt"
+ "os"
+ "path/filepath"
+ "regexp"
+ "strings"
+ "time"
+
+ systemdDbus "github.com/coreos/go-systemd/v22/dbus"
+ dbus "github.com/godbus/dbus/v5"
+ "github.com/opencontainers/runc/libcontainer/cgroups"
+ "github.com/opencontainers/runc/libcontainer/configs"
+ "github.com/opencontainers/runc/libcontainer/seccomp"
+ libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils"
+ "github.com/opencontainers/runtime-spec/specs-go"
+
+ "golang.org/x/sys/unix"
+)
+
+const wildcard = -1
+
+var namespaceMapping = map[specs.LinuxNamespaceType]configs.NamespaceType{
+ specs.PIDNamespace: configs.NEWPID,
+ specs.NetworkNamespace: configs.NEWNET,
+ specs.MountNamespace: configs.NEWNS,
+ specs.UserNamespace: configs.NEWUSER,
+ specs.IPCNamespace: configs.NEWIPC,
+ specs.UTSNamespace: configs.NEWUTS,
+ specs.CgroupNamespace: configs.NEWCGROUP,
+}
+
+var mountPropagationMapping = map[string]int{
+ "rprivate": unix.MS_PRIVATE | unix.MS_REC,
+ "private": unix.MS_PRIVATE,
+ "rslave": unix.MS_SLAVE | unix.MS_REC,
+ "slave": unix.MS_SLAVE,
+ "rshared": unix.MS_SHARED | unix.MS_REC,
+ "shared": unix.MS_SHARED,
+ "runbindable": unix.MS_UNBINDABLE | unix.MS_REC,
+ "unbindable": unix.MS_UNBINDABLE,
+ "": 0,
+}
+
+// AllowedDevices is the set of devices which are automatically included for
+// all containers.
+//
+// XXX (cyphar)
+// This behaviour is at the very least "questionable" (if not outright
+// wrong) according to the runtime-spec.
+//
+// Yes, we have to include certain devices other than the ones the user
+// specifies, but several devices listed here are not part of the spec
+// (including "mknod for any device"?!). In addition, these rules are
+// appended to the user-provided set which means that users *cannot disable
+// this behaviour*.
+//
+// ... unfortunately I'm too scared to change this now because who knows how
+// many people depend on this (incorrect and arguably insecure) behaviour.
+var AllowedDevices = []*configs.Device{
+ // allow mknod for any device
+ {
+ DeviceRule: configs.DeviceRule{
+ Type: configs.CharDevice,
+ Major: configs.Wildcard,
+ Minor: configs.Wildcard,
+ Permissions: "m",
+ Allow: true,
+ },
+ },
+ {
+ DeviceRule: configs.DeviceRule{
+ Type: configs.BlockDevice,
+ Major: configs.Wildcard,
+ Minor: configs.Wildcard,
+ Permissions: "m",
+ Allow: true,
+ },
+ },
+ {
+ Path: "/dev/null",
+ FileMode: 0666,
+ Uid: 0,
+ Gid: 0,
+ DeviceRule: configs.DeviceRule{
+ Type: configs.CharDevice,
+ Major: 1,
+ Minor: 3,
+ Permissions: "rwm",
+ Allow: true,
+ },
+ },
+ {
+ Path: "/dev/random",
+ FileMode: 0666,
+ Uid: 0,
+ Gid: 0,
+ DeviceRule: configs.DeviceRule{
+ Type: configs.CharDevice,
+ Major: 1,
+ Minor: 8,
+ Permissions: "rwm",
+ Allow: true,
+ },
+ },
+ {
+ Path: "/dev/full",
+ FileMode: 0666,
+ Uid: 0,
+ Gid: 0,
+ DeviceRule: configs.DeviceRule{
+ Type: configs.CharDevice,
+ Major: 1,
+ Minor: 7,
+ Permissions: "rwm",
+ Allow: true,
+ },
+ },
+ {
+ Path: "/dev/tty",
+ FileMode: 0666,
+ Uid: 0,
+ Gid: 0,
+ DeviceRule: configs.DeviceRule{
+ Type: configs.CharDevice,
+ Major: 5,
+ Minor: 0,
+ Permissions: "rwm",
+ Allow: true,
+ },
+ },
+ {
+ Path: "/dev/zero",
+ FileMode: 0666,
+ Uid: 0,
+ Gid: 0,
+ DeviceRule: configs.DeviceRule{
+ Type: configs.CharDevice,
+ Major: 1,
+ Minor: 5,
+ Permissions: "rwm",
+ Allow: true,
+ },
+ },
+ {
+ Path: "/dev/urandom",
+ FileMode: 0666,
+ Uid: 0,
+ Gid: 0,
+ DeviceRule: configs.DeviceRule{
+ Type: configs.CharDevice,
+ Major: 1,
+ Minor: 9,
+ Permissions: "rwm",
+ Allow: true,
+ },
+ },
+ // /dev/pts/ - pts namespaces are "coming soon"
+ {
+ DeviceRule: configs.DeviceRule{
+ Type: configs.CharDevice,
+ Major: 136,
+ Minor: configs.Wildcard,
+ Permissions: "rwm",
+ Allow: true,
+ },
+ },
+ {
+ DeviceRule: configs.DeviceRule{
+ Type: configs.CharDevice,
+ Major: 5,
+ Minor: 2,
+ Permissions: "rwm",
+ Allow: true,
+ },
+ },
+ // tuntap
+ {
+ DeviceRule: configs.DeviceRule{
+ Type: configs.CharDevice,
+ Major: 10,
+ Minor: 200,
+ Permissions: "rwm",
+ Allow: true,
+ },
+ },
+}
+
+type CreateOpts struct {
+ CgroupName string
+ UseSystemdCgroup bool
+ NoPivotRoot bool
+ NoNewKeyring bool
+ Spec *specs.Spec
+ RootlessEUID bool
+ RootlessCgroups bool
+}
+
+// CreateLibcontainerConfig creates a new libcontainer configuration from a
+// given specification and a cgroup name
+func CreateLibcontainerConfig(opts *CreateOpts) (*configs.Config, error) {
+ // runc's cwd will always be the bundle path
+ rcwd, err := os.Getwd()
+ if err != nil {
+ return nil, err
+ }
+ cwd, err := filepath.Abs(rcwd)
+ if err != nil {
+ return nil, err
+ }
+ spec := opts.Spec
+ if spec.Root == nil {
+ return nil, fmt.Errorf("Root must be specified")
+ }
+ rootfsPath := spec.Root.Path
+ if !filepath.IsAbs(rootfsPath) {
+ rootfsPath = filepath.Join(cwd, rootfsPath)
+ }
+ labels := []string{}
+ for k, v := range spec.Annotations {
+ labels = append(labels, fmt.Sprintf("%s=%s", k, v))
+ }
+ config := &configs.Config{
+ Rootfs: rootfsPath,
+ NoPivotRoot: opts.NoPivotRoot,
+ Readonlyfs: spec.Root.Readonly,
+ Hostname: spec.Hostname,
+ Labels: append(labels, fmt.Sprintf("bundle=%s", cwd)),
+ NoNewKeyring: opts.NoNewKeyring,
+ RootlessEUID: opts.RootlessEUID,
+ RootlessCgroups: opts.RootlessCgroups,
+ }
+
+ exists := false
+ for _, m := range spec.Mounts {
+ config.Mounts = append(config.Mounts, createLibcontainerMount(cwd, m))
+ }
+ if err := createDevices(spec, config); err != nil {
+ return nil, err
+ }
+ c, err := CreateCgroupConfig(opts)
+ if err != nil {
+ return nil, err
+ }
+ config.Cgroups = c
+ // set linux-specific config
+ if spec.Linux != nil {
+ if config.RootPropagation, exists = mountPropagationMapping[spec.Linux.RootfsPropagation]; !exists {
+ return nil, fmt.Errorf("rootfsPropagation=%v is not supported", spec.Linux.RootfsPropagation)
+ }
+ if config.NoPivotRoot && (config.RootPropagation&unix.MS_PRIVATE != 0) {
+ return nil, fmt.Errorf("rootfsPropagation of [r]private is not safe without pivot_root")
+ }
+
+ for _, ns := range spec.Linux.Namespaces {
+ t, exists := namespaceMapping[ns.Type]
+ if !exists {
+ return nil, fmt.Errorf("namespace %q does not exist", ns)
+ }
+ if config.Namespaces.Contains(t) {
+ return nil, fmt.Errorf("malformed spec file: duplicated ns %q", ns)
+ }
+ config.Namespaces.Add(t, ns.Path)
+ }
+ if config.Namespaces.Contains(configs.NEWNET) && config.Namespaces.PathOf(configs.NEWNET) == "" {
+ config.Networks = []*configs.Network{
+ {
+ Type: "loopback",
+ },
+ }
+ }
+ if config.Namespaces.Contains(configs.NEWUSER) {
+ if err := setupUserNamespace(spec, config); err != nil {
+ return nil, err
+ }
+ }
+ config.MaskPaths = spec.Linux.MaskedPaths
+ config.ReadonlyPaths = spec.Linux.ReadonlyPaths
+ config.MountLabel = spec.Linux.MountLabel
+ config.Sysctl = spec.Linux.Sysctl
+ if spec.Linux.Seccomp != nil {
+ seccomp, err := SetupSeccomp(spec.Linux.Seccomp)
+ if err != nil {
+ return nil, err
+ }
+ config.Seccomp = seccomp
+ }
+ if spec.Linux.IntelRdt != nil {
+ config.IntelRdt = &configs.IntelRdt{}
+ if spec.Linux.IntelRdt.L3CacheSchema != "" {
+ config.IntelRdt.L3CacheSchema = spec.Linux.IntelRdt.L3CacheSchema
+ }
+ if spec.Linux.IntelRdt.MemBwSchema != "" {
+ config.IntelRdt.MemBwSchema = spec.Linux.IntelRdt.MemBwSchema
+ }
+ }
+ }
+ if spec.Process != nil {
+ config.OomScoreAdj = spec.Process.OOMScoreAdj
+ config.NoNewPrivileges = spec.Process.NoNewPrivileges
+ if spec.Process.SelinuxLabel != "" {
+ config.ProcessLabel = spec.Process.SelinuxLabel
+ }
+ if spec.Process.Capabilities != nil {
+ config.Capabilities = &configs.Capabilities{
+ Bounding: spec.Process.Capabilities.Bounding,
+ Effective: spec.Process.Capabilities.Effective,
+ Permitted: spec.Process.Capabilities.Permitted,
+ Inheritable: spec.Process.Capabilities.Inheritable,
+ Ambient: spec.Process.Capabilities.Ambient,
+ }
+ }
+ }
+ createHooks(spec, config)
+ config.Version = specs.Version
+ return config, nil
+}
+
+func createLibcontainerMount(cwd string, m specs.Mount) *configs.Mount {
+ flags, pgflags, data, ext := parseMountOptions(m.Options)
+ source := m.Source
+ device := m.Type
+ if flags&unix.MS_BIND != 0 {
+ // Any "type" the user specified is meaningless (and ignored) for
+ // bind-mounts -- so we set it to "bind" because rootfs_linux.go
+ // (incorrectly) relies on this for some checks.
+ device = "bind"
+ if !filepath.IsAbs(source) {
+ source = filepath.Join(cwd, m.Source)
+ }
+ }
+ return &configs.Mount{
+ Device: device,
+ Source: source,
+ Destination: m.Destination,
+ Data: data,
+ Flags: flags,
+ PropagationFlags: pgflags,
+ Extensions: ext,
+ }
+}
+
+// systemd property name check: latin letters only, at least 3 of them
+var isValidName = regexp.MustCompile(`^[a-zA-Z]{3,}$`).MatchString
+
+var isSecSuffix = regexp.MustCompile(`[a-z]Sec$`).MatchString
+
+// Some systemd properties are documented as having "Sec" suffix
+// (e.g. TimeoutStopSec) but are expected to have "USec" suffix
+// here, so let's provide conversion to improve compatibility.
+func convertSecToUSec(value dbus.Variant) (dbus.Variant, error) {
+ var sec uint64
+ const M = 1000000
+ vi := value.Value()
+ switch value.Signature().String() {
+ case "y":
+ sec = uint64(vi.(byte)) * M
+ case "n":
+ sec = uint64(vi.(int16)) * M
+ case "q":
+ sec = uint64(vi.(uint16)) * M
+ case "i":
+ sec = uint64(vi.(int32)) * M
+ case "u":
+ sec = uint64(vi.(uint32)) * M
+ case "x":
+ sec = uint64(vi.(int64)) * M
+ case "t":
+ sec = vi.(uint64) * M
+ case "d":
+ sec = uint64(vi.(float64) * M)
+ default:
+ return value, errors.New("not a number")
+ }
+ return dbus.MakeVariant(sec), nil
+}
+
+func initSystemdProps(spec *specs.Spec) ([]systemdDbus.Property, error) {
+ const keyPrefix = "org.systemd.property."
+ var sp []systemdDbus.Property
+
+ for k, v := range spec.Annotations {
+ name := strings.TrimPrefix(k, keyPrefix)
+ if len(name) == len(k) { // prefix not there
+ continue
+ }
+ if !isValidName(name) {
+ return nil, fmt.Errorf("Annotation %s name incorrect: %s", k, name)
+ }
+ value, err := dbus.ParseVariant(v, dbus.Signature{})
+ if err != nil {
+ return nil, fmt.Errorf("Annotation %s=%s value parse error: %v", k, v, err)
+ }
+ if isSecSuffix(name) {
+ name = strings.TrimSuffix(name, "Sec") + "USec"
+ value, err = convertSecToUSec(value)
+ if err != nil {
+ return nil, fmt.Errorf("Annotation %s=%s value parse error: %v", k, v, err)
+ }
+ }
+ sp = append(sp, systemdDbus.Property{Name: name, Value: value})
+ }
+
+ return sp, nil
+}
+
+func CreateCgroupConfig(opts *CreateOpts) (*configs.Cgroup, error) {
+ var (
+ myCgroupPath string
+
+ spec = opts.Spec
+ useSystemdCgroup = opts.UseSystemdCgroup
+ name = opts.CgroupName
+ )
+
+ c := &configs.Cgroup{
+ Resources: &configs.Resources{},
+ }
+
+ if useSystemdCgroup {
+ sp, err := initSystemdProps(spec)
+ if err != nil {
+ return nil, err
+ }
+ c.SystemdProps = sp
+ }
+
+ if spec.Linux != nil && spec.Linux.CgroupsPath != "" {
+ myCgroupPath = libcontainerUtils.CleanPath(spec.Linux.CgroupsPath)
+ if useSystemdCgroup {
+ myCgroupPath = spec.Linux.CgroupsPath
+ }
+ }
+
+ if useSystemdCgroup {
+ if myCgroupPath == "" {
+ c.Parent = "system.slice"
+ c.ScopePrefix = "runc"
+ c.Name = name
+ } else {
+ // Parse the path from expected "slice:prefix:name"
+ // for e.g. "system.slice:docker:1234"
+ parts := strings.Split(myCgroupPath, ":")
+ if len(parts) != 3 {
+ return nil, fmt.Errorf("expected cgroupsPath to be of format \"slice:prefix:name\" for systemd cgroups, got %q instead", myCgroupPath)
+ }
+ c.Parent = parts[0]
+ c.ScopePrefix = parts[1]
+ c.Name = parts[2]
+ }
+ } else {
+ if myCgroupPath == "" {
+ c.Name = name
+ }
+ c.Path = myCgroupPath
+ }
+
+ // In rootless containers, any attempt to make cgroup changes is likely to fail.
+ // libcontainer will validate this but ignores the error.
+ if spec.Linux != nil {
+ r := spec.Linux.Resources
+ if r != nil {
+ for i, d := range spec.Linux.Resources.Devices {
+ var (
+ t = "a"
+ major = int64(-1)
+ minor = int64(-1)
+ )
+ if d.Type != "" {
+ t = d.Type
+ }
+ if d.Major != nil {
+ major = *d.Major
+ }
+ if d.Minor != nil {
+ minor = *d.Minor
+ }
+ if d.Access == "" {
+ return nil, fmt.Errorf("device access at %d field cannot be empty", i)
+ }
+ dt, err := stringToCgroupDeviceRune(t)
+ if err != nil {
+ return nil, err
+ }
+ c.Resources.Devices = append(c.Resources.Devices, &configs.DeviceRule{
+ Type: dt,
+ Major: major,
+ Minor: minor,
+ Permissions: configs.DevicePermissions(d.Access),
+ Allow: d.Allow,
+ })
+ }
+ if r.Memory != nil {
+ if r.Memory.Limit != nil {
+ c.Resources.Memory = *r.Memory.Limit
+ }
+ if r.Memory.Reservation != nil {
+ c.Resources.MemoryReservation = *r.Memory.Reservation
+ }
+ if r.Memory.Swap != nil {
+ c.Resources.MemorySwap = *r.Memory.Swap
+ }
+ if r.Memory.Kernel != nil {
+ c.Resources.KernelMemory = *r.Memory.Kernel
+ }
+ if r.Memory.KernelTCP != nil {
+ c.Resources.KernelMemoryTCP = *r.Memory.KernelTCP
+ }
+ if r.Memory.Swappiness != nil {
+ c.Resources.MemorySwappiness = r.Memory.Swappiness
+ }
+ if r.Memory.DisableOOMKiller != nil {
+ c.Resources.OomKillDisable = *r.Memory.DisableOOMKiller
+ }
+ }
+ if r.CPU != nil {
+ if r.CPU.Shares != nil {
+ c.Resources.CpuShares = *r.CPU.Shares
+
+ //CpuWeight is used for cgroupv2 and should be converted
+ c.Resources.CpuWeight = cgroups.ConvertCPUSharesToCgroupV2Value(c.Resources.CpuShares)
+ }
+ if r.CPU.Quota != nil {
+ c.Resources.CpuQuota = *r.CPU.Quota
+ }
+ if r.CPU.Period != nil {
+ c.Resources.CpuPeriod = *r.CPU.Period
+ }
+ if r.CPU.RealtimeRuntime != nil {
+ c.Resources.CpuRtRuntime = *r.CPU.RealtimeRuntime
+ }
+ if r.CPU.RealtimePeriod != nil {
+ c.Resources.CpuRtPeriod = *r.CPU.RealtimePeriod
+ }
+ if r.CPU.Cpus != "" {
+ c.Resources.CpusetCpus = r.CPU.Cpus
+ }
+ if r.CPU.Mems != "" {
+ c.Resources.CpusetMems = r.CPU.Mems
+ }
+ }
+ if r.Pids != nil {
+ c.Resources.PidsLimit = r.Pids.Limit
+ }
+ if r.BlockIO != nil {
+ if r.BlockIO.Weight != nil {
+ c.Resources.BlkioWeight = *r.BlockIO.Weight
+ }
+ if r.BlockIO.LeafWeight != nil {
+ c.Resources.BlkioLeafWeight = *r.BlockIO.LeafWeight
+ }
+ if r.BlockIO.WeightDevice != nil {
+ for _, wd := range r.BlockIO.WeightDevice {
+ var weight, leafWeight uint16
+ if wd.Weight != nil {
+ weight = *wd.Weight
+ }
+ if wd.LeafWeight != nil {
+ leafWeight = *wd.LeafWeight
+ }
+ weightDevice := configs.NewWeightDevice(wd.Major, wd.Minor, weight, leafWeight)
+ c.Resources.BlkioWeightDevice = append(c.Resources.BlkioWeightDevice, weightDevice)
+ }
+ }
+ if r.BlockIO.ThrottleReadBpsDevice != nil {
+ for _, td := range r.BlockIO.ThrottleReadBpsDevice {
+ rate := td.Rate
+ throttleDevice := configs.NewThrottleDevice(td.Major, td.Minor, rate)
+ c.Resources.BlkioThrottleReadBpsDevice = append(c.Resources.BlkioThrottleReadBpsDevice, throttleDevice)
+ }
+ }
+ if r.BlockIO.ThrottleWriteBpsDevice != nil {
+ for _, td := range r.BlockIO.ThrottleWriteBpsDevice {
+ rate := td.Rate
+ throttleDevice := configs.NewThrottleDevice(td.Major, td.Minor, rate)
+ c.Resources.BlkioThrottleWriteBpsDevice = append(c.Resources.BlkioThrottleWriteBpsDevice, throttleDevice)
+ }
+ }
+ if r.BlockIO.ThrottleReadIOPSDevice != nil {
+ for _, td := range r.BlockIO.ThrottleReadIOPSDevice {
+ rate := td.Rate
+ throttleDevice := configs.NewThrottleDevice(td.Major, td.Minor, rate)
+ c.Resources.BlkioThrottleReadIOPSDevice = append(c.Resources.BlkioThrottleReadIOPSDevice, throttleDevice)
+ }
+ }
+ if r.BlockIO.ThrottleWriteIOPSDevice != nil {
+ for _, td := range r.BlockIO.ThrottleWriteIOPSDevice {
+ rate := td.Rate
+ throttleDevice := configs.NewThrottleDevice(td.Major, td.Minor, rate)
+ c.Resources.BlkioThrottleWriteIOPSDevice = append(c.Resources.BlkioThrottleWriteIOPSDevice, throttleDevice)
+ }
+ }
+ }
+ for _, l := range r.HugepageLimits {
+ c.Resources.HugetlbLimit = append(c.Resources.HugetlbLimit, &configs.HugepageLimit{
+ Pagesize: l.Pagesize,
+ Limit: l.Limit,
+ })
+ }
+ if r.Network != nil {
+ if r.Network.ClassID != nil {
+ c.Resources.NetClsClassid = *r.Network.ClassID
+ }
+ for _, m := range r.Network.Priorities {
+ c.Resources.NetPrioIfpriomap = append(c.Resources.NetPrioIfpriomap, &configs.IfPrioMap{
+ Interface: m.Name,
+ Priority: int64(m.Priority),
+ })
+ }
+ }
+ }
+ }
+ // Append the default allowed devices to the end of the list.
+ // XXX: Really this should be prefixed...
+ for _, device := range AllowedDevices {
+ c.Resources.Devices = append(c.Resources.Devices, &device.DeviceRule)
+ }
+ return c, nil
+}
+
+func stringToCgroupDeviceRune(s string) (configs.DeviceType, error) {
+ switch s {
+ case "a":
+ return configs.WildcardDevice, nil
+ case "b":
+ return configs.BlockDevice, nil
+ case "c":
+ return configs.CharDevice, nil
+ default:
+ return 0, fmt.Errorf("invalid cgroup device type %q", s)
+ }
+}
+
+func stringToDeviceRune(s string) (configs.DeviceType, error) {
+ switch s {
+ case "p":
+ return configs.FifoDevice, nil
+ case "u", "c":
+ return configs.CharDevice, nil
+ case "b":
+ return configs.BlockDevice, nil
+ default:
+ return 0, fmt.Errorf("invalid device type %q", s)
+ }
+}
+
+func createDevices(spec *specs.Spec, config *configs.Config) error {
+ // Add default set of devices.
+ for _, device := range AllowedDevices {
+ if device.Path != "" {
+ config.Devices = append(config.Devices, device)
+ }
+ }
+ // Merge in additional devices from the spec.
+ if spec.Linux != nil {
+ for _, d := range spec.Linux.Devices {
+ var uid, gid uint32
+ var filemode os.FileMode = 0666
+
+ if d.UID != nil {
+ uid = *d.UID
+ }
+ if d.GID != nil {
+ gid = *d.GID
+ }
+ dt, err := stringToDeviceRune(d.Type)
+ if err != nil {
+ return err
+ }
+ if d.FileMode != nil {
+ filemode = *d.FileMode
+ }
+ device := &configs.Device{
+ DeviceRule: configs.DeviceRule{
+ Type: dt,
+ Major: d.Major,
+ Minor: d.Minor,
+ },
+ Path: d.Path,
+ FileMode: filemode,
+ Uid: uid,
+ Gid: gid,
+ }
+ config.Devices = append(config.Devices, device)
+ }
+ }
+ return nil
+}
+
+func setupUserNamespace(spec *specs.Spec, config *configs.Config) error {
+ create := func(m specs.LinuxIDMapping) configs.IDMap {
+ return configs.IDMap{
+ HostID: int(m.HostID),
+ ContainerID: int(m.ContainerID),
+ Size: int(m.Size),
+ }
+ }
+ if spec.Linux != nil {
+ for _, m := range spec.Linux.UIDMappings {
+ config.UidMappings = append(config.UidMappings, create(m))
+ }
+ for _, m := range spec.Linux.GIDMappings {
+ config.GidMappings = append(config.GidMappings, create(m))
+ }
+ }
+ rootUID, err := config.HostRootUID()
+ if err != nil {
+ return err
+ }
+ rootGID, err := config.HostRootGID()
+ if err != nil {
+ return err
+ }
+ for _, node := range config.Devices {
+ node.Uid = uint32(rootUID)
+ node.Gid = uint32(rootGID)
+ }
+ return nil
+}
+
+// parseMountOptions parses the string and returns the flags, propagation
+// flags and any mount data that it contains.
+func parseMountOptions(options []string) (int, []int, string, int) {
+ var (
+ flag int
+ pgflag []int
+ data []string
+ extFlags int
+ )
+ flags := map[string]struct {
+ clear bool
+ flag int
+ }{
+ "acl": {false, unix.MS_POSIXACL},
+ "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},
+ "iversion": {false, unix.MS_I_VERSION},
+ "lazytime": {false, unix.MS_LAZYTIME},
+ "loud": {true, unix.MS_SILENT},
+ "mand": {false, unix.MS_MANDLOCK},
+ "noacl": {true, unix.MS_POSIXACL},
+ "noatime": {false, unix.MS_NOATIME},
+ "nodev": {false, unix.MS_NODEV},
+ "nodiratime": {false, unix.MS_NODIRATIME},
+ "noexec": {false, unix.MS_NOEXEC},
+ "noiversion": {true, unix.MS_I_VERSION},
+ "nolazytime": {true, unix.MS_LAZYTIME},
+ "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},
+ "silent": {false, unix.MS_SILENT},
+ "strictatime": {false, unix.MS_STRICTATIME},
+ "suid": {true, unix.MS_NOSUID},
+ "sync": {false, unix.MS_SYNCHRONOUS},
+ }
+ propagationFlags := map[string]int{
+ "private": unix.MS_PRIVATE,
+ "shared": unix.MS_SHARED,
+ "slave": unix.MS_SLAVE,
+ "unbindable": unix.MS_UNBINDABLE,
+ "rprivate": unix.MS_PRIVATE | unix.MS_REC,
+ "rshared": unix.MS_SHARED | unix.MS_REC,
+ "rslave": unix.MS_SLAVE | unix.MS_REC,
+ "runbindable": unix.MS_UNBINDABLE | unix.MS_REC,
+ }
+ extensionFlags := map[string]struct {
+ clear bool
+ flag int
+ }{
+ "tmpcopyup": {false, configs.EXT_COPYUP},
+ }
+ 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 if f, exists := propagationFlags[o]; exists && f != 0 {
+ pgflag = append(pgflag, f)
+ } else if f, exists := extensionFlags[o]; exists && f.flag != 0 {
+ if f.clear {
+ extFlags &= ^f.flag
+ } else {
+ extFlags |= f.flag
+ }
+ } else {
+ data = append(data, o)
+ }
+ }
+ return flag, pgflag, strings.Join(data, ","), extFlags
+}
+
+func SetupSeccomp(config *specs.LinuxSeccomp) (*configs.Seccomp, error) {
+ if config == nil {
+ return nil, nil
+ }
+
+ // No default action specified, no syscalls listed, assume seccomp disabled
+ if config.DefaultAction == "" && len(config.Syscalls) == 0 {
+ return nil, nil
+ }
+
+ newConfig := new(configs.Seccomp)
+ newConfig.Syscalls = []*configs.Syscall{}
+
+ if len(config.Architectures) > 0 {
+ newConfig.Architectures = []string{}
+ for _, arch := range config.Architectures {
+ newArch, err := seccomp.ConvertStringToArch(string(arch))
+ if err != nil {
+ return nil, err
+ }
+ newConfig.Architectures = append(newConfig.Architectures, newArch)
+ }
+ }
+
+ // Convert default action from string representation
+ newDefaultAction, err := seccomp.ConvertStringToAction(string(config.DefaultAction))
+ if err != nil {
+ return nil, err
+ }
+ newConfig.DefaultAction = newDefaultAction
+
+ // Loop through all syscall blocks and convert them to libcontainer format
+ for _, call := range config.Syscalls {
+ newAction, err := seccomp.ConvertStringToAction(string(call.Action))
+ if err != nil {
+ return nil, err
+ }
+
+ for _, name := range call.Names {
+ newCall := configs.Syscall{
+ Name: name,
+ Action: newAction,
+ ErrnoRet: call.ErrnoRet,
+ Args: []*configs.Arg{},
+ }
+ // Loop through all the arguments of the syscall and convert them
+ for _, arg := range call.Args {
+ newOp, err := seccomp.ConvertStringToOperator(string(arg.Op))
+ if err != nil {
+ return nil, err
+ }
+
+ newArg := configs.Arg{
+ Index: arg.Index,
+ Value: arg.Value,
+ ValueTwo: arg.ValueTwo,
+ Op: newOp,
+ }
+
+ newCall.Args = append(newCall.Args, &newArg)
+ }
+ newConfig.Syscalls = append(newConfig.Syscalls, &newCall)
+ }
+ }
+
+ return newConfig, nil
+}
+
+func createHooks(rspec *specs.Spec, config *configs.Config) {
+ config.Hooks = configs.Hooks{}
+ if rspec.Hooks != nil {
+ for _, h := range rspec.Hooks.Prestart {
+ cmd := createCommandHook(h)
+ config.Hooks[configs.Prestart] = append(config.Hooks[configs.Prestart], configs.NewCommandHook(cmd))
+ }
+ for _, h := range rspec.Hooks.CreateRuntime {
+ cmd := createCommandHook(h)
+ config.Hooks[configs.CreateRuntime] = append(config.Hooks[configs.CreateRuntime], configs.NewCommandHook(cmd))
+ }
+ for _, h := range rspec.Hooks.CreateContainer {
+ cmd := createCommandHook(h)
+ config.Hooks[configs.CreateContainer] = append(config.Hooks[configs.CreateContainer], configs.NewCommandHook(cmd))
+ }
+ for _, h := range rspec.Hooks.StartContainer {
+ cmd := createCommandHook(h)
+ config.Hooks[configs.StartContainer] = append(config.Hooks[configs.StartContainer], configs.NewCommandHook(cmd))
+ }
+ for _, h := range rspec.Hooks.Poststart {
+ cmd := createCommandHook(h)
+ config.Hooks[configs.Poststart] = append(config.Hooks[configs.Poststart], configs.NewCommandHook(cmd))
+ }
+ for _, h := range rspec.Hooks.Poststop {
+ cmd := createCommandHook(h)
+ config.Hooks[configs.Poststop] = append(config.Hooks[configs.Poststop], configs.NewCommandHook(cmd))
+ }
+ }
+}
+
+func createCommandHook(h specs.Hook) configs.Command {
+ cmd := configs.Command{
+ Path: h.Path,
+ Args: h.Args,
+ Env: h.Env,
+ }
+ if h.Timeout != nil {
+ d := time.Duration(*h.Timeout) * time.Second
+ cmd.Timeout = &d
+ }
+ return cmd
+}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/standard_init_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/standard_init_linux.go
index 4e03b8bc0..b20ce1485 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/standard_init_linux.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/standard_init_linux.go
@@ -7,16 +7,15 @@ import (
"os"
"os/exec"
"runtime"
- "syscall" //only for Exec
"github.com/opencontainers/runc/libcontainer/apparmor"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runc/libcontainer/keys"
"github.com/opencontainers/runc/libcontainer/seccomp"
"github.com/opencontainers/runc/libcontainer/system"
- "github.com/opencontainers/selinux/go-selinux/label"
+ "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/opencontainers/selinux/go-selinux"
"github.com/pkg/errors"
-
"golang.org/x/sys/unix"
)
@@ -48,10 +47,10 @@ func (l *linuxStandardInit) Init() error {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
if !l.config.Config.NoNewKeyring {
- if err := label.SetKeyLabel(l.config.ProcessLabel); err != nil {
+ if err := selinux.SetKeyLabel(l.config.ProcessLabel); err != nil {
return err
}
- defer label.SetKeyLabel("")
+ defer selinux.SetKeyLabel("")
ringname, keepperms, newperms := l.getSessionRingParams()
// Do not inherit the parent's session keyring.
@@ -84,7 +83,8 @@ func (l *linuxStandardInit) Init() error {
return err
}
- label.Init()
+ // initialises the labeling system
+ selinux.GetEnabled()
if err := prepareRootfs(l.pipe, l.config); err != nil {
return err
}
@@ -146,10 +146,10 @@ func (l *linuxStandardInit) Init() error {
if err := syncParentReady(l.pipe); err != nil {
return errors.Wrap(err, "sync ready")
}
- if err := label.SetProcessLabel(l.config.ProcessLabel); err != nil {
+ if err := selinux.SetExecLabel(l.config.ProcessLabel); err != nil {
return errors.Wrap(err, "set process label")
}
- defer label.SetProcessLabel("")
+ defer selinux.SetExecLabel("")
// Without NoNewPrivileges seccomp is a privileged operation, so we need to
// do this before dropping capabilities; otherwise do it as late as possible
// just before execve so as few syscalls take place after it as possible.
@@ -207,7 +207,15 @@ func (l *linuxStandardInit) Init() error {
return newSystemErrorWithCause(err, "init seccomp")
}
}
- if err := syscall.Exec(name, l.config.Args[0:], os.Environ()); err != nil {
+
+ s := l.config.SpecState
+ s.Pid = unix.Getpid()
+ s.Status = specs.StateCreated
+ if err := l.config.Config.Hooks[configs.StartContainer].RunHooks(s); err != nil {
+ return err
+ }
+
+ if err := unix.Exec(name, l.config.Args[0:], os.Environ()); err != nil {
return newSystemErrorWithCause(err, "exec user process")
}
return nil
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/state_linux.go b/vendor/github.com/opencontainers/runc/libcontainer/state_linux.go
index 5c16a423f..0deb22d1f 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/state_linux.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/state_linux.go
@@ -8,7 +8,7 @@ import (
"path/filepath"
"github.com/opencontainers/runc/libcontainer/configs"
-
+ "github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
@@ -61,17 +61,21 @@ func destroy(c *linuxContainer) error {
}
func runPoststopHooks(c *linuxContainer) error {
- if c.config.Hooks != nil {
- s, err := c.currentOCIState()
- if err != nil {
- return err
- }
- for _, hook := range c.config.Hooks.Poststop {
- if err := hook.Run(s); err != nil {
- return err
- }
- }
+ hooks := c.config.Hooks
+ if hooks == nil {
+ return nil
}
+
+ s, err := c.currentOCIState()
+ if err != nil {
+ return err
+ }
+ s.Status = specs.StateStopped
+
+ if err := hooks[configs.Poststop].RunHooks(s); err != nil {
+ return err
+ }
+
return nil
}
@@ -111,11 +115,7 @@ func (r *runningState) status() Status {
func (r *runningState) transition(s containerState) error {
switch s.(type) {
case *stoppedState:
- t, err := r.c.runType()
- if err != nil {
- return err
- }
- if t == Running {
+ if r.c.runType() == Running {
return newGenericError(fmt.Errorf("container still running"), ContainerNotStopped)
}
r.c.state = s
@@ -130,11 +130,7 @@ func (r *runningState) transition(s containerState) error {
}
func (r *runningState) destroy() error {
- t, err := r.c.runType()
- if err != nil {
- return err
- }
- if t == Running {
+ if r.c.runType() == Running {
return newGenericError(fmt.Errorf("container is not destroyed"), ContainerNotStopped)
}
return destroy(r.c)
@@ -186,10 +182,7 @@ func (p *pausedState) transition(s containerState) error {
}
func (p *pausedState) destroy() error {
- t, err := p.c.runType()
- if err != nil {
- return err
- }
+ t := p.c.runType()
if t != Running && t != Created {
if err := p.c.cgroupManager.Freeze(configs.Thawed); err != nil {
return err
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/sync.go b/vendor/github.com/opencontainers/runc/libcontainer/sync.go
index a8704a267..ac88ad22a 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/sync.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/sync.go
@@ -2,6 +2,7 @@ package libcontainer
import (
"encoding/json"
+ "errors"
"fmt"
"io"
@@ -19,11 +20,6 @@ type syncType string
// procHooks --> [run hooks]
// <-- procResume
//
-// procConsole -->
-// <-- procConsoleReq
-// [send(fd)] --> [recv(fd)]
-// <-- procConsoleAck
-//
// procReady --> [final setup]
// <-- procRun
const (
@@ -50,22 +46,23 @@ func readSync(pipe io.Reader, expected syncType) error {
var procSync syncT
if err := json.NewDecoder(pipe).Decode(&procSync); err != nil {
if err == io.EOF {
- return fmt.Errorf("parent closed synchronisation channel")
+ return errors.New("parent closed synchronisation channel")
+ }
+ return fmt.Errorf("failed reading error from parent: %v", err)
+ }
+
+ if procSync.Type == procError {
+ var ierr genericError
+
+ if err := json.NewDecoder(pipe).Decode(&ierr); err != nil {
+ return fmt.Errorf("failed reading error from parent: %v", err)
}
- if procSync.Type == procError {
- var ierr genericError
+ return &ierr
+ }
- if err := json.NewDecoder(pipe).Decode(&ierr); err != nil {
- return fmt.Errorf("failed reading error from parent: %v", err)
- }
-
- return &ierr
- }
-
- if procSync.Type != expected {
- return fmt.Errorf("invalid synchronisation flag from parent")
- }
+ if procSync.Type != expected {
+ return errors.New("invalid synchronisation flag from parent")
}
return nil
}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/system/linux.go b/vendor/github.com/opencontainers/runc/libcontainer/system/linux.go
index a4ae8901a..49471960b 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/system/linux.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/system/linux.go
@@ -5,26 +5,13 @@ package system
import (
"os"
"os/exec"
- "syscall" // only for exec
+ "sync"
"unsafe"
"github.com/opencontainers/runc/libcontainer/user"
"golang.org/x/sys/unix"
)
-// If arg2 is nonzero, set the "child subreaper" attribute of the
-// calling process; if arg2 is zero, unset the attribute. When a
-// process is marked as a child subreaper, all of the children
-// that it creates, and their descendants, will be marked as
-// having a subreaper. In effect, a subreaper fulfills the role
-// of init(1) for its descendant processes. Upon termination of
-// a process that is orphaned (i.e., its immediate parent has
-// already terminated) and marked as having a subreaper, the
-// nearest still living ancestor subreaper will receive a SIGCHLD
-// signal and be able to wait(2) on the process to discover its
-// termination status.
-const PR_SET_CHILD_SUBREAPER = 36
-
type ParentDeathSignal int
func (p ParentDeathSignal) Restore() error {
@@ -51,7 +38,7 @@ func Execv(cmd string, args []string, env []string) error {
return err
}
- return syscall.Exec(name, args, env)
+ return unix.Exec(name, args, env)
}
func Prlimit(pid, resource int, limit unix.Rlimit) error {
@@ -100,15 +87,23 @@ func Setctty() error {
return nil
}
+var (
+ inUserNS bool
+ nsOnce sync.Once
+)
+
// RunningInUserNS detects whether we are currently running in a user namespace.
// Originally copied from github.com/lxc/lxd/shared/util.go
func RunningInUserNS() bool {
- uidmap, err := user.CurrentProcessUIDMap()
- if err != nil {
- // This kernel-provided file only exists if user namespaces are supported
- return false
- }
- return UIDMapInUserNS(uidmap)
+ nsOnce.Do(func() {
+ uidmap, err := user.CurrentProcessUIDMap()
+ if err != nil {
+ // This kernel-provided file only exists if user namespaces are supported
+ return
+ }
+ inUserNS = UIDMapInUserNS(uidmap)
+ })
+ return inUserNS
}
func UIDMapInUserNS(uidmap []user.IDMap) bool {
@@ -140,7 +135,7 @@ func GetParentNSeuid() int64 {
// SetSubreaper sets the value i as the subreaper setting for the calling process
func SetSubreaper(i int) error {
- return unix.Prctl(PR_SET_CHILD_SUBREAPER, uintptr(i), 0, 0, 0)
+ return unix.Prctl(unix.PR_SET_CHILD_SUBREAPER, uintptr(i), 0, 0, 0)
}
// GetSubreaper returns the subreaper setting for the calling process
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/system/sysconfig.go b/vendor/github.com/opencontainers/runc/libcontainer/system/sysconfig.go
deleted file mode 100644
index b8434f105..000000000
--- a/vendor/github.com/opencontainers/runc/libcontainer/system/sysconfig.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// +build cgo,linux
-
-package system
-
-/*
-#include
-*/
-import "C"
-
-func GetClockTicks() int {
- return int(C.sysconf(C._SC_CLK_TCK))
-}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/system/sysconfig_notcgo.go b/vendor/github.com/opencontainers/runc/libcontainer/system/sysconfig_notcgo.go
deleted file mode 100644
index d93b5d5fd..000000000
--- a/vendor/github.com/opencontainers/runc/libcontainer/system/sysconfig_notcgo.go
+++ /dev/null
@@ -1,15 +0,0 @@
-// +build !cgo windows
-
-package system
-
-func GetClockTicks() int {
- // TODO figure out a better alternative for platforms where we're missing cgo
- //
- // TODO Windows. This could be implemented using Win32 QueryPerformanceFrequency().
- // https://msdn.microsoft.com/en-us/library/windows/desktop/ms644905(v=vs.85).aspx
- //
- // An example of its usage can be found here.
- // https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx
-
- return 100
-}
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/user/user.go b/vendor/github.com/opencontainers/runc/libcontainer/user/user.go
index 7b912bbf8..4b89dad73 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/user/user.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/user/user.go
@@ -60,7 +60,7 @@ type Group struct {
// groupFromOS converts an os/user.(*Group) to local Group
//
-// (This does not include Pass, Shell or Gecos)
+// (This does not include Pass or List)
func groupFromOS(g *user.Group) (Group, error) {
newGroup := Group{
Name: g.Name,
@@ -162,10 +162,6 @@ func ParsePasswdFilter(r io.Reader, filter func(User) bool) ([]User, error) {
)
for s.Scan() {
- if err := s.Err(); err != nil {
- return nil, err
- }
-
line := strings.TrimSpace(s.Text())
if line == "" {
continue
@@ -183,6 +179,9 @@ func ParsePasswdFilter(r io.Reader, filter func(User) bool) ([]User, error) {
out = append(out, p)
}
}
+ if err := s.Err(); err != nil {
+ return nil, err
+ }
return out, nil
}
@@ -221,10 +220,6 @@ func ParseGroupFilter(r io.Reader, filter func(Group) bool) ([]Group, error) {
)
for s.Scan() {
- if err := s.Err(); err != nil {
- return nil, err
- }
-
text := s.Text()
if text == "" {
continue
@@ -242,6 +237,9 @@ func ParseGroupFilter(r io.Reader, filter func(Group) bool) ([]Group, error) {
out = append(out, p)
}
}
+ if err := s.Err(); err != nil {
+ return nil, err
+ }
return out, nil
}
@@ -532,10 +530,6 @@ func ParseSubIDFilter(r io.Reader, filter func(SubID) bool) ([]SubID, error) {
)
for s.Scan() {
- if err := s.Err(); err != nil {
- return nil, err
- }
-
line := strings.TrimSpace(s.Text())
if line == "" {
continue
@@ -549,6 +543,9 @@ func ParseSubIDFilter(r io.Reader, filter func(SubID) bool) ([]SubID, error) {
out = append(out, p)
}
}
+ if err := s.Err(); err != nil {
+ return nil, err
+ }
return out, nil
}
@@ -586,10 +583,6 @@ func ParseIDMapFilter(r io.Reader, filter func(IDMap) bool) ([]IDMap, error) {
)
for s.Scan() {
- if err := s.Err(); err != nil {
- return nil, err
- }
-
line := strings.TrimSpace(s.Text())
if line == "" {
continue
@@ -603,6 +596,9 @@ func ParseIDMapFilter(r io.Reader, filter func(IDMap) bool) ([]IDMap, error) {
out = append(out, p)
}
}
+ if err := s.Err(); err != nil {
+ return nil, err
+ }
return out, nil
}
diff --git a/vendor/github.com/opencontainers/runc/types/events.go b/vendor/github.com/opencontainers/runc/types/events.go
index c6f0e97a3..6f9a12f15 100644
--- a/vendor/github.com/opencontainers/runc/types/events.go
+++ b/vendor/github.com/opencontainers/runc/types/events.go
@@ -1,5 +1,7 @@
package types
+import "github.com/opencontainers/runc/libcontainer/intelrdt"
+
// Event struct for encoding the event data to json.
type Event struct {
Type string `json:"type"`
@@ -55,10 +57,12 @@ type Throttling struct {
type CpuUsage struct {
// Units: nanoseconds.
- Total uint64 `json:"total,omitempty"`
- Percpu []uint64 `json:"percpu,omitempty"`
- Kernel uint64 `json:"kernel"`
- User uint64 `json:"user"`
+ Total uint64 `json:"total,omitempty"`
+ Percpu []uint64 `json:"percpu,omitempty"`
+ PercpuKernel []uint64 `json:"percpu_kernel,omitempty"`
+ PercpuUser []uint64 `json:"percpu_user,omitempty"`
+ Kernel uint64 `json:"kernel"`
+ User uint64 `json:"user"`
}
type Cpu struct {
@@ -113,6 +117,12 @@ type IntelRdt struct {
// The memory bandwidth schema in 'container_id' group
MemBwSchema string `json:"mem_bw_schema,omitempty"`
+
+ // The memory bandwidth monitoring statistics from NUMA nodes in 'container_id' group
+ MBMStats *[]intelrdt.MBMNumaNodeStats `json:"mbm_stats,omitempty"`
+
+ // The cache monitoring technology statistics from NUMA nodes in 'container_id' group
+ CMTStats *[]intelrdt.CMTNumaNodeStats `json:"cmt_stats,omitempty"`
}
type NetworkInterface struct {
diff --git a/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go b/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
index c7c7c3d08..3dc9efd23 100644
--- a/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
+++ b/vendor/github.com/opencontainers/runtime-spec/specs-go/config.go
@@ -90,7 +90,7 @@ type User struct {
// GID is the group id.
GID uint32 `json:"gid" platform:"linux,solaris"`
// Umask is the umask for the init process.
- Umask uint32 `json:"umask,omitempty" platform:"linux,solaris"`
+ Umask *uint32 `json:"umask,omitempty" platform:"linux,solaris"`
// AdditionalGids are additional group ids set for the container's process.
AdditionalGids []uint32 `json:"additionalGids,omitempty" platform:"linux,solaris"`
// Username is the user name.
@@ -635,12 +635,13 @@ type LinuxSeccompAction string
// Define actions for Seccomp rules
const (
- ActKill LinuxSeccompAction = "SCMP_ACT_KILL"
- ActTrap LinuxSeccompAction = "SCMP_ACT_TRAP"
- ActErrno LinuxSeccompAction = "SCMP_ACT_ERRNO"
- ActTrace LinuxSeccompAction = "SCMP_ACT_TRACE"
- ActAllow LinuxSeccompAction = "SCMP_ACT_ALLOW"
- ActLog LinuxSeccompAction = "SCMP_ACT_LOG"
+ ActKill LinuxSeccompAction = "SCMP_ACT_KILL"
+ ActKillProcess LinuxSeccompAction = "SCMP_ACT_KILL_PROCESS"
+ ActTrap LinuxSeccompAction = "SCMP_ACT_TRAP"
+ ActErrno LinuxSeccompAction = "SCMP_ACT_ERRNO"
+ ActTrace LinuxSeccompAction = "SCMP_ACT_TRACE"
+ ActAllow LinuxSeccompAction = "SCMP_ACT_ALLOW"
+ ActLog LinuxSeccompAction = "SCMP_ACT_LOG"
)
// LinuxSeccompOperator used to match syscall arguments in Seccomp
@@ -667,9 +668,10 @@ type LinuxSeccompArg struct {
// LinuxSyscall is used to match a syscall in Seccomp
type LinuxSyscall struct {
- Names []string `json:"names"`
- Action LinuxSeccompAction `json:"action"`
- Args []LinuxSeccompArg `json:"args,omitempty"`
+ Names []string `json:"names"`
+ Action LinuxSeccompAction `json:"action"`
+ ErrnoRet *uint `json:"errnoRet,omitempty"`
+ Args []LinuxSeccompArg `json:"args,omitempty"`
}
// LinuxIntelRdt has container runtime resource constraints for Intel RDT
diff --git a/vendor/github.com/opencontainers/runtime-spec/specs-go/state.go b/vendor/github.com/opencontainers/runtime-spec/specs-go/state.go
index 89dce34be..e2e64c663 100644
--- a/vendor/github.com/opencontainers/runtime-spec/specs-go/state.go
+++ b/vendor/github.com/opencontainers/runtime-spec/specs-go/state.go
@@ -1,5 +1,23 @@
package specs
+// ContainerState represents the state of a container.
+type ContainerState string
+
+const (
+ // StateCreating indicates that the container is being created
+ StateCreating ContainerState = "creating"
+
+ // StateCreated indicates that the runtime has finished the create operation
+ StateCreated ContainerState = "created"
+
+ // StateRunning indicates that the container process has executed the
+ // user-specified program but has not exited
+ StateRunning ContainerState = "running"
+
+ // StateStopped indicates that the container process has exited
+ StateStopped ContainerState = "stopped"
+)
+
// State holds information about the runtime state of the container.
type State struct {
// Version is the version of the specification that is supported.
@@ -7,7 +25,7 @@ type State struct {
// ID is the container ID
ID string `json:"id"`
// Status is the runtime status of the container.
- Status string `json:"status"`
+ Status ContainerState `json:"status"`
// Pid is the process ID for the container process.
Pid int `json:"pid,omitempty"`
// Bundle is the path to the container's bundle directory.
diff --git a/vendor/github.com/opencontainers/runtime-spec/specs-go/version.go b/vendor/github.com/opencontainers/runtime-spec/specs-go/version.go
index b920fc1b3..596af0c2f 100644
--- a/vendor/github.com/opencontainers/runtime-spec/specs-go/version.go
+++ b/vendor/github.com/opencontainers/runtime-spec/specs-go/version.go
@@ -8,7 +8,7 @@ const (
// VersionMinor is for functionality in a backwards-compatible manner
VersionMinor = 0
// VersionPatch is for backwards-compatible bug fixes
- VersionPatch = 1
+ VersionPatch = 2
// VersionDev indicates development branch. Releases will be empty string.
VersionDev = "-dev"
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/doc.go b/vendor/github.com/opencontainers/selinux/go-selinux/doc.go
new file mode 100644
index 000000000..79a8e6446
--- /dev/null
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/doc.go
@@ -0,0 +1,21 @@
+/*
+Package selinux provides a high-level interface for interacting with selinux.
+
+This package uses a selinux build tag to enable the selinux functionality. This
+allows non-linux and linux users who do not have selinux support to still use
+tools that rely on this library.
+
+To compile with full selinux support use the -tags=selinux option in your build
+and test commands.
+
+Usage:
+
+ import "github.com/opencontainers/selinux/go-selinux"
+
+ // Ensure that selinux is enforcing mode.
+ if selinux.EnforceMode() != selinux.Enforcing {
+ selinux.SetEnforceMode(selinux.Enforcing)
+ }
+
+*/
+package selinux
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go b/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go
index 6e38d3d32..fea096c18 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go
@@ -1,6 +1,8 @@
package label
import (
+ "fmt"
+
"github.com/opencontainers/selinux/go-selinux"
)
@@ -46,7 +48,7 @@ var PidLabel = selinux.PidLabel
// Init initialises the labeling system
func Init() {
- selinux.GetEnabled()
+ _ = selinux.GetEnabled()
}
// ClearLabels will clear all reserved labels
@@ -75,3 +77,21 @@ func ReleaseLabel(label string) error {
// can be used to set duplicate labels on future container processes
// Deprecated: use selinux.DupSecOpt
var DupSecOpt = selinux.DupSecOpt
+
+// FormatMountLabel returns a string to be used by the mount command.
+// The format of this string will be used to alter the labeling of the mountpoint.
+// The string returned is suitable to be used as the options field of the mount command.
+// If you need to have additional mount point options, you can pass them in as
+// the first parameter. Second parameter is the label that you wish to apply
+// to all content in the mount point.
+func FormatMountLabel(src, mountLabel string) string {
+ if mountLabel != "" {
+ switch src {
+ case "":
+ src = fmt.Sprintf("context=%q", mountLabel)
+ default:
+ src = fmt.Sprintf("%s,context=%q", src, mountLabel)
+ }
+ }
+ return src
+}
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go
index 903829958..10ac15a85 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go
@@ -3,7 +3,6 @@
package label
import (
- "fmt"
"os"
"os/user"
"strings"
@@ -43,7 +42,7 @@ func InitLabels(options []string) (plabel string, mlabel string, Err error) {
if err != nil {
return "", "", err
}
-
+ mcsLevel := pcon["level"]
mcon, err := selinux.NewContext(mountLabel)
if err != nil {
return "", "", err
@@ -62,16 +61,21 @@ func InitLabels(options []string) (plabel string, mlabel string, Err error) {
}
if con[0] == "filetype" {
mcon["type"] = con[1]
+ continue
}
pcon[con[0]] = con[1]
if con[0] == "level" || con[0] == "user" {
mcon[con[0]] = con[1]
}
}
- selinux.ReleaseLabel(processLabel)
- processLabel = pcon.Get()
+ if pcon.Get() != processLabel {
+ if pcon["level"] != mcsLevel {
+ selinux.ReleaseLabel(processLabel)
+ }
+ processLabel = pcon.Get()
+ selinux.ReserveLabel(processLabel)
+ }
mountLabel = mcon.Get()
- selinux.ReserveLabel(processLabel)
}
return processLabel, mountLabel, nil
}
@@ -82,24 +86,6 @@ func GenLabels(options string) (string, string, error) {
return InitLabels(strings.Fields(options))
}
-// FormatMountLabel returns a string to be used by the mount command.
-// The format of this string will be used to alter the labeling of the mountpoint.
-// The string returned is suitable to be used as the options field of the mount command.
-// If you need to have additional mount point options, you can pass them in as
-// the first parameter. Second parameter is the label that you wish to apply
-// to all content in the mount point.
-func FormatMountLabel(src, mountLabel string) string {
- if mountLabel != "" {
- switch src {
- case "":
- src = fmt.Sprintf("context=%q", mountLabel)
- default:
- src = fmt.Sprintf("%s,context=%q", src, mountLabel)
- }
- }
- return src
-}
-
// SetFileLabel modifies the "path" label to the specified file label
func SetFileLabel(path string, fileLabel string) error {
if !selinux.GetEnabled() || fileLabel == "" {
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go
index cda59d671..a7d2d5e34 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_stub.go
@@ -15,10 +15,6 @@ func GenLabels(options string) (string, string, error) {
return "", "", nil
}
-func FormatMountLabel(src string, mountLabel string) string {
- return src
-}
-
func SetFileLabel(path string, fileLabel string) error {
return nil
}
@@ -34,7 +30,6 @@ func Relabel(path string, fileLabel string, shared bool) error {
// DisableSecOpt returns a security opt that can disable labeling
// support for future container processes
func DisableSecOpt() []string {
- // TODO the selinux.DisableSecOpt stub returns []string{"disable"} instead of "nil"
return nil
}
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go
new file mode 100644
index 000000000..50760dc93
--- /dev/null
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go
@@ -0,0 +1,249 @@
+package selinux
+
+import (
+ "github.com/pkg/errors"
+)
+
+const (
+ // Enforcing constant indicate SELinux is in enforcing mode
+ Enforcing = 1
+ // Permissive constant to indicate SELinux is in permissive mode
+ Permissive = 0
+ // Disabled constant to indicate SELinux is disabled
+ Disabled = -1
+
+ // DefaultCategoryRange is the upper bound on the category range
+ DefaultCategoryRange = uint32(1024)
+)
+
+var (
+ // ErrMCSAlreadyExists is returned when trying to allocate a duplicate MCS.
+ ErrMCSAlreadyExists = errors.New("MCS label already exists")
+ // ErrEmptyPath is returned when an empty path has been specified.
+ ErrEmptyPath = errors.New("empty path")
+
+ // InvalidLabel is returned when an invalid label is specified.
+ InvalidLabel = errors.New("Invalid Label")
+
+ // ErrIncomparable is returned two levels are not comparable
+ ErrIncomparable = errors.New("incomparable levels")
+ // ErrLevelSyntax is returned when a sensitivity or category do not have correct syntax in a level
+ ErrLevelSyntax = errors.New("invalid level syntax")
+
+ // CategoryRange allows the upper bound on the category range to be adjusted
+ CategoryRange = DefaultCategoryRange
+)
+
+// Context is a representation of the SELinux label broken into 4 parts
+type Context map[string]string
+
+// SetDisabled disables SELinux support for the package
+func SetDisabled() {
+ setDisabled()
+}
+
+// GetEnabled returns whether SELinux is currently enabled.
+func GetEnabled() bool {
+ return getEnabled()
+}
+
+// ClassIndex returns the int index for an object class in the loaded policy,
+// or -1 and an error
+func ClassIndex(class string) (int, error) {
+ return classIndex(class)
+}
+
+// SetFileLabel sets the SELinux label for this path or returns an error.
+func SetFileLabel(fpath string, label string) error {
+ return setFileLabel(fpath, label)
+}
+
+// FileLabel returns the SELinux label for this path or returns an error.
+func FileLabel(fpath string) (string, error) {
+ return fileLabel(fpath)
+}
+
+// SetFSCreateLabel tells kernel the label to create all file system objects
+// created by this task. Setting label="" to return to default.
+func SetFSCreateLabel(label string) error {
+ return setFSCreateLabel(label)
+}
+
+// FSCreateLabel returns the default label the kernel which the kernel is using
+// for file system objects created by this task. "" indicates default.
+func FSCreateLabel() (string, error) {
+ return fsCreateLabel()
+}
+
+// CurrentLabel returns the SELinux label of the current process thread, or an error.
+func CurrentLabel() (string, error) {
+ return currentLabel()
+}
+
+// PidLabel returns the SELinux label of the given pid, or an error.
+func PidLabel(pid int) (string, error) {
+ return pidLabel(pid)
+}
+
+// ExecLabel returns the SELinux label that the kernel will use for any programs
+// that are executed by the current process thread, or an error.
+func ExecLabel() (string, error) {
+ return execLabel()
+}
+
+// CanonicalizeContext takes a context string and writes it to the kernel
+// the function then returns the context that the kernel will use. Use this
+// function to check if two contexts are equivalent
+func CanonicalizeContext(val string) (string, error) {
+ return canonicalizeContext(val)
+}
+
+// ComputeCreateContext requests the type transition from source to target for
+// class from the kernel.
+func ComputeCreateContext(source string, target string, class string) (string, error) {
+ return computeCreateContext(source, target, class)
+}
+
+// CalculateGlbLub computes the glb (greatest lower bound) and lub (least upper bound)
+// of a source and target range.
+// The glblub is calculated as the greater of the low sensitivities and
+// the lower of the high sensitivities and the and of each category bitset.
+func CalculateGlbLub(sourceRange, targetRange string) (string, error) {
+ return calculateGlbLub(sourceRange, targetRange)
+}
+
+// SetExecLabel sets the SELinux label that the kernel will use for any programs
+// that are executed by the current process thread, or an error.
+func SetExecLabel(label string) error {
+ return setExecLabel(label)
+}
+
+// SetTaskLabel sets the SELinux label for the current thread, or an error.
+// This requires the dyntransition permission.
+func SetTaskLabel(label string) error {
+ return setTaskLabel(label)
+}
+
+// SetSocketLabel takes a process label and tells the kernel to assign the
+// label to the next socket that gets created
+func SetSocketLabel(label string) error {
+ return setSocketLabel(label)
+}
+
+// SocketLabel retrieves the current socket label setting
+func SocketLabel() (string, error) {
+ return socketLabel()
+}
+
+// PeerLabel retrieves the label of the client on the other side of a socket
+func PeerLabel(fd uintptr) (string, error) {
+ return peerLabel(fd)
+}
+
+// SetKeyLabel takes a process label and tells the kernel to assign the
+// label to the next kernel keyring that gets created
+func SetKeyLabel(label string) error {
+ return setKeyLabel(label)
+}
+
+// KeyLabel retrieves the current kernel keyring label setting
+func KeyLabel() (string, error) {
+ return keyLabel()
+}
+
+// Get returns the Context as a string
+func (c Context) Get() string {
+ return c.get()
+}
+
+// NewContext creates a new Context struct from the specified label
+func NewContext(label string) (Context, error) {
+ return newContext(label)
+}
+
+// ClearLabels clears all reserved labels
+func ClearLabels() {
+ clearLabels()
+}
+
+// ReserveLabel reserves the MLS/MCS level component of the specified label
+func ReserveLabel(label string) {
+ reserveLabel(label)
+}
+
+// EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled
+func EnforceMode() int {
+ return enforceMode()
+}
+
+// SetEnforceMode sets the current SELinux mode Enforcing, Permissive.
+// Disabled is not valid, since this needs to be set at boot time.
+func SetEnforceMode(mode int) error {
+ return setEnforceMode(mode)
+}
+
+// DefaultEnforceMode returns the systems default SELinux mode Enforcing,
+// Permissive or Disabled. Note this is is just the default at boot time.
+// EnforceMode tells you the systems current mode.
+func DefaultEnforceMode() int {
+ return defaultEnforceMode()
+}
+
+// ReleaseLabel un-reserves the MLS/MCS Level field of the specified label,
+// allowing it to be used by another process.
+func ReleaseLabel(label string) {
+ releaseLabel(label)
+}
+
+// ROFileLabel returns the specified SELinux readonly file label
+func ROFileLabel() string {
+ return roFileLabel()
+}
+
+// KVMContainerLabels returns the default processLabel and mountLabel to be used
+// for kvm containers by the calling process.
+func KVMContainerLabels() (string, string) {
+ return kvmContainerLabels()
+}
+
+// InitContainerLabels returns the default processLabel and file labels to be
+// used for containers running an init system like systemd by the calling process.
+func InitContainerLabels() (string, string) {
+ return initContainerLabels()
+}
+
+// ContainerLabels returns an allocated processLabel and fileLabel to be used for
+// container labeling by the calling process.
+func ContainerLabels() (processLabel string, fileLabel string) {
+ return containerLabels()
+}
+
+// SecurityCheckContext validates that the SELinux label is understood by the kernel
+func SecurityCheckContext(val string) error {
+ return securityCheckContext(val)
+}
+
+// CopyLevel returns a label with the MLS/MCS level from src label replaced on
+// the dest label.
+func CopyLevel(src, dest string) (string, error) {
+ return copyLevel(src, dest)
+}
+
+// Chcon changes the fpath file object to the SELinux label label.
+// If fpath is a directory and recurse is true, then Chcon walks the
+// directory tree setting the label.
+func Chcon(fpath string, label string, recurse bool) error {
+ return chcon(fpath, label, recurse)
+}
+
+// DupSecOpt takes an SELinux process label and returns security options that
+// can be used to set the SELinux Type and Level for future container processes.
+func DupSecOpt(src string) ([]string, error) {
+ return dupSecOpt(src)
+}
+
+// DisableSecOpt returns a security opt that can be used to disable SELinux
+// labeling support for future container processes.
+func DisableSecOpt() []string {
+ return disableSecOpt()
+}
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go
index 599bdb6e2..d6b0d49db 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go
@@ -20,17 +20,13 @@ import (
"github.com/opencontainers/selinux/pkg/pwalk"
"github.com/pkg/errors"
+ "github.com/willf/bitset"
"golang.org/x/sys/unix"
)
const (
- // Enforcing constant indicate SELinux is in enforcing mode
- Enforcing = 1
- // Permissive constant to indicate SELinux is in permissive mode
- Permissive = 0
- // Disabled constant to indicate SELinux is disabled
- Disabled = -1
-
+ minSensLen = 2
+ contextFile = "/usr/share/containers/selinux/contexts"
selinuxDir = "/etc/selinux/"
selinuxConfig = selinuxDir + "config"
selinuxfsMount = "/sys/fs/selinux"
@@ -48,17 +44,27 @@ type selinuxState struct {
sync.Mutex
}
-var (
- // ErrMCSAlreadyExists is returned when trying to allocate a duplicate MCS.
- ErrMCSAlreadyExists = errors.New("MCS label already exists")
- // ErrEmptyPath is returned when an empty path has been specified.
- ErrEmptyPath = errors.New("empty path")
- // InvalidLabel is returned when an invalid label is specified.
- InvalidLabel = errors.New("Invalid Label")
+type level struct {
+ sens uint
+ cats *bitset.BitSet
+}
- assignRegex = regexp.MustCompile(`^([^=]+)=(.*)$`)
- roFileLabel string
- state = selinuxState{
+type mlsRange struct {
+ low *level
+ high *level
+}
+
+type levelItem byte
+
+const (
+ sensitivity levelItem = 's'
+ category levelItem = 'c'
+)
+
+var (
+ assignRegex = regexp.MustCompile(`^([^=]+)=(.*)$`)
+ readOnlyFileLabel string
+ state = selinuxState{
mcsList: make(map[string]bool),
}
@@ -67,9 +73,6 @@ var (
haveThreadSelf bool
)
-// Context is a representation of the SELinux label broken into 4 parts
-type Context map[string]string
-
func (s *selinuxState) setEnable(enabled bool) bool {
s.Lock()
defer s.Unlock()
@@ -96,8 +99,8 @@ func (s *selinuxState) getEnabled() bool {
return s.setEnable(enabled)
}
-// SetDisabled disables selinux support for the package
-func SetDisabled() {
+// setDisabled disables SELinux support for the package
+func setDisabled() {
state.setEnable(false)
}
@@ -189,15 +192,15 @@ func (s *selinuxState) getSELinuxfs() string {
// getSelinuxMountPoint returns the path to the mountpoint of an selinuxfs
// filesystem or an empty string if no mountpoint is found. Selinuxfs is
-// a proc-like pseudo-filesystem that exposes the selinux policy API to
+// a proc-like pseudo-filesystem that exposes the SELinux policy API to
// processes. The existence of an selinuxfs mount is used to determine
-// whether selinux is currently enabled or not.
+// whether SELinux is currently enabled or not.
func getSelinuxMountPoint() string {
return state.getSELinuxfs()
}
-// GetEnabled returns whether selinux is currently enabled.
-func GetEnabled() bool {
+// getEnabled returns whether SELinux is currently enabled.
+func getEnabled() bool {
return state.getEnabled()
}
@@ -281,8 +284,9 @@ func readCon(fpath string) (string, error) {
return strings.Trim(retval, "\x00"), nil
}
-// ClassIndex returns the int index for an object class in the loaded policy, or -1 and an error
-func ClassIndex(class string) (int, error) {
+// classIndex returns the int index for an object class in the loaded policy,
+// or -1 and an error
+func classIndex(class string) (int, error) {
permpath := fmt.Sprintf("class/%s/index", class)
indexpath := filepath.Join(getSelinuxMountPoint(), permpath)
@@ -298,8 +302,8 @@ func ClassIndex(class string) (int, error) {
return index, nil
}
-// SetFileLabel sets the SELinux label for this path or returns an error.
-func SetFileLabel(fpath string, label string) error {
+// setFileLabel sets the SELinux label for this path or returns an error.
+func setFileLabel(fpath string, label string) error {
if fpath == "" {
return ErrEmptyPath
}
@@ -309,8 +313,8 @@ func SetFileLabel(fpath string, label string) error {
return nil
}
-// FileLabel returns the SELinux label for this path or returns an error.
-func FileLabel(fpath string) (string, error) {
+// fileLabel returns the SELinux label for this path or returns an error.
+func fileLabel(fpath string) (string, error) {
if fpath == "" {
return "", ErrEmptyPath
}
@@ -326,37 +330,31 @@ func FileLabel(fpath string) (string, error) {
return string(label), nil
}
-/*
-SetFSCreateLabel tells kernel the label to create all file system objects
-created by this task. Setting label="" to return to default.
-*/
-func SetFSCreateLabel(label string) error {
+// setFSCreateLabel tells kernel the label to create all file system objects
+// created by this task. Setting label="" to return to default.
+func setFSCreateLabel(label string) error {
return writeAttr("fscreate", label)
}
-/*
-FSCreateLabel returns the default label the kernel which the kernel is using
-for file system objects created by this task. "" indicates default.
-*/
-func FSCreateLabel() (string, error) {
+// fsCreateLabel returns the default label the kernel which the kernel is using
+// for file system objects created by this task. "" indicates default.
+func fsCreateLabel() (string, error) {
return readAttr("fscreate")
}
-// CurrentLabel returns the SELinux label of the current process thread, or an error.
-func CurrentLabel() (string, error) {
+// currentLabel returns the SELinux label of the current process thread, or an error.
+func currentLabel() (string, error) {
return readAttr("current")
}
-// PidLabel returns the SELinux label of the given pid, or an error.
-func PidLabel(pid int) (string, error) {
+// pidLabel returns the SELinux label of the given pid, or an error.
+func pidLabel(pid int) (string, error) {
return readCon(fmt.Sprintf("/proc/%d/attr/current", pid))
}
-/*
-ExecLabel returns the SELinux label that the kernel will use for any programs
-that are executed by the current process thread, or an error.
-*/
-func ExecLabel() (string, error) {
+// ExecLabel returns the SELinux label that the kernel will use for any programs
+// that are executed by the current process thread, or an error.
+func execLabel() (string, error) {
return readAttr("exec")
}
@@ -365,7 +363,7 @@ func writeCon(fpath, val string) error {
return ErrEmptyPath
}
if val == "" {
- if !GetEnabled() {
+ if !getEnabled() {
return nil
}
}
@@ -417,20 +415,17 @@ func writeAttr(attr, val string) error {
return writeCon(attrPath(attr), val)
}
-/*
-CanonicalizeContext takes a context string and writes it to the kernel
-the function then returns the context that the kernel will use. This function
-can be used to see if two contexts are equivalent
-*/
-func CanonicalizeContext(val string) (string, error) {
+// canonicalizeContext takes a context string and writes it to the kernel
+// the function then returns the context that the kernel will use. Use this
+// function to check if two contexts are equivalent
+func canonicalizeContext(val string) (string, error) {
return readWriteCon(filepath.Join(getSelinuxMountPoint(), "context"), val)
}
-/*
-ComputeCreateContext requests the type transition from source to target for class from the kernel.
-*/
-func ComputeCreateContext(source string, target string, class string) (string, error) {
- classidx, err := ClassIndex(class)
+// computeCreateContext requests the type transition from source to target for
+// class from the kernel.
+func computeCreateContext(source string, target string, class string) (string, error) {
+ classidx, err := classIndex(class)
if err != nil {
return "", err
}
@@ -438,6 +433,217 @@ func ComputeCreateContext(source string, target string, class string) (string, e
return readWriteCon(filepath.Join(getSelinuxMountPoint(), "create"), fmt.Sprintf("%s %s %d", source, target, classidx))
}
+// catsToBitset stores categories in a bitset.
+func catsToBitset(cats string) (*bitset.BitSet, error) {
+ bitset := &bitset.BitSet{}
+
+ catlist := strings.Split(cats, ",")
+ for _, r := range catlist {
+ ranges := strings.SplitN(r, ".", 2)
+ if len(ranges) > 1 {
+ catstart, err := parseLevelItem(ranges[0], category)
+ if err != nil {
+ return nil, err
+ }
+ catend, err := parseLevelItem(ranges[1], category)
+ if err != nil {
+ return nil, err
+ }
+ for i := catstart; i <= catend; i++ {
+ bitset.Set(i)
+ }
+ } else {
+ cat, err := parseLevelItem(ranges[0], category)
+ if err != nil {
+ return nil, err
+ }
+ bitset.Set(cat)
+ }
+ }
+
+ return bitset, nil
+}
+
+// parseLevelItem parses and verifies that a sensitivity or category are valid
+func parseLevelItem(s string, sep levelItem) (uint, error) {
+ if len(s) < minSensLen || levelItem(s[0]) != sep {
+ return 0, ErrLevelSyntax
+ }
+ val, err := strconv.ParseUint(s[1:], 10, 32)
+ if err != nil {
+ return 0, err
+ }
+
+ return uint(val), nil
+}
+
+// parseLevel fills a level from a string that contains
+// a sensitivity and categories
+func (l *level) parseLevel(levelStr string) error {
+ lvl := strings.SplitN(levelStr, ":", 2)
+ sens, err := parseLevelItem(lvl[0], sensitivity)
+ if err != nil {
+ return errors.Wrap(err, "failed to parse sensitivity")
+ }
+ l.sens = sens
+ if len(lvl) > 1 {
+ cats, err := catsToBitset(lvl[1])
+ if err != nil {
+ return errors.Wrap(err, "failed to parse categories")
+ }
+ l.cats = cats
+ }
+
+ return nil
+}
+
+// rangeStrToMLSRange marshals a string representation of a range.
+func rangeStrToMLSRange(rangeStr string) (*mlsRange, error) {
+ mlsRange := &mlsRange{}
+ levelSlice := strings.SplitN(rangeStr, "-", 2)
+
+ switch len(levelSlice) {
+ // rangeStr that has a low and a high level, e.g. s4:c0.c1023-s6:c0.c1023
+ case 2:
+ mlsRange.high = &level{}
+ if err := mlsRange.high.parseLevel(levelSlice[1]); err != nil {
+ return nil, errors.Wrapf(err, "failed to parse high level %q", levelSlice[1])
+ }
+ fallthrough
+ // rangeStr that is single level, e.g. s6:c0,c3,c5,c30.c1023
+ case 1:
+ mlsRange.low = &level{}
+ if err := mlsRange.low.parseLevel(levelSlice[0]); err != nil {
+ return nil, errors.Wrapf(err, "failed to parse low level %q", levelSlice[0])
+ }
+ }
+
+ if mlsRange.high == nil {
+ mlsRange.high = mlsRange.low
+ }
+
+ return mlsRange, nil
+}
+
+// bitsetToStr takes a category bitset and returns it in the
+// canonical selinux syntax
+func bitsetToStr(c *bitset.BitSet) string {
+ var str string
+ i, e := c.NextSet(0)
+ len := 0
+ for e {
+ if len == 0 {
+ if str != "" {
+ str += ","
+ }
+ str += "c" + strconv.Itoa(int(i))
+ }
+
+ next, e := c.NextSet(i + 1)
+ if e {
+ // consecutive cats
+ if next == i+1 {
+ len++
+ i = next
+ continue
+ }
+ }
+ if len == 1 {
+ str += ",c" + strconv.Itoa(int(i))
+ } else if len > 1 {
+ str += ".c" + strconv.Itoa(int(i))
+ }
+ if !e {
+ break
+ }
+ len = 0
+ i = next
+ }
+
+ return str
+}
+
+func (l1 *level) equal(l2 *level) bool {
+ if l2 == nil || l1 == nil {
+ return l1 == l2
+ }
+ if l1.sens != l2.sens {
+ return false
+ }
+ return l1.cats.Equal(l2.cats)
+}
+
+// String returns an mlsRange as a string.
+func (m mlsRange) String() string {
+ low := "s" + strconv.Itoa(int(m.low.sens))
+ if m.low.cats != nil && m.low.cats.Count() > 0 {
+ low += ":" + bitsetToStr(m.low.cats)
+ }
+
+ if m.low.equal(m.high) {
+ return low
+ }
+
+ high := "s" + strconv.Itoa(int(m.high.sens))
+ if m.high.cats != nil && m.high.cats.Count() > 0 {
+ high += ":" + bitsetToStr(m.high.cats)
+ }
+
+ return low + "-" + high
+}
+
+func max(a, b uint) uint {
+ if a > b {
+ return a
+ }
+ return b
+}
+
+func min(a, b uint) uint {
+ if a < b {
+ return a
+ }
+ return b
+}
+
+// calculateGlbLub computes the glb (greatest lower bound) and lub (least upper bound)
+// of a source and target range.
+// The glblub is calculated as the greater of the low sensitivities and
+// the lower of the high sensitivities and the and of each category bitset.
+func calculateGlbLub(sourceRange, targetRange string) (string, error) {
+ s, err := rangeStrToMLSRange(sourceRange)
+ if err != nil {
+ return "", err
+ }
+ t, err := rangeStrToMLSRange(targetRange)
+ if err != nil {
+ return "", err
+ }
+
+ if s.high.sens < t.low.sens || t.high.sens < s.low.sens {
+ /* these ranges have no common sensitivities */
+ return "", ErrIncomparable
+ }
+
+ outrange := &mlsRange{low: &level{}, high: &level{}}
+
+ /* take the greatest of the low */
+ outrange.low.sens = max(s.low.sens, t.low.sens)
+
+ /* take the least of the high */
+ outrange.high.sens = min(s.high.sens, t.high.sens)
+
+ /* find the intersecting categories */
+ if s.low.cats != nil && t.low.cats != nil {
+ outrange.low.cats = s.low.cats.Intersection(t.low.cats)
+ }
+ if s.high.cats != nil && t.high.cats != nil {
+ outrange.high.cats = s.high.cats.Intersection(t.high.cats)
+ }
+
+ return outrange.String(), nil
+}
+
func readWriteCon(fpath string, val string) (string, error) {
if fpath == "" {
return "", ErrEmptyPath
@@ -460,41 +666,37 @@ func readWriteCon(fpath string, val string) (string, error) {
return strings.Trim(retval, "\x00"), nil
}
-/*
-SetExecLabel sets the SELinux label that the kernel will use for any programs
-that are executed by the current process thread, or an error.
-*/
-func SetExecLabel(label string) error {
+// setExecLabel sets the SELinux label that the kernel will use for any programs
+// that are executed by the current process thread, or an error.
+func setExecLabel(label string) error {
return writeAttr("exec", label)
}
-/*
-SetTaskLabel sets the SELinux label for the current thread, or an error.
-This requires the dyntransition permission.
-*/
-func SetTaskLabel(label string) error {
+// setTaskLabel sets the SELinux label for the current thread, or an error.
+// This requires the dyntransition permission.
+func setTaskLabel(label string) error {
return writeAttr("current", label)
}
-// SetSocketLabel takes a process label and tells the kernel to assign the
+// setSocketLabel takes a process label and tells the kernel to assign the
// label to the next socket that gets created
-func SetSocketLabel(label string) error {
+func setSocketLabel(label string) error {
return writeAttr("sockcreate", label)
}
-// SocketLabel retrieves the current socket label setting
-func SocketLabel() (string, error) {
+// socketLabel retrieves the current socket label setting
+func socketLabel() (string, error) {
return readAttr("sockcreate")
}
-// PeerLabel retrieves the label of the client on the other side of a socket
-func PeerLabel(fd uintptr) (string, error) {
+// peerLabel retrieves the label of the client on the other side of a socket
+func peerLabel(fd uintptr) (string, error) {
return unix.GetsockoptString(int(fd), unix.SOL_SOCKET, unix.SO_PEERSEC)
}
-// SetKeyLabel takes a process label and tells the kernel to assign the
+// setKeyLabel takes a process label and tells the kernel to assign the
// label to the next kernel keyring that gets created
-func SetKeyLabel(label string) error {
+func setKeyLabel(label string) error {
err := writeCon("/proc/self/attr/keycreate", label)
if os.IsNotExist(errors.Cause(err)) {
return nil
@@ -505,21 +707,21 @@ func SetKeyLabel(label string) error {
return err
}
-// KeyLabel retrieves the current kernel keyring label setting
-func KeyLabel() (string, error) {
+// keyLabel retrieves the current kernel keyring label setting
+func keyLabel() (string, error) {
return readCon("/proc/self/attr/keycreate")
}
-// Get returns the Context as a string
-func (c Context) Get() string {
+// get returns the Context as a string
+func (c Context) get() string {
if c["level"] != "" {
return fmt.Sprintf("%s:%s:%s:%s", c["user"], c["role"], c["type"], c["level"])
}
return fmt.Sprintf("%s:%s:%s", c["user"], c["role"], c["type"])
}
-// NewContext creates a new Context struct from the specified label
-func NewContext(label string) (Context, error) {
+// newContext creates a new Context struct from the specified label
+func newContext(label string) (Context, error) {
c := make(Context)
if len(label) != 0 {
@@ -537,15 +739,15 @@ func NewContext(label string) (Context, error) {
return c, nil
}
-// ClearLabels clears all reserved labels
-func ClearLabels() {
+// clearLabels clears all reserved labels
+func clearLabels() {
state.Lock()
state.mcsList = make(map[string]bool)
state.Unlock()
}
-// ReserveLabel reserves the MLS/MCS level component of the specified label
-func ReserveLabel(label string) {
+// reserveLabel reserves the MLS/MCS level component of the specified label
+func reserveLabel(label string) {
if len(label) != 0 {
con := strings.SplitN(label, ":", 4)
if len(con) > 3 {
@@ -558,8 +760,8 @@ func selinuxEnforcePath() string {
return path.Join(getSelinuxMountPoint(), "enforce")
}
-// EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled
-func EnforceMode() int {
+// enforceMode returns the current SELinux mode Enforcing, Permissive, Disabled
+func enforceMode() int {
var enforce int
enforceB, err := ioutil.ReadFile(selinuxEnforcePath())
@@ -573,20 +775,16 @@ func EnforceMode() int {
return enforce
}
-/*
-SetEnforceMode sets the current SELinux mode Enforcing, Permissive.
-Disabled is not valid, since this needs to be set at boot time.
-*/
-func SetEnforceMode(mode int) error {
+// setEnforceMode sets the current SELinux mode Enforcing, Permissive.
+// Disabled is not valid, since this needs to be set at boot time.
+func setEnforceMode(mode int) error {
return ioutil.WriteFile(selinuxEnforcePath(), []byte(strconv.Itoa(mode)), 0644)
}
-/*
-DefaultEnforceMode returns the systems default SELinux mode Enforcing,
-Permissive or Disabled. Note this is is just the default at boot time.
-EnforceMode tells you the systems current mode.
-*/
-func DefaultEnforceMode() int {
+// defaultEnforceMode returns the systems default SELinux mode Enforcing,
+// Permissive or Disabled. Note this is is just the default at boot time.
+// EnforceMode tells you the systems current mode.
+func defaultEnforceMode() int {
switch readConfig(selinuxTag) {
case "enforcing":
return Enforcing
@@ -666,11 +864,9 @@ func uniqMcs(catRange uint32) string {
return mcs
}
-/*
-ReleaseLabel will unreserve the MLS/MCS Level field of the specified label.
-Allowing it to be used by another process.
-*/
-func ReleaseLabel(label string) {
+// releaseLabel un-reserves the MLS/MCS Level field of the specified label,
+// allowing it to be used by another process.
+func releaseLabel(label string) {
if len(label) != 0 {
con := strings.SplitN(label, ":", 4)
if len(con) > 3 {
@@ -679,28 +875,31 @@ func ReleaseLabel(label string) {
}
}
-// ROFileLabel returns the specified SELinux readonly file label
-func ROFileLabel() string {
- return roFileLabel
+// roFileLabel returns the specified SELinux readonly file label
+func roFileLabel() string {
+ return readOnlyFileLabel
}
-/*
-ContainerLabels returns an allocated processLabel and fileLabel to be used for
-container labeling by the calling process.
-*/
-func ContainerLabels() (processLabel string, fileLabel string) {
+func openContextFile() (*os.File, error) {
+ if f, err := os.Open(contextFile); err == nil {
+ return f, nil
+ }
+ lxcPath := filepath.Join(getSELinuxPolicyRoot(), "/contexts/lxc_contexts")
+ return os.Open(lxcPath)
+}
+
+var labels = loadLabels()
+
+func loadLabels() map[string]string {
var (
val, key string
bufin *bufio.Reader
)
- if !GetEnabled() {
- return "", ""
- }
- lxcPath := fmt.Sprintf("%s/contexts/lxc_contexts", getSELinuxPolicyRoot())
- in, err := os.Open(lxcPath)
+ labels := make(map[string]string)
+ in, err := openContextFile()
if err != nil {
- return "", ""
+ return labels
}
defer in.Close()
@@ -712,7 +911,7 @@ func ContainerLabels() (processLabel string, fileLabel string) {
if err == io.EOF {
done = true
} else {
- goto exit
+ break
}
}
line = strings.TrimSpace(line)
@@ -726,29 +925,61 @@ func ContainerLabels() (processLabel string, fileLabel string) {
}
if groups := assignRegex.FindStringSubmatch(line); groups != nil {
key, val = strings.TrimSpace(groups[1]), strings.TrimSpace(groups[2])
- if key == "process" {
- processLabel = strings.Trim(val, "\"")
- }
- if key == "file" {
- fileLabel = strings.Trim(val, "\"")
- }
- if key == "ro_file" {
- roFileLabel = strings.Trim(val, "\"")
- }
+ labels[key] = strings.Trim(val, "\"")
}
}
- if processLabel == "" || fileLabel == "" {
+ return labels
+}
+
+// kvmContainerLabels returns the default processLabel and mountLabel to be used
+// for kvm containers by the calling process.
+func kvmContainerLabels() (string, string) {
+ processLabel := labels["kvm_process"]
+ if processLabel == "" {
+ processLabel = labels["process"]
+ }
+
+ return addMcs(processLabel, labels["file"])
+}
+
+// initContainerLabels returns the default processLabel and file labels to be
+// used for containers running an init system like systemd by the calling process.
+func initContainerLabels() (string, string) {
+ processLabel := labels["init_process"]
+ if processLabel == "" {
+ processLabel = labels["process"]
+ }
+
+ return addMcs(processLabel, labels["file"])
+}
+
+// containerLabels returns an allocated processLabel and fileLabel to be used for
+// container labeling by the calling process.
+func containerLabels() (processLabel string, fileLabel string) {
+ if !getEnabled() {
return "", ""
}
- if roFileLabel == "" {
- roFileLabel = fileLabel
+ processLabel = labels["process"]
+ fileLabel = labels["file"]
+ readOnlyFileLabel = labels["ro_file"]
+
+ if processLabel == "" || fileLabel == "" {
+ return "", fileLabel
}
-exit:
+
+ if readOnlyFileLabel == "" {
+ readOnlyFileLabel = fileLabel
+ }
+
+ return addMcs(processLabel, fileLabel)
+}
+
+func addMcs(processLabel, fileLabel string) (string, string) {
scon, _ := NewContext(processLabel)
if scon["level"] != "" {
- mcs := uniqMcs(1024)
+ mcs := uniqMcs(CategoryRange)
scon["level"] = mcs
processLabel = scon.Get()
scon, _ = NewContext(fileLabel)
@@ -758,16 +989,14 @@ exit:
return processLabel, fileLabel
}
-// SecurityCheckContext validates that the SELinux label is understood by the kernel
-func SecurityCheckContext(val string) error {
+// securityCheckContext validates that the SELinux label is understood by the kernel
+func securityCheckContext(val string) error {
return ioutil.WriteFile(path.Join(getSelinuxMountPoint(), "context"), []byte(val), 0644)
}
-/*
-CopyLevel returns a label with the MLS/MCS level from src label replaced on
-the dest label.
-*/
-func CopyLevel(src, dest string) (string, error) {
+// copyLevel returns a label with the MLS/MCS level from src label replaced on
+// the dest label.
+func copyLevel(src, dest string) (string, error) {
if src == "" {
return "", nil
}
@@ -791,7 +1020,7 @@ func CopyLevel(src, dest string) (string, error) {
return tcon.Get(), nil
}
-// Prevent users from relabing system files
+// Prevent users from relabeling system files
func badPrefix(fpath string) error {
if fpath == "" {
return ErrEmptyPath
@@ -806,10 +1035,10 @@ func badPrefix(fpath string) error {
return nil
}
-// Chcon changes the fpath file object to the SELinux label label.
-// If fpath is a directory and recurse is true, Chcon will walk the
+// chcon changes the fpath file object to the SELinux label label.
+// If fpath is a directory and recurse is true, then chcon walks the
// directory tree setting the label.
-func Chcon(fpath string, label string, recurse bool) error {
+func chcon(fpath string, label string, recurse bool) error {
if fpath == "" {
return ErrEmptyPath
}
@@ -834,9 +1063,9 @@ func Chcon(fpath string, label string, recurse bool) error {
})
}
-// DupSecOpt takes an SELinux process label and returns security options that
+// dupSecOpt takes an SELinux process label and returns security options that
// can be used to set the SELinux Type and Level for future container processes.
-func DupSecOpt(src string) ([]string, error) {
+func dupSecOpt(src string) ([]string, error) {
if src == "" {
return nil, nil
}
@@ -861,8 +1090,8 @@ func DupSecOpt(src string) ([]string, error) {
return dup, nil
}
-// DisableSecOpt returns a security opt that can be used to disable SELinux
+// disableSecOpt returns a security opt that can be used to disable SELinux
// labeling support for future container processes.
-func DisableSecOpt() []string {
+func disableSecOpt() []string {
return []string{"disable"}
}
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go
index f349513d9..c526b210f 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go
@@ -2,241 +2,147 @@
package selinux
-import (
- "errors"
-)
-
-const (
- // Enforcing constant indicate SELinux is in enforcing mode
- Enforcing = 1
- // Permissive constant to indicate SELinux is in permissive mode
- Permissive = 0
- // Disabled constant to indicate SELinux is disabled
- Disabled = -1
-)
-
-var (
- // ErrMCSAlreadyExists is returned when trying to allocate a duplicate MCS.
- ErrMCSAlreadyExists = errors.New("MCS label already exists")
- // ErrEmptyPath is returned when an empty path has been specified.
- ErrEmptyPath = errors.New("empty path")
-)
-
-// Context is a representation of the SELinux label broken into 4 parts
-type Context map[string]string
-
-// SetDisabled disables selinux support for the package
-func SetDisabled() {
- return
+func setDisabled() {
}
-// GetEnabled returns whether selinux is currently enabled.
-func GetEnabled() bool {
+func getEnabled() bool {
return false
}
-// ClassIndex returns the int index for an object class in the loaded policy, or -1 and an error
-func ClassIndex(class string) (int, error) {
+func classIndex(class string) (int, error) {
return -1, nil
}
-// SetFileLabel sets the SELinux label for this path or returns an error.
-func SetFileLabel(fpath string, label string) error {
+func setFileLabel(fpath string, label string) error {
return nil
}
-// FileLabel returns the SELinux label for this path or returns an error.
-func FileLabel(fpath string) (string, error) {
+func fileLabel(fpath string) (string, error) {
return "", nil
}
-/*
-SetFSCreateLabel tells kernel the label to create all file system objects
-created by this task. Setting label="" to return to default.
-*/
-func SetFSCreateLabel(label string) error {
+func setFSCreateLabel(label string) error {
return nil
}
-/*
-FSCreateLabel returns the default label the kernel which the kernel is using
-for file system objects created by this task. "" indicates default.
-*/
-func FSCreateLabel() (string, error) {
+func fsCreateLabel() (string, error) {
return "", nil
}
-// CurrentLabel returns the SELinux label of the current process thread, or an error.
-func CurrentLabel() (string, error) {
+func currentLabel() (string, error) {
return "", nil
}
-// PidLabel returns the SELinux label of the given pid, or an error.
-func PidLabel(pid int) (string, error) {
+func pidLabel(pid int) (string, error) {
return "", nil
}
-/*
-ExecLabel returns the SELinux label that the kernel will use for any programs
-that are executed by the current process thread, or an error.
-*/
-func ExecLabel() (string, error) {
+func execLabel() (string, error) {
return "", nil
}
-/*
-CanonicalizeContext takes a context string and writes it to the kernel
-the function then returns the context that the kernel will use. This function
-can be used to see if two contexts are equivalent
-*/
-func CanonicalizeContext(val string) (string, error) {
+func canonicalizeContext(val string) (string, error) {
return "", nil
}
-/*
-ComputeCreateContext requests the type transition from source to target for class from the kernel.
-*/
-func ComputeCreateContext(source string, target string, class string) (string, error) {
+func computeCreateContext(source string, target string, class string) (string, error) {
return "", nil
}
-/*
-SetExecLabel sets the SELinux label that the kernel will use for any programs
-that are executed by the current process thread, or an error.
-*/
-func SetExecLabel(label string) error {
+func calculateGlbLub(sourceRange, targetRange string) (string, error) {
+ return "", nil
+}
+
+func setExecLabel(label string) error {
return nil
}
-/*
-SetTaskLabel sets the SELinux label for the current thread, or an error.
-This requires the dyntransition permission.
-*/
-func SetTaskLabel(label string) error {
- return nil
-}
-
-/*
-SetSocketLabel sets the SELinux label that the kernel will use for any programs
-that are executed by the current process thread, or an error.
-*/
-func SetSocketLabel(label string) error {
+func setTaskLabel(label string) error {
return nil
}
-// SocketLabel retrieves the current socket label setting
-func SocketLabel() (string, error) {
- return "", nil
-}
-
-// PeerLabel retrieves the label of the client on the other side of a socket
-func PeerLabel(fd uintptr) (string, error) {
- return "", nil
-}
-
-// SetKeyLabel takes a process label and tells the kernel to assign the
-// label to the next kernel keyring that gets created
-func SetKeyLabel(label string) error {
+func setSocketLabel(label string) error {
return nil
}
-// KeyLabel retrieves the current kernel keyring label setting
-func KeyLabel() (string, error) {
+func socketLabel() (string, error) {
return "", nil
}
-// Get returns the Context as a string
-func (c Context) Get() string {
+func peerLabel(fd uintptr) (string, error) {
+ return "", nil
+}
+
+func setKeyLabel(label string) error {
+ return nil
+}
+
+func keyLabel() (string, error) {
+ return "", nil
+}
+
+func (c Context) get() string {
return ""
}
-// NewContext creates a new Context struct from the specified label
-func NewContext(label string) (Context, error) {
+func newContext(label string) (Context, error) {
c := make(Context)
return c, nil
}
-// ClearLabels clears all reserved MLS/MCS levels
-func ClearLabels() {
- return
+func clearLabels() {
}
-// ReserveLabel reserves the MLS/MCS level component of the specified label
-func ReserveLabel(label string) {
- return
+func reserveLabel(label string) {
}
-// EnforceMode returns the current SELinux mode Enforcing, Permissive, Disabled
-func EnforceMode() int {
+func enforceMode() int {
return Disabled
}
-/*
-SetEnforceMode sets the current SELinux mode Enforcing, Permissive.
-Disabled is not valid, since this needs to be set at boot time.
-*/
-func SetEnforceMode(mode int) error {
+func setEnforceMode(mode int) error {
return nil
}
-/*
-DefaultEnforceMode returns the systems default SELinux mode Enforcing,
-Permissive or Disabled. Note this is is just the default at boot time.
-EnforceMode tells you the systems current mode.
-*/
-func DefaultEnforceMode() int {
+func defaultEnforceMode() int {
return Disabled
}
-/*
-ReleaseLabel will unreserve the MLS/MCS Level field of the specified label.
-Allowing it to be used by another process.
-*/
-func ReleaseLabel(label string) {
- return
+func releaseLabel(label string) {
}
-// ROFileLabel returns the specified SELinux readonly file label
-func ROFileLabel() string {
+func roFileLabel() string {
return ""
}
-/*
-ContainerLabels returns an allocated processLabel and fileLabel to be used for
-container labeling by the calling process.
-*/
-func ContainerLabels() (processLabel string, fileLabel string) {
+func kvmContainerLabels() (string, string) {
return "", ""
}
-// SecurityCheckContext validates that the SELinux label is understood by the kernel
-func SecurityCheckContext(val string) error {
+func initContainerLabels() (string, string) {
+ return "", ""
+}
+
+func containerLabels() (processLabel string, fileLabel string) {
+ return "", ""
+}
+
+func securityCheckContext(val string) error {
return nil
}
-/*
-CopyLevel returns a label with the MLS/MCS level from src label replaced on
-the dest label.
-*/
-func CopyLevel(src, dest string) (string, error) {
+func copyLevel(src, dest string) (string, error) {
return "", nil
}
-// Chcon changes the `fpath` file object to the SELinux label `label`.
-// If `fpath` is a directory and `recurse`` is true, Chcon will walk the
-// directory tree setting the label.
-func Chcon(fpath string, label string, recurse bool) error {
+func chcon(fpath string, label string, recurse bool) error {
return nil
}
-// DupSecOpt takes an SELinux process label and returns security options that
-// can be used to set the SELinux Type and Level for future container processes.
-func DupSecOpt(src string) ([]string, error) {
+func dupSecOpt(src string) ([]string, error) {
return nil, nil
}
-// DisableSecOpt returns a security opt that can be used to disable SELinux
-// labeling support for future container processes.
-func DisableSecOpt() []string {
+func disableSecOpt() []string {
return []string{"disable"}
}
diff --git a/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go b/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go
index 2ee0d0150..63fde1842 100644
--- a/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go
+++ b/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go
@@ -48,7 +48,11 @@ func WalkN(root string, walkFn WalkFunc, num int) error {
errCh := make(chan error, 1) // get the first error, ignore others
// Start walking a tree asap
- var err error
+ var (
+ err error
+ wg sync.WaitGroup
+ )
+ wg.Add(1)
go func() {
err = filepath.Walk(root, func(p string, info os.FileInfo, err error) error {
if err != nil {
@@ -68,9 +72,9 @@ func WalkN(root string, walkFn WalkFunc, num int) error {
if err == nil {
close(files)
}
+ wg.Done()
}()
- var wg sync.WaitGroup
wg.Add(num)
for i := 0; i < num; i++ {
go func() {
diff --git a/vendor/github.com/willf/bitset/.gitignore b/vendor/github.com/willf/bitset/.gitignore
new file mode 100644
index 000000000..5c204d28b
--- /dev/null
+++ b/vendor/github.com/willf/bitset/.gitignore
@@ -0,0 +1,26 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
+
+target
diff --git a/vendor/github.com/willf/bitset/.travis.yml b/vendor/github.com/willf/bitset/.travis.yml
new file mode 100644
index 000000000..094aa5ce0
--- /dev/null
+++ b/vendor/github.com/willf/bitset/.travis.yml
@@ -0,0 +1,37 @@
+language: go
+
+sudo: false
+
+branches:
+ except:
+ - release
+
+branches:
+ only:
+ - master
+ - travis
+
+go:
+ - "1.11.x"
+ - tip
+
+matrix:
+ allow_failures:
+ - go: tip
+
+before_install:
+ - if [ -n "$GH_USER" ]; then git config --global github.user ${GH_USER}; fi;
+ - if [ -n "$GH_TOKEN" ]; then git config --global github.token ${GH_TOKEN}; fi;
+ - go get github.com/mattn/goveralls
+
+before_script:
+ - make deps
+
+script:
+ - make qa
+
+after_failure:
+ - cat ./target/test/report.xml
+
+after_success:
+ - if [ "$TRAVIS_GO_VERSION" = "1.11.1" ]; then $HOME/gopath/bin/goveralls -covermode=count -coverprofile=target/report/coverage.out -service=travis-ci; fi;
diff --git a/vendor/github.com/willf/bitset/LICENSE b/vendor/github.com/willf/bitset/LICENSE
new file mode 100644
index 000000000..59cab8a93
--- /dev/null
+++ b/vendor/github.com/willf/bitset/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2014 Will Fitzgerald. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/willf/bitset/Makefile b/vendor/github.com/willf/bitset/Makefile
new file mode 100644
index 000000000..db8377106
--- /dev/null
+++ b/vendor/github.com/willf/bitset/Makefile
@@ -0,0 +1,191 @@
+# MAKEFILE
+#
+# @author Nicola Asuni
+# @link https://github.com/willf/bitset
+# ------------------------------------------------------------------------------
+
+# List special make targets that are not associated with files
+.PHONY: help all test format fmtcheck vet lint coverage cyclo ineffassign misspell structcheck varcheck errcheck gosimple astscan qa deps clean nuke
+
+# Use bash as shell (Note: Ubuntu now uses dash which doesn't support PIPESTATUS).
+SHELL=/bin/bash
+
+# CVS path (path to the parent dir containing the project)
+CVSPATH=github.com/willf
+
+# Project owner
+OWNER=willf
+
+# Project vendor
+VENDOR=willf
+
+# Project name
+PROJECT=bitset
+
+# Project version
+VERSION=$(shell cat VERSION)
+
+# Name of RPM or DEB package
+PKGNAME=${VENDOR}-${PROJECT}
+
+# Current directory
+CURRENTDIR=$(shell pwd)
+
+# GO lang path
+ifneq ($(GOPATH),)
+ ifeq ($(findstring $(GOPATH),$(CURRENTDIR)),)
+ # the defined GOPATH is not valid
+ GOPATH=
+ endif
+endif
+ifeq ($(GOPATH),)
+ # extract the GOPATH
+ GOPATH=$(firstword $(subst /src/, ,$(CURRENTDIR)))
+endif
+
+# --- MAKE TARGETS ---
+
+# Display general help about this command
+help:
+ @echo ""
+ @echo "$(PROJECT) Makefile."
+ @echo "GOPATH=$(GOPATH)"
+ @echo "The following commands are available:"
+ @echo ""
+ @echo " make qa : Run all the tests"
+ @echo " make test : Run the unit tests"
+ @echo ""
+ @echo " make format : Format the source code"
+ @echo " make fmtcheck : Check if the source code has been formatted"
+ @echo " make vet : Check for suspicious constructs"
+ @echo " make lint : Check for style errors"
+ @echo " make coverage : Generate the coverage report"
+ @echo " make cyclo : Generate the cyclomatic complexity report"
+ @echo " make ineffassign : Detect ineffectual assignments"
+ @echo " make misspell : Detect commonly misspelled words in source files"
+ @echo " make structcheck : Find unused struct fields"
+ @echo " make varcheck : Find unused global variables and constants"
+ @echo " make errcheck : Check that error return values are used"
+ @echo " make gosimple : Suggest code simplifications"
+ @echo " make astscan : GO AST scanner"
+ @echo ""
+ @echo " make docs : Generate source code documentation"
+ @echo ""
+ @echo " make deps : Get the dependencies"
+ @echo " make clean : Remove any build artifact"
+ @echo " make nuke : Deletes any intermediate file"
+ @echo ""
+
+# Alias for help target
+all: help
+
+# Run the unit tests
+test:
+ @mkdir -p target/test
+ @mkdir -p target/report
+ GOPATH=$(GOPATH) \
+ go test \
+ -covermode=atomic \
+ -bench=. \
+ -race \
+ -cpuprofile=target/report/cpu.out \
+ -memprofile=target/report/mem.out \
+ -mutexprofile=target/report/mutex.out \
+ -coverprofile=target/report/coverage.out \
+ -v ./... | \
+ tee >(PATH=$(GOPATH)/bin:$(PATH) go-junit-report > target/test/report.xml); \
+ test $${PIPESTATUS[0]} -eq 0
+
+# Format the source code
+format:
+ @find . -type f -name "*.go" -exec gofmt -s -w {} \;
+
+# Check if the source code has been formatted
+fmtcheck:
+ @mkdir -p target
+ @find . -type f -name "*.go" -exec gofmt -s -d {} \; | tee target/format.diff
+ @test ! -s target/format.diff || { echo "ERROR: the source code has not been formatted - please use 'make format' or 'gofmt'"; exit 1; }
+
+# Check for syntax errors
+vet:
+ GOPATH=$(GOPATH) go vet .
+
+# Check for style errors
+lint:
+ GOPATH=$(GOPATH) PATH=$(GOPATH)/bin:$(PATH) golint .
+
+# Generate the coverage report
+coverage:
+ @mkdir -p target/report
+ GOPATH=$(GOPATH) \
+ go tool cover -html=target/report/coverage.out -o target/report/coverage.html
+
+# Report cyclomatic complexity
+cyclo:
+ @mkdir -p target/report
+ GOPATH=$(GOPATH) gocyclo -avg ./ | tee target/report/cyclo.txt ; test $${PIPESTATUS[0]} -eq 0
+
+# Detect ineffectual assignments
+ineffassign:
+ @mkdir -p target/report
+ GOPATH=$(GOPATH) ineffassign ./ | tee target/report/ineffassign.txt ; test $${PIPESTATUS[0]} -eq 0
+
+# Detect commonly misspelled words in source files
+misspell:
+ @mkdir -p target/report
+ GOPATH=$(GOPATH) misspell -error ./ | tee target/report/misspell.txt ; test $${PIPESTATUS[0]} -eq 0
+
+# Find unused struct fields
+structcheck:
+ @mkdir -p target/report
+ GOPATH=$(GOPATH) structcheck -a ./ | tee target/report/structcheck.txt
+
+# Find unused global variables and constants
+varcheck:
+ @mkdir -p target/report
+ GOPATH=$(GOPATH) varcheck -e ./ | tee target/report/varcheck.txt
+
+# Check that error return values are used
+errcheck:
+ @mkdir -p target/report
+ GOPATH=$(GOPATH) errcheck ./ | tee target/report/errcheck.txt
+
+# AST scanner
+astscan:
+ @mkdir -p target/report
+ GOPATH=$(GOPATH) gosec . | tee target/report/astscan.txt ; test $${PIPESTATUS[0]} -eq 0 || true
+
+# Generate source docs
+docs:
+ @mkdir -p target/docs
+ nohup sh -c 'GOPATH=$(GOPATH) godoc -http=127.0.0.1:6060' > target/godoc_server.log 2>&1 &
+ wget --directory-prefix=target/docs/ --execute robots=off --retry-connrefused --recursive --no-parent --adjust-extension --page-requisites --convert-links http://127.0.0.1:6060/pkg/github.com/${VENDOR}/${PROJECT}/ ; kill -9 `lsof -ti :6060`
+ @echo ''${PKGNAME}' Documentation ...' > target/docs/index.html
+
+# Alias to run all quality-assurance checks
+qa: fmtcheck test vet lint coverage cyclo ineffassign misspell structcheck varcheck errcheck gosimple astscan
+
+# --- INSTALL ---
+
+# Get the dependencies
+deps:
+ GOPATH=$(GOPATH) go get ./...
+ GOPATH=$(GOPATH) go get golang.org/x/lint/golint
+ GOPATH=$(GOPATH) go get github.com/jstemmer/go-junit-report
+ GOPATH=$(GOPATH) go get github.com/axw/gocov/gocov
+ GOPATH=$(GOPATH) go get github.com/fzipp/gocyclo
+ GOPATH=$(GOPATH) go get github.com/gordonklaus/ineffassign
+ GOPATH=$(GOPATH) go get github.com/client9/misspell/cmd/misspell
+ GOPATH=$(GOPATH) go get github.com/opennota/check/cmd/structcheck
+ GOPATH=$(GOPATH) go get github.com/opennota/check/cmd/varcheck
+ GOPATH=$(GOPATH) go get github.com/kisielk/errcheck
+ GOPATH=$(GOPATH) go get github.com/securego/gosec/cmd/gosec/...
+
+# Remove any build artifact
+clean:
+ GOPATH=$(GOPATH) go clean ./...
+
+# Deletes any intermediate file
+nuke:
+ rm -rf ./target
+ GOPATH=$(GOPATH) go clean -i ./...
diff --git a/vendor/github.com/willf/bitset/README.md b/vendor/github.com/willf/bitset/README.md
new file mode 100644
index 000000000..6c62b20c6
--- /dev/null
+++ b/vendor/github.com/willf/bitset/README.md
@@ -0,0 +1,96 @@
+# bitset
+
+*Go language library to map between non-negative integers and boolean values*
+
+[![Master Build Status](https://secure.travis-ci.org/willf/bitset.png?branch=master)](https://travis-ci.org/willf/bitset?branch=master)
+[![Master Coverage Status](https://coveralls.io/repos/willf/bitset/badge.svg?branch=master&service=github)](https://coveralls.io/github/willf/bitset?branch=master)
+[![Go Report Card](https://goreportcard.com/badge/github.com/willf/bitset)](https://goreportcard.com/report/github.com/willf/bitset)
+[![GoDoc](https://godoc.org/github.com/willf/bitset?status.svg)](http://godoc.org/github.com/willf/bitset)
+
+
+## Description
+
+Package bitset implements bitsets, a mapping between non-negative integers and boolean values.
+It should be more efficient than map[uint] bool.
+
+It provides methods for setting, clearing, flipping, and testing individual integers.
+
+But it also provides set intersection, union, difference, complement, and symmetric operations, as well as tests to check whether any, all, or no bits are set, and querying a bitset's current length and number of positive bits.
+
+BitSets are expanded to the size of the largest set bit; the memory allocation is approximately Max bits, where Max is the largest set bit. BitSets are never shrunk. On creation, a hint can be given for the number of bits that will be used.
+
+Many of the methods, including Set, Clear, and Flip, return a BitSet pointer, which allows for chaining.
+
+### Example use:
+
+```go
+package main
+
+import (
+ "fmt"
+ "math/rand"
+
+ "github.com/willf/bitset"
+)
+
+func main() {
+ fmt.Printf("Hello from BitSet!\n")
+ var b bitset.BitSet
+ // play some Go Fish
+ for i := 0; i < 100; i++ {
+ card1 := uint(rand.Intn(52))
+ card2 := uint(rand.Intn(52))
+ b.Set(card1)
+ if b.Test(card2) {
+ fmt.Println("Go Fish!")
+ }
+ b.Clear(card1)
+ }
+
+ // Chaining
+ b.Set(10).Set(11)
+
+ for i, e := b.NextSet(0); e; i, e = b.NextSet(i + 1) {
+ fmt.Println("The following bit is set:", i)
+ }
+ if b.Intersection(bitset.New(100).Set(10)).Count() == 1 {
+ fmt.Println("Intersection works.")
+ } else {
+ fmt.Println("Intersection doesn't work???")
+ }
+}
+```
+
+As an alternative to BitSets, one should check out the 'big' package, which provides a (less set-theoretical) view of bitsets.
+
+Godoc documentation is at: https://godoc.org/github.com/willf/bitset
+
+
+## Implementation Note
+
+Go 1.9 introduced a native `math/bits` library. We provide backward compatibility to Go 1.7, which might be removed.
+
+It is possible that a later version will match the `math/bits` return signature for counts (which is `int`, rather than our library's `unit64`). If so, the version will be bumped.
+
+## Installation
+
+```bash
+go get github.com/willf/bitset
+```
+
+## Contributing
+
+If you wish to contribute to this project, please branch and issue a pull request against master ("[GitHub Flow](https://guides.github.com/introduction/flow/)")
+
+This project include a Makefile that allows you to test and build the project with simple commands.
+To see all available options:
+```bash
+make help
+```
+
+## Running all tests
+
+Before committing the code, please check if it passes all tests using (note: this will install some dependencies):
+```bash
+make qa
+```
diff --git a/vendor/github.com/willf/bitset/azure-pipelines.yml b/vendor/github.com/willf/bitset/azure-pipelines.yml
new file mode 100644
index 000000000..f9b295918
--- /dev/null
+++ b/vendor/github.com/willf/bitset/azure-pipelines.yml
@@ -0,0 +1,39 @@
+# Go
+# Build your Go project.
+# Add steps that test, save build artifacts, deploy, and more:
+# https://docs.microsoft.com/azure/devops/pipelines/languages/go
+
+trigger:
+- master
+
+pool:
+ vmImage: 'Ubuntu-16.04'
+
+variables:
+ GOBIN: '$(GOPATH)/bin' # Go binaries path
+ GOROOT: '/usr/local/go1.11' # Go installation path
+ GOPATH: '$(system.defaultWorkingDirectory)/gopath' # Go workspace path
+ modulePath: '$(GOPATH)/src/github.com/$(build.repository.name)' # Path to the module's code
+
+steps:
+- script: |
+ mkdir -p '$(GOBIN)'
+ mkdir -p '$(GOPATH)/pkg'
+ mkdir -p '$(modulePath)'
+ shopt -s extglob
+ shopt -s dotglob
+ mv !(gopath) '$(modulePath)'
+ echo '##vso[task.prependpath]$(GOBIN)'
+ echo '##vso[task.prependpath]$(GOROOT)/bin'
+ displayName: 'Set up the Go workspace'
+
+- script: |
+ go version
+ go get -v -t -d ./...
+ if [ -f Gopkg.toml ]; then
+ curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
+ dep ensure
+ fi
+ go build -v .
+ workingDirectory: '$(modulePath)'
+ displayName: 'Get dependencies, then build'
diff --git a/vendor/github.com/willf/bitset/bitset.go b/vendor/github.com/willf/bitset/bitset.go
new file mode 100644
index 000000000..22e5d42e5
--- /dev/null
+++ b/vendor/github.com/willf/bitset/bitset.go
@@ -0,0 +1,879 @@
+/*
+Package bitset implements bitsets, a mapping
+between non-negative integers and boolean values. It should be more
+efficient than map[uint] bool.
+
+It provides methods for setting, clearing, flipping, and testing
+individual integers.
+
+But it also provides set intersection, union, difference,
+complement, and symmetric operations, as well as tests to
+check whether any, all, or no bits are set, and querying a
+bitset's current length and number of positive bits.
+
+BitSets are expanded to the size of the largest set bit; the
+memory allocation is approximately Max bits, where Max is
+the largest set bit. BitSets are never shrunk. On creation,
+a hint can be given for the number of bits that will be used.
+
+Many of the methods, including Set,Clear, and Flip, return
+a BitSet pointer, which allows for chaining.
+
+Example use:
+
+ import "bitset"
+ var b BitSet
+ b.Set(10).Set(11)
+ if b.Test(1000) {
+ b.Clear(1000)
+ }
+ if B.Intersection(bitset.New(100).Set(10)).Count() > 1 {
+ fmt.Println("Intersection works.")
+ }
+
+As an alternative to BitSets, one should check out the 'big' package,
+which provides a (less set-theoretical) view of bitsets.
+
+*/
+package bitset
+
+import (
+ "bufio"
+ "bytes"
+ "encoding/base64"
+ "encoding/binary"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "strconv"
+)
+
+// the wordSize of a bit set
+const wordSize = uint(64)
+
+// log2WordSize is lg(wordSize)
+const log2WordSize = uint(6)
+
+// allBits has every bit set
+const allBits uint64 = 0xffffffffffffffff
+
+// default binary BigEndian
+var binaryOrder binary.ByteOrder = binary.BigEndian
+
+// default json encoding base64.URLEncoding
+var base64Encoding = base64.URLEncoding
+
+// Base64StdEncoding Marshal/Unmarshal BitSet with base64.StdEncoding(Default: base64.URLEncoding)
+func Base64StdEncoding() { base64Encoding = base64.StdEncoding }
+
+// LittleEndian Marshal/Unmarshal Binary as Little Endian(Default: binary.BigEndian)
+func LittleEndian() { binaryOrder = binary.LittleEndian }
+
+// A BitSet is a set of bits. The zero value of a BitSet is an empty set of length 0.
+type BitSet struct {
+ length uint
+ set []uint64
+}
+
+// Error is used to distinguish errors (panics) generated in this package.
+type Error string
+
+// safeSet will fixup b.set to be non-nil and return the field value
+func (b *BitSet) safeSet() []uint64 {
+ if b.set == nil {
+ b.set = make([]uint64, wordsNeeded(0))
+ }
+ return b.set
+}
+
+// From is a constructor used to create a BitSet from an array of integers
+func From(buf []uint64) *BitSet {
+ return &BitSet{uint(len(buf)) * 64, buf}
+}
+
+// Bytes returns the bitset as array of integers
+func (b *BitSet) Bytes() []uint64 {
+ return b.set
+}
+
+// wordsNeeded calculates the number of words needed for i bits
+func wordsNeeded(i uint) int {
+ if i > (Cap() - wordSize + 1) {
+ return int(Cap() >> log2WordSize)
+ }
+ return int((i + (wordSize - 1)) >> log2WordSize)
+}
+
+// New creates a new BitSet with a hint that length bits will be required
+func New(length uint) (bset *BitSet) {
+ defer func() {
+ if r := recover(); r != nil {
+ bset = &BitSet{
+ 0,
+ make([]uint64, 0),
+ }
+ }
+ }()
+
+ bset = &BitSet{
+ length,
+ make([]uint64, wordsNeeded(length)),
+ }
+
+ return bset
+}
+
+// Cap returns the total possible capacity, or number of bits
+func Cap() uint {
+ return ^uint(0)
+}
+
+// Len returns the number of bits in the BitSet.
+// Note the difference to method Count, see example.
+func (b *BitSet) Len() uint {
+ return b.length
+}
+
+// extendSetMaybe adds additional words to incorporate new bits if needed
+func (b *BitSet) extendSetMaybe(i uint) {
+ if i >= b.length { // if we need more bits, make 'em
+ nsize := wordsNeeded(i + 1)
+ if b.set == nil {
+ b.set = make([]uint64, nsize)
+ } else if cap(b.set) >= nsize {
+ b.set = b.set[:nsize] // fast resize
+ } else if len(b.set) < nsize {
+ newset := make([]uint64, nsize, 2*nsize) // increase capacity 2x
+ copy(newset, b.set)
+ b.set = newset
+ }
+ b.length = i + 1
+ }
+}
+
+// Test whether bit i is set.
+func (b *BitSet) Test(i uint) bool {
+ if i >= b.length {
+ return false
+ }
+ return b.set[i>>log2WordSize]&(1<<(i&(wordSize-1))) != 0
+}
+
+// Set bit i to 1
+func (b *BitSet) Set(i uint) *BitSet {
+ b.extendSetMaybe(i)
+ b.set[i>>log2WordSize] |= 1 << (i & (wordSize - 1))
+ return b
+}
+
+// Clear bit i to 0
+func (b *BitSet) Clear(i uint) *BitSet {
+ if i >= b.length {
+ return b
+ }
+ b.set[i>>log2WordSize] &^= 1 << (i & (wordSize - 1))
+ return b
+}
+
+// SetTo sets bit i to value
+func (b *BitSet) SetTo(i uint, value bool) *BitSet {
+ if value {
+ return b.Set(i)
+ }
+ return b.Clear(i)
+}
+
+// Flip bit at i
+func (b *BitSet) Flip(i uint) *BitSet {
+ if i >= b.length {
+ return b.Set(i)
+ }
+ b.set[i>>log2WordSize] ^= 1 << (i & (wordSize - 1))
+ return b
+}
+
+// Shrink shrinks BitSet to desired length in bits. It clears all bits > length
+// and reduces the size and length of the set.
+//
+// A new slice is allocated to store the new bits, so you may see an increase in
+// memory usage until the GC runs. Normally this should not be a problem, but if you
+// have an extremely large BitSet its important to understand that the old BitSet will
+// remain in memory until the GC frees it.
+func (b *BitSet) Shrink(length uint) *BitSet {
+ idx := wordsNeeded(length + 1)
+ if idx > len(b.set) {
+ return b
+ }
+ shrunk := make([]uint64, idx)
+ copy(shrunk, b.set[:idx])
+ b.set = shrunk
+ b.length = length + 1
+ b.set[idx-1] &= (allBits >> (uint64(64) - uint64(length&(wordSize-1)) - 1))
+ return b
+}
+
+// InsertAt takes an index which indicates where a bit should be
+// inserted. Then it shifts all the bits in the set to the left by 1, starting
+// from the given index position, and sets the index position to 0.
+//
+// Depending on the size of your BitSet, and where you are inserting the new entry,
+// this method could be extremely slow and in some cases might cause the entire BitSet
+// to be recopied.
+func (b *BitSet) InsertAt(idx uint) *BitSet {
+ insertAtElement := (idx >> log2WordSize)
+
+ // if length of set is a multiple of wordSize we need to allocate more space first
+ if b.isLenExactMultiple() {
+ b.set = append(b.set, uint64(0))
+ }
+
+ var i uint
+ for i = uint(len(b.set) - 1); i > insertAtElement; i-- {
+ // all elements above the position where we want to insert can simply by shifted
+ b.set[i] <<= 1
+
+ // we take the most significant bit of the previous element and set it as
+ // the least significant bit of the current element
+ b.set[i] |= (b.set[i-1] & 0x8000000000000000) >> 63
+ }
+
+ // generate a mask to extract the data that we need to shift left
+ // within the element where we insert a bit
+ dataMask := ^(uint64(1)< 0x40000 {
+ buffer.WriteString("...")
+ break
+ }
+ buffer.WriteString(strconv.FormatInt(int64(i), 10))
+ i, e = b.NextSet(i + 1)
+ if e {
+ buffer.WriteString(",")
+ }
+ }
+ buffer.WriteString("}")
+ return buffer.String()
+}
+
+// DeleteAt deletes the bit at the given index position from
+// within the bitset
+// All the bits residing on the left of the deleted bit get
+// shifted right by 1
+// The running time of this operation may potentially be
+// relatively slow, O(length)
+func (b *BitSet) DeleteAt(i uint) *BitSet {
+ // the index of the slice element where we'll delete a bit
+ deleteAtElement := i >> log2WordSize
+
+ // generate a mask for the data that needs to be shifted right
+ // within that slice element that gets modified
+ dataMask := ^((uint64(1) << (i & (wordSize - 1))) - 1)
+
+ // extract the data that we'll shift right from the slice element
+ data := b.set[deleteAtElement] & dataMask
+
+ // set the masked area to 0 while leaving the rest as it is
+ b.set[deleteAtElement] &= ^dataMask
+
+ // shift the previously extracted data to the right and then
+ // set it in the previously masked area
+ b.set[deleteAtElement] |= (data >> 1) & dataMask
+
+ // loop over all the consecutive slice elements to copy each
+ // lowest bit into the highest position of the previous element,
+ // then shift the entire content to the right by 1
+ for i := int(deleteAtElement) + 1; i < len(b.set); i++ {
+ b.set[i-1] |= (b.set[i] & 1) << 63
+ b.set[i] >>= 1
+ }
+
+ b.length = b.length - 1
+
+ return b
+}
+
+// NextSet returns the next bit set from the specified index,
+// including possibly the current index
+// along with an error code (true = valid, false = no set bit found)
+// for i,e := v.NextSet(0); e; i,e = v.NextSet(i + 1) {...}
+func (b *BitSet) NextSet(i uint) (uint, bool) {
+ x := int(i >> log2WordSize)
+ if x >= len(b.set) {
+ return 0, false
+ }
+ w := b.set[x]
+ w = w >> (i & (wordSize - 1))
+ if w != 0 {
+ return i + trailingZeroes64(w), true
+ }
+ x = x + 1
+ for x < len(b.set) {
+ if b.set[x] != 0 {
+ return uint(x)*wordSize + trailingZeroes64(b.set[x]), true
+ }
+ x = x + 1
+
+ }
+ return 0, false
+}
+
+// NextSetMany returns many next bit sets from the specified index,
+// including possibly the current index and up to cap(buffer).
+// If the returned slice has len zero, then no more set bits were found
+//
+// buffer := make([]uint, 256) // this should be reused
+// j := uint(0)
+// j, buffer = bitmap.NextSetMany(j, buffer)
+// for ; len(buffer) > 0; j, buffer = bitmap.NextSetMany(j,buffer) {
+// for k := range buffer {
+// do something with buffer[k]
+// }
+// j += 1
+// }
+//
+func (b *BitSet) NextSetMany(i uint, buffer []uint) (uint, []uint) {
+ myanswer := buffer
+ capacity := cap(buffer)
+ x := int(i >> log2WordSize)
+ if x >= len(b.set) || capacity == 0 {
+ return 0, myanswer[:0]
+ }
+ skip := i & (wordSize - 1)
+ word := b.set[x] >> skip
+ myanswer = myanswer[:capacity]
+ size := int(0)
+ for word != 0 {
+ r := trailingZeroes64(word)
+ t := word & ((^word) + 1)
+ myanswer[size] = r + i
+ size++
+ if size == capacity {
+ goto End
+ }
+ word = word ^ t
+ }
+ x++
+ for idx, word := range b.set[x:] {
+ for word != 0 {
+ r := trailingZeroes64(word)
+ t := word & ((^word) + 1)
+ myanswer[size] = r + (uint(x+idx) << 6)
+ size++
+ if size == capacity {
+ goto End
+ }
+ word = word ^ t
+ }
+ }
+End:
+ if size > 0 {
+ return myanswer[size-1], myanswer[:size]
+ }
+ return 0, myanswer[:0]
+}
+
+// NextClear returns the next clear bit from the specified index,
+// including possibly the current index
+// along with an error code (true = valid, false = no bit found i.e. all bits are set)
+func (b *BitSet) NextClear(i uint) (uint, bool) {
+ x := int(i >> log2WordSize)
+ if x >= len(b.set) {
+ return 0, false
+ }
+ w := b.set[x]
+ w = w >> (i & (wordSize - 1))
+ wA := allBits >> (i & (wordSize - 1))
+ index := i + trailingZeroes64(^w)
+ if w != wA && index < b.length {
+ return index, true
+ }
+ x++
+ for x < len(b.set) {
+ index = uint(x)*wordSize + trailingZeroes64(^b.set[x])
+ if b.set[x] != allBits && index < b.length {
+ return index, true
+ }
+ x++
+ }
+ return 0, false
+}
+
+// ClearAll clears the entire BitSet
+func (b *BitSet) ClearAll() *BitSet {
+ if b != nil && b.set != nil {
+ for i := range b.set {
+ b.set[i] = 0
+ }
+ }
+ return b
+}
+
+// wordCount returns the number of words used in a bit set
+func (b *BitSet) wordCount() int {
+ return len(b.set)
+}
+
+// Clone this BitSet
+func (b *BitSet) Clone() *BitSet {
+ c := New(b.length)
+ if b.set != nil { // Clone should not modify current object
+ copy(c.set, b.set)
+ }
+ return c
+}
+
+// Copy into a destination BitSet
+// Returning the size of the destination BitSet
+// like array copy
+func (b *BitSet) Copy(c *BitSet) (count uint) {
+ if c == nil {
+ return
+ }
+ if b.set != nil { // Copy should not modify current object
+ copy(c.set, b.set)
+ }
+ count = c.length
+ if b.length < c.length {
+ count = b.length
+ }
+ return
+}
+
+// Count (number of set bits).
+// Also known as "popcount" or "popularity count".
+func (b *BitSet) Count() uint {
+ if b != nil && b.set != nil {
+ return uint(popcntSlice(b.set))
+ }
+ return 0
+}
+
+// Equal tests the equivalence of two BitSets.
+// False if they are of different sizes, otherwise true
+// only if all the same bits are set
+func (b *BitSet) Equal(c *BitSet) bool {
+ if c == nil || b == nil {
+ return c == b
+ }
+ if b.length != c.length {
+ return false
+ }
+ if b.length == 0 { // if they have both length == 0, then could have nil set
+ return true
+ }
+ // testing for equality shoud not transform the bitset (no call to safeSet)
+
+ for p, v := range b.set {
+ if c.set[p] != v {
+ return false
+ }
+ }
+ return true
+}
+
+func panicIfNull(b *BitSet) {
+ if b == nil {
+ panic(Error("BitSet must not be null"))
+ }
+}
+
+// Difference of base set and other set
+// This is the BitSet equivalent of &^ (and not)
+func (b *BitSet) Difference(compare *BitSet) (result *BitSet) {
+ panicIfNull(b)
+ panicIfNull(compare)
+ result = b.Clone() // clone b (in case b is bigger than compare)
+ l := int(compare.wordCount())
+ if l > int(b.wordCount()) {
+ l = int(b.wordCount())
+ }
+ for i := 0; i < l; i++ {
+ result.set[i] = b.set[i] &^ compare.set[i]
+ }
+ return
+}
+
+// DifferenceCardinality computes the cardinality of the differnce
+func (b *BitSet) DifferenceCardinality(compare *BitSet) uint {
+ panicIfNull(b)
+ panicIfNull(compare)
+ l := int(compare.wordCount())
+ if l > int(b.wordCount()) {
+ l = int(b.wordCount())
+ }
+ cnt := uint64(0)
+ cnt += popcntMaskSlice(b.set[:l], compare.set[:l])
+ cnt += popcntSlice(b.set[l:])
+ return uint(cnt)
+}
+
+// InPlaceDifference computes the difference of base set and other set
+// This is the BitSet equivalent of &^ (and not)
+func (b *BitSet) InPlaceDifference(compare *BitSet) {
+ panicIfNull(b)
+ panicIfNull(compare)
+ l := int(compare.wordCount())
+ if l > int(b.wordCount()) {
+ l = int(b.wordCount())
+ }
+ for i := 0; i < l; i++ {
+ b.set[i] &^= compare.set[i]
+ }
+}
+
+// Convenience function: return two bitsets ordered by
+// increasing length. Note: neither can be nil
+func sortByLength(a *BitSet, b *BitSet) (ap *BitSet, bp *BitSet) {
+ if a.length <= b.length {
+ ap, bp = a, b
+ } else {
+ ap, bp = b, a
+ }
+ return
+}
+
+// Intersection of base set and other set
+// This is the BitSet equivalent of & (and)
+func (b *BitSet) Intersection(compare *BitSet) (result *BitSet) {
+ panicIfNull(b)
+ panicIfNull(compare)
+ b, compare = sortByLength(b, compare)
+ result = New(b.length)
+ for i, word := range b.set {
+ result.set[i] = word & compare.set[i]
+ }
+ return
+}
+
+// IntersectionCardinality computes the cardinality of the union
+func (b *BitSet) IntersectionCardinality(compare *BitSet) uint {
+ panicIfNull(b)
+ panicIfNull(compare)
+ b, compare = sortByLength(b, compare)
+ cnt := popcntAndSlice(b.set, compare.set)
+ return uint(cnt)
+}
+
+// InPlaceIntersection destructively computes the intersection of
+// base set and the compare set.
+// This is the BitSet equivalent of & (and)
+func (b *BitSet) InPlaceIntersection(compare *BitSet) {
+ panicIfNull(b)
+ panicIfNull(compare)
+ l := int(compare.wordCount())
+ if l > int(b.wordCount()) {
+ l = int(b.wordCount())
+ }
+ for i := 0; i < l; i++ {
+ b.set[i] &= compare.set[i]
+ }
+ for i := l; i < len(b.set); i++ {
+ b.set[i] = 0
+ }
+ if compare.length > 0 {
+ b.extendSetMaybe(compare.length - 1)
+ }
+}
+
+// Union of base set and other set
+// This is the BitSet equivalent of | (or)
+func (b *BitSet) Union(compare *BitSet) (result *BitSet) {
+ panicIfNull(b)
+ panicIfNull(compare)
+ b, compare = sortByLength(b, compare)
+ result = compare.Clone()
+ for i, word := range b.set {
+ result.set[i] = word | compare.set[i]
+ }
+ return
+}
+
+// UnionCardinality computes the cardinality of the uniton of the base set
+// and the compare set.
+func (b *BitSet) UnionCardinality(compare *BitSet) uint {
+ panicIfNull(b)
+ panicIfNull(compare)
+ b, compare = sortByLength(b, compare)
+ cnt := popcntOrSlice(b.set, compare.set)
+ if len(compare.set) > len(b.set) {
+ cnt += popcntSlice(compare.set[len(b.set):])
+ }
+ return uint(cnt)
+}
+
+// InPlaceUnion creates the destructive union of base set and compare set.
+// This is the BitSet equivalent of | (or).
+func (b *BitSet) InPlaceUnion(compare *BitSet) {
+ panicIfNull(b)
+ panicIfNull(compare)
+ l := int(compare.wordCount())
+ if l > int(b.wordCount()) {
+ l = int(b.wordCount())
+ }
+ if compare.length > 0 {
+ b.extendSetMaybe(compare.length - 1)
+ }
+ for i := 0; i < l; i++ {
+ b.set[i] |= compare.set[i]
+ }
+ if len(compare.set) > l {
+ for i := l; i < len(compare.set); i++ {
+ b.set[i] = compare.set[i]
+ }
+ }
+}
+
+// SymmetricDifference of base set and other set
+// This is the BitSet equivalent of ^ (xor)
+func (b *BitSet) SymmetricDifference(compare *BitSet) (result *BitSet) {
+ panicIfNull(b)
+ panicIfNull(compare)
+ b, compare = sortByLength(b, compare)
+ // compare is bigger, so clone it
+ result = compare.Clone()
+ for i, word := range b.set {
+ result.set[i] = word ^ compare.set[i]
+ }
+ return
+}
+
+// SymmetricDifferenceCardinality computes the cardinality of the symmetric difference
+func (b *BitSet) SymmetricDifferenceCardinality(compare *BitSet) uint {
+ panicIfNull(b)
+ panicIfNull(compare)
+ b, compare = sortByLength(b, compare)
+ cnt := popcntXorSlice(b.set, compare.set)
+ if len(compare.set) > len(b.set) {
+ cnt += popcntSlice(compare.set[len(b.set):])
+ }
+ return uint(cnt)
+}
+
+// InPlaceSymmetricDifference creates the destructive SymmetricDifference of base set and other set
+// This is the BitSet equivalent of ^ (xor)
+func (b *BitSet) InPlaceSymmetricDifference(compare *BitSet) {
+ panicIfNull(b)
+ panicIfNull(compare)
+ l := int(compare.wordCount())
+ if l > int(b.wordCount()) {
+ l = int(b.wordCount())
+ }
+ if compare.length > 0 {
+ b.extendSetMaybe(compare.length - 1)
+ }
+ for i := 0; i < l; i++ {
+ b.set[i] ^= compare.set[i]
+ }
+ if len(compare.set) > l {
+ for i := l; i < len(compare.set); i++ {
+ b.set[i] = compare.set[i]
+ }
+ }
+}
+
+// Is the length an exact multiple of word sizes?
+func (b *BitSet) isLenExactMultiple() bool {
+ return b.length%wordSize == 0
+}
+
+// Clean last word by setting unused bits to 0
+func (b *BitSet) cleanLastWord() {
+ if !b.isLenExactMultiple() {
+ b.set[len(b.set)-1] &= allBits >> (wordSize - b.length%wordSize)
+ }
+}
+
+// Complement computes the (local) complement of a biset (up to length bits)
+func (b *BitSet) Complement() (result *BitSet) {
+ panicIfNull(b)
+ result = New(b.length)
+ for i, word := range b.set {
+ result.set[i] = ^word
+ }
+ result.cleanLastWord()
+ return
+}
+
+// All returns true if all bits are set, false otherwise. Returns true for
+// empty sets.
+func (b *BitSet) All() bool {
+ panicIfNull(b)
+ return b.Count() == b.length
+}
+
+// None returns true if no bit is set, false otherwise. Returns true for
+// empty sets.
+func (b *BitSet) None() bool {
+ panicIfNull(b)
+ if b != nil && b.set != nil {
+ for _, word := range b.set {
+ if word > 0 {
+ return false
+ }
+ }
+ return true
+ }
+ return true
+}
+
+// Any returns true if any bit is set, false otherwise
+func (b *BitSet) Any() bool {
+ panicIfNull(b)
+ return !b.None()
+}
+
+// IsSuperSet returns true if this is a superset of the other set
+func (b *BitSet) IsSuperSet(other *BitSet) bool {
+ for i, e := other.NextSet(0); e; i, e = other.NextSet(i + 1) {
+ if !b.Test(i) {
+ return false
+ }
+ }
+ return true
+}
+
+// IsStrictSuperSet returns true if this is a strict superset of the other set
+func (b *BitSet) IsStrictSuperSet(other *BitSet) bool {
+ return b.Count() > other.Count() && b.IsSuperSet(other)
+}
+
+// DumpAsBits dumps a bit set as a string of bits
+func (b *BitSet) DumpAsBits() string {
+ if b.set == nil {
+ return "."
+ }
+ buffer := bytes.NewBufferString("")
+ i := len(b.set) - 1
+ for ; i >= 0; i-- {
+ fmt.Fprintf(buffer, "%064b.", b.set[i])
+ }
+ return buffer.String()
+}
+
+// BinaryStorageSize returns the binary storage requirements
+func (b *BitSet) BinaryStorageSize() int {
+ return binary.Size(uint64(0)) + binary.Size(b.set)
+}
+
+// WriteTo writes a BitSet to a stream
+func (b *BitSet) WriteTo(stream io.Writer) (int64, error) {
+ length := uint64(b.length)
+
+ // Write length
+ err := binary.Write(stream, binaryOrder, length)
+ if err != nil {
+ return 0, err
+ }
+
+ // Write set
+ err = binary.Write(stream, binaryOrder, b.set)
+ return int64(b.BinaryStorageSize()), err
+}
+
+// ReadFrom reads a BitSet from a stream written using WriteTo
+func (b *BitSet) ReadFrom(stream io.Reader) (int64, error) {
+ var length uint64
+
+ // Read length first
+ err := binary.Read(stream, binaryOrder, &length)
+ if err != nil {
+ return 0, err
+ }
+ newset := New(uint(length))
+
+ if uint64(newset.length) != length {
+ return 0, errors.New("Unmarshalling error: type mismatch")
+ }
+
+ // Read remaining bytes as set
+ err = binary.Read(stream, binaryOrder, newset.set)
+ if err != nil {
+ return 0, err
+ }
+
+ *b = *newset
+ return int64(b.BinaryStorageSize()), nil
+}
+
+// MarshalBinary encodes a BitSet into a binary form and returns the result.
+func (b *BitSet) MarshalBinary() ([]byte, error) {
+ var buf bytes.Buffer
+ writer := bufio.NewWriter(&buf)
+
+ _, err := b.WriteTo(writer)
+ if err != nil {
+ return []byte{}, err
+ }
+
+ err = writer.Flush()
+
+ return buf.Bytes(), err
+}
+
+// UnmarshalBinary decodes the binary form generated by MarshalBinary.
+func (b *BitSet) UnmarshalBinary(data []byte) error {
+ buf := bytes.NewReader(data)
+ reader := bufio.NewReader(buf)
+
+ _, err := b.ReadFrom(reader)
+
+ return err
+}
+
+// MarshalJSON marshals a BitSet as a JSON structure
+func (b *BitSet) MarshalJSON() ([]byte, error) {
+ buffer := bytes.NewBuffer(make([]byte, 0, b.BinaryStorageSize()))
+ _, err := b.WriteTo(buffer)
+ if err != nil {
+ return nil, err
+ }
+
+ // URLEncode all bytes
+ return json.Marshal(base64Encoding.EncodeToString(buffer.Bytes()))
+}
+
+// UnmarshalJSON unmarshals a BitSet from JSON created using MarshalJSON
+func (b *BitSet) UnmarshalJSON(data []byte) error {
+ // Unmarshal as string
+ var s string
+ err := json.Unmarshal(data, &s)
+ if err != nil {
+ return err
+ }
+
+ // URLDecode string
+ buf, err := base64Encoding.DecodeString(s)
+ if err != nil {
+ return err
+ }
+
+ _, err = b.ReadFrom(bytes.NewReader(buf))
+ return err
+}
diff --git a/vendor/github.com/willf/bitset/popcnt.go b/vendor/github.com/willf/bitset/popcnt.go
new file mode 100644
index 000000000..76577a838
--- /dev/null
+++ b/vendor/github.com/willf/bitset/popcnt.go
@@ -0,0 +1,53 @@
+package bitset
+
+// bit population count, take from
+// https://code.google.com/p/go/issues/detail?id=4988#c11
+// credit: https://code.google.com/u/arnehormann/
+func popcount(x uint64) (n uint64) {
+ x -= (x >> 1) & 0x5555555555555555
+ x = (x>>2)&0x3333333333333333 + x&0x3333333333333333
+ x += x >> 4
+ x &= 0x0f0f0f0f0f0f0f0f
+ x *= 0x0101010101010101
+ return x >> 56
+}
+
+func popcntSliceGo(s []uint64) uint64 {
+ cnt := uint64(0)
+ for _, x := range s {
+ cnt += popcount(x)
+ }
+ return cnt
+}
+
+func popcntMaskSliceGo(s, m []uint64) uint64 {
+ cnt := uint64(0)
+ for i := range s {
+ cnt += popcount(s[i] &^ m[i])
+ }
+ return cnt
+}
+
+func popcntAndSliceGo(s, m []uint64) uint64 {
+ cnt := uint64(0)
+ for i := range s {
+ cnt += popcount(s[i] & m[i])
+ }
+ return cnt
+}
+
+func popcntOrSliceGo(s, m []uint64) uint64 {
+ cnt := uint64(0)
+ for i := range s {
+ cnt += popcount(s[i] | m[i])
+ }
+ return cnt
+}
+
+func popcntXorSliceGo(s, m []uint64) uint64 {
+ cnt := uint64(0)
+ for i := range s {
+ cnt += popcount(s[i] ^ m[i])
+ }
+ return cnt
+}
diff --git a/vendor/github.com/willf/bitset/popcnt_19.go b/vendor/github.com/willf/bitset/popcnt_19.go
new file mode 100644
index 000000000..fc8ff4f36
--- /dev/null
+++ b/vendor/github.com/willf/bitset/popcnt_19.go
@@ -0,0 +1,45 @@
+// +build go1.9
+
+package bitset
+
+import "math/bits"
+
+func popcntSlice(s []uint64) uint64 {
+ var cnt int
+ for _, x := range s {
+ cnt += bits.OnesCount64(x)
+ }
+ return uint64(cnt)
+}
+
+func popcntMaskSlice(s, m []uint64) uint64 {
+ var cnt int
+ for i := range s {
+ cnt += bits.OnesCount64(s[i] &^ m[i])
+ }
+ return uint64(cnt)
+}
+
+func popcntAndSlice(s, m []uint64) uint64 {
+ var cnt int
+ for i := range s {
+ cnt += bits.OnesCount64(s[i] & m[i])
+ }
+ return uint64(cnt)
+}
+
+func popcntOrSlice(s, m []uint64) uint64 {
+ var cnt int
+ for i := range s {
+ cnt += bits.OnesCount64(s[i] | m[i])
+ }
+ return uint64(cnt)
+}
+
+func popcntXorSlice(s, m []uint64) uint64 {
+ var cnt int
+ for i := range s {
+ cnt += bits.OnesCount64(s[i] ^ m[i])
+ }
+ return uint64(cnt)
+}
diff --git a/vendor/github.com/willf/bitset/popcnt_amd64.go b/vendor/github.com/willf/bitset/popcnt_amd64.go
new file mode 100644
index 000000000..4cf64f24a
--- /dev/null
+++ b/vendor/github.com/willf/bitset/popcnt_amd64.go
@@ -0,0 +1,68 @@
+// +build !go1.9
+// +build amd64,!appengine
+
+package bitset
+
+// *** the following functions are defined in popcnt_amd64.s
+
+//go:noescape
+
+func hasAsm() bool
+
+// useAsm is a flag used to select the GO or ASM implementation of the popcnt function
+var useAsm = hasAsm()
+
+//go:noescape
+
+func popcntSliceAsm(s []uint64) uint64
+
+//go:noescape
+
+func popcntMaskSliceAsm(s, m []uint64) uint64
+
+//go:noescape
+
+func popcntAndSliceAsm(s, m []uint64) uint64
+
+//go:noescape
+
+func popcntOrSliceAsm(s, m []uint64) uint64
+
+//go:noescape
+
+func popcntXorSliceAsm(s, m []uint64) uint64
+
+func popcntSlice(s []uint64) uint64 {
+ if useAsm {
+ return popcntSliceAsm(s)
+ }
+ return popcntSliceGo(s)
+}
+
+func popcntMaskSlice(s, m []uint64) uint64 {
+ if useAsm {
+ return popcntMaskSliceAsm(s, m)
+ }
+ return popcntMaskSliceGo(s, m)
+}
+
+func popcntAndSlice(s, m []uint64) uint64 {
+ if useAsm {
+ return popcntAndSliceAsm(s, m)
+ }
+ return popcntAndSliceGo(s, m)
+}
+
+func popcntOrSlice(s, m []uint64) uint64 {
+ if useAsm {
+ return popcntOrSliceAsm(s, m)
+ }
+ return popcntOrSliceGo(s, m)
+}
+
+func popcntXorSlice(s, m []uint64) uint64 {
+ if useAsm {
+ return popcntXorSliceAsm(s, m)
+ }
+ return popcntXorSliceGo(s, m)
+}
diff --git a/vendor/github.com/willf/bitset/popcnt_amd64.s b/vendor/github.com/willf/bitset/popcnt_amd64.s
new file mode 100644
index 000000000..666c0dcc1
--- /dev/null
+++ b/vendor/github.com/willf/bitset/popcnt_amd64.s
@@ -0,0 +1,104 @@
+// +build !go1.9
+// +build amd64,!appengine
+
+TEXT ·hasAsm(SB),4,$0-1
+MOVQ $1, AX
+CPUID
+SHRQ $23, CX
+ANDQ $1, CX
+MOVB CX, ret+0(FP)
+RET
+
+#define POPCNTQ_DX_DX BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0xd2
+
+TEXT ·popcntSliceAsm(SB),4,$0-32
+XORQ AX, AX
+MOVQ s+0(FP), SI
+MOVQ s_len+8(FP), CX
+TESTQ CX, CX
+JZ popcntSliceEnd
+popcntSliceLoop:
+BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0x16 // POPCNTQ (SI), DX
+ADDQ DX, AX
+ADDQ $8, SI
+LOOP popcntSliceLoop
+popcntSliceEnd:
+MOVQ AX, ret+24(FP)
+RET
+
+TEXT ·popcntMaskSliceAsm(SB),4,$0-56
+XORQ AX, AX
+MOVQ s+0(FP), SI
+MOVQ s_len+8(FP), CX
+TESTQ CX, CX
+JZ popcntMaskSliceEnd
+MOVQ m+24(FP), DI
+popcntMaskSliceLoop:
+MOVQ (DI), DX
+NOTQ DX
+ANDQ (SI), DX
+POPCNTQ_DX_DX
+ADDQ DX, AX
+ADDQ $8, SI
+ADDQ $8, DI
+LOOP popcntMaskSliceLoop
+popcntMaskSliceEnd:
+MOVQ AX, ret+48(FP)
+RET
+
+TEXT ·popcntAndSliceAsm(SB),4,$0-56
+XORQ AX, AX
+MOVQ s+0(FP), SI
+MOVQ s_len+8(FP), CX
+TESTQ CX, CX
+JZ popcntAndSliceEnd
+MOVQ m+24(FP), DI
+popcntAndSliceLoop:
+MOVQ (DI), DX
+ANDQ (SI), DX
+POPCNTQ_DX_DX
+ADDQ DX, AX
+ADDQ $8, SI
+ADDQ $8, DI
+LOOP popcntAndSliceLoop
+popcntAndSliceEnd:
+MOVQ AX, ret+48(FP)
+RET
+
+TEXT ·popcntOrSliceAsm(SB),4,$0-56
+XORQ AX, AX
+MOVQ s+0(FP), SI
+MOVQ s_len+8(FP), CX
+TESTQ CX, CX
+JZ popcntOrSliceEnd
+MOVQ m+24(FP), DI
+popcntOrSliceLoop:
+MOVQ (DI), DX
+ORQ (SI), DX
+POPCNTQ_DX_DX
+ADDQ DX, AX
+ADDQ $8, SI
+ADDQ $8, DI
+LOOP popcntOrSliceLoop
+popcntOrSliceEnd:
+MOVQ AX, ret+48(FP)
+RET
+
+TEXT ·popcntXorSliceAsm(SB),4,$0-56
+XORQ AX, AX
+MOVQ s+0(FP), SI
+MOVQ s_len+8(FP), CX
+TESTQ CX, CX
+JZ popcntXorSliceEnd
+MOVQ m+24(FP), DI
+popcntXorSliceLoop:
+MOVQ (DI), DX
+XORQ (SI), DX
+POPCNTQ_DX_DX
+ADDQ DX, AX
+ADDQ $8, SI
+ADDQ $8, DI
+LOOP popcntXorSliceLoop
+popcntXorSliceEnd:
+MOVQ AX, ret+48(FP)
+RET
diff --git a/vendor/github.com/willf/bitset/popcnt_generic.go b/vendor/github.com/willf/bitset/popcnt_generic.go
new file mode 100644
index 000000000..21e0ff7b4
--- /dev/null
+++ b/vendor/github.com/willf/bitset/popcnt_generic.go
@@ -0,0 +1,24 @@
+// +build !go1.9
+// +build !amd64 appengine
+
+package bitset
+
+func popcntSlice(s []uint64) uint64 {
+ return popcntSliceGo(s)
+}
+
+func popcntMaskSlice(s, m []uint64) uint64 {
+ return popcntMaskSliceGo(s, m)
+}
+
+func popcntAndSlice(s, m []uint64) uint64 {
+ return popcntAndSliceGo(s, m)
+}
+
+func popcntOrSlice(s, m []uint64) uint64 {
+ return popcntOrSliceGo(s, m)
+}
+
+func popcntXorSlice(s, m []uint64) uint64 {
+ return popcntXorSliceGo(s, m)
+}
diff --git a/vendor/github.com/willf/bitset/trailing_zeros_18.go b/vendor/github.com/willf/bitset/trailing_zeros_18.go
new file mode 100644
index 000000000..c52b61be9
--- /dev/null
+++ b/vendor/github.com/willf/bitset/trailing_zeros_18.go
@@ -0,0 +1,14 @@
+// +build !go1.9
+
+package bitset
+
+var deBruijn = [...]byte{
+ 0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4,
+ 62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5,
+ 63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11,
+ 54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6,
+}
+
+func trailingZeroes64(v uint64) uint {
+ return uint(deBruijn[((v&-v)*0x03f79d71b4ca8b09)>>58])
+}
diff --git a/vendor/github.com/willf/bitset/trailing_zeros_19.go b/vendor/github.com/willf/bitset/trailing_zeros_19.go
new file mode 100644
index 000000000..36a988e71
--- /dev/null
+++ b/vendor/github.com/willf/bitset/trailing_zeros_19.go
@@ -0,0 +1,9 @@
+// +build go1.9
+
+package bitset
+
+import "math/bits"
+
+func trailingZeroes64(v uint64) uint {
+ return uint(bits.TrailingZeros64(v))
+}
diff --git a/vendor/golang.org/x/sys/cpu/byteorder.go b/vendor/golang.org/x/sys/cpu/byteorder.go
index ed8da8dea..dcbb14ef3 100644
--- a/vendor/golang.org/x/sys/cpu/byteorder.go
+++ b/vendor/golang.org/x/sys/cpu/byteorder.go
@@ -39,20 +39,25 @@ func (bigEndian) Uint64(b []byte) uint64 {
uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
}
-// hostByteOrder returns binary.LittleEndian on little-endian machines and
-// binary.BigEndian on big-endian machines.
+// hostByteOrder returns littleEndian on little-endian machines and
+// bigEndian on big-endian machines.
func hostByteOrder() byteOrder {
switch runtime.GOARCH {
case "386", "amd64", "amd64p32",
+ "alpha",
"arm", "arm64",
"mipsle", "mips64le", "mips64p32le",
+ "nios2",
"ppc64le",
- "riscv", "riscv64":
+ "riscv", "riscv64",
+ "sh":
return littleEndian{}
case "armbe", "arm64be",
+ "m68k",
"mips", "mips64", "mips64p32",
"ppc", "ppc64",
"s390", "s390x",
+ "shbe",
"sparc", "sparc64":
return bigEndian{}
}
diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh
index 780e387e3..53a249312 100644
--- a/vendor/golang.org/x/sys/unix/mkerrors.sh
+++ b/vendor/golang.org/x/sys/unix/mkerrors.sh
@@ -107,6 +107,7 @@ includes_FreeBSD='
#include
#include
#include
+#include
#include
#include
#include
@@ -297,6 +298,7 @@ includes_NetBSD='
#include
#include
#include
+#include
#include
#include
#include
@@ -325,6 +327,7 @@ includes_OpenBSD='
#include
#include
#include
+#include
#include
#include
#include
@@ -507,9 +510,11 @@ ccflags="$@"
$2 ~ /^(CLOCK|TIMER)_/ ||
$2 ~ /^CAN_/ ||
$2 ~ /^CAP_/ ||
+ $2 ~ /^CP_/ ||
+ $2 ~ /^CPUSTATES$/ ||
$2 ~ /^ALG_/ ||
$2 ~ /^FS_(POLICY_FLAGS|KEY_DESC|ENCRYPTION_MODE|[A-Z0-9_]+_KEY_SIZE)/ ||
- $2 ~ /^FS_IOC_.*(ENCRYPTION|VERITY|GETFLAGS)/ ||
+ $2 ~ /^FS_IOC_.*(ENCRYPTION|VERITY|[GS]ETFLAGS)/ ||
$2 ~ /^FS_VERITY_/ ||
$2 ~ /^FSCRYPT_/ ||
$2 ~ /^GRND_/ ||
diff --git a/vendor/golang.org/x/sys/unix/syscall_bsd.go b/vendor/golang.org/x/sys/unix/syscall_bsd.go
index 68605db62..60bbe10ad 100644
--- a/vendor/golang.org/x/sys/unix/syscall_bsd.go
+++ b/vendor/golang.org/x/sys/unix/syscall_bsd.go
@@ -527,6 +527,23 @@ func SysctlClockinfo(name string) (*Clockinfo, error) {
return &ci, nil
}
+func SysctlTimeval(name string) (*Timeval, error) {
+ mib, err := sysctlmib(name)
+ if err != nil {
+ return nil, err
+ }
+
+ var tv Timeval
+ n := uintptr(unsafe.Sizeof(tv))
+ if err := sysctl(mib, (*byte)(unsafe.Pointer(&tv)), &n, nil, 0); err != nil {
+ return nil, err
+ }
+ if n != unsafe.Sizeof(tv) {
+ return nil, EIO
+ }
+ return &tv, nil
+}
+
//sys utimes(path string, timeval *[2]Timeval) (err error)
func Utimes(path string, tv []Timeval) error {
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux.go b/vendor/golang.org/x/sys/unix/syscall_linux.go
index 942a4bbf7..fad483bb9 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux.go
@@ -97,6 +97,12 @@ func IoctlSetRTCTime(fd int, value *RTCTime) error {
return err
}
+func IoctlSetRTCWkAlrm(fd int, value *RTCWkAlrm) error {
+ err := ioctl(fd, RTC_WKALM_SET, uintptr(unsafe.Pointer(value)))
+ runtime.KeepAlive(value)
+ return err
+}
+
func IoctlGetUint32(fd int, req uint) (uint32, error) {
var value uint32
err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
@@ -109,6 +115,12 @@ func IoctlGetRTCTime(fd int) (*RTCTime, error) {
return &value, err
}
+func IoctlGetRTCWkAlrm(fd int) (*RTCWkAlrm, error) {
+ var value RTCWkAlrm
+ err := ioctl(fd, RTC_WKALM_RD, uintptr(unsafe.Pointer(&value)))
+ return &value, err
+}
+
//sys Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error)
func Link(oldpath string, newpath string) (err error) {
@@ -1938,6 +1950,20 @@ func Vmsplice(fd int, iovs []Iovec, flags int) (int, error) {
return int(n), nil
}
+func isGroupMember(gid int) bool {
+ groups, err := Getgroups()
+ if err != nil {
+ return false
+ }
+
+ for _, g := range groups {
+ if g == gid {
+ return true
+ }
+ }
+ return false
+}
+
//sys faccessat(dirfd int, path string, mode uint32) (err error)
func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
@@ -1995,7 +2021,7 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
gid = Getgid()
}
- if uint32(gid) == st.Gid {
+ if uint32(gid) == st.Gid || isGroupMember(gid) {
fmode = (st.Mode >> 3) & 7
} else {
fmode = st.Mode & 7
@@ -2096,6 +2122,18 @@ func Klogset(typ int, arg int) (err error) {
return nil
}
+// RemoteIovec is Iovec with the pointer replaced with an integer.
+// It is used for ProcessVMReadv and ProcessVMWritev, where the pointer
+// refers to a location in a different process' address space, which
+// would confuse the Go garbage collector.
+type RemoteIovec struct {
+ Base uintptr
+ Len int
+}
+
+//sys ProcessVMReadv(pid int, localIov []Iovec, remoteIov []RemoteIovec, flags uint) (n int, err error) = SYS_PROCESS_VM_READV
+//sys ProcessVMWritev(pid int, localIov []Iovec, remoteIov []RemoteIovec, flags uint) (n int, err error) = SYS_PROCESS_VM_WRITEV
+
/*
* Unimplemented
*/
diff --git a/vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go b/vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go
index 848245873..3689c8084 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_freebsd_386.go
@@ -339,6 +339,12 @@ const (
CLOCK_UPTIME_FAST = 0x8
CLOCK_UPTIME_PRECISE = 0x7
CLOCK_VIRTUAL = 0x1
+ CPUSTATES = 0x5
+ CP_IDLE = 0x4
+ CP_INTR = 0x3
+ CP_NICE = 0x1
+ CP_SYS = 0x2
+ CP_USER = 0x0
CREAD = 0x800
CRTSCTS = 0x30000
CS5 = 0x0
diff --git a/vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go
index 4acd101c3..b8f7c3c93 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_freebsd_amd64.go
@@ -339,6 +339,12 @@ const (
CLOCK_UPTIME_FAST = 0x8
CLOCK_UPTIME_PRECISE = 0x7
CLOCK_VIRTUAL = 0x1
+ CPUSTATES = 0x5
+ CP_IDLE = 0x4
+ CP_INTR = 0x3
+ CP_NICE = 0x1
+ CP_SYS = 0x2
+ CP_USER = 0x0
CREAD = 0x800
CRTSCTS = 0x30000
CS5 = 0x0
diff --git a/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go b/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go
index e4719873b..be14bb1a4 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm.go
@@ -339,6 +339,12 @@ const (
CLOCK_UPTIME_FAST = 0x8
CLOCK_UPTIME_PRECISE = 0x7
CLOCK_VIRTUAL = 0x1
+ CPUSTATES = 0x5
+ CP_IDLE = 0x4
+ CP_INTR = 0x3
+ CP_NICE = 0x1
+ CP_SYS = 0x2
+ CP_USER = 0x0
CREAD = 0x800
CRTSCTS = 0x30000
CS5 = 0x0
diff --git a/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm64.go
index 5e49769d9..7ce9c0081 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_freebsd_arm64.go
@@ -339,6 +339,12 @@ const (
CLOCK_UPTIME_FAST = 0x8
CLOCK_UPTIME_PRECISE = 0x7
CLOCK_VIRTUAL = 0x1
+ CPUSTATES = 0x5
+ CP_IDLE = 0x4
+ CP_INTR = 0x3
+ CP_NICE = 0x1
+ CP_SYS = 0x2
+ CP_USER = 0x0
CREAD = 0x800
CRTSCTS = 0x30000
CS5 = 0x0
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux.go b/vendor/golang.org/x/sys/unix/zerrors_linux.go
index 6e3cfec46..f8bd50c11 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux.go
@@ -160,78 +160,28 @@ const (
BPF_A = 0x10
BPF_ABS = 0x20
BPF_ADD = 0x0
- BPF_ADJ_ROOM_ENCAP_L2_MASK = 0xff
- BPF_ADJ_ROOM_ENCAP_L2_SHIFT = 0x38
BPF_ALU = 0x4
BPF_ALU64 = 0x7
BPF_AND = 0x50
- BPF_ANY = 0x0
BPF_ARSH = 0xc0
BPF_B = 0x10
BPF_BUILD_ID_SIZE = 0x14
BPF_CALL = 0x80
- BPF_DEVCG_ACC_MKNOD = 0x1
- BPF_DEVCG_ACC_READ = 0x2
- BPF_DEVCG_ACC_WRITE = 0x4
- BPF_DEVCG_DEV_BLOCK = 0x1
- BPF_DEVCG_DEV_CHAR = 0x2
BPF_DIV = 0x30
BPF_DW = 0x18
BPF_END = 0xd0
- BPF_EXIST = 0x2
BPF_EXIT = 0x90
- BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG = 0x1
- BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP = 0x4
- BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL = 0x2
BPF_FROM_BE = 0x8
BPF_FROM_LE = 0x0
BPF_FS_MAGIC = 0xcafe4a11
- BPF_F_ADJ_ROOM_ENCAP_L3_IPV4 = 0x2
- BPF_F_ADJ_ROOM_ENCAP_L3_IPV6 = 0x4
- BPF_F_ADJ_ROOM_ENCAP_L4_GRE = 0x8
- BPF_F_ADJ_ROOM_ENCAP_L4_UDP = 0x10
- BPF_F_ADJ_ROOM_FIXED_GSO = 0x1
BPF_F_ALLOW_MULTI = 0x2
BPF_F_ALLOW_OVERRIDE = 0x1
BPF_F_ANY_ALIGNMENT = 0x2
- BPF_F_CLONE = 0x200
- BPF_F_CTXLEN_MASK = 0xfffff00000000
- BPF_F_CURRENT_CPU = 0xffffffff
- BPF_F_CURRENT_NETNS = -0x1
- BPF_F_DONT_FRAGMENT = 0x4
- BPF_F_FAST_STACK_CMP = 0x200
- BPF_F_HDR_FIELD_MASK = 0xf
- BPF_F_INDEX_MASK = 0xffffffff
- BPF_F_INGRESS = 0x1
- BPF_F_INVALIDATE_HASH = 0x2
- BPF_F_LOCK = 0x4
- BPF_F_MARK_ENFORCE = 0x40
- BPF_F_MARK_MANGLED_0 = 0x20
- BPF_F_MMAPABLE = 0x400
- BPF_F_NO_COMMON_LRU = 0x2
- BPF_F_NO_PREALLOC = 0x1
- BPF_F_NUMA_NODE = 0x4
- BPF_F_PSEUDO_HDR = 0x10
BPF_F_QUERY_EFFECTIVE = 0x1
- BPF_F_RDONLY = 0x8
- BPF_F_RDONLY_PROG = 0x80
- BPF_F_RECOMPUTE_CSUM = 0x1
BPF_F_REPLACE = 0x4
- BPF_F_REUSE_STACKID = 0x400
- BPF_F_SEQ_NUMBER = 0x8
- BPF_F_SKIP_FIELD_MASK = 0xff
- BPF_F_STACK_BUILD_ID = 0x20
BPF_F_STRICT_ALIGNMENT = 0x1
- BPF_F_SYSCTL_BASE_NAME = 0x1
BPF_F_TEST_RND_HI32 = 0x4
BPF_F_TEST_STATE_FREQ = 0x8
- BPF_F_TUNINFO_IPV6 = 0x1
- BPF_F_USER_BUILD_ID = 0x800
- BPF_F_USER_STACK = 0x100
- BPF_F_WRONLY = 0x10
- BPF_F_WRONLY_PROG = 0x100
- BPF_F_ZERO_CSUM_TX = 0x2
- BPF_F_ZERO_SEED = 0x40
BPF_H = 0x8
BPF_IMM = 0x0
BPF_IND = 0x40
@@ -267,7 +217,6 @@ const (
BPF_MUL = 0x20
BPF_NEG = 0x80
BPF_NET_OFF = -0x100000
- BPF_NOEXIST = 0x1
BPF_OBJ_NAME_LEN = 0x10
BPF_OR = 0x40
BPF_PSEUDO_CALL = 0x1
@@ -275,12 +224,6 @@ const (
BPF_PSEUDO_MAP_VALUE = 0x2
BPF_RET = 0x6
BPF_RSH = 0x70
- BPF_SK_STORAGE_GET_F_CREATE = 0x1
- BPF_SOCK_OPS_ALL_CB_FLAGS = 0xf
- BPF_SOCK_OPS_RETRANS_CB_FLAG = 0x2
- BPF_SOCK_OPS_RTO_CB_FLAG = 0x1
- BPF_SOCK_OPS_RTT_CB_FLAG = 0x8
- BPF_SOCK_OPS_STATE_CB_FLAG = 0x4
BPF_ST = 0x2
BPF_STX = 0x3
BPF_SUB = 0x10
@@ -378,12 +321,14 @@ const (
CLOCK_TXINT = 0x3
CLONE_ARGS_SIZE_VER0 = 0x40
CLONE_ARGS_SIZE_VER1 = 0x50
+ CLONE_ARGS_SIZE_VER2 = 0x58
CLONE_CHILD_CLEARTID = 0x200000
CLONE_CHILD_SETTID = 0x1000000
CLONE_CLEAR_SIGHAND = 0x100000000
CLONE_DETACHED = 0x400000
CLONE_FILES = 0x400
CLONE_FS = 0x200
+ CLONE_INTO_CGROUP = 0x200000000
CLONE_IO = 0x80000000
CLONE_NEWCGROUP = 0x2000000
CLONE_NEWIPC = 0x8000000
@@ -598,7 +543,9 @@ const (
FAN_DELETE = 0x200
FAN_DELETE_SELF = 0x400
FAN_DENY = 0x2
+ FAN_DIR_MODIFY = 0x80000
FAN_ENABLE_AUDIT = 0x40
+ FAN_EVENT_INFO_TYPE_DFID_NAME = 0x2
FAN_EVENT_INFO_TYPE_FID = 0x1
FAN_EVENT_METADATA_LEN = 0x18
FAN_EVENT_ON_CHILD = 0x8000000
@@ -2108,8 +2055,6 @@ const (
TCOFLUSH = 0x1
TCOOFF = 0x0
TCOON = 0x1
- TCP_BPF_IW = 0x3e9
- TCP_BPF_SNDCWND_CLAMP = 0x3ea
TCP_CC_INFO = 0x1a
TCP_CM_INQ = 0x24
TCP_CONGESTION = 0xd
@@ -2384,8 +2329,9 @@ const (
XDP_COPY = 0x2
XDP_FLAGS_DRV_MODE = 0x4
XDP_FLAGS_HW_MODE = 0x8
- XDP_FLAGS_MASK = 0xf
+ XDP_FLAGS_MASK = 0x1f
XDP_FLAGS_MODES = 0xe
+ XDP_FLAGS_REPLACE = 0x10
XDP_FLAGS_SKB_MODE = 0x2
XDP_FLAGS_UPDATE_IF_NOEXIST = 0x1
XDP_MMAP_OFFSETS = 0x1
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go
index 5e974110d..11b25f68c 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go
@@ -75,8 +75,10 @@ const (
FP_XSTATE_MAGIC2 = 0x46505845
FS_IOC_ENABLE_VERITY = 0x40806685
FS_IOC_GETFLAGS = 0x80046601
+ FS_IOC_GET_ENCRYPTION_NONCE = 0x8010661b
FS_IOC_GET_ENCRYPTION_POLICY = 0x400c6615
FS_IOC_GET_ENCRYPTION_PWSALT = 0x40106614
+ FS_IOC_SETFLAGS = 0x40046602
FS_IOC_SET_ENCRYPTION_POLICY = 0x800c6613
F_GETLK = 0xc
F_GETLK64 = 0xc
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go
index 47a57fe46..f92cff6ea 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go
@@ -75,8 +75,10 @@ const (
FP_XSTATE_MAGIC2 = 0x46505845
FS_IOC_ENABLE_VERITY = 0x40806685
FS_IOC_GETFLAGS = 0x80086601
+ FS_IOC_GET_ENCRYPTION_NONCE = 0x8010661b
FS_IOC_GET_ENCRYPTION_POLICY = 0x400c6615
FS_IOC_GET_ENCRYPTION_PWSALT = 0x40106614
+ FS_IOC_SETFLAGS = 0x40086602
FS_IOC_SET_ENCRYPTION_POLICY = 0x800c6613
F_GETLK = 0x5
F_GETLK64 = 0x5
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go
index df2eea4bb..12bcbf88d 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go
@@ -74,8 +74,10 @@ const (
FLUSHO = 0x1000
FS_IOC_ENABLE_VERITY = 0x40806685
FS_IOC_GETFLAGS = 0x80046601
+ FS_IOC_GET_ENCRYPTION_NONCE = 0x8010661b
FS_IOC_GET_ENCRYPTION_POLICY = 0x400c6615
FS_IOC_GET_ENCRYPTION_PWSALT = 0x40106614
+ FS_IOC_SETFLAGS = 0x40046602
FS_IOC_SET_ENCRYPTION_POLICY = 0x800c6613
F_GETLK = 0xc
F_GETLK64 = 0xc
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go
index 4e1214217..8b0e024b9 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go
@@ -77,8 +77,10 @@ const (
FPSIMD_MAGIC = 0x46508001
FS_IOC_ENABLE_VERITY = 0x40806685
FS_IOC_GETFLAGS = 0x80086601
+ FS_IOC_GET_ENCRYPTION_NONCE = 0x8010661b
FS_IOC_GET_ENCRYPTION_POLICY = 0x400c6615
FS_IOC_GET_ENCRYPTION_PWSALT = 0x40106614
+ FS_IOC_SETFLAGS = 0x40086602
FS_IOC_SET_ENCRYPTION_POLICY = 0x800c6613
F_GETLK = 0x5
F_GETLK64 = 0x5
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go
index a23b08029..eeadea943 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go
@@ -74,8 +74,10 @@ const (
FLUSHO = 0x2000
FS_IOC_ENABLE_VERITY = 0x80806685
FS_IOC_GETFLAGS = 0x40046601
+ FS_IOC_GET_ENCRYPTION_NONCE = 0x4010661b
FS_IOC_GET_ENCRYPTION_POLICY = 0x800c6615
FS_IOC_GET_ENCRYPTION_PWSALT = 0x80106614
+ FS_IOC_SETFLAGS = 0x80046602
FS_IOC_SET_ENCRYPTION_POLICY = 0x400c6613
F_GETLK = 0x21
F_GETLK64 = 0x21
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go
index a5a921e43..0be6c4ccc 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go
@@ -74,8 +74,10 @@ const (
FLUSHO = 0x2000
FS_IOC_ENABLE_VERITY = 0x80806685
FS_IOC_GETFLAGS = 0x40086601
+ FS_IOC_GET_ENCRYPTION_NONCE = 0x4010661b
FS_IOC_GET_ENCRYPTION_POLICY = 0x800c6615
FS_IOC_GET_ENCRYPTION_PWSALT = 0x80106614
+ FS_IOC_SETFLAGS = 0x80086602
FS_IOC_SET_ENCRYPTION_POLICY = 0x400c6613
F_GETLK = 0xe
F_GETLK64 = 0xe
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go
index d088e197b..0880b745c 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go
@@ -74,8 +74,10 @@ const (
FLUSHO = 0x2000
FS_IOC_ENABLE_VERITY = 0x80806685
FS_IOC_GETFLAGS = 0x40086601
+ FS_IOC_GET_ENCRYPTION_NONCE = 0x4010661b
FS_IOC_GET_ENCRYPTION_POLICY = 0x800c6615
FS_IOC_GET_ENCRYPTION_PWSALT = 0x80106614
+ FS_IOC_SETFLAGS = 0x80086602
FS_IOC_SET_ENCRYPTION_POLICY = 0x400c6613
F_GETLK = 0xe
F_GETLK64 = 0xe
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go
index 0ddf9d5fe..c8a66627a 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go
@@ -74,8 +74,10 @@ const (
FLUSHO = 0x2000
FS_IOC_ENABLE_VERITY = 0x80806685
FS_IOC_GETFLAGS = 0x40046601
+ FS_IOC_GET_ENCRYPTION_NONCE = 0x4010661b
FS_IOC_GET_ENCRYPTION_POLICY = 0x800c6615
FS_IOC_GET_ENCRYPTION_PWSALT = 0x80106614
+ FS_IOC_SETFLAGS = 0x80046602
FS_IOC_SET_ENCRYPTION_POLICY = 0x400c6613
F_GETLK = 0x21
F_GETLK64 = 0x21
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go
index a93ffc180..97aae63f1 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go
@@ -74,8 +74,10 @@ const (
FLUSHO = 0x800000
FS_IOC_ENABLE_VERITY = 0x80806685
FS_IOC_GETFLAGS = 0x40086601
+ FS_IOC_GET_ENCRYPTION_NONCE = 0x4010661b
FS_IOC_GET_ENCRYPTION_POLICY = 0x800c6615
FS_IOC_GET_ENCRYPTION_PWSALT = 0x80106614
+ FS_IOC_SETFLAGS = 0x80086602
FS_IOC_SET_ENCRYPTION_POLICY = 0x400c6613
F_GETLK = 0x5
F_GETLK64 = 0xc
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go
index c1ea48b95..b0c3b0664 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go
@@ -74,8 +74,10 @@ const (
FLUSHO = 0x800000
FS_IOC_ENABLE_VERITY = 0x80806685
FS_IOC_GETFLAGS = 0x40086601
+ FS_IOC_GET_ENCRYPTION_NONCE = 0x4010661b
FS_IOC_GET_ENCRYPTION_POLICY = 0x800c6615
FS_IOC_GET_ENCRYPTION_PWSALT = 0x80106614
+ FS_IOC_SETFLAGS = 0x80086602
FS_IOC_SET_ENCRYPTION_POLICY = 0x400c6613
F_GETLK = 0x5
F_GETLK64 = 0xc
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go
index 7def950ba..0c0518193 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go
@@ -74,8 +74,10 @@ const (
FLUSHO = 0x1000
FS_IOC_ENABLE_VERITY = 0x40806685
FS_IOC_GETFLAGS = 0x80086601
+ FS_IOC_GET_ENCRYPTION_NONCE = 0x8010661b
FS_IOC_GET_ENCRYPTION_POLICY = 0x400c6615
FS_IOC_GET_ENCRYPTION_PWSALT = 0x40106614
+ FS_IOC_SETFLAGS = 0x40086602
FS_IOC_SET_ENCRYPTION_POLICY = 0x800c6613
F_GETLK = 0x5
F_GETLK64 = 0x5
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go
index d39293c87..0b96bd462 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go
@@ -74,8 +74,10 @@ const (
FLUSHO = 0x1000
FS_IOC_ENABLE_VERITY = 0x40806685
FS_IOC_GETFLAGS = 0x80086601
+ FS_IOC_GET_ENCRYPTION_NONCE = 0x8010661b
FS_IOC_GET_ENCRYPTION_POLICY = 0x400c6615
FS_IOC_GET_ENCRYPTION_PWSALT = 0x40106614
+ FS_IOC_SETFLAGS = 0x40086602
FS_IOC_SET_ENCRYPTION_POLICY = 0x800c6613
F_GETLK = 0x5
F_GETLK64 = 0x5
diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go
index 3ff3ec681..bd5c30577 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go
@@ -78,8 +78,10 @@ const (
FLUSHO = 0x1000
FS_IOC_ENABLE_VERITY = 0x80806685
FS_IOC_GETFLAGS = 0x40086601
+ FS_IOC_GET_ENCRYPTION_NONCE = 0x4010661b
FS_IOC_GET_ENCRYPTION_POLICY = 0x800c6615
FS_IOC_GET_ENCRYPTION_PWSALT = 0x80106614
+ FS_IOC_SETFLAGS = 0x80086602
FS_IOC_SET_ENCRYPTION_POLICY = 0x400c6613
F_GETLK = 0x7
F_GETLK64 = 0x7
diff --git a/vendor/golang.org/x/sys/unix/zerrors_netbsd_386.go b/vendor/golang.org/x/sys/unix/zerrors_netbsd_386.go
index 96b9b8ab3..20f3a5799 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_netbsd_386.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_netbsd_386.go
@@ -158,6 +158,12 @@ const (
CLONE_SIGHAND = 0x800
CLONE_VFORK = 0x4000
CLONE_VM = 0x100
+ CPUSTATES = 0x5
+ CP_IDLE = 0x4
+ CP_INTR = 0x3
+ CP_NICE = 0x1
+ CP_SYS = 0x2
+ CP_USER = 0x0
CREAD = 0x800
CRTSCTS = 0x10000
CS5 = 0x0
diff --git a/vendor/golang.org/x/sys/unix/zerrors_netbsd_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_netbsd_amd64.go
index ed522a84e..90b8fcd29 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_netbsd_amd64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_netbsd_amd64.go
@@ -158,6 +158,12 @@ const (
CLONE_SIGHAND = 0x800
CLONE_VFORK = 0x4000
CLONE_VM = 0x100
+ CPUSTATES = 0x5
+ CP_IDLE = 0x4
+ CP_INTR = 0x3
+ CP_NICE = 0x1
+ CP_SYS = 0x2
+ CP_USER = 0x0
CREAD = 0x800
CRTSCTS = 0x10000
CS5 = 0x0
diff --git a/vendor/golang.org/x/sys/unix/zerrors_netbsd_arm.go b/vendor/golang.org/x/sys/unix/zerrors_netbsd_arm.go
index c8d36fe99..c5c03993b 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_netbsd_arm.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_netbsd_arm.go
@@ -150,6 +150,12 @@ const (
BRKINT = 0x2
CFLUSH = 0xf
CLOCAL = 0x8000
+ CPUSTATES = 0x5
+ CP_IDLE = 0x4
+ CP_INTR = 0x3
+ CP_NICE = 0x1
+ CP_SYS = 0x2
+ CP_USER = 0x0
CREAD = 0x800
CRTSCTS = 0x10000
CS5 = 0x0
diff --git a/vendor/golang.org/x/sys/unix/zerrors_netbsd_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_netbsd_arm64.go
index f1c146a74..14dd3c1d1 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_netbsd_arm64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_netbsd_arm64.go
@@ -158,6 +158,12 @@ const (
CLONE_SIGHAND = 0x800
CLONE_VFORK = 0x4000
CLONE_VM = 0x100
+ CPUSTATES = 0x5
+ CP_IDLE = 0x4
+ CP_INTR = 0x3
+ CP_NICE = 0x1
+ CP_SYS = 0x2
+ CP_USER = 0x0
CREAD = 0x800
CRTSCTS = 0x10000
CS5 = 0x0
diff --git a/vendor/golang.org/x/sys/unix/zerrors_openbsd_386.go b/vendor/golang.org/x/sys/unix/zerrors_openbsd_386.go
index 5402bd55c..c865a10df 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_openbsd_386.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_openbsd_386.go
@@ -146,6 +146,13 @@ const (
BRKINT = 0x2
CFLUSH = 0xf
CLOCAL = 0x8000
+ CPUSTATES = 0x6
+ CP_IDLE = 0x5
+ CP_INTR = 0x4
+ CP_NICE = 0x1
+ CP_SPIN = 0x3
+ CP_SYS = 0x2
+ CP_USER = 0x0
CREAD = 0x800
CRTSCTS = 0x10000
CS5 = 0x0
diff --git a/vendor/golang.org/x/sys/unix/zerrors_openbsd_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_openbsd_amd64.go
index ffaf2d2f9..9db6b2fb6 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_openbsd_amd64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_openbsd_amd64.go
@@ -153,6 +153,13 @@ const (
CLOCK_REALTIME = 0x0
CLOCK_THREAD_CPUTIME_ID = 0x4
CLOCK_UPTIME = 0x5
+ CPUSTATES = 0x6
+ CP_IDLE = 0x5
+ CP_INTR = 0x4
+ CP_NICE = 0x1
+ CP_SPIN = 0x3
+ CP_SYS = 0x2
+ CP_USER = 0x0
CREAD = 0x800
CRTSCTS = 0x10000
CS5 = 0x0
diff --git a/vendor/golang.org/x/sys/unix/zerrors_openbsd_arm.go b/vendor/golang.org/x/sys/unix/zerrors_openbsd_arm.go
index 7aa796a64..7072526a6 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_openbsd_arm.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_openbsd_arm.go
@@ -146,6 +146,13 @@ const (
BRKINT = 0x2
CFLUSH = 0xf
CLOCAL = 0x8000
+ CPUSTATES = 0x6
+ CP_IDLE = 0x5
+ CP_INTR = 0x4
+ CP_NICE = 0x1
+ CP_SPIN = 0x3
+ CP_SYS = 0x2
+ CP_USER = 0x0
CREAD = 0x800
CRTSCTS = 0x10000
CS5 = 0x0
diff --git a/vendor/golang.org/x/sys/unix/zerrors_openbsd_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_openbsd_arm64.go
index 1792d3f13..ac5efbe5a 100644
--- a/vendor/golang.org/x/sys/unix/zerrors_openbsd_arm64.go
+++ b/vendor/golang.org/x/sys/unix/zerrors_openbsd_arm64.go
@@ -156,6 +156,13 @@ const (
CLOCK_REALTIME = 0x0
CLOCK_THREAD_CPUTIME_ID = 0x4
CLOCK_UPTIME = 0x5
+ CPUSTATES = 0x6
+ CP_IDLE = 0x5
+ CP_INTR = 0x4
+ CP_NICE = 0x1
+ CP_SPIN = 0x3
+ CP_SYS = 0x2
+ CP_USER = 0x0
CREAD = 0x800
CRTSCTS = 0x10000
CS5 = 0x0
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_linux.go b/vendor/golang.org/x/sys/unix/zsyscall_linux.go
index df217825f..f6603de4f 100644
--- a/vendor/golang.org/x/sys/unix/zsyscall_linux.go
+++ b/vendor/golang.org/x/sys/unix/zsyscall_linux.go
@@ -1847,6 +1847,52 @@ func openByHandleAt(mountFD int, fh *fileHandle, flags int) (fd int, err error)
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func ProcessVMReadv(pid int, localIov []Iovec, remoteIov []RemoteIovec, flags uint) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(localIov) > 0 {
+ _p0 = unsafe.Pointer(&localIov[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ var _p1 unsafe.Pointer
+ if len(remoteIov) > 0 {
+ _p1 = unsafe.Pointer(&remoteIov[0])
+ } else {
+ _p1 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PROCESS_VM_READV, uintptr(pid), uintptr(_p0), uintptr(len(localIov)), uintptr(_p1), uintptr(len(remoteIov)), uintptr(flags))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func ProcessVMWritev(pid int, localIov []Iovec, remoteIov []RemoteIovec, flags uint) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(localIov) > 0 {
+ _p0 = unsafe.Pointer(&localIov[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ var _p1 unsafe.Pointer
+ if len(remoteIov) > 0 {
+ _p1 = unsafe.Pointer(&remoteIov[0])
+ } else {
+ _p1 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PROCESS_VM_WRITEV, uintptr(pid), uintptr(_p0), uintptr(len(localIov)), uintptr(_p1), uintptr(len(remoteIov)), uintptr(flags))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func pipe2(p *[2]_C_int, flags int) (err error) {
_, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
if e1 != 0 {
diff --git a/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go
index 6f79227d7..b91c2ae0f 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go
@@ -125,9 +125,9 @@ type Statfs_t struct {
Owner uint32
Fsid Fsid
Charspare [80]int8
- Fstypename [16]int8
- Mntfromname [1024]int8
- Mntonname [1024]int8
+ Fstypename [16]byte
+ Mntfromname [1024]byte
+ Mntonname [1024]byte
}
type statfs_freebsd11_t struct {
@@ -150,9 +150,9 @@ type statfs_freebsd11_t struct {
Owner uint32
Fsid Fsid
Charspare [80]int8
- Fstypename [16]int8
- Mntfromname [88]int8
- Mntonname [88]int8
+ Fstypename [16]byte
+ Mntfromname [88]byte
+ Mntonname [88]byte
}
type Flock_t struct {
diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux.go b/vendor/golang.org/x/sys/unix/ztypes_linux.go
index 416f7767e..27d67ac8f 100644
--- a/vendor/golang.org/x/sys/unix/ztypes_linux.go
+++ b/vendor/golang.org/x/sys/unix/ztypes_linux.go
@@ -1871,175 +1871,249 @@ const (
)
const (
- BPF_REG_0 = 0x0
- BPF_REG_1 = 0x1
- BPF_REG_2 = 0x2
- BPF_REG_3 = 0x3
- BPF_REG_4 = 0x4
- BPF_REG_5 = 0x5
- BPF_REG_6 = 0x6
- BPF_REG_7 = 0x7
- BPF_REG_8 = 0x8
- BPF_REG_9 = 0x9
- BPF_REG_10 = 0xa
- BPF_MAP_CREATE = 0x0
- BPF_MAP_LOOKUP_ELEM = 0x1
- BPF_MAP_UPDATE_ELEM = 0x2
- BPF_MAP_DELETE_ELEM = 0x3
- BPF_MAP_GET_NEXT_KEY = 0x4
- BPF_PROG_LOAD = 0x5
- BPF_OBJ_PIN = 0x6
- BPF_OBJ_GET = 0x7
- BPF_PROG_ATTACH = 0x8
- BPF_PROG_DETACH = 0x9
- BPF_PROG_TEST_RUN = 0xa
- BPF_PROG_GET_NEXT_ID = 0xb
- BPF_MAP_GET_NEXT_ID = 0xc
- BPF_PROG_GET_FD_BY_ID = 0xd
- BPF_MAP_GET_FD_BY_ID = 0xe
- BPF_OBJ_GET_INFO_BY_FD = 0xf
- BPF_PROG_QUERY = 0x10
- BPF_RAW_TRACEPOINT_OPEN = 0x11
- BPF_BTF_LOAD = 0x12
- BPF_BTF_GET_FD_BY_ID = 0x13
- BPF_TASK_FD_QUERY = 0x14
- BPF_MAP_LOOKUP_AND_DELETE_ELEM = 0x15
- BPF_MAP_FREEZE = 0x16
- BPF_BTF_GET_NEXT_ID = 0x17
- BPF_MAP_TYPE_UNSPEC = 0x0
- BPF_MAP_TYPE_HASH = 0x1
- BPF_MAP_TYPE_ARRAY = 0x2
- BPF_MAP_TYPE_PROG_ARRAY = 0x3
- BPF_MAP_TYPE_PERF_EVENT_ARRAY = 0x4
- BPF_MAP_TYPE_PERCPU_HASH = 0x5
- BPF_MAP_TYPE_PERCPU_ARRAY = 0x6
- BPF_MAP_TYPE_STACK_TRACE = 0x7
- BPF_MAP_TYPE_CGROUP_ARRAY = 0x8
- BPF_MAP_TYPE_LRU_HASH = 0x9
- BPF_MAP_TYPE_LRU_PERCPU_HASH = 0xa
- BPF_MAP_TYPE_LPM_TRIE = 0xb
- BPF_MAP_TYPE_ARRAY_OF_MAPS = 0xc
- BPF_MAP_TYPE_HASH_OF_MAPS = 0xd
- BPF_MAP_TYPE_DEVMAP = 0xe
- BPF_MAP_TYPE_SOCKMAP = 0xf
- BPF_MAP_TYPE_CPUMAP = 0x10
- BPF_MAP_TYPE_XSKMAP = 0x11
- BPF_MAP_TYPE_SOCKHASH = 0x12
- BPF_MAP_TYPE_CGROUP_STORAGE = 0x13
- BPF_MAP_TYPE_REUSEPORT_SOCKARRAY = 0x14
- BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE = 0x15
- BPF_MAP_TYPE_QUEUE = 0x16
- BPF_MAP_TYPE_STACK = 0x17
- BPF_MAP_TYPE_SK_STORAGE = 0x18
- BPF_MAP_TYPE_DEVMAP_HASH = 0x19
- BPF_PROG_TYPE_UNSPEC = 0x0
- BPF_PROG_TYPE_SOCKET_FILTER = 0x1
- BPF_PROG_TYPE_KPROBE = 0x2
- BPF_PROG_TYPE_SCHED_CLS = 0x3
- BPF_PROG_TYPE_SCHED_ACT = 0x4
- BPF_PROG_TYPE_TRACEPOINT = 0x5
- BPF_PROG_TYPE_XDP = 0x6
- BPF_PROG_TYPE_PERF_EVENT = 0x7
- BPF_PROG_TYPE_CGROUP_SKB = 0x8
- BPF_PROG_TYPE_CGROUP_SOCK = 0x9
- BPF_PROG_TYPE_LWT_IN = 0xa
- BPF_PROG_TYPE_LWT_OUT = 0xb
- BPF_PROG_TYPE_LWT_XMIT = 0xc
- BPF_PROG_TYPE_SOCK_OPS = 0xd
- BPF_PROG_TYPE_SK_SKB = 0xe
- BPF_PROG_TYPE_CGROUP_DEVICE = 0xf
- BPF_PROG_TYPE_SK_MSG = 0x10
- BPF_PROG_TYPE_RAW_TRACEPOINT = 0x11
- BPF_PROG_TYPE_CGROUP_SOCK_ADDR = 0x12
- BPF_PROG_TYPE_LWT_SEG6LOCAL = 0x13
- BPF_PROG_TYPE_LIRC_MODE2 = 0x14
- BPF_PROG_TYPE_SK_REUSEPORT = 0x15
- BPF_PROG_TYPE_FLOW_DISSECTOR = 0x16
- BPF_PROG_TYPE_CGROUP_SYSCTL = 0x17
- BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE = 0x18
- BPF_PROG_TYPE_CGROUP_SOCKOPT = 0x19
- BPF_PROG_TYPE_TRACING = 0x1a
- BPF_CGROUP_INET_INGRESS = 0x0
- BPF_CGROUP_INET_EGRESS = 0x1
- BPF_CGROUP_INET_SOCK_CREATE = 0x2
- BPF_CGROUP_SOCK_OPS = 0x3
- BPF_SK_SKB_STREAM_PARSER = 0x4
- BPF_SK_SKB_STREAM_VERDICT = 0x5
- BPF_CGROUP_DEVICE = 0x6
- BPF_SK_MSG_VERDICT = 0x7
- BPF_CGROUP_INET4_BIND = 0x8
- BPF_CGROUP_INET6_BIND = 0x9
- BPF_CGROUP_INET4_CONNECT = 0xa
- BPF_CGROUP_INET6_CONNECT = 0xb
- BPF_CGROUP_INET4_POST_BIND = 0xc
- BPF_CGROUP_INET6_POST_BIND = 0xd
- BPF_CGROUP_UDP4_SENDMSG = 0xe
- BPF_CGROUP_UDP6_SENDMSG = 0xf
- BPF_LIRC_MODE2 = 0x10
- BPF_FLOW_DISSECTOR = 0x11
- BPF_CGROUP_SYSCTL = 0x12
- BPF_CGROUP_UDP4_RECVMSG = 0x13
- BPF_CGROUP_UDP6_RECVMSG = 0x14
- BPF_CGROUP_GETSOCKOPT = 0x15
- BPF_CGROUP_SETSOCKOPT = 0x16
- BPF_TRACE_RAW_TP = 0x17
- BPF_TRACE_FENTRY = 0x18
- BPF_TRACE_FEXIT = 0x19
- BPF_STACK_BUILD_ID_EMPTY = 0x0
- BPF_STACK_BUILD_ID_VALID = 0x1
- BPF_STACK_BUILD_ID_IP = 0x2
- BPF_ADJ_ROOM_NET = 0x0
- BPF_ADJ_ROOM_MAC = 0x1
- BPF_HDR_START_MAC = 0x0
- BPF_HDR_START_NET = 0x1
- BPF_LWT_ENCAP_SEG6 = 0x0
- BPF_LWT_ENCAP_SEG6_INLINE = 0x1
- BPF_LWT_ENCAP_IP = 0x2
- BPF_OK = 0x0
- BPF_DROP = 0x2
- BPF_REDIRECT = 0x7
- BPF_LWT_REROUTE = 0x80
- BPF_SOCK_OPS_VOID = 0x0
- BPF_SOCK_OPS_TIMEOUT_INIT = 0x1
- BPF_SOCK_OPS_RWND_INIT = 0x2
- BPF_SOCK_OPS_TCP_CONNECT_CB = 0x3
- BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB = 0x4
- BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB = 0x5
- BPF_SOCK_OPS_NEEDS_ECN = 0x6
- BPF_SOCK_OPS_BASE_RTT = 0x7
- BPF_SOCK_OPS_RTO_CB = 0x8
- BPF_SOCK_OPS_RETRANS_CB = 0x9
- BPF_SOCK_OPS_STATE_CB = 0xa
- BPF_SOCK_OPS_TCP_LISTEN_CB = 0xb
- BPF_SOCK_OPS_RTT_CB = 0xc
- BPF_TCP_ESTABLISHED = 0x1
- BPF_TCP_SYN_SENT = 0x2
- BPF_TCP_SYN_RECV = 0x3
- BPF_TCP_FIN_WAIT1 = 0x4
- BPF_TCP_FIN_WAIT2 = 0x5
- BPF_TCP_TIME_WAIT = 0x6
- BPF_TCP_CLOSE = 0x7
- BPF_TCP_CLOSE_WAIT = 0x8
- BPF_TCP_LAST_ACK = 0x9
- BPF_TCP_LISTEN = 0xa
- BPF_TCP_CLOSING = 0xb
- BPF_TCP_NEW_SYN_RECV = 0xc
- BPF_TCP_MAX_STATES = 0xd
- BPF_FIB_LKUP_RET_SUCCESS = 0x0
- BPF_FIB_LKUP_RET_BLACKHOLE = 0x1
- BPF_FIB_LKUP_RET_UNREACHABLE = 0x2
- BPF_FIB_LKUP_RET_PROHIBIT = 0x3
- BPF_FIB_LKUP_RET_NOT_FWDED = 0x4
- BPF_FIB_LKUP_RET_FWD_DISABLED = 0x5
- BPF_FIB_LKUP_RET_UNSUPP_LWT = 0x6
- BPF_FIB_LKUP_RET_NO_NEIGH = 0x7
- BPF_FIB_LKUP_RET_FRAG_NEEDED = 0x8
- BPF_FD_TYPE_RAW_TRACEPOINT = 0x0
- BPF_FD_TYPE_TRACEPOINT = 0x1
- BPF_FD_TYPE_KPROBE = 0x2
- BPF_FD_TYPE_KRETPROBE = 0x3
- BPF_FD_TYPE_UPROBE = 0x4
- BPF_FD_TYPE_URETPROBE = 0x5
+ BPF_REG_0 = 0x0
+ BPF_REG_1 = 0x1
+ BPF_REG_2 = 0x2
+ BPF_REG_3 = 0x3
+ BPF_REG_4 = 0x4
+ BPF_REG_5 = 0x5
+ BPF_REG_6 = 0x6
+ BPF_REG_7 = 0x7
+ BPF_REG_8 = 0x8
+ BPF_REG_9 = 0x9
+ BPF_REG_10 = 0xa
+ BPF_MAP_CREATE = 0x0
+ BPF_MAP_LOOKUP_ELEM = 0x1
+ BPF_MAP_UPDATE_ELEM = 0x2
+ BPF_MAP_DELETE_ELEM = 0x3
+ BPF_MAP_GET_NEXT_KEY = 0x4
+ BPF_PROG_LOAD = 0x5
+ BPF_OBJ_PIN = 0x6
+ BPF_OBJ_GET = 0x7
+ BPF_PROG_ATTACH = 0x8
+ BPF_PROG_DETACH = 0x9
+ BPF_PROG_TEST_RUN = 0xa
+ BPF_PROG_GET_NEXT_ID = 0xb
+ BPF_MAP_GET_NEXT_ID = 0xc
+ BPF_PROG_GET_FD_BY_ID = 0xd
+ BPF_MAP_GET_FD_BY_ID = 0xe
+ BPF_OBJ_GET_INFO_BY_FD = 0xf
+ BPF_PROG_QUERY = 0x10
+ BPF_RAW_TRACEPOINT_OPEN = 0x11
+ BPF_BTF_LOAD = 0x12
+ BPF_BTF_GET_FD_BY_ID = 0x13
+ BPF_TASK_FD_QUERY = 0x14
+ BPF_MAP_LOOKUP_AND_DELETE_ELEM = 0x15
+ BPF_MAP_FREEZE = 0x16
+ BPF_BTF_GET_NEXT_ID = 0x17
+ BPF_MAP_LOOKUP_BATCH = 0x18
+ BPF_MAP_LOOKUP_AND_DELETE_BATCH = 0x19
+ BPF_MAP_UPDATE_BATCH = 0x1a
+ BPF_MAP_DELETE_BATCH = 0x1b
+ BPF_LINK_CREATE = 0x1c
+ BPF_LINK_UPDATE = 0x1d
+ BPF_MAP_TYPE_UNSPEC = 0x0
+ BPF_MAP_TYPE_HASH = 0x1
+ BPF_MAP_TYPE_ARRAY = 0x2
+ BPF_MAP_TYPE_PROG_ARRAY = 0x3
+ BPF_MAP_TYPE_PERF_EVENT_ARRAY = 0x4
+ BPF_MAP_TYPE_PERCPU_HASH = 0x5
+ BPF_MAP_TYPE_PERCPU_ARRAY = 0x6
+ BPF_MAP_TYPE_STACK_TRACE = 0x7
+ BPF_MAP_TYPE_CGROUP_ARRAY = 0x8
+ BPF_MAP_TYPE_LRU_HASH = 0x9
+ BPF_MAP_TYPE_LRU_PERCPU_HASH = 0xa
+ BPF_MAP_TYPE_LPM_TRIE = 0xb
+ BPF_MAP_TYPE_ARRAY_OF_MAPS = 0xc
+ BPF_MAP_TYPE_HASH_OF_MAPS = 0xd
+ BPF_MAP_TYPE_DEVMAP = 0xe
+ BPF_MAP_TYPE_SOCKMAP = 0xf
+ BPF_MAP_TYPE_CPUMAP = 0x10
+ BPF_MAP_TYPE_XSKMAP = 0x11
+ BPF_MAP_TYPE_SOCKHASH = 0x12
+ BPF_MAP_TYPE_CGROUP_STORAGE = 0x13
+ BPF_MAP_TYPE_REUSEPORT_SOCKARRAY = 0x14
+ BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE = 0x15
+ BPF_MAP_TYPE_QUEUE = 0x16
+ BPF_MAP_TYPE_STACK = 0x17
+ BPF_MAP_TYPE_SK_STORAGE = 0x18
+ BPF_MAP_TYPE_DEVMAP_HASH = 0x19
+ BPF_MAP_TYPE_STRUCT_OPS = 0x1a
+ BPF_PROG_TYPE_UNSPEC = 0x0
+ BPF_PROG_TYPE_SOCKET_FILTER = 0x1
+ BPF_PROG_TYPE_KPROBE = 0x2
+ BPF_PROG_TYPE_SCHED_CLS = 0x3
+ BPF_PROG_TYPE_SCHED_ACT = 0x4
+ BPF_PROG_TYPE_TRACEPOINT = 0x5
+ BPF_PROG_TYPE_XDP = 0x6
+ BPF_PROG_TYPE_PERF_EVENT = 0x7
+ BPF_PROG_TYPE_CGROUP_SKB = 0x8
+ BPF_PROG_TYPE_CGROUP_SOCK = 0x9
+ BPF_PROG_TYPE_LWT_IN = 0xa
+ BPF_PROG_TYPE_LWT_OUT = 0xb
+ BPF_PROG_TYPE_LWT_XMIT = 0xc
+ BPF_PROG_TYPE_SOCK_OPS = 0xd
+ BPF_PROG_TYPE_SK_SKB = 0xe
+ BPF_PROG_TYPE_CGROUP_DEVICE = 0xf
+ BPF_PROG_TYPE_SK_MSG = 0x10
+ BPF_PROG_TYPE_RAW_TRACEPOINT = 0x11
+ BPF_PROG_TYPE_CGROUP_SOCK_ADDR = 0x12
+ BPF_PROG_TYPE_LWT_SEG6LOCAL = 0x13
+ BPF_PROG_TYPE_LIRC_MODE2 = 0x14
+ BPF_PROG_TYPE_SK_REUSEPORT = 0x15
+ BPF_PROG_TYPE_FLOW_DISSECTOR = 0x16
+ BPF_PROG_TYPE_CGROUP_SYSCTL = 0x17
+ BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE = 0x18
+ BPF_PROG_TYPE_CGROUP_SOCKOPT = 0x19
+ BPF_PROG_TYPE_TRACING = 0x1a
+ BPF_PROG_TYPE_STRUCT_OPS = 0x1b
+ BPF_PROG_TYPE_EXT = 0x1c
+ BPF_PROG_TYPE_LSM = 0x1d
+ BPF_CGROUP_INET_INGRESS = 0x0
+ BPF_CGROUP_INET_EGRESS = 0x1
+ BPF_CGROUP_INET_SOCK_CREATE = 0x2
+ BPF_CGROUP_SOCK_OPS = 0x3
+ BPF_SK_SKB_STREAM_PARSER = 0x4
+ BPF_SK_SKB_STREAM_VERDICT = 0x5
+ BPF_CGROUP_DEVICE = 0x6
+ BPF_SK_MSG_VERDICT = 0x7
+ BPF_CGROUP_INET4_BIND = 0x8
+ BPF_CGROUP_INET6_BIND = 0x9
+ BPF_CGROUP_INET4_CONNECT = 0xa
+ BPF_CGROUP_INET6_CONNECT = 0xb
+ BPF_CGROUP_INET4_POST_BIND = 0xc
+ BPF_CGROUP_INET6_POST_BIND = 0xd
+ BPF_CGROUP_UDP4_SENDMSG = 0xe
+ BPF_CGROUP_UDP6_SENDMSG = 0xf
+ BPF_LIRC_MODE2 = 0x10
+ BPF_FLOW_DISSECTOR = 0x11
+ BPF_CGROUP_SYSCTL = 0x12
+ BPF_CGROUP_UDP4_RECVMSG = 0x13
+ BPF_CGROUP_UDP6_RECVMSG = 0x14
+ BPF_CGROUP_GETSOCKOPT = 0x15
+ BPF_CGROUP_SETSOCKOPT = 0x16
+ BPF_TRACE_RAW_TP = 0x17
+ BPF_TRACE_FENTRY = 0x18
+ BPF_TRACE_FEXIT = 0x19
+ BPF_MODIFY_RETURN = 0x1a
+ BPF_LSM_MAC = 0x1b
+ BPF_ANY = 0x0
+ BPF_NOEXIST = 0x1
+ BPF_EXIST = 0x2
+ BPF_F_LOCK = 0x4
+ BPF_F_NO_PREALLOC = 0x1
+ BPF_F_NO_COMMON_LRU = 0x2
+ BPF_F_NUMA_NODE = 0x4
+ BPF_F_RDONLY = 0x8
+ BPF_F_WRONLY = 0x10
+ BPF_F_STACK_BUILD_ID = 0x20
+ BPF_F_ZERO_SEED = 0x40
+ BPF_F_RDONLY_PROG = 0x80
+ BPF_F_WRONLY_PROG = 0x100
+ BPF_F_CLONE = 0x200
+ BPF_F_MMAPABLE = 0x400
+ BPF_STACK_BUILD_ID_EMPTY = 0x0
+ BPF_STACK_BUILD_ID_VALID = 0x1
+ BPF_STACK_BUILD_ID_IP = 0x2
+ BPF_F_RECOMPUTE_CSUM = 0x1
+ BPF_F_INVALIDATE_HASH = 0x2
+ BPF_F_HDR_FIELD_MASK = 0xf
+ BPF_F_PSEUDO_HDR = 0x10
+ BPF_F_MARK_MANGLED_0 = 0x20
+ BPF_F_MARK_ENFORCE = 0x40
+ BPF_F_INGRESS = 0x1
+ BPF_F_TUNINFO_IPV6 = 0x1
+ BPF_F_SKIP_FIELD_MASK = 0xff
+ BPF_F_USER_STACK = 0x100
+ BPF_F_FAST_STACK_CMP = 0x200
+ BPF_F_REUSE_STACKID = 0x400
+ BPF_F_USER_BUILD_ID = 0x800
+ BPF_F_ZERO_CSUM_TX = 0x2
+ BPF_F_DONT_FRAGMENT = 0x4
+ BPF_F_SEQ_NUMBER = 0x8
+ BPF_F_INDEX_MASK = 0xffffffff
+ BPF_F_CURRENT_CPU = 0xffffffff
+ BPF_F_CTXLEN_MASK = 0xfffff00000000
+ BPF_F_CURRENT_NETNS = -0x1
+ BPF_F_ADJ_ROOM_FIXED_GSO = 0x1
+ BPF_F_ADJ_ROOM_ENCAP_L3_IPV4 = 0x2
+ BPF_F_ADJ_ROOM_ENCAP_L3_IPV6 = 0x4
+ BPF_F_ADJ_ROOM_ENCAP_L4_GRE = 0x8
+ BPF_F_ADJ_ROOM_ENCAP_L4_UDP = 0x10
+ BPF_ADJ_ROOM_ENCAP_L2_MASK = 0xff
+ BPF_ADJ_ROOM_ENCAP_L2_SHIFT = 0x38
+ BPF_F_SYSCTL_BASE_NAME = 0x1
+ BPF_SK_STORAGE_GET_F_CREATE = 0x1
+ BPF_F_GET_BRANCH_RECORDS_SIZE = 0x1
+ BPF_ADJ_ROOM_NET = 0x0
+ BPF_ADJ_ROOM_MAC = 0x1
+ BPF_HDR_START_MAC = 0x0
+ BPF_HDR_START_NET = 0x1
+ BPF_LWT_ENCAP_SEG6 = 0x0
+ BPF_LWT_ENCAP_SEG6_INLINE = 0x1
+ BPF_LWT_ENCAP_IP = 0x2
+ BPF_OK = 0x0
+ BPF_DROP = 0x2
+ BPF_REDIRECT = 0x7
+ BPF_LWT_REROUTE = 0x80
+ BPF_SOCK_OPS_RTO_CB_FLAG = 0x1
+ BPF_SOCK_OPS_RETRANS_CB_FLAG = 0x2
+ BPF_SOCK_OPS_STATE_CB_FLAG = 0x4
+ BPF_SOCK_OPS_RTT_CB_FLAG = 0x8
+ BPF_SOCK_OPS_ALL_CB_FLAGS = 0xf
+ BPF_SOCK_OPS_VOID = 0x0
+ BPF_SOCK_OPS_TIMEOUT_INIT = 0x1
+ BPF_SOCK_OPS_RWND_INIT = 0x2
+ BPF_SOCK_OPS_TCP_CONNECT_CB = 0x3
+ BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB = 0x4
+ BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB = 0x5
+ BPF_SOCK_OPS_NEEDS_ECN = 0x6
+ BPF_SOCK_OPS_BASE_RTT = 0x7
+ BPF_SOCK_OPS_RTO_CB = 0x8
+ BPF_SOCK_OPS_RETRANS_CB = 0x9
+ BPF_SOCK_OPS_STATE_CB = 0xa
+ BPF_SOCK_OPS_TCP_LISTEN_CB = 0xb
+ BPF_SOCK_OPS_RTT_CB = 0xc
+ BPF_TCP_ESTABLISHED = 0x1
+ BPF_TCP_SYN_SENT = 0x2
+ BPF_TCP_SYN_RECV = 0x3
+ BPF_TCP_FIN_WAIT1 = 0x4
+ BPF_TCP_FIN_WAIT2 = 0x5
+ BPF_TCP_TIME_WAIT = 0x6
+ BPF_TCP_CLOSE = 0x7
+ BPF_TCP_CLOSE_WAIT = 0x8
+ BPF_TCP_LAST_ACK = 0x9
+ BPF_TCP_LISTEN = 0xa
+ BPF_TCP_CLOSING = 0xb
+ BPF_TCP_NEW_SYN_RECV = 0xc
+ BPF_TCP_MAX_STATES = 0xd
+ TCP_BPF_IW = 0x3e9
+ TCP_BPF_SNDCWND_CLAMP = 0x3ea
+ BPF_DEVCG_ACC_MKNOD = 0x1
+ BPF_DEVCG_ACC_READ = 0x2
+ BPF_DEVCG_ACC_WRITE = 0x4
+ BPF_DEVCG_DEV_BLOCK = 0x1
+ BPF_DEVCG_DEV_CHAR = 0x2
+ BPF_FIB_LOOKUP_DIRECT = 0x1
+ BPF_FIB_LOOKUP_OUTPUT = 0x2
+ BPF_FIB_LKUP_RET_SUCCESS = 0x0
+ BPF_FIB_LKUP_RET_BLACKHOLE = 0x1
+ BPF_FIB_LKUP_RET_UNREACHABLE = 0x2
+ BPF_FIB_LKUP_RET_PROHIBIT = 0x3
+ BPF_FIB_LKUP_RET_NOT_FWDED = 0x4
+ BPF_FIB_LKUP_RET_FWD_DISABLED = 0x5
+ BPF_FIB_LKUP_RET_UNSUPP_LWT = 0x6
+ BPF_FIB_LKUP_RET_NO_NEIGH = 0x7
+ BPF_FIB_LKUP_RET_FRAG_NEEDED = 0x8
+ BPF_FD_TYPE_RAW_TRACEPOINT = 0x0
+ BPF_FD_TYPE_TRACEPOINT = 0x1
+ BPF_FD_TYPE_KPROBE = 0x2
+ BPF_FD_TYPE_KRETPROBE = 0x3
+ BPF_FD_TYPE_UPROBE = 0x4
+ BPF_FD_TYPE_URETPROBE = 0x5
+ BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG = 0x1
+ BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL = 0x2
+ BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP = 0x4
)
const (
@@ -2205,7 +2279,7 @@ const (
DEVLINK_CMD_DPIPE_ENTRIES_GET = 0x20
DEVLINK_CMD_DPIPE_HEADERS_GET = 0x21
DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET = 0x22
- DEVLINK_CMD_MAX = 0x44
+ DEVLINK_CMD_MAX = 0x48
DEVLINK_PORT_TYPE_NOTSET = 0x0
DEVLINK_PORT_TYPE_AUTO = 0x1
DEVLINK_PORT_TYPE_ETH = 0x2
@@ -2285,7 +2359,7 @@ const (
DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE = 0x3c
DEVLINK_ATTR_PAD = 0x3d
DEVLINK_ATTR_ESWITCH_ENCAP_MODE = 0x3e
- DEVLINK_ATTR_MAX = 0x8c
+ DEVLINK_ATTR_MAX = 0x90
DEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE = 0x0
DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX = 0x1
DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT = 0x0
diff --git a/vendor/golang.org/x/sys/windows/memory_windows.go b/vendor/golang.org/x/sys/windows/memory_windows.go
index f80a4204f..e409d76f0 100644
--- a/vendor/golang.org/x/sys/windows/memory_windows.go
+++ b/vendor/golang.org/x/sys/windows/memory_windows.go
@@ -23,4 +23,9 @@ const (
PAGE_EXECUTE_READ = 0x20
PAGE_EXECUTE_READWRITE = 0x40
PAGE_EXECUTE_WRITECOPY = 0x80
+
+ QUOTA_LIMITS_HARDWS_MIN_DISABLE = 0x00000002
+ QUOTA_LIMITS_HARDWS_MIN_ENABLE = 0x00000001
+ QUOTA_LIMITS_HARDWS_MAX_DISABLE = 0x00000008
+ QUOTA_LIMITS_HARDWS_MAX_ENABLE = 0x00000004
)
diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go
index 12c0544cb..62cf70e9f 100644
--- a/vendor/golang.org/x/sys/windows/syscall_windows.go
+++ b/vendor/golang.org/x/sys/windows/syscall_windows.go
@@ -308,6 +308,8 @@ func NewCallbackCDecl(fn interface{}) uintptr {
//sys GetProcessId(process Handle) (id uint32, err error)
//sys OpenThread(desiredAccess uint32, inheritHandle bool, threadId uint32) (handle Handle, err error)
//sys SetProcessPriorityBoost(process Handle, disable bool) (err error) = kernel32.SetProcessPriorityBoost
+//sys GetProcessWorkingSetSizeEx(hProcess Handle, lpMinimumWorkingSetSize *uintptr, lpMaximumWorkingSetSize *uintptr, flags *uint32)
+//sys SetProcessWorkingSetSizeEx(hProcess Handle, dwMinimumWorkingSetSize uintptr, dwMaximumWorkingSetSize uintptr, flags uint32) (err error)
// Volume Management Functions
//sys DefineDosDevice(flags uint32, deviceName *uint16, targetPath *uint16) (err error) = DefineDosDeviceW
diff --git a/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/vendor/golang.org/x/sys/windows/zsyscall_windows.go
index 2aa4fa642..8a562feed 100644
--- a/vendor/golang.org/x/sys/windows/zsyscall_windows.go
+++ b/vendor/golang.org/x/sys/windows/zsyscall_windows.go
@@ -217,6 +217,8 @@ var (
procGetProcessId = modkernel32.NewProc("GetProcessId")
procOpenThread = modkernel32.NewProc("OpenThread")
procSetProcessPriorityBoost = modkernel32.NewProc("SetProcessPriorityBoost")
+ procGetProcessWorkingSetSizeEx = modkernel32.NewProc("GetProcessWorkingSetSizeEx")
+ procSetProcessWorkingSetSizeEx = modkernel32.NewProc("SetProcessWorkingSetSizeEx")
procDefineDosDeviceW = modkernel32.NewProc("DefineDosDeviceW")
procDeleteVolumeMountPointW = modkernel32.NewProc("DeleteVolumeMountPointW")
procFindFirstVolumeW = modkernel32.NewProc("FindFirstVolumeW")
@@ -2414,6 +2416,23 @@ func SetProcessPriorityBoost(process Handle, disable bool) (err error) {
return
}
+func GetProcessWorkingSetSizeEx(hProcess Handle, lpMinimumWorkingSetSize *uintptr, lpMaximumWorkingSetSize *uintptr, flags *uint32) {
+ syscall.Syscall6(procGetProcessWorkingSetSizeEx.Addr(), 4, uintptr(hProcess), uintptr(unsafe.Pointer(lpMinimumWorkingSetSize)), uintptr(unsafe.Pointer(lpMaximumWorkingSetSize)), uintptr(unsafe.Pointer(flags)), 0, 0)
+ return
+}
+
+func SetProcessWorkingSetSizeEx(hProcess Handle, dwMinimumWorkingSetSize uintptr, dwMaximumWorkingSetSize uintptr, flags uint32) (err error) {
+ r1, _, e1 := syscall.Syscall6(procSetProcessWorkingSetSizeEx.Addr(), 4, uintptr(hProcess), uintptr(dwMinimumWorkingSetSize), uintptr(dwMaximumWorkingSetSize), uintptr(flags), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
func DefineDosDevice(flags uint32, deviceName *uint16, targetPath *uint16) (err error) {
r1, _, e1 := syscall.Syscall(procDefineDosDeviceW.Addr(), 3, uintptr(flags), uintptr(unsafe.Pointer(deviceName)), uintptr(unsafe.Pointer(targetPath)))
if r1 == 0 {
diff --git a/vendor/modules.txt b/vendor/modules.txt
index a8f7e61c5..d1683d1a5 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -127,11 +127,10 @@ github.com/census-instrumentation/opencensus-proto/gen-go/resource/v1
github.com/census-instrumentation/opencensus-proto/gen-go/trace/v1
# github.com/cespare/xxhash/v2 v2.1.1
github.com/cespare/xxhash/v2
-# github.com/checkpoint-restore/go-criu v0.0.0-20190109184317-bdb7599cd87b
-## explicit
-github.com/checkpoint-restore/go-criu/rpc
-# github.com/cilium/ebpf v0.0.0-20200617135954-7acf5cc039f4
-## explicit
+# github.com/checkpoint-restore/go-criu/v4 v4.1.0
+github.com/checkpoint-restore/go-criu/v4
+github.com/checkpoint-restore/go-criu/v4/rpc
+# github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775
github.com/cilium/ebpf
github.com/cilium/ebpf/asm
github.com/cilium/ebpf/internal
@@ -148,7 +147,6 @@ github.com/circonus-labs/circonusllhist
## explicit
github.com/container-storage-interface/spec/lib/go/csi
# github.com/containerd/console v1.0.0
-## explicit
github.com/containerd/console
# github.com/containerd/containerd v1.3.2
github.com/containerd/containerd/errdefs
@@ -176,8 +174,8 @@ github.com/coreos/go-iptables/iptables
# github.com/coreos/go-semver v0.3.0
## explicit
github.com/coreos/go-semver/semver
-# github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f
-github.com/coreos/go-systemd/dbus
+# github.com/coreos/go-systemd/v22 v22.1.0
+github.com/coreos/go-systemd/v22/dbus
# github.com/cyphar/filepath-securejoin v0.2.3-0.20190205144030-7efe413b52e1
## explicit
github.com/cyphar/filepath-securejoin
@@ -279,11 +277,11 @@ github.com/fsouza/go-dockerclient
# github.com/go-ole/go-ole v1.2.1
github.com/go-ole/go-ole
github.com/go-ole/go-ole/oleutil
-# github.com/godbus/dbus v4.1.0+incompatible => github.com/godbus/dbus v5.0.1+incompatible
-github.com/godbus/dbus
+# github.com/godbus/dbus/v5 v5.0.3
+github.com/godbus/dbus/v5
# github.com/gogo/protobuf v1.3.1
github.com/gogo/protobuf/proto
-# github.com/golang/protobuf v1.3.4
+# github.com/golang/protobuf v1.4.2 => github.com/golang/protobuf v1.3.4
## explicit
github.com/golang/protobuf/jsonpb
github.com/golang/protobuf/proto
@@ -583,10 +581,11 @@ github.com/mitchellh/hashstructure
github.com/mitchellh/mapstructure
# github.com/mitchellh/reflectwalk v1.0.1
github.com/mitchellh/reflectwalk
+# github.com/moby/sys/mountinfo v0.1.3
+github.com/moby/sys/mountinfo
# github.com/morikuni/aec v1.0.0
github.com/morikuni/aec
-# github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618
-## explicit
+# github.com/mrunalp/fileutils v0.0.0-20200520151820-abd8a0e76976
github.com/mrunalp/fileutils
# github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2
github.com/nicolai86/scaleway-sdk
@@ -634,11 +633,12 @@ github.com/opencontainers/go-digest
# github.com/opencontainers/image-spec v1.0.1
github.com/opencontainers/image-spec/specs-go
github.com/opencontainers/image-spec/specs-go/v1
-# github.com/opencontainers/runc v1.0.0-rc90
+# github.com/opencontainers/runc v1.0.0-rc92
## explicit
github.com/opencontainers/runc/libcontainer
github.com/opencontainers/runc/libcontainer/apparmor
github.com/opencontainers/runc/libcontainer/cgroups
+github.com/opencontainers/runc/libcontainer/cgroups/devices
github.com/opencontainers/runc/libcontainer/cgroups/ebpf
github.com/opencontainers/runc/libcontainer/cgroups/ebpf/devicefilter
github.com/opencontainers/runc/libcontainer/cgroups/fs
@@ -651,19 +651,17 @@ github.com/opencontainers/runc/libcontainer/devices
github.com/opencontainers/runc/libcontainer/intelrdt
github.com/opencontainers/runc/libcontainer/keys
github.com/opencontainers/runc/libcontainer/logs
-github.com/opencontainers/runc/libcontainer/mount
github.com/opencontainers/runc/libcontainer/nsenter
github.com/opencontainers/runc/libcontainer/seccomp
+github.com/opencontainers/runc/libcontainer/specconv
github.com/opencontainers/runc/libcontainer/stacktrace
github.com/opencontainers/runc/libcontainer/system
github.com/opencontainers/runc/libcontainer/user
github.com/opencontainers/runc/libcontainer/utils
github.com/opencontainers/runc/types
-# github.com/opencontainers/runtime-spec v1.0.2-0.20200307132014-f49fed0d6290
-## explicit
+# github.com/opencontainers/runtime-spec v1.0.3-0.20200728170252-4d89ac9fbff6
github.com/opencontainers/runtime-spec/specs-go
-# github.com/opencontainers/selinux v1.4.1-0.20200311111634-a2f0d9c2aafc
-## explicit
+# github.com/opencontainers/selinux v1.6.0
github.com/opencontainers/selinux/go-selinux
github.com/opencontainers/selinux/go-selinux/label
github.com/opencontainers/selinux/pkg/pwalk
@@ -726,7 +724,6 @@ github.com/shirou/gopsutil/mem
github.com/shirou/gopsutil/net
github.com/shirou/gopsutil/process
# github.com/sirupsen/logrus v1.6.0
-## explicit
github.com/sirupsen/logrus
# github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c
## explicit
@@ -763,7 +760,6 @@ github.com/ulikunitz/xz/internal/hash
github.com/ulikunitz/xz/internal/xlog
github.com/ulikunitz/xz/lzma
# github.com/vishvananda/netlink v1.1.0
-## explicit
github.com/vishvananda/netlink
github.com/vishvananda/netlink/nl
# github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df
@@ -788,6 +784,8 @@ github.com/vmware/govmomi/vim25/progress
github.com/vmware/govmomi/vim25/soap
github.com/vmware/govmomi/vim25/types
github.com/vmware/govmomi/vim25/xml
+# github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243
+github.com/willf/bitset
# github.com/zclconf/go-cty v1.4.1
## explicit
github.com/zclconf/go-cty/cty
@@ -877,7 +875,7 @@ golang.org/x/oauth2/jwt
## explicit
golang.org/x/sync/errgroup
golang.org/x/sync/semaphore
-# golang.org/x/sys v0.0.0-20200523222454-059865788121
+# golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1
## explicit
golang.org/x/sys/cpu
golang.org/x/sys/internal/unsafeheader
@@ -1076,3 +1074,4 @@ honnef.co/go/tools/version
# github.com/hashicorp/nomad/api => ./api
# github.com/kr/pty => github.com/kr/pty v1.1.5
# github.com/shirou/gopsutil => github.com/hashicorp/gopsutil v2.18.13-0.20200531184148-5aca383d4f9d+incompatible
+# github.com/golang/protobuf => github.com/golang/protobuf v1.3.4