Merge pull request #83527 from odinuge/runc-rc9

Bump dependency opencontainers/runc@v1.0.0-rc9
This commit is contained in:
Kubernetes Prow Robot
2019-10-08 03:45:44 -07:00
committed by GitHub
68 changed files with 2498 additions and 612 deletions

24
go.mod
View File

@@ -39,7 +39,7 @@ require (
github.com/containernetworking/cni v0.7.1 github.com/containernetworking/cni v0.7.1
github.com/coredns/corefile-migration v1.0.2 github.com/coredns/corefile-migration v1.0.2
github.com/coreos/etcd v3.3.15+incompatible github.com/coreos/etcd v3.3.15+incompatible
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea
github.com/coreos/rkt v1.30.0 // indirect github.com/coreos/rkt v1.30.0 // indirect
github.com/cpuguy83/go-md2man v1.0.10 github.com/cpuguy83/go-md2man v1.0.10
@@ -61,7 +61,7 @@ require (
github.com/go-openapi/strfmt v0.19.0 github.com/go-openapi/strfmt v0.19.0
github.com/go-openapi/validate v0.19.2 github.com/go-openapi/validate v0.19.2
github.com/go-ozzo/ozzo-validation v3.5.0+incompatible // indirect github.com/go-ozzo/ozzo-validation v3.5.0+incompatible // indirect
github.com/godbus/dbus v4.1.0+incompatible // indirect github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f // indirect
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903
github.com/golang/mock v1.2.0 github.com/golang/mock v1.2.0
@@ -90,16 +90,16 @@ require (
github.com/mistifyio/go-zfs v2.1.1+incompatible // indirect github.com/mistifyio/go-zfs v2.1.1+incompatible // indirect
github.com/mohae/deepcopy v0.0.0-20170603005431-491d3605edfb // indirect github.com/mohae/deepcopy v0.0.0-20170603005431-491d3605edfb // indirect
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c // indirect github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c // indirect
github.com/mrunalp/fileutils v0.0.0-20160930181131-4ee1cc9a8058 // indirect github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618 // indirect
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d
github.com/mvdan/xurls v1.1.0 github.com/mvdan/xurls v1.1.0
github.com/onsi/ginkgo v1.10.1 github.com/onsi/ginkgo v1.10.1
github.com/onsi/gomega v1.7.0 github.com/onsi/gomega v1.7.0
github.com/opencontainers/go-digest v1.0.0-rc1 github.com/opencontainers/go-digest v1.0.0-rc1
github.com/opencontainers/image-spec v1.0.1 // indirect github.com/opencontainers/image-spec v1.0.1 // indirect
github.com/opencontainers/runc v1.0.0-rc2.0.20190611121236-6cc515888830 github.com/opencontainers/runc v1.0.0-rc9
github.com/opencontainers/runtime-spec v1.0.0 // indirect github.com/opencontainers/runtime-spec v1.0.0 // indirect
github.com/opencontainers/selinux v1.2.2 github.com/opencontainers/selinux v1.3.1-0.20190929122143-5215b1806f52
github.com/pborman/uuid v1.2.0 github.com/pborman/uuid v1.2.0
github.com/pkg/errors v0.8.0 github.com/pkg/errors v0.8.0
github.com/pmezard/go-difflib v1.0.0 github.com/pmezard/go-difflib v1.0.0
@@ -118,7 +118,7 @@ require (
github.com/spf13/viper v1.3.2 github.com/spf13/viper v1.3.2
github.com/storageos/go-api v0.0.0-20180912212459-343b3eff91fc github.com/storageos/go-api v0.0.0-20180912212459-343b3eff91fc
github.com/stretchr/testify v1.3.0 github.com/stretchr/testify v1.3.0
github.com/syndtr/gocapability v0.0.0-20160928074757-e7cb7fa329f4 // indirect github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 // indirect
github.com/thecodeteam/goscaleio v0.1.0 github.com/thecodeteam/goscaleio v0.1.0
github.com/urfave/negroni v1.0.0 // indirect github.com/urfave/negroni v1.0.0 // indirect
github.com/vishvananda/netlink v0.0.0-20171020171820-b2de5d10e38e github.com/vishvananda/netlink v0.0.0-20171020171820-b2de5d10e38e
@@ -231,7 +231,7 @@ replace (
github.com/coreos/go-etcd => github.com/coreos/go-etcd v2.0.0+incompatible github.com/coreos/go-etcd => github.com/coreos/go-etcd v2.0.0+incompatible
github.com/coreos/go-oidc => github.com/coreos/go-oidc v2.1.0+incompatible github.com/coreos/go-oidc => github.com/coreos/go-oidc v2.1.0+incompatible
github.com/coreos/go-semver => github.com/coreos/go-semver v0.3.0 github.com/coreos/go-semver => github.com/coreos/go-semver v0.3.0
github.com/coreos/go-systemd => github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 github.com/coreos/go-systemd => github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e
github.com/coreos/pkg => github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea github.com/coreos/pkg => github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea
github.com/coreos/rkt => github.com/coreos/rkt v1.30.0 github.com/coreos/rkt => github.com/coreos/rkt v1.30.0
github.com/cpuguy83/go-md2man => github.com/cpuguy83/go-md2man v1.0.10 github.com/cpuguy83/go-md2man => github.com/cpuguy83/go-md2man v1.0.10
@@ -275,7 +275,7 @@ replace (
github.com/go-openapi/validate => github.com/go-openapi/validate v0.19.2 github.com/go-openapi/validate => github.com/go-openapi/validate v0.19.2
github.com/go-ozzo/ozzo-validation => github.com/go-ozzo/ozzo-validation v3.5.0+incompatible github.com/go-ozzo/ozzo-validation => github.com/go-ozzo/ozzo-validation v3.5.0+incompatible
github.com/go-stack/stack => github.com/go-stack/stack v1.8.0 github.com/go-stack/stack => github.com/go-stack/stack v1.8.0
github.com/godbus/dbus => github.com/godbus/dbus v4.1.0+incompatible github.com/godbus/dbus => github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f
github.com/gogo/protobuf => github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d github.com/gogo/protobuf => github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d
github.com/golang/glog => github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b github.com/golang/glog => github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/golang/groupcache => github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 github.com/golang/groupcache => github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903
@@ -356,7 +356,7 @@ replace (
github.com/modern-go/reflect2 => github.com/modern-go/reflect2 v1.0.1 github.com/modern-go/reflect2 => github.com/modern-go/reflect2 v1.0.1
github.com/mohae/deepcopy => github.com/mohae/deepcopy v0.0.0-20170603005431-491d3605edfb github.com/mohae/deepcopy => github.com/mohae/deepcopy v0.0.0-20170603005431-491d3605edfb
github.com/morikuni/aec => github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c github.com/morikuni/aec => github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c
github.com/mrunalp/fileutils => github.com/mrunalp/fileutils v0.0.0-20160930181131-4ee1cc9a8058 github.com/mrunalp/fileutils => github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618
github.com/munnerz/goautoneg => github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d github.com/munnerz/goautoneg => github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d
github.com/mvdan/xurls => github.com/mvdan/xurls v1.1.0 github.com/mvdan/xurls => github.com/mvdan/xurls v1.1.0
github.com/mwitkow/go-conntrack => github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223 github.com/mwitkow/go-conntrack => github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223
@@ -367,9 +367,9 @@ replace (
github.com/onsi/gomega => github.com/onsi/gomega v1.7.0 github.com/onsi/gomega => github.com/onsi/gomega v1.7.0
github.com/opencontainers/go-digest => github.com/opencontainers/go-digest v1.0.0-rc1 github.com/opencontainers/go-digest => github.com/opencontainers/go-digest v1.0.0-rc1
github.com/opencontainers/image-spec => github.com/opencontainers/image-spec v1.0.1 github.com/opencontainers/image-spec => github.com/opencontainers/image-spec v1.0.1
github.com/opencontainers/runc => github.com/opencontainers/runc v1.0.0-rc2.0.20190611121236-6cc515888830 github.com/opencontainers/runc => github.com/opencontainers/runc v1.0.0-rc9
github.com/opencontainers/runtime-spec => github.com/opencontainers/runtime-spec v1.0.0 github.com/opencontainers/runtime-spec => github.com/opencontainers/runtime-spec v1.0.0
github.com/opencontainers/selinux => github.com/opencontainers/selinux v1.2.2 github.com/opencontainers/selinux => github.com/opencontainers/selinux v1.3.1-0.20190929122143-5215b1806f52
github.com/pborman/uuid => github.com/pborman/uuid v1.2.0 github.com/pborman/uuid => github.com/pborman/uuid v1.2.0
github.com/pelletier/go-toml => github.com/pelletier/go-toml v1.2.0 github.com/pelletier/go-toml => github.com/pelletier/go-toml v1.2.0
github.com/peterbourgon/diskv => github.com/peterbourgon/diskv v2.0.1+incompatible github.com/peterbourgon/diskv => github.com/peterbourgon/diskv v2.0.1+incompatible
@@ -402,7 +402,7 @@ replace (
github.com/storageos/go-api => github.com/storageos/go-api v0.0.0-20180912212459-343b3eff91fc github.com/storageos/go-api => github.com/storageos/go-api v0.0.0-20180912212459-343b3eff91fc
github.com/stretchr/objx => github.com/stretchr/objx v0.2.0 github.com/stretchr/objx => github.com/stretchr/objx v0.2.0
github.com/stretchr/testify => github.com/stretchr/testify v1.3.0 github.com/stretchr/testify => github.com/stretchr/testify v1.3.0
github.com/syndtr/gocapability => github.com/syndtr/gocapability v0.0.0-20160928074757-e7cb7fa329f4 github.com/syndtr/gocapability => github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2
github.com/thecodeteam/goscaleio => github.com/thecodeteam/goscaleio v0.1.0 github.com/thecodeteam/goscaleio => github.com/thecodeteam/goscaleio v0.1.0
github.com/tmc/grpc-websocket-proxy => github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8 github.com/tmc/grpc-websocket-proxy => github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8
github.com/ugorji/go/codec => github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8 github.com/ugorji/go/codec => github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8

24
go.sum
View File

@@ -104,8 +104,8 @@ github.com/coreos/go-oidc v2.1.0+incompatible h1:sdJrfw8akMnCuUlaZU3tE/uYXFgfqom
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 h1:u9SHYsPQNyt5tgDm3YN7+9dYrpK96E5wFilTFWIDZOM= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea h1:n2Ltr3SrfQlf/9nOna1DoGKxLx3qTSI8Ttl6Xrqp6mw= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea h1:n2Ltr3SrfQlf/9nOna1DoGKxLx3qTSI8Ttl6Xrqp6mw=
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/coreos/rkt v1.30.0 h1:Kkt6sYeEGKxA3Y7SCrY+nHoXkWed6Jr2BBY42GqMymM= github.com/coreos/rkt v1.30.0 h1:Kkt6sYeEGKxA3Y7SCrY+nHoXkWed6Jr2BBY42GqMymM=
@@ -185,8 +185,8 @@ github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2K
github.com/go-ozzo/ozzo-validation v3.5.0+incompatible h1:sUy/in/P6askYr16XJgTKq/0SZhiWsdg4WZGaLsGQkM= github.com/go-ozzo/ozzo-validation v3.5.0+incompatible h1:sUy/in/P6askYr16XJgTKq/0SZhiWsdg4WZGaLsGQkM=
github.com/go-ozzo/ozzo-validation v3.5.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU= github.com/go-ozzo/ozzo-validation v3.5.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/godbus/dbus v4.1.0+incompatible h1:WqqLRTsQic3apZUK9qC5sGNfXthmPXzUZ7nQPrNITa4= github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f h1:zlOR3rOlPAVvtfuxGKoghCmop5B0TRyu/ZieziZuGiM=
github.com/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
@@ -326,8 +326,8 @@ github.com/mohae/deepcopy v0.0.0-20170603005431-491d3605edfb h1:e+l77LJOEqXTIQih
github.com/mohae/deepcopy v0.0.0-20170603005431-491d3605edfb/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/mohae/deepcopy v0.0.0-20170603005431-491d3605edfb/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c h1:nXxl5PrvVm2L/wCy8dQu6DMTwH4oIuGN8GJDAlqDdVE= github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c h1:nXxl5PrvVm2L/wCy8dQu6DMTwH4oIuGN8GJDAlqDdVE=
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/mrunalp/fileutils v0.0.0-20160930181131-4ee1cc9a8058 h1:A4y2IxU1GcIzlcmUlQ6yr/mrvYZhqo+HakAPwgwaa6s= github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618 h1:7InQ7/zrOh6SlFjaXFubv0xX0HsuC9qJsdqm7bNQpYM=
github.com/mrunalp/fileutils v0.0.0-20160930181131-4ee1cc9a8058/go.mod h1:x8F1gnqOkIEiO4rqoeEEEqQbo7HjGMTvyoq3gej4iT0= github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618/go.mod h1:x8F1gnqOkIEiO4rqoeEEEqQbo7HjGMTvyoq3gej4iT0=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d h1:7PxY7LVfSZm7PEeBTyK1rj1gABdCO2mbri6GKO1cMDs= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d h1:7PxY7LVfSZm7PEeBTyK1rj1gABdCO2mbri6GKO1cMDs=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mvdan/xurls v1.1.0 h1:OpuDelGQ1R1ueQ6sSryzi6P+1RtBpfQHM8fJwlE45ww= github.com/mvdan/xurls v1.1.0 h1:OpuDelGQ1R1ueQ6sSryzi6P+1RtBpfQHM8fJwlE45ww=
@@ -345,12 +345,12 @@ github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2i
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/runc v1.0.0-rc2.0.20190611121236-6cc515888830 h1:yvQ/2Pupw60ON8TYEIGGTAI77yZsWYkiOeHFZWkwlCk= github.com/opencontainers/runc v1.0.0-rc9 h1:/k06BMULKF5hidyoZymkoDCzdJzltZpz/UU4LguQVtc=
github.com/opencontainers/runc v1.0.0-rc2.0.20190611121236-6cc515888830/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runtime-spec v1.0.0 h1:O6L965K88AilqnxeYPks/75HLpp4IG+FjeSCI3cVdRg= github.com/opencontainers/runtime-spec v1.0.0 h1:O6L965K88AilqnxeYPks/75HLpp4IG+FjeSCI3cVdRg=
github.com/opencontainers/runtime-spec v1.0.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/selinux v1.2.2 h1:Kx9J6eDG5/24A6DtUquGSpJQ+m2MUTahn4FtGEe8bFg= github.com/opencontainers/selinux v1.3.1-0.20190929122143-5215b1806f52 h1:B8hYj3NxHmjsC3T+tnlZ1UhInqUgnyF1zlGPmzNg2Qk=
github.com/opencontainers/selinux v1.2.2/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs= github.com/opencontainers/selinux v1.3.1-0.20190929122143-5215b1806f52/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs=
github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
@@ -413,8 +413,8 @@ github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/syndtr/gocapability v0.0.0-20160928074757-e7cb7fa329f4 h1:w58e6FAOMd+rUgOfhaBb+ZVOQIOfUkpv5AAQVmf6hsI= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 h1:b6uOv7YOFK0TYG7HtkIgExQo+2RdLuwRft63jn2HWj8=
github.com/syndtr/gocapability v0.0.0-20160928074757-e7cb7fa329f4/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/thecodeteam/goscaleio v0.1.0 h1:SB5tO98lawC+UK8ds/U2jyfOCH7GTcFztcF5x9gbut4= github.com/thecodeteam/goscaleio v0.1.0 h1:SB5tO98lawC+UK8ds/U2jyfOCH7GTcFztcF5x9gbut4=
github.com/thecodeteam/goscaleio v0.1.0/go.mod h1:68sdkZAsK8bvEwBlbQnlLS+xU+hvLYM/iQ8KXej1AwM= github.com/thecodeteam/goscaleio v0.1.0/go.mod h1:68sdkZAsK8bvEwBlbQnlLS+xU+hvLYM/iQ8KXej1AwM=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8 h1:ndzgwNDnKIqyCvHTXaCqh9KlOWKvBry6nuXMJmonVsE= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8 h1:ndzgwNDnKIqyCvHTXaCqh9KlOWKvBry6nuXMJmonVsE=

View File

@@ -153,7 +153,7 @@ func (l *libcontainerAdapter) newManager(cgroups *libcontainerconfigs.Cgroup, pa
if !cgroupsystemd.UseSystemd() { if !cgroupsystemd.UseSystemd() {
panic("systemd cgroup manager not available") panic("systemd cgroup manager not available")
} }
return &cgroupsystemd.Manager{ return &cgroupsystemd.LegacyManager{
Cgroups: cgroups, Cgroups: cgroups,
Paths: paths, Paths: paths,
}, nil }, nil

View File

@@ -46,8 +46,8 @@ github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHo
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 h1:u9SHYsPQNyt5tgDm3YN7+9dYrpK96E5wFilTFWIDZOM= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea h1:n2Ltr3SrfQlf/9nOna1DoGKxLx3qTSI8Ttl6Xrqp6mw= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea h1:n2Ltr3SrfQlf/9nOna1DoGKxLx3qTSI8Ttl6Xrqp6mw=
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=

View File

@@ -10,7 +10,7 @@ require (
github.com/coreos/etcd v3.3.15+incompatible github.com/coreos/etcd v3.3.15+incompatible
github.com/coreos/go-oidc v2.1.0+incompatible github.com/coreos/go-oidc v2.1.0+incompatible
github.com/coreos/go-semver v0.3.0 // indirect github.com/coreos/go-semver v0.3.0 // indirect
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea
github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0 github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0
github.com/emicklei/go-restful v2.9.5+incompatible github.com/emicklei/go-restful v2.9.5+incompatible

View File

@@ -37,8 +37,8 @@ github.com/coreos/go-oidc v2.1.0+incompatible h1:sdJrfw8akMnCuUlaZU3tE/uYXFgfqom
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 h1:u9SHYsPQNyt5tgDm3YN7+9dYrpK96E5wFilTFWIDZOM= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea h1:n2Ltr3SrfQlf/9nOna1DoGKxLx3qTSI8Ttl6Xrqp6mw= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea h1:n2Ltr3SrfQlf/9nOna1DoGKxLx3qTSI8Ttl6Xrqp6mw=
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=

View File

@@ -40,8 +40,8 @@ github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHo
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 h1:u9SHYsPQNyt5tgDm3YN7+9dYrpK96E5wFilTFWIDZOM= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea h1:n2Ltr3SrfQlf/9nOna1DoGKxLx3qTSI8Ttl6Xrqp6mw= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea h1:n2Ltr3SrfQlf/9nOna1DoGKxLx3qTSI8Ttl6Xrqp6mw=
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=

View File

@@ -46,7 +46,7 @@ github.com/coreos/bbolt v1.3.1-coreos.6/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE55
github.com/coreos/etcd v3.3.15+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.15+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=

View File

@@ -40,8 +40,8 @@ github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHo
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 h1:u9SHYsPQNyt5tgDm3YN7+9dYrpK96E5wFilTFWIDZOM= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea h1:n2Ltr3SrfQlf/9nOna1DoGKxLx3qTSI8Ttl6Xrqp6mw= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea h1:n2Ltr3SrfQlf/9nOna1DoGKxLx3qTSI8Ttl6Xrqp6mw=
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=

View File

@@ -143,7 +143,7 @@ func NewUserConnection() (*Conn, error) {
func NewSystemdConnection() (*Conn, error) { func NewSystemdConnection() (*Conn, error) {
return NewConnection(func() (*dbus.Conn, error) { return NewConnection(func() (*dbus.Conn, error) {
// We skip Hello when talking directly to systemd. // We skip Hello when talking directly to systemd.
return dbusAuthConnection(func() (*dbus.Conn, error) { return dbusAuthConnection(func(opts ...dbus.ConnOption) (*dbus.Conn, error) {
return dbus.Dial("unix:path=/run/systemd/private") return dbus.Dial("unix:path=/run/systemd/private")
}) })
}) })
@@ -201,7 +201,7 @@ func (c *Conn) GetManagerProperty(prop string) (string, error) {
return variant.String(), nil return variant.String(), nil
} }
func dbusAuthConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) { func dbusAuthConnection(createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) {
conn, err := createBus() conn, err := createBus()
if err != nil { if err != nil {
return nil, err return nil, err
@@ -221,7 +221,7 @@ func dbusAuthConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error
return conn, nil return conn, nil
} }
func dbusAuthHelloConnection(createBus func() (*dbus.Conn, error)) (*dbus.Conn, error) { func dbusAuthHelloConnection(createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) {
conn, err := dbusAuthConnection(createBus) conn, err := dbusAuthConnection(createBus)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@@ -117,13 +117,13 @@ func (c *Conn) TryRestartUnit(name string, mode string, ch chan<- string) (int,
return c.startJob(ch, "org.freedesktop.systemd1.Manager.TryRestartUnit", name, mode) return c.startJob(ch, "org.freedesktop.systemd1.Manager.TryRestartUnit", name, mode)
} }
// ReloadOrRestart attempts a reload if the unit supports it and use a restart // ReloadOrRestartUnit attempts a reload if the unit supports it and use a restart
// otherwise. // otherwise.
func (c *Conn) ReloadOrRestartUnit(name string, mode string, ch chan<- string) (int, error) { func (c *Conn) ReloadOrRestartUnit(name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrRestartUnit", name, mode) return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrRestartUnit", name, mode)
} }
// ReloadOrTryRestart attempts a reload if the unit supports it and use a "Try" // ReloadOrTryRestartUnit attempts a reload if the unit supports it and use a "Try"
// flavored restart otherwise. // flavored restart otherwise.
func (c *Conn) ReloadOrTryRestartUnit(name string, mode string, ch chan<- string) (int, error) { func (c *Conn) ReloadOrTryRestartUnit(name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrTryRestartUnit", name, mode) return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadOrTryRestartUnit", name, mode)
@@ -192,7 +192,7 @@ func (c *Conn) GetUnitProperties(unit string) (map[string]interface{}, error) {
return c.getProperties(path, "org.freedesktop.systemd1.Unit") return c.getProperties(path, "org.freedesktop.systemd1.Unit")
} }
// GetUnitProperties takes the (escaped) unit path and returns all of its dbus object properties. // GetUnitPathProperties takes the (escaped) unit path and returns all of its dbus object properties.
func (c *Conn) GetUnitPathProperties(path dbus.ObjectPath) (map[string]interface{}, error) { func (c *Conn) GetUnitPathProperties(path dbus.ObjectPath) (map[string]interface{}, error) {
return c.getProperties(path, "org.freedesktop.systemd1.Unit") return c.getProperties(path, "org.freedesktop.systemd1.Unit")
} }
@@ -291,6 +291,8 @@ func (c *Conn) listUnitsInternal(f storeFunc) ([]UnitStatus, error) {
// ListUnits returns an array with all currently loaded units. Note that // ListUnits returns an array with all currently loaded units. Note that
// units may be known by multiple names at the same time, and hence there might // units may be known by multiple names at the same time, and hence there might
// be more unit names loaded than actual units behind them. // be more unit names loaded than actual units behind them.
// Also note that a unit is only loaded if it is active and/or enabled.
// Units that are both disabled and inactive will thus not be returned.
func (c *Conn) ListUnits() ([]UnitStatus, error) { func (c *Conn) ListUnits() ([]UnitStatus, error) {
return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnits", 0).Store) return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnits", 0).Store)
} }

View File

@@ -94,7 +94,7 @@ func (c *Conn) dispatch() {
}() }()
} }
// Returns two unbuffered channels which will receive all changed units every // SubscribeUnits returns two unbuffered channels which will receive all changed units every
// interval. Deleted units are sent as nil. // interval. Deleted units are sent as nil.
func (c *Conn) SubscribeUnits(interval time.Duration) (<-chan map[string]*UnitStatus, <-chan error) { func (c *Conn) SubscribeUnits(interval time.Duration) (<-chan map[string]*UnitStatus, <-chan error) {
return c.SubscribeUnitsCustom(interval, 0, func(u1, u2 *UnitStatus) bool { return *u1 != *u2 }, nil) return c.SubscribeUnitsCustom(interval, 0, func(u1, u2 *UnitStatus) bool { return *u1 != *u2 }, nil)

View File

@@ -33,7 +33,10 @@ import (
"os" "os"
"strconv" "strconv"
"strings" "strings"
"sync"
"sync/atomic"
"syscall" "syscall"
"unsafe"
) )
// Priority of a journal message // Priority of a journal message
@@ -50,19 +53,35 @@ const (
PriDebug PriDebug
) )
var conn net.Conn var (
// This can be overridden at build-time:
// https://github.com/golang/go/wiki/GcToolchainTricks#including-build-information-in-the-executable
journalSocket = "/run/systemd/journal/socket"
// unixConnPtr atomically holds the local unconnected Unix-domain socket.
// Concrete safe pointer type: *net.UnixConn
unixConnPtr unsafe.Pointer
// onceConn ensures that unixConnPtr is initialized exactly once.
onceConn sync.Once
)
func init() { func init() {
var err error onceConn.Do(initConn)
conn, err = net.Dial("unixgram", "/run/systemd/journal/socket")
if err != nil {
conn = nil
}
} }
// Enabled returns true if the local systemd journal is available for logging // Enabled checks whether the local systemd journal is available for logging.
func Enabled() bool { func Enabled() bool {
return conn != nil onceConn.Do(initConn)
if (*net.UnixConn)(atomic.LoadPointer(&unixConnPtr)) == nil {
return false
}
if _, err := net.Dial("unixgram", journalSocket); err != nil {
return false
}
return true
} }
// Send a message to the local systemd journal. vars is a map of journald // Send a message to the local systemd journal. vars is a map of journald
@@ -73,8 +92,14 @@ func Enabled() bool {
// (http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html) // (http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html)
// for more details. vars may be nil. // for more details. vars may be nil.
func Send(message string, priority Priority, vars map[string]string) error { func Send(message string, priority Priority, vars map[string]string) error {
conn := (*net.UnixConn)(atomic.LoadPointer(&unixConnPtr))
if conn == nil { if conn == nil {
return journalError("could not connect to journald socket") return errors.New("could not initialize socket to journald")
}
socketAddr := &net.UnixAddr{
Name: journalSocket,
Net: "unixgram",
} }
data := new(bytes.Buffer) data := new(bytes.Buffer)
@@ -84,32 +109,30 @@ func Send(message string, priority Priority, vars map[string]string) error {
appendVariable(data, k, v) appendVariable(data, k, v)
} }
_, err := io.Copy(conn, data) _, _, err := conn.WriteMsgUnix(data.Bytes(), nil, socketAddr)
if err != nil && isSocketSpaceError(err) { if err == nil {
return nil
}
if !isSocketSpaceError(err) {
return err
}
// Large log entry, send it via tempfile and ancillary-fd.
file, err := tempFd() file, err := tempFd()
if err != nil { if err != nil {
return journalError(err.Error()) return err
} }
defer file.Close() defer file.Close()
_, err = io.Copy(file, data) _, err = io.Copy(file, data)
if err != nil { if err != nil {
return journalError(err.Error()) return err
} }
rights := syscall.UnixRights(int(file.Fd())) rights := syscall.UnixRights(int(file.Fd()))
_, _, err = conn.WriteMsgUnix([]byte{}, rights, socketAddr)
/* this connection should always be a UnixConn, but better safe than sorry */
unixConn, ok := conn.(*net.UnixConn)
if !ok {
return journalError("can't send file through non-Unix connection")
}
_, _, err = unixConn.WriteMsgUnix([]byte{}, rights, nil)
if err != nil { if err != nil {
return journalError(err.Error()) return err
}
} else if err != nil {
return journalError(err.Error())
} }
return nil return nil
} }
@@ -119,8 +142,8 @@ func Print(priority Priority, format string, a ...interface{}) error {
} }
func appendVariable(w io.Writer, name, value string) { func appendVariable(w io.Writer, name, value string) {
if !validVarName(name) { if err := validVarName(name); err != nil {
journalError("variable name contains invalid character, ignoring") fmt.Fprintf(os.Stderr, "variable name %s contains invalid character, ignoring\n", name)
} }
if strings.ContainsRune(value, '\n') { if strings.ContainsRune(value, '\n') {
/* When the value contains a newline, we write: /* When the value contains a newline, we write:
@@ -137,32 +160,42 @@ func appendVariable(w io.Writer, name, value string) {
} }
} }
func validVarName(name string) bool { // validVarName validates a variable name to make sure journald will accept it.
/* The variable name must be in uppercase and consist only of characters, // The variable name must be in uppercase and consist only of characters,
* numbers and underscores, and may not begin with an underscore. (from the docs) // numbers and underscores, and may not begin with an underscore:
*/ // https://www.freedesktop.org/software/systemd/man/sd_journal_print.html
func validVarName(name string) error {
valid := name[0] != '_' if name == "" {
for _, c := range name { return errors.New("Empty variable name")
valid = valid && ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' } else if name[0] == '_' {
return errors.New("Variable name begins with an underscore")
} }
return valid
for _, c := range name {
if !(('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_') {
return errors.New("Variable name contains invalid characters")
}
}
return nil
} }
// isSocketSpaceError checks whether the error is signaling
// an "overlarge message" condition.
func isSocketSpaceError(err error) bool { func isSocketSpaceError(err error) bool {
opErr, ok := err.(*net.OpError) opErr, ok := err.(*net.OpError)
if !ok { if !ok || opErr == nil {
return false return false
} }
sysErr, ok := opErr.Err.(syscall.Errno) sysErr, ok := opErr.Err.(*os.SyscallError)
if !ok { if !ok || sysErr == nil {
return false return false
} }
return sysErr == syscall.EMSGSIZE || sysErr == syscall.ENOBUFS return sysErr.Err == syscall.EMSGSIZE || sysErr.Err == syscall.ENOBUFS
} }
// tempFd creates a temporary, unlinked file under `/dev/shm`.
func tempFd() (*os.File, error) { func tempFd() (*os.File, error) {
file, err := ioutil.TempFile("/dev/shm/", "journal.XXXXX") file, err := ioutil.TempFile("/dev/shm/", "journal.XXXXX")
if err != nil { if err != nil {
@@ -175,8 +208,18 @@ func tempFd() (*os.File, error) {
return file, nil return file, nil
} }
func journalError(s string) error { // initConn initializes the global `unixConnPtr` socket.
s = "journal error: " + s // It is meant to be called exactly once, at program startup.
fmt.Fprintln(os.Stderr, s) func initConn() {
return errors.New(s) autobind, err := net.ResolveUnixAddr("unixgram", "")
if err != nil {
return
}
sock, err := net.ListenUnixgram("unixgram", autobind)
if err != nil {
return
}
atomic.StorePointer(&unixConnPtr, unsafe.Pointer(sock))
} }

View File

@@ -4,8 +4,10 @@ go_import_path: github.com/godbus/dbus
sudo: true sudo: true
go: go:
- 1.6.3
- 1.7.3 - 1.7.3
- 1.8.7
- 1.9.5
- 1.10.1
- tip - tip
env: env:
@@ -38,3 +40,7 @@ addons:
- dbus-x11 - dbus-x11
before_install: 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

View File

@@ -4,12 +4,15 @@ go_library(
name = "go_default_library", name = "go_default_library",
srcs = [ srcs = [
"auth.go", "auth.go",
"auth_anonymous.go",
"auth_external.go", "auth_external.go",
"auth_sha1.go", "auth_sha1.go",
"call.go", "call.go",
"conn.go", "conn.go",
"conn_darwin.go", "conn_darwin.go",
"conn_other.go", "conn_other.go",
"conn_unix.go",
"conn_windows.go",
"dbus.go", "dbus.go",
"decoder.go", "decoder.go",
"default_handler.go", "default_handler.go",
@@ -24,6 +27,7 @@ go_library(
"sig.go", "sig.go",
"transport_darwin.go", "transport_darwin.go",
"transport_generic.go", "transport_generic.go",
"transport_nonce_tcp.go",
"transport_tcp.go", "transport_tcp.go",
"transport_unix.go", "transport_unix.go",
"transport_unixcred_dragonfly.go", "transport_unixcred_dragonfly.go",

View File

@@ -14,7 +14,7 @@ D-Bus message bus system.
### Installation ### Installation
This packages requires Go 1.1. If you installed it and set up your GOPATH, just run: This packages requires Go 1.7. If you installed it and set up your GOPATH, just run:
``` ```
go get github.com/godbus/dbus go get github.com/godbus/dbus

View File

@@ -116,7 +116,6 @@ func (conn *Conn) Auth(methods []Auth) error {
return err return err
} }
go conn.inWorker() go conn.inWorker()
go conn.outWorker()
return nil return nil
} }
} }

16
vendor/github.com/godbus/dbus/auth_anonymous.go generated vendored Normal file
View File

@@ -0,0 +1,16 @@
package dbus
// AuthAnonymous returns an Auth that uses the ANONYMOUS mechanism.
func AuthAnonymous() Auth {
return &authAnonymous{}
}
type authAnonymous struct{}
func (a *authAnonymous) FirstData() (name, resp []byte, status AuthStatus) {
return []byte("ANONYMOUS"), nil, AuthOk
}
func (a *authAnonymous) HandleData(data []byte) (resp []byte, status AuthStatus) {
return nil, AuthError
}

View File

@@ -1,9 +1,12 @@
package dbus package dbus
import ( import (
"context"
"errors" "errors"
) )
var errSignature = errors.New("dbus: mismatched signature")
// Call represents a pending or completed method call. // Call represents a pending or completed method call.
type Call struct { type Call struct {
Destination string Destination string
@@ -20,9 +23,25 @@ type Call struct {
// Holds the response once the call is done. // Holds the response once the call is done.
Body []interface{} Body []interface{}
// tracks context and canceler
ctx context.Context
ctxCanceler context.CancelFunc
} }
var errSignature = errors.New("dbus: mismatched signature") func (c *Call) Context() context.Context {
if c.ctx == nil {
return context.Background()
}
return c.ctx
}
func (c *Call) ContextCancel() {
if c.ctxCanceler != nil {
c.ctxCanceler()
}
}
// Store stores the body of the reply into the provided pointers. It returns // Store stores the body of the reply into the provided pointers. It returns
// an error if the signatures of the body and retvalues don't match, or if // an error if the signatures of the body and retvalues don't match, or if
@@ -34,3 +53,8 @@ func (c *Call) Store(retvalues ...interface{}) error {
return Store(c.Body, retvalues...) return Store(c.Body, retvalues...)
} }
func (c *Call) done() {
c.Done <- c
c.ContextCancel()
}

554
vendor/github.com/godbus/dbus/conn.go generated vendored
View File

@@ -1,6 +1,7 @@
package dbus package dbus
import ( import (
"context"
"errors" "errors"
"io" "io"
"os" "os"
@@ -14,7 +15,6 @@ var (
systemBusLck sync.Mutex systemBusLck sync.Mutex
sessionBus *Conn sessionBus *Conn
sessionBusLck sync.Mutex sessionBusLck sync.Mutex
sessionEnvLck sync.Mutex
) )
// ErrClosed is the error returned by calls on a closed connection. // ErrClosed is the error returned by calls on a closed connection.
@@ -35,23 +35,13 @@ type Conn struct {
unixFD bool unixFD bool
uuid string uuid string
names []string
namesLck sync.RWMutex
serialLck sync.Mutex
nextSerial uint32
serialUsed map[uint32]bool
calls map[uint32]*Call
callsLck sync.RWMutex
handler Handler handler Handler
out chan *Message
closed bool
outLck sync.RWMutex
signalHandler SignalHandler signalHandler SignalHandler
serialGen SerialGenerator
names *nameTracker
calls *callTracker
outHandler *outputHandler
eavesdropped chan<- *Message eavesdropped chan<- *Message
eavesdroppedLck sync.Mutex eavesdroppedLck sync.Mutex
@@ -87,32 +77,31 @@ func SessionBus() (conn *Conn, err error) {
} }
func getSessionBusAddress() (string, error) { func getSessionBusAddress() (string, error) {
sessionEnvLck.Lock() if address := os.Getenv("DBUS_SESSION_BUS_ADDRESS"); address != "" && address != "autolaunch:" {
defer sessionEnvLck.Unlock() return address, nil
address := os.Getenv("DBUS_SESSION_BUS_ADDRESS")
if address != "" && address != "autolaunch:" { } else if address := tryDiscoverDbusSessionBusAddress(); address != "" {
os.Setenv("DBUS_SESSION_BUS_ADDRESS", address)
return address, nil return address, nil
} }
return getSessionBusPlatformAddress() return getSessionBusPlatformAddress()
} }
// SessionBusPrivate returns a new private connection to the session bus. // SessionBusPrivate returns a new private connection to the session bus.
func SessionBusPrivate() (*Conn, error) { func SessionBusPrivate(opts ...ConnOption) (*Conn, error) {
address, err := getSessionBusAddress() address, err := getSessionBusAddress()
if err != nil { if err != nil {
return nil, err return nil, err
} }
return Dial(address) return Dial(address, opts...)
} }
// SessionBusPrivate returns a new private connection to the session bus. // SessionBusPrivate returns a new private connection to the session bus.
//
// Deprecated: use SessionBusPrivate with options instead.
func SessionBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Conn, error) { func SessionBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Conn, error) {
address, err := getSessionBusAddress() return SessionBusPrivate(WithHandler(handler), WithSignalHandler(signalHandler))
if err != nil {
return nil, err
}
return DialHandler(address, handler, signalHandler)
} }
// SystemBus returns a shared connection to the system bus, connecting to it if // SystemBus returns a shared connection to the system bus, connecting to it if
@@ -145,53 +134,93 @@ func SystemBus() (conn *Conn, err error) {
} }
// SystemBusPrivate returns a new private connection to the system bus. // SystemBusPrivate returns a new private connection to the system bus.
func SystemBusPrivate() (*Conn, error) { func SystemBusPrivate(opts ...ConnOption) (*Conn, error) {
return Dial(getSystemBusPlatformAddress()) return Dial(getSystemBusPlatformAddress(), opts...)
} }
// SystemBusPrivateHandler returns a new private connection to the system bus, using the provided handlers. // SystemBusPrivateHandler returns a new private connection to the system bus, using the provided handlers.
//
// Deprecated: use SystemBusPrivate with options instead.
func SystemBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Conn, error) { func SystemBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Conn, error) {
return DialHandler(getSystemBusPlatformAddress(), handler, signalHandler) return SystemBusPrivate(WithHandler(handler), WithSignalHandler(signalHandler))
} }
// Dial establishes a new private connection to the message bus specified by address. // Dial establishes a new private connection to the message bus specified by address.
func Dial(address string) (*Conn, error) { func Dial(address string, opts ...ConnOption) (*Conn, error) {
tr, err := getTransport(address) tr, err := getTransport(address)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return newConn(tr, NewDefaultHandler(), NewDefaultSignalHandler()) return newConn(tr, opts...)
} }
// DialHandler establishes a new private connection to the message bus specified by address, using the supplied handlers. // DialHandler establishes a new private connection to the message bus specified by address, using the supplied handlers.
//
// Deprecated: use Dial with options instead.
func DialHandler(address string, handler Handler, signalHandler SignalHandler) (*Conn, error) { func DialHandler(address string, handler Handler, signalHandler SignalHandler) (*Conn, error) {
tr, err := getTransport(address) return Dial(address, WithSignalHandler(signalHandler))
if err != nil { }
return nil, err
// ConnOption is a connection option.
type ConnOption func(conn *Conn) error
// WithHandler overrides the default handler.
func WithHandler(handler Handler) ConnOption {
return func(conn *Conn) error {
conn.handler = handler
return nil
}
}
// WithSignalHandler overrides the default signal handler.
func WithSignalHandler(handler SignalHandler) ConnOption {
return func(conn *Conn) error {
conn.signalHandler = handler
return nil
}
}
// WithSerialGenerator overrides the default signals generator.
func WithSerialGenerator(gen SerialGenerator) ConnOption {
return func(conn *Conn) error {
conn.serialGen = gen
return nil
} }
return newConn(tr, handler, signalHandler)
} }
// NewConn creates a new private *Conn from an already established connection. // NewConn creates a new private *Conn from an already established connection.
func NewConn(conn io.ReadWriteCloser) (*Conn, error) { func NewConn(conn io.ReadWriteCloser, opts ...ConnOption) (*Conn, error) {
return NewConnHandler(conn, NewDefaultHandler(), NewDefaultSignalHandler()) return newConn(genericTransport{conn}, opts...)
} }
// NewConnHandler creates a new private *Conn from an already established connection, using the supplied handlers. // NewConnHandler creates a new private *Conn from an already established connection, using the supplied handlers.
//
// Deprecated: use NewConn with options instead.
func NewConnHandler(conn io.ReadWriteCloser, handler Handler, signalHandler SignalHandler) (*Conn, error) { func NewConnHandler(conn io.ReadWriteCloser, handler Handler, signalHandler SignalHandler) (*Conn, error) {
return newConn(genericTransport{conn}, handler, signalHandler) return NewConn(genericTransport{conn}, WithHandler(handler), WithSignalHandler(signalHandler))
} }
// newConn creates a new *Conn from a transport. // newConn creates a new *Conn from a transport.
func newConn(tr transport, handler Handler, signalHandler SignalHandler) (*Conn, error) { func newConn(tr transport, opts ...ConnOption) (*Conn, error) {
conn := new(Conn) conn := new(Conn)
conn.transport = tr conn.transport = tr
conn.calls = make(map[uint32]*Call) for _, opt := range opts {
conn.out = make(chan *Message, 10) if err := opt(conn); err != nil {
conn.handler = handler return nil, err
conn.signalHandler = signalHandler }
conn.nextSerial = 1 }
conn.serialUsed = map[uint32]bool{0: true} conn.calls = newCallTracker()
if conn.handler == nil {
conn.handler = NewDefaultHandler()
}
if conn.signalHandler == nil {
conn.signalHandler = NewDefaultSignalHandler()
}
if conn.serialGen == nil {
conn.serialGen = newSerialGenerator()
}
conn.outHandler = &outputHandler{conn: conn}
conn.names = newNameTracker()
conn.busObj = conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus") conn.busObj = conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus")
return conn, nil return conn, nil
} }
@@ -206,18 +235,7 @@ func (conn *Conn) BusObject() BusObject {
// and the channels passed to Eavesdrop and Signal are closed. This method must // and the channels passed to Eavesdrop and Signal are closed. This method must
// not be called on shared connections. // not be called on shared connections.
func (conn *Conn) Close() error { func (conn *Conn) Close() error {
conn.outLck.Lock() conn.outHandler.close()
if conn.closed {
// inWorker calls Close on read error, the read error may
// be caused by another caller calling Close to shutdown the
// dbus connection, a double-close scenario we prevent here.
conn.outLck.Unlock()
return nil
}
close(conn.out)
conn.closed = true
conn.outLck.Unlock()
if term, ok := conn.signalHandler.(Terminator); ok { if term, ok := conn.signalHandler.(Terminator); ok {
term.Terminate() term.Terminate()
} }
@@ -249,17 +267,9 @@ func (conn *Conn) Eavesdrop(ch chan<- *Message) {
conn.eavesdroppedLck.Unlock() conn.eavesdroppedLck.Unlock()
} }
// getSerial returns an unused serial. // GetSerial returns an unused serial.
func (conn *Conn) getSerial() uint32 { func (conn *Conn) getSerial() uint32 {
conn.serialLck.Lock() return conn.serialGen.GetSerial()
defer conn.serialLck.Unlock()
n := conn.nextSerial
for conn.serialUsed[n] {
n++
}
conn.serialUsed[n] = true
conn.nextSerial = n + 1
return n
} }
// Hello sends the initial org.freedesktop.DBus.Hello call. This method must be // Hello sends the initial org.freedesktop.DBus.Hello call. This method must be
@@ -271,10 +281,7 @@ func (conn *Conn) Hello() error {
if err != nil { if err != nil {
return err return err
} }
conn.namesLck.Lock() conn.names.acquireUniqueConnectionName(s)
conn.names = make([]string, 1)
conn.names[0] = s
conn.namesLck.Unlock()
return nil return nil
} }
@@ -283,7 +290,18 @@ func (conn *Conn) Hello() error {
func (conn *Conn) inWorker() { func (conn *Conn) inWorker() {
for { for {
msg, err := conn.ReadMessage() msg, err := conn.ReadMessage()
if err == nil { if err != nil {
if _, ok := err.(InvalidMessageError); !ok {
// Some read error occured (usually EOF); we can't really do
// anything but to shut down all stuff and returns errors to all
// pending replies.
conn.Close()
conn.calls.finalizeAllWithError(err)
return
}
// invalid messages are ignored
continue
}
conn.eavesdroppedLck.Lock() conn.eavesdroppedLck.Lock()
if conn.eavesdropped != nil { if conn.eavesdropped != nil {
select { select {
@@ -295,46 +313,29 @@ func (conn *Conn) inWorker() {
} }
conn.eavesdroppedLck.Unlock() conn.eavesdroppedLck.Unlock()
dest, _ := msg.Headers[FieldDestination].value.(string) dest, _ := msg.Headers[FieldDestination].value.(string)
found := false found := dest == "" ||
if dest == "" { !conn.names.uniqueNameIsKnown() ||
found = true conn.names.isKnownName(dest)
} else {
conn.namesLck.RLock()
if len(conn.names) == 0 {
found = true
}
for _, v := range conn.names {
if dest == v {
found = true
break
}
}
conn.namesLck.RUnlock()
}
if !found { if !found {
// Eavesdropped a message, but no channel for it is registered. // Eavesdropped a message, but no channel for it is registered.
// Ignore it. // Ignore it.
continue continue
} }
switch msg.Type { switch msg.Type {
case TypeMethodReply, TypeError: case TypeError:
serial := msg.Headers[FieldReplySerial].value.(uint32) conn.serialGen.RetireSerial(conn.calls.handleDBusError(msg))
conn.callsLck.Lock() case TypeMethodReply:
if c, ok := conn.calls[serial]; ok { conn.serialGen.RetireSerial(conn.calls.handleReply(msg))
if msg.Type == TypeError {
name, _ := msg.Headers[FieldErrorName].value.(string)
c.Err = Error{name, msg.Body}
} else {
c.Body = msg.Body
}
c.Done <- c
conn.serialLck.Lock()
delete(conn.serialUsed, serial)
conn.serialLck.Unlock()
delete(conn.calls, serial)
}
conn.callsLck.Unlock()
case TypeSignal: case TypeSignal:
conn.handleSignal(msg)
case TypeMethodCall:
go conn.handleCall(msg)
}
}
}
func (conn *Conn) handleSignal(msg *Message) {
iface := msg.Headers[FieldInterface].value.(string) iface := msg.Headers[FieldInterface].value.(string)
member := msg.Headers[FieldMember].value.(string) member := msg.Headers[FieldMember].value.(string)
// as per http://dbus.freedesktop.org/doc/dbus-specification.html , // as per http://dbus.freedesktop.org/doc/dbus-specification.html ,
@@ -348,14 +349,7 @@ func (conn *Conn) inWorker() {
if !ok { if !ok {
panic("Unable to read the lost name") panic("Unable to read the lost name")
} }
conn.namesLck.Lock() conn.names.loseName(name)
for i, v := range conn.names {
if v == name {
conn.names = append(conn.names[:i],
conn.names[i+1:]...)
}
}
conn.namesLck.Unlock()
} else if member == "NameAcquired" { } else if member == "NameAcquired" {
// If we acquired the name on the bus, add it to our // If we acquired the name on the bus, add it to our
// tracking list. // tracking list.
@@ -363,38 +357,9 @@ func (conn *Conn) inWorker() {
if !ok { if !ok {
panic("Unable to read the acquired name") panic("Unable to read the acquired name")
} }
conn.namesLck.Lock() conn.names.acquireName(name)
conn.names = append(conn.names, name)
conn.namesLck.Unlock()
} }
} }
conn.handleSignal(msg)
case TypeMethodCall:
go conn.handleCall(msg)
}
} else if _, ok := err.(InvalidMessageError); !ok {
// Some read error occured (usually EOF); we can't really do
// anything but to shut down all stuff and returns errors to all
// pending replies.
conn.Close()
conn.callsLck.RLock()
for _, v := range conn.calls {
v.Err = err
v.Done <- v
}
conn.callsLck.RUnlock()
return
}
// invalid messages are ignored
}
}
func (conn *Conn) handleSignal(msg *Message) {
iface := msg.Headers[FieldInterface].value.(string)
member := msg.Headers[FieldMember].value.(string)
// as per http://dbus.freedesktop.org/doc/dbus-specification.html ,
// sender is optional for signals.
sender, _ := msg.Headers[FieldSender].value.(string)
signal := &Signal{ signal := &Signal{
Sender: sender, Sender: sender,
Path: msg.Headers[FieldPath].value.(ObjectPath), Path: msg.Headers[FieldPath].value.(ObjectPath),
@@ -408,12 +373,7 @@ func (conn *Conn) handleSignal(msg *Message) {
// connection. The slice is always at least one element long, the first element // connection. The slice is always at least one element long, the first element
// being the unique name of the connection. // being the unique name of the connection.
func (conn *Conn) Names() []string { func (conn *Conn) Names() []string {
conn.namesLck.RLock() return conn.names.listKnownNames()
// copy the slice so it can't be modified
s := make([]string, len(conn.names))
copy(s, conn.names)
conn.namesLck.RUnlock()
return s
} }
// Object returns the object identified by the given destination name and path. // Object returns the object identified by the given destination name and path.
@@ -423,24 +383,17 @@ func (conn *Conn) Object(dest string, path ObjectPath) BusObject {
// outWorker runs in an own goroutine, encoding and sending messages that are // outWorker runs in an own goroutine, encoding and sending messages that are
// sent to conn.out. // sent to conn.out.
func (conn *Conn) outWorker() { func (conn *Conn) sendMessage(msg *Message) {
for msg := range conn.out { conn.sendMessageAndIfClosed(msg, func() {})
err := conn.SendMessage(msg) }
conn.callsLck.RLock()
func (conn *Conn) sendMessageAndIfClosed(msg *Message, ifClosed func()) {
err := conn.outHandler.sendAndIfClosed(msg, ifClosed)
conn.calls.handleSendError(msg, err)
if err != nil { if err != nil {
if c := conn.calls[msg.serial]; c != nil { conn.serialGen.RetireSerial(msg.serial)
c.Err = err
c.Done <- c
}
conn.serialLck.Lock()
delete(conn.serialUsed, msg.serial)
conn.serialLck.Unlock()
} else if msg.Type != TypeMethodCall { } else if msg.Type != TypeMethodCall {
conn.serialLck.Lock() conn.serialGen.RetireSerial(msg.serial)
delete(conn.serialUsed, msg.serial)
conn.serialLck.Unlock()
}
conn.callsLck.RUnlock()
} }
} }
@@ -451,8 +404,21 @@ func (conn *Conn) outWorker() {
// once the call is complete. Otherwise, ch is ignored and a Call structure is // once the call is complete. Otherwise, ch is ignored and a Call structure is
// returned of which only the Err member is valid. // returned of which only the Err member is valid.
func (conn *Conn) Send(msg *Message, ch chan *Call) *Call { func (conn *Conn) Send(msg *Message, ch chan *Call) *Call {
var call *Call return conn.send(context.Background(), msg, ch)
}
// SendWithContext acts like Send but takes a context
func (conn *Conn) SendWithContext(ctx context.Context, msg *Message, ch chan *Call) *Call {
return conn.send(ctx, msg, ch)
}
func (conn *Conn) send(ctx context.Context, msg *Message, ch chan *Call) *Call {
if ctx == nil {
panic("nil context")
}
var call *Call
ctx, canceler := context.WithCancel(ctx)
msg.serial = conn.getSerial() msg.serial = conn.getSerial()
if msg.Type == TypeMethodCall && msg.Flags&FlagNoReplyExpected == 0 { if msg.Type == TypeMethodCall && msg.Flags&FlagNoReplyExpected == 0 {
if ch == nil { if ch == nil {
@@ -468,26 +434,23 @@ func (conn *Conn) Send(msg *Message, ch chan *Call) *Call {
call.Method = iface + "." + member call.Method = iface + "." + member
call.Args = msg.Body call.Args = msg.Body
call.Done = ch call.Done = ch
conn.callsLck.Lock() call.ctx = ctx
conn.calls[msg.serial] = call call.ctxCanceler = canceler
conn.callsLck.Unlock() conn.calls.track(msg.serial, call)
conn.outLck.RLock() go func() {
if conn.closed { <-ctx.Done()
call.Err = ErrClosed conn.calls.handleSendError(msg, ctx.Err())
call.Done <- call }()
conn.sendMessageAndIfClosed(msg, func() {
conn.calls.handleSendError(msg, ErrClosed)
canceler()
})
} else { } else {
conn.out <- msg canceler()
}
conn.outLck.RUnlock()
} else {
conn.outLck.RLock()
if conn.closed {
call = &Call{Err: ErrClosed}
} else {
conn.out <- msg
call = &Call{Err: nil} call = &Call{Err: nil}
} conn.sendMessageAndIfClosed(msg, func() {
conn.outLck.RUnlock() call = &Call{Err: ErrClosed}
})
} }
return call return call
} }
@@ -520,11 +483,7 @@ func (conn *Conn) sendError(err error, dest string, serial uint32) {
if len(e.Body) > 0 { if len(e.Body) > 0 {
msg.Headers[FieldSignature] = MakeVariant(SignatureOf(e.Body...)) msg.Headers[FieldSignature] = MakeVariant(SignatureOf(e.Body...))
} }
conn.outLck.RLock() conn.sendMessage(msg)
if !conn.closed {
conn.out <- msg
}
conn.outLck.RUnlock()
} }
// sendReply creates a method reply message corresponding to the parameters and // sendReply creates a method reply message corresponding to the parameters and
@@ -542,11 +501,7 @@ func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) {
if len(values) > 0 { if len(values) > 0 {
msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...)) msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...))
} }
conn.outLck.RLock() conn.sendMessage(msg)
if !conn.closed {
conn.out <- msg
}
conn.outLck.RUnlock()
} }
func (conn *Conn) defaultSignalAction(fn func(h *defaultSignalHandler, ch chan<- *Signal), ch chan<- *Signal) { func (conn *Conn) defaultSignalAction(fn func(h *defaultSignalHandler, ch chan<- *Signal), ch chan<- *Signal) {
@@ -681,3 +636,212 @@ func getKey(s, key string) string {
} }
return "" return ""
} }
type outputHandler struct {
conn *Conn
sendLck sync.Mutex
closed struct {
isClosed bool
lck sync.RWMutex
}
}
func (h *outputHandler) sendAndIfClosed(msg *Message, ifClosed func()) error {
h.closed.lck.RLock()
defer h.closed.lck.RUnlock()
if h.closed.isClosed {
ifClosed()
return nil
}
h.sendLck.Lock()
defer h.sendLck.Unlock()
return h.conn.SendMessage(msg)
}
func (h *outputHandler) close() {
h.closed.lck.Lock()
defer h.closed.lck.Unlock()
h.closed.isClosed = true
}
type serialGenerator struct {
lck sync.Mutex
nextSerial uint32
serialUsed map[uint32]bool
}
func newSerialGenerator() *serialGenerator {
return &serialGenerator{
serialUsed: map[uint32]bool{0: true},
nextSerial: 1,
}
}
func (gen *serialGenerator) GetSerial() uint32 {
gen.lck.Lock()
defer gen.lck.Unlock()
n := gen.nextSerial
for gen.serialUsed[n] {
n++
}
gen.serialUsed[n] = true
gen.nextSerial = n + 1
return n
}
func (gen *serialGenerator) RetireSerial(serial uint32) {
gen.lck.Lock()
defer gen.lck.Unlock()
delete(gen.serialUsed, serial)
}
type nameTracker struct {
lck sync.RWMutex
unique string
names map[string]struct{}
}
func newNameTracker() *nameTracker {
return &nameTracker{names: map[string]struct{}{}}
}
func (tracker *nameTracker) acquireUniqueConnectionName(name string) {
tracker.lck.Lock()
defer tracker.lck.Unlock()
tracker.unique = name
}
func (tracker *nameTracker) acquireName(name string) {
tracker.lck.Lock()
defer tracker.lck.Unlock()
tracker.names[name] = struct{}{}
}
func (tracker *nameTracker) loseName(name string) {
tracker.lck.Lock()
defer tracker.lck.Unlock()
delete(tracker.names, name)
}
func (tracker *nameTracker) uniqueNameIsKnown() bool {
tracker.lck.RLock()
defer tracker.lck.RUnlock()
return tracker.unique != ""
}
func (tracker *nameTracker) isKnownName(name string) bool {
tracker.lck.RLock()
defer tracker.lck.RUnlock()
_, ok := tracker.names[name]
return ok || name == tracker.unique
}
func (tracker *nameTracker) listKnownNames() []string {
tracker.lck.RLock()
defer tracker.lck.RUnlock()
out := make([]string, 0, len(tracker.names)+1)
out = append(out, tracker.unique)
for k := range tracker.names {
out = append(out, k)
}
return out
}
type callTracker struct {
calls map[uint32]*Call
lck sync.RWMutex
}
func newCallTracker() *callTracker {
return &callTracker{calls: map[uint32]*Call{}}
}
func (tracker *callTracker) track(sn uint32, call *Call) {
tracker.lck.Lock()
tracker.calls[sn] = call
tracker.lck.Unlock()
}
func (tracker *callTracker) handleReply(msg *Message) uint32 {
serial := msg.Headers[FieldReplySerial].value.(uint32)
tracker.lck.RLock()
_, ok := tracker.calls[serial]
tracker.lck.RUnlock()
if ok {
tracker.finalizeWithBody(serial, msg.Body)
}
return serial
}
func (tracker *callTracker) handleDBusError(msg *Message) uint32 {
serial := msg.Headers[FieldReplySerial].value.(uint32)
tracker.lck.RLock()
_, ok := tracker.calls[serial]
tracker.lck.RUnlock()
if ok {
name, _ := msg.Headers[FieldErrorName].value.(string)
tracker.finalizeWithError(serial, Error{name, msg.Body})
}
return serial
}
func (tracker *callTracker) handleSendError(msg *Message, err error) {
if err == nil {
return
}
tracker.lck.RLock()
_, ok := tracker.calls[msg.serial]
tracker.lck.RUnlock()
if ok {
tracker.finalizeWithError(msg.serial, err)
}
}
// finalize was the only func that did not strobe Done
func (tracker *callTracker) finalize(sn uint32) {
tracker.lck.Lock()
defer tracker.lck.Unlock()
c, ok := tracker.calls[sn]
if ok {
delete(tracker.calls, sn)
c.ContextCancel()
}
return
}
func (tracker *callTracker) finalizeWithBody(sn uint32, body []interface{}) {
tracker.lck.Lock()
c, ok := tracker.calls[sn]
if ok {
delete(tracker.calls, sn)
}
tracker.lck.Unlock()
if ok {
c.Body = body
c.done()
}
return
}
func (tracker *callTracker) finalizeWithError(sn uint32, err error) {
tracker.lck.Lock()
c, ok := tracker.calls[sn]
if ok {
delete(tracker.calls, sn)
}
tracker.lck.Unlock()
if ok {
c.Err = err
c.done()
}
return
}
func (tracker *callTracker) finalizeAllWithError(err error) {
tracker.lck.Lock()
closedCalls := make([]*Call, 0, len(tracker.calls))
for sn := range tracker.calls {
closedCalls = append(closedCalls, tracker.calls[sn])
}
tracker.calls = map[uint32]*Call{}
tracker.lck.Unlock()
for _, call := range closedCalls {
call.Err = err
call.done()
}
}

View File

@@ -31,3 +31,7 @@ func getSystemBusPlatformAddress() string {
} }
return defaultSystemBusAddress return defaultSystemBusAddress
} }
func tryDiscoverDbusSessionBusAddress() string {
return ""
}

View File

@@ -6,12 +6,14 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"os/exec" "os/exec"
"os/user"
"path"
"strings"
) )
const defaultSystemBusAddress = "unix:path=/var/run/dbus/system_bus_socket"
func getSessionBusPlatformAddress() (string, error) { func getSessionBusPlatformAddress() (string, error) {
cmd := exec.Command("dbus-launch") cmd := exec.Command("dbus-launch")
b, err := cmd.CombinedOutput() b, err := cmd.CombinedOutput()
@@ -33,10 +35,57 @@ func getSessionBusPlatformAddress() (string, error) {
return addr, nil return addr, nil
} }
func getSystemBusPlatformAddress() string { // tryDiscoverDbusSessionBusAddress tries to discover an existing dbus session
address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS") // and return the value of its DBUS_SESSION_BUS_ADDRESS.
if address != "" { // It tries different techniques employed by different operating systems,
return fmt.Sprintf("unix:path=%s", address) // returning the first valid address it finds, or an empty string.
//
// * /run/user/<uid>/bus if this exists, it *is* the bus socket. present on
// Ubuntu 18.04
// * /run/user/<uid>/dbus-session: if this exists, it can be parsed for the bus
// address. present on Ubuntu 16.04
//
// See https://dbus.freedesktop.org/doc/dbus-launch.1.html
func tryDiscoverDbusSessionBusAddress() string {
if runtimeDirectory, err := getRuntimeDirectory(); err == nil {
if runUserBusFile := path.Join(runtimeDirectory, "bus"); fileExists(runUserBusFile) {
// if /run/user/<uid>/bus exists, that file itself
// *is* the unix socket, so return its path
return fmt.Sprintf("unix:path=%s", runUserBusFile)
}
if runUserSessionDbusFile := path.Join(runtimeDirectory, "dbus-session"); fileExists(runUserSessionDbusFile) {
// if /run/user/<uid>/dbus-session exists, it's a
// text file // containing the address of the socket, e.g.:
// DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-E1c73yNqrG
if f, err := ioutil.ReadFile(runUserSessionDbusFile); err == nil {
fileContent := string(f)
prefix := "DBUS_SESSION_BUS_ADDRESS="
if strings.HasPrefix(fileContent, prefix) {
address := strings.TrimRight(strings.TrimPrefix(fileContent, prefix), "\n\r")
return address
}
}
}
}
return ""
}
func getRuntimeDirectory() (string, error) {
if currentUser, err := user.Current(); err != nil {
return "", err
} else {
return fmt.Sprintf("/run/user/%s", currentUser.Uid), nil
}
}
func fileExists(filename string) bool {
if _, err := os.Stat(filename); !os.IsNotExist(err) {
return true
} else {
return false
} }
return defaultSystemBusAddress
} }

18
vendor/github.com/godbus/dbus/conn_unix.go generated vendored Normal file
View File

@@ -0,0 +1,18 @@
//+build !windows,!solaris,!darwin
package dbus
import (
"os"
"fmt"
)
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 defaultSystemBusAddress
}

15
vendor/github.com/godbus/dbus/conn_windows.go generated vendored Normal file
View File

@@ -0,0 +1,15 @@
//+build windows
package dbus
import "os"
const defaultSystemBusAddress = "tcp:host=127.0.0.1,port=12434"
func getSystemBusPlatformAddress() string {
address := os.Getenv("DBUS_SYSTEM_BUS_ADDRESS")
if address != "" {
return address
}
return defaultSystemBusAddress
}

View File

@@ -191,7 +191,14 @@ func (dec *decoder) decode(s string, depth int) interface{} {
length := dec.decode("u", depth).(uint32) length := dec.decode("u", depth).(uint32)
v := reflect.MakeSlice(reflect.SliceOf(typeFor(s[1:])), 0, int(length)) v := reflect.MakeSlice(reflect.SliceOf(typeFor(s[1:])), 0, int(length))
// Even for empty arrays, the correct padding must be included // Even for empty arrays, the correct padding must be included
dec.align(alignment(typeFor(s[1:]))) align := alignment(typeFor(s[1:]))
if len(s) > 1 && s[1] == '(' {
//Special case for arrays of structs
//structs decode as a slice of interface{} values
//but the dbus alignment does not match this
align = 8
}
dec.align(align)
spos := dec.pos spos := dec.pos
for dec.pos < spos+int(length) { for dec.pos < spos+int(length) {
ev := dec.decode(s[1:], depth+1) ev := dec.decode(s[1:], depth+1)

View File

@@ -21,6 +21,8 @@ func newIntrospectIntf(h *defaultHandler) *exportedIntf {
//NewDefaultHandler returns an instance of the default //NewDefaultHandler returns an instance of the default
//call handler. This is useful if you want to implement only //call handler. This is useful if you want to implement only
//one of the two handlers but not both. //one of the two handlers but not both.
//
// Deprecated: this is the default value, don't use it, it will be unexported.
func NewDefaultHandler() *defaultHandler { func NewDefaultHandler() *defaultHandler {
h := &defaultHandler{ h := &defaultHandler{
objects: make(map[ObjectPath]*exportedObj), objects: make(map[ObjectPath]*exportedObj),
@@ -161,6 +163,7 @@ func newExportedObject() *exportedObj {
} }
type exportedObj struct { type exportedObj struct {
mu sync.RWMutex
interfaces map[string]*exportedIntf interfaces map[string]*exportedIntf
} }
@@ -168,19 +171,27 @@ func (obj *exportedObj) LookupInterface(name string) (Interface, bool) {
if name == "" { if name == "" {
return obj, true return obj, true
} }
obj.mu.RLock()
defer obj.mu.RUnlock()
intf, exists := obj.interfaces[name] intf, exists := obj.interfaces[name]
return intf, exists return intf, exists
} }
func (obj *exportedObj) AddInterface(name string, iface *exportedIntf) { func (obj *exportedObj) AddInterface(name string, iface *exportedIntf) {
obj.mu.Lock()
defer obj.mu.Unlock()
obj.interfaces[name] = iface obj.interfaces[name] = iface
} }
func (obj *exportedObj) DeleteInterface(name string) { func (obj *exportedObj) DeleteInterface(name string) {
obj.mu.Lock()
defer obj.mu.Unlock()
delete(obj.interfaces, name) delete(obj.interfaces, name)
} }
func (obj *exportedObj) LookupMethod(name string) (Method, bool) { func (obj *exportedObj) LookupMethod(name string) (Method, bool) {
obj.mu.RLock()
defer obj.mu.RUnlock()
for _, intf := range obj.interfaces { for _, intf := range obj.interfaces {
method, exists := intf.LookupMethod(name) method, exists := intf.LookupMethod(name)
if exists { if exists {
@@ -220,8 +231,12 @@ func (obj *exportedIntf) isFallbackInterface() bool {
//NewDefaultSignalHandler returns an instance of the default //NewDefaultSignalHandler returns an instance of the default
//signal handler. This is useful if you want to implement only //signal handler. This is useful if you want to implement only
//one of the two handlers but not both. //one of the two handlers but not both.
//
// Deprecated: this is the default value, don't use it, it will be unexported.
func NewDefaultSignalHandler() *defaultSignalHandler { func NewDefaultSignalHandler() *defaultSignalHandler {
return &defaultSignalHandler{} return &defaultSignalHandler{
closeChan: make(chan struct{}),
}
} }
func isDefaultSignalHandler(handler SignalHandler) bool { func isDefaultSignalHandler(handler SignalHandler) bool {
@@ -233,30 +248,45 @@ type defaultSignalHandler struct {
sync.RWMutex sync.RWMutex
closed bool closed bool
signals []chan<- *Signal signals []chan<- *Signal
closeChan chan struct{}
} }
func (sh *defaultSignalHandler) DeliverSignal(intf, name string, signal *Signal) { func (sh *defaultSignalHandler) DeliverSignal(intf, name string, signal *Signal) {
go func() {
sh.RLock() sh.RLock()
defer sh.RUnlock() defer sh.RUnlock()
if sh.closed { if sh.closed {
return return
} }
for _, ch := range sh.signals { for _, ch := range sh.signals {
ch <- signal select {
case ch <- signal:
case <-sh.closeChan:
return
default:
go func() {
select {
case ch <- signal:
case <-sh.closeChan:
return
} }
}() }()
}
}
} }
func (sh *defaultSignalHandler) Init() error { func (sh *defaultSignalHandler) Init() error {
sh.Lock() sh.Lock()
sh.signals = make([]chan<- *Signal, 0) sh.signals = make([]chan<- *Signal, 0)
sh.closeChan = make(chan struct{})
sh.Unlock() sh.Unlock()
return nil return nil
} }
func (sh *defaultSignalHandler) Terminate() { func (sh *defaultSignalHandler) Terminate() {
sh.Lock() sh.Lock()
if !sh.closed {
close(sh.closeChan)
}
sh.closed = true sh.closed = true
for _, ch := range sh.signals { for _, ch := range sh.signals {
close(ch) close(ch)

View File

@@ -170,11 +170,8 @@ func (conn *Conn) handleCall(msg *Message) {
reply.Body[i] = ret[i] reply.Body[i] = ret[i]
} }
reply.Headers[FieldSignature] = MakeVariant(SignatureOf(reply.Body...)) reply.Headers[FieldSignature] = MakeVariant(SignatureOf(reply.Body...))
conn.outLck.RLock()
if !conn.closed { conn.sendMessage(reply)
conn.out <- reply
}
conn.outLck.RUnlock()
} }
} }
@@ -207,12 +204,14 @@ func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) erro
if len(values) > 0 { if len(values) > 0 {
msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...)) msg.Headers[FieldSignature] = MakeVariant(SignatureOf(values...))
} }
conn.outLck.RLock()
defer conn.outLck.RUnlock() var closed bool
if conn.closed { conn.sendMessageAndIfClosed(msg, func() {
closed = true
})
if closed {
return ErrClosed return ErrClosed
} }
conn.out <- msg
return nil return nil
} }

1
vendor/github.com/godbus/dbus/go.mod generated vendored Normal file
View File

@@ -0,0 +1 @@
module github.com/godbus/dbus

View File

@@ -1,6 +1,7 @@
package dbus package dbus
import ( import (
"context"
"errors" "errors"
"strings" "strings"
) )
@@ -9,7 +10,11 @@ import (
// invoked. // invoked.
type BusObject interface { type BusObject interface {
Call(method string, flags Flags, args ...interface{}) *Call Call(method string, flags Flags, args ...interface{}) *Call
CallWithContext(ctx context.Context, method string, flags Flags, args ...interface{}) *Call
Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call
GoWithContext(ctx context.Context, method string, flags Flags, ch chan *Call, args ...interface{}) *Call
AddMatchSignal(iface, member string, options ...MatchOption) *Call
RemoveMatchSignal(iface, member string, options ...MatchOption) *Call
GetProperty(p string) (Variant, error) GetProperty(p string) (Variant, error)
Destination() string Destination() string
Path() ObjectPath Path() ObjectPath
@@ -24,16 +29,73 @@ type Object struct {
// Call calls a method with (*Object).Go and waits for its reply. // Call calls a method with (*Object).Go and waits for its reply.
func (o *Object) Call(method string, flags Flags, args ...interface{}) *Call { func (o *Object) Call(method string, flags Flags, args ...interface{}) *Call {
return <-o.Go(method, flags, make(chan *Call, 1), args...).Done return <-o.createCall(context.Background(), method, flags, make(chan *Call, 1), args...).Done
} }
// AddMatchSignal subscribes BusObject to signals from specified interface and // CallWithContext acts like Call but takes a context
// method (member). func (o *Object) CallWithContext(ctx context.Context, method string, flags Flags, args ...interface{}) *Call {
func (o *Object) AddMatchSignal(iface, member string) *Call { return <-o.createCall(ctx, method, flags, make(chan *Call, 1), args...).Done
return o.Call( }
// 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.
func (o *Object) AddMatchSignal(iface, member string, options ...MatchOption) *Call {
base := []MatchOption{
{"type", "signal"},
{"interface", iface},
{"member", member},
}
options = append(base, options...)
return o.conn.BusObject().Call(
"org.freedesktop.DBus.AddMatch", "org.freedesktop.DBus.AddMatch",
0, 0,
"type='signal',interface='"+iface+"',member='"+member+"'", formatMatchOptions(options),
)
}
// RemoveMatchSignal unsubscribes BusObject from signals from specified interface,
// method (member). Additional filter rules can be added via WithMatch* option constructors
func (o *Object) RemoveMatchSignal(iface, member string, options ...MatchOption) *Call {
base := []MatchOption{
{"type", "signal"},
{"interface", iface},
{"member", member},
}
options = append(base, options...)
return o.conn.BusObject().Call(
"org.freedesktop.DBus.RemoveMatch",
0,
formatMatchOptions(options),
) )
} }
@@ -49,6 +111,18 @@ func (o *Object) AddMatchSignal(iface, member string) *Call {
// If the method parameter contains a dot ('.'), the part before the last dot // If the method parameter contains a dot ('.'), the part before the last dot
// specifies the interface on which the method is called. // specifies the interface on which the method is called.
func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call { func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface{}) *Call {
return o.createCall(context.Background(), method, flags, ch, args...)
}
// GoWithContext acts like Go but takes a context
func (o *Object) GoWithContext(ctx context.Context, method string, flags Flags, ch chan *Call, args ...interface{}) *Call {
return o.createCall(ctx, method, flags, ch, args...)
}
func (o *Object) createCall(ctx context.Context, method string, flags Flags, ch chan *Call, args ...interface{}) *Call {
if ctx == nil {
panic("nil context")
}
iface := "" iface := ""
i := strings.LastIndex(method, ".") i := strings.LastIndex(method, ".")
if i != -1 { if i != -1 {
@@ -76,28 +150,28 @@ func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface
} else if cap(ch) == 0 { } else if cap(ch) == 0 {
panic("dbus: unbuffered channel passed to (*Object).Go") panic("dbus: unbuffered channel passed to (*Object).Go")
} }
ctx, cancel := context.WithCancel(ctx)
call := &Call{ call := &Call{
Destination: o.dest, Destination: o.dest,
Path: o.path, Path: o.path,
Method: method, Method: method,
Args: args, Args: args,
Done: ch, Done: ch,
ctxCanceler: cancel,
ctx: ctx,
} }
o.conn.callsLck.Lock() o.conn.calls.track(msg.serial, call)
o.conn.calls[msg.serial] = call o.conn.sendMessageAndIfClosed(msg, func() {
o.conn.callsLck.Unlock() o.conn.calls.handleSendError(msg, ErrClosed)
o.conn.outLck.RLock() cancel()
if o.conn.closed { })
call.Err = ErrClosed go func() {
call.Done <- call <-ctx.Done()
} else { o.conn.calls.handleSendError(msg, ctx.Err())
o.conn.out <- msg }()
}
o.conn.outLck.RUnlock()
return call return call
} }
o.conn.outLck.RLock()
defer o.conn.outLck.RUnlock()
done := make(chan *Call, 1) done := make(chan *Call, 1)
call := &Call{ call := &Call{
Err: nil, Err: nil,
@@ -107,11 +181,9 @@ func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface
call.Done <- call call.Done <- call
close(done) close(done)
}() }()
if o.conn.closed { o.conn.sendMessageAndIfClosed(msg, func() {
call.Err = ErrClosed call.Err = ErrClosed
return call })
}
o.conn.out <- msg
return call return call
} }

View File

@@ -87,3 +87,13 @@ type SignalHandler interface {
type DBusError interface { type DBusError interface {
DBusError() (string, []interface{}) DBusError() (string, []interface{})
} }
// SerialGenerator is responsible for serials generation.
//
// Different approaches for the serial generation can be used,
// maintaining a map guarded with a mutex (the standard way) or
// simply increment an atomic counter.
type SerialGenerator interface {
GetSerial() uint32
RetireSerial(serial uint32)
}

39
vendor/github.com/godbus/dbus/transport_nonce_tcp.go generated vendored Normal file
View File

@@ -0,0 +1,39 @@
//+build !windows
package dbus
import (
"errors"
"io/ioutil"
"net"
)
func init() {
transports["nonce-tcp"] = newNonceTcpTransport
}
func newNonceTcpTransport(keys string) (transport, error) {
host := getKey(keys, "host")
port := getKey(keys, "port")
noncefile := getKey(keys, "noncefile")
if host == "" || port == "" || noncefile == "" {
return nil, errors.New("dbus: unsupported address (must set host, port and noncefile)")
}
protocol, err := tcpFamily(keys)
if err != nil {
return nil, err
}
socket, err := net.Dial(protocol, net.JoinHostPort(host, port))
if err != nil {
return nil, err
}
b, err := ioutil.ReadFile(noncefile)
if err != nil {
return nil, err
}
_, err = socket.Write(b)
if err != nil {
return nil, err
}
return NewConn(socket)
}

View File

@@ -31,6 +31,7 @@ func (o *oobReader) Read(b []byte) (n int, err error) {
type unixTransport struct { type unixTransport struct {
*net.UnixConn *net.UnixConn
rdr *oobReader
hasUnixFDs bool hasUnixFDs bool
} }
@@ -79,10 +80,15 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
// To be sure that all bytes of out-of-band data are read, we use a special // To be sure that all bytes of out-of-band data are read, we use a special
// reader that uses ReadUnix on the underlying connection instead of Read // reader that uses ReadUnix on the underlying connection instead of Read
// and gathers the out-of-band data in a buffer. // and gathers the out-of-band data in a buffer.
rd := &oobReader{conn: t.UnixConn} if t.rdr == nil {
t.rdr = &oobReader{conn: t.UnixConn}
} else {
t.rdr.oob = nil
}
// read the first 16 bytes (the part of the header that has a constant size), // read the first 16 bytes (the part of the header that has a constant size),
// from which we can figure out the length of the rest of the message // from which we can figure out the length of the rest of the message
if _, err := io.ReadFull(rd, csheader[:]); err != nil { if _, err := io.ReadFull(t.rdr, csheader[:]); err != nil {
return nil, err return nil, err
} }
switch csheader[0] { switch csheader[0] {
@@ -104,7 +110,7 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
// decode headers and look for unix fds // decode headers and look for unix fds
headerdata := make([]byte, hlen+4) headerdata := make([]byte, hlen+4)
copy(headerdata, csheader[12:]) copy(headerdata, csheader[12:])
if _, err := io.ReadFull(t, headerdata[4:]); err != nil { if _, err := io.ReadFull(t.rdr, headerdata[4:]); err != nil {
return nil, err return nil, err
} }
dec := newDecoder(bytes.NewBuffer(headerdata), order) dec := newDecoder(bytes.NewBuffer(headerdata), order)
@@ -122,7 +128,7 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
all := make([]byte, 16+hlen+blen) all := make([]byte, 16+hlen+blen)
copy(all, csheader[:]) copy(all, csheader[:])
copy(all[16:], headerdata[4:]) copy(all[16:], headerdata[4:])
if _, err := io.ReadFull(rd, all[16+hlen:]); err != nil { if _, err := io.ReadFull(t.rdr, all[16+hlen:]); err != nil {
return nil, err return nil, err
} }
if unixfds != 0 { if unixfds != 0 {
@@ -130,7 +136,7 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
return nil, errors.New("dbus: got unix fds on unsupported transport") return nil, errors.New("dbus: got unix fds on unsupported transport")
} }
// read the fds from the OOB data // read the fds from the OOB data
scms, err := syscall.ParseSocketControlMessage(rd.oob) scms, err := syscall.ParseSocketControlMessage(t.rdr.oob)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -148,11 +154,23 @@ func (t *unixTransport) ReadMessage() (*Message, error) {
// substitute the values in the message body (which are indices for the // substitute the values in the message body (which are indices for the
// array receiver via OOB) with the actual values // array receiver via OOB) with the actual values
for i, v := range msg.Body { for i, v := range msg.Body {
if j, ok := v.(UnixFDIndex); ok { switch v.(type) {
case UnixFDIndex:
j := v.(UnixFDIndex)
if uint32(j) >= unixfds { if uint32(j) >= unixfds {
return nil, InvalidMessageError("invalid index for unix fd") return nil, InvalidMessageError("invalid index for unix fd")
} }
msg.Body[i] = UnixFD(fds[j]) msg.Body[i] = UnixFD(fds[j])
case []UnixFDIndex:
idxArray := v.([]UnixFDIndex)
fdArray := make([]UnixFD, len(idxArray))
for k, j := range idxArray {
if uint32(j) >= unixfds {
return nil, InvalidMessageError("invalid index for unix fd")
}
fdArray[k] = UnixFD(fds[j])
}
msg.Body[i] = fdArray
} }
} }
return msg, nil return msg, nil

View File

@@ -139,19 +139,16 @@ func CopyDirectory(source string, dest string) error {
return nil return nil
} }
// Copy the file. return CopyFile(path, filepath.Join(dest, relPath))
if err := CopyFile(path, filepath.Join(dest, relPath)); err != nil {
return err
}
return nil
}) })
} }
// Gives a number indicating the device driver to be used to access the passed device
func major(device uint64) uint64 { func major(device uint64) uint64 {
return (device >> 8) & 0xfff return (device >> 8) & 0xfff
} }
// Gives a number that serves as a flag to the device driver for the passed device
func minor(device uint64) uint64 { func minor(device uint64) uint64 {
return (device & 0xff) | ((device >> 12) & 0xfff00) return (device & 0xff) | ((device >> 12) & 0xfff00)
} }

View File

@@ -261,6 +261,7 @@ process := &libcontainer.Process{
Stdin: os.Stdin, Stdin: os.Stdin,
Stdout: os.Stdout, Stdout: os.Stdout,
Stderr: os.Stderr, Stderr: os.Stderr,
Init: true,
} }
err := container.Run(process) err := container.Run(process)

View File

@@ -6,6 +6,8 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"github.com/opencontainers/runc/libcontainer/utils"
) )
// IsEnabled returns true if apparmor is enabled for the host. // IsEnabled returns true if apparmor is enabled for the host.
@@ -19,7 +21,7 @@ func IsEnabled() bool {
return false return false
} }
func setprocattr(attr, value string) error { func setProcAttr(attr, value string) error {
// Under AppArmor you can only change your own attr, so use /proc/self/ // Under AppArmor you can only change your own attr, so use /proc/self/
// instead of /proc/<tid>/ like libapparmor does // instead of /proc/<tid>/ like libapparmor does
path := fmt.Sprintf("/proc/self/attr/%s", attr) path := fmt.Sprintf("/proc/self/attr/%s", attr)
@@ -30,6 +32,10 @@ func setprocattr(attr, value string) error {
} }
defer f.Close() defer f.Close()
if err := utils.EnsureProcHandle(f); err != nil {
return err
}
_, err = fmt.Fprintf(f, "%s", value) _, err = fmt.Fprintf(f, "%s", value)
return err return err
} }
@@ -37,7 +43,7 @@ func setprocattr(attr, value string) error {
// changeOnExec reimplements aa_change_onexec from libapparmor in Go // changeOnExec reimplements aa_change_onexec from libapparmor in Go
func changeOnExec(name string) error { func changeOnExec(name string) error {
value := "exec " + name value := "exec " + name
if err := setprocattr("exec", value); err != nil { if err := setProcAttr("exec", value); err != nil {
return fmt.Errorf("apparmor failed to apply profile: %s", err) return fmt.Errorf("apparmor failed to apply profile: %s", err)
} }
return nil return nil

View File

@@ -71,7 +71,11 @@ func newContainerCapList(capConfig *configs.Capabilities) (*containerCapabilitie
} }
ambient = append(ambient, v) ambient = append(ambient, v)
} }
pid, err := capability.NewPid(0) pid, err := capability.NewPid2(0)
if err != nil {
return nil, err
}
err = pid.Load()
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -6,19 +6,25 @@ go_library(
"apply_raw.go", "apply_raw.go",
"blkio.go", "blkio.go",
"cpu.go", "cpu.go",
"cpu_v2.go",
"cpuacct.go", "cpuacct.go",
"cpuset.go", "cpuset.go",
"cpuset_v2.go",
"devices.go", "devices.go",
"freezer.go", "freezer.go",
"freezer_v2.go",
"fs_unsupported.go", "fs_unsupported.go",
"hugetlb.go", "hugetlb.go",
"io_v2.go",
"kmem.go", "kmem.go",
"memory.go", "memory.go",
"memory_v2.go",
"name.go", "name.go",
"net_cls.go", "net_cls.go",
"net_prio.go", "net_prio.go",
"perf_event.go", "perf_event.go",
"pids.go", "pids.go",
"pids_v2.go",
"utils.go", "utils.go",
], ],
importmap = "k8s.io/kubernetes/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs", importmap = "k8s.io/kubernetes/vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs",

View File

@@ -18,7 +18,7 @@ import (
) )
var ( var (
subsystems = subsystemSet{ subsystemsLegacy = subsystemSet{
&CpusetGroup{}, &CpusetGroup{},
&DevicesGroup{}, &DevicesGroup{},
&MemoryGroup{}, &MemoryGroup{},
@@ -33,6 +33,14 @@ var (
&FreezerGroup{}, &FreezerGroup{},
&NameGroup{GroupName: "name=systemd", Join: true}, &NameGroup{GroupName: "name=systemd", Join: true},
} }
subsystemsUnified = subsystemSet{
&CpusetGroupV2{},
&FreezerGroupV2{},
&CpuGroupV2{},
&MemoryGroupV2{},
&IOGroupV2{},
&PidsGroupV2{},
}
HugePageSizes, _ = cgroups.GetHugePageSize() HugePageSizes, _ = cgroups.GetHugePageSize()
) )
@@ -129,6 +137,13 @@ func isIgnorableError(rootless bool, err error) bool {
return errno == unix.EROFS || errno == unix.EPERM || errno == unix.EACCES return errno == unix.EROFS || errno == unix.EPERM || errno == unix.EACCES
} }
func (m *Manager) getSubsystems() subsystemSet {
if cgroups.IsCgroup2UnifiedMode() {
return subsystemsUnified
}
return subsystemsLegacy
}
func (m *Manager) Apply(pid int) (err error) { func (m *Manager) Apply(pid int) (err error) {
if m.Cgroups == nil { if m.Cgroups == nil {
return nil return nil
@@ -158,7 +173,7 @@ func (m *Manager) Apply(pid int) (err error) {
return cgroups.EnterPid(m.Paths, pid) return cgroups.EnterPid(m.Paths, pid)
} }
for _, sys := range subsystems { for _, sys := range m.getSubsystems() {
// TODO: Apply should, ideally, be reentrant or be broken up into a separate // 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 // 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 // created then join consists of writing the process pids to cgroup.procs
@@ -214,7 +229,7 @@ func (m *Manager) GetStats() (*cgroups.Stats, error) {
defer m.mu.Unlock() defer m.mu.Unlock()
stats := cgroups.NewStats() stats := cgroups.NewStats()
for name, path := range m.Paths { for name, path := range m.Paths {
sys, err := subsystems.Get(name) sys, err := m.getSubsystems().Get(name)
if err == errSubsystemDoesNotExist || !cgroups.PathExists(path) { if err == errSubsystemDoesNotExist || !cgroups.PathExists(path) {
continue continue
} }
@@ -226,14 +241,18 @@ func (m *Manager) GetStats() (*cgroups.Stats, error) {
} }
func (m *Manager) Set(container *configs.Config) error { 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 // If Paths are set, then we are just joining cgroups paths
// and there is no need to set any values. // and there is no need to set any values.
if m.Cgroups.Paths != nil { if m.Cgroups != nil && m.Cgroups.Paths != nil {
return nil return nil
} }
paths := m.GetPaths() paths := m.GetPaths()
for _, sys := range subsystems { for _, sys := range m.getSubsystems() {
path := paths[sys.Name()] path := paths[sys.Name()]
if err := sys.Set(path, container.Cgroups); err != nil { if err := sys.Set(path, container.Cgroups); err != nil {
if m.Rootless && sys.Name() == "devices" { if m.Rootless && sys.Name() == "devices" {
@@ -262,11 +281,15 @@ func (m *Manager) Set(container *configs.Config) error {
// Freeze toggles the container's freezer cgroup depending on the state // Freeze toggles the container's freezer cgroup depending on the state
// provided // provided
func (m *Manager) Freeze(state configs.FreezerState) error { 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() paths := m.GetPaths()
dir := paths["freezer"] dir := paths["freezer"]
prevState := m.Cgroups.Resources.Freezer prevState := m.Cgroups.Resources.Freezer
m.Cgroups.Resources.Freezer = state m.Cgroups.Resources.Freezer = state
freezer, err := subsystems.Get("freezer") freezer, err := m.getSubsystems().Get("freezer")
if err != nil { if err != nil {
return err return err
} }

View File

@@ -0,0 +1,92 @@
// +build linux
package fs
import (
"bufio"
"os"
"path/filepath"
"strconv"
"github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/configs"
)
type CpuGroupV2 struct {
}
func (s *CpuGroupV2) Name() string {
return "cpu"
}
func (s *CpuGroupV2) 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 *CpuGroupV2) ApplyDir(path string, cgroup *configs.Cgroup, pid int) error {
// This might happen if we have no cpu cgroup mounted.
// Just do nothing and don't fail.
if path == "" {
return nil
}
if err := os.MkdirAll(path, 0755); err != nil {
return err
}
return cgroups.WriteCgroupProc(path, pid)
}
func (s *CpuGroupV2) Set(path string, cgroup *configs.Cgroup) error {
if cgroup.Resources.CpuWeight != 0 {
if err := writeFile(path, "cpu.weight", strconv.FormatUint(cgroup.Resources.CpuWeight, 10)); err != nil {
return err
}
}
if cgroup.Resources.CpuMax != "" {
if err := writeFile(path, "cpu.max", cgroup.Resources.CpuMax); err != nil {
return err
}
}
return nil
}
func (s *CpuGroupV2) Remove(d *cgroupData) error {
return removePath(d.path("cpu"))
}
func (s *CpuGroupV2) GetStats(path string, stats *cgroups.Stats) error {
f, err := os.Open(filepath.Join(path, "cpu.stat"))
if err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}
defer f.Close()
sc := bufio.NewScanner(f)
for sc.Scan() {
t, v, err := getCgroupParamKeyValue(sc.Text())
if err != nil {
return err
}
switch t {
case "usage_usec":
stats.CpuStats.CpuUsage.TotalUsage = v * 1000
case "user_usec":
stats.CpuStats.CpuUsage.UsageInUsermode = v * 1000
case "system_usec":
stats.CpuStats.CpuUsage.UsageInKernelmode = v * 1000
}
}
return nil
}

View File

@@ -0,0 +1,159 @@
// +build linux
package fs
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/configs"
libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils"
)
type CpusetGroupV2 struct {
}
func (s *CpusetGroupV2) Name() string {
return "cpuset"
}
func (s *CpusetGroupV2) 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 *CpusetGroupV2) Set(path string, cgroup *configs.Cgroup) error {
if cgroup.Resources.CpusetCpus != "" {
if err := writeFile(path, "cpuset.cpus", cgroup.Resources.CpusetCpus); err != nil {
return err
}
}
if cgroup.Resources.CpusetMems != "" {
if err := writeFile(path, "cpuset.mems", cgroup.Resources.CpusetMems); err != nil {
return err
}
}
return nil
}
func (s *CpusetGroupV2) Remove(d *cgroupData) error {
return removePath(d.path("cpuset"))
}
func (s *CpusetGroupV2) GetStats(path string, stats *cgroups.Stats) error {
return nil
}
func (s *CpusetGroupV2) 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")
if err != nil {
return err
}
root := filepath.Dir(cgroups.GetClosestMountpointAncestor(dir, string(mountInfo)))
// 'ensureParent' start with parent because we don't want to
// explicitly inherit from parent, it could conflict with
// 'cpuset.cpu_exclusive'.
if err := s.ensureParent(filepath.Dir(dir), root); err != nil {
return err
}
if err := os.MkdirAll(dir, 0755); err != nil {
return err
}
// We didn't inherit cpuset configs from parent, but we have
// to ensure cpuset configs are set before moving task into the
// cgroup.
// The logic is, if user specified cpuset configs, use these
// specified configs, otherwise, inherit from parent. This makes
// cpuset configs work correctly with 'cpuset.cpu_exclusive', and
// keep backward compatibility.
if err := s.ensureCpusAndMems(dir, cgroup); 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(dir, pid)
}
func (s *CpusetGroupV2) getSubsystemSettings(parent string) (cpus []byte, mems []byte, err error) {
if cpus, err = ioutil.ReadFile(filepath.Join(parent, "cpuset.cpus.effective")); err != nil {
return
}
if mems, err = ioutil.ReadFile(filepath.Join(parent, "cpuset.mems.effective")); err != nil {
return
}
return cpus, mems, nil
}
// ensureParent makes sure that the parent directory of current is created
// and populated with the proper cpus and mems files copied from
// it's parent.
func (s *CpusetGroupV2) ensureParent(current, root string) error {
parent := filepath.Dir(current)
if libcontainerUtils.CleanPath(parent) == root {
return nil
}
// Avoid infinite recursion.
if parent == current {
return fmt.Errorf("cpuset: cgroup parent path outside cgroup root")
}
if err := s.ensureParent(parent, root); err != nil {
return err
}
if err := os.MkdirAll(current, 0755); err != nil {
return err
}
return s.copyIfNeeded(current, parent)
}
// copyIfNeeded copies the cpuset.cpus and cpuset.mems from the parent
// directory to the current directory if the file's contents are 0
func (s *CpusetGroupV2) copyIfNeeded(current, parent string) error {
var (
err error
currentCpus, currentMems []byte
parentCpus, parentMems []byte
)
if currentCpus, currentMems, err = s.getSubsystemSettings(current); err != nil {
return err
}
if parentCpus, parentMems, err = s.getSubsystemSettings(parent); err != nil {
return err
}
if s.isEmpty(currentCpus) {
if err := writeFile(current, "cpuset.cpus", string(parentCpus)); err != nil {
return err
}
}
if s.isEmpty(currentMems) {
if err := writeFile(current, "cpuset.mems", string(parentMems)); err != nil {
return err
}
}
return nil
}
func (s *CpusetGroupV2) isEmpty(b []byte) bool {
return len(bytes.Trim(b, "\n")) == 0
}
func (s *CpusetGroupV2) ensureCpusAndMems(path string, cgroup *configs.Cgroup) error {
if err := s.Set(path, cgroup); err != nil {
return err
}
return s.copyIfNeeded(path, filepath.Dir(path))
}

View File

@@ -0,0 +1,74 @@
// +build linux
package fs
import (
"fmt"
"strings"
"time"
"github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/configs"
)
type FreezerGroupV2 struct {
}
func (s *FreezerGroupV2) Name() string {
return "freezer"
}
func (s *FreezerGroupV2) Apply(d *cgroupData) error {
_, err := d.join("freezer")
if err != nil && !cgroups.IsNotFound(err) {
return err
}
return nil
}
func (s *FreezerGroupV2) Set(path string, cgroup *configs.Cgroup) error {
var desiredState string
filename := "cgroup.freeze"
if cgroup.Resources.Freezer == configs.Frozen {
desiredState = "1"
} else {
desiredState = "0"
}
switch cgroup.Resources.Freezer {
case configs.Frozen, configs.Thawed:
for {
// In case this loop does not exit because it doesn't get the expected
// state, let's write again this state, hoping it's going to be properly
// set this time. Otherwise, this loop could run infinitely, waiting for
// a state change that would never happen.
if err := writeFile(path, filename, desiredState); err != nil {
return err
}
state, err := readFile(path, filename)
if err != nil {
return err
}
if strings.TrimSpace(state) == desiredState {
break
}
time.Sleep(1 * time.Millisecond)
}
case configs.Undefined:
return nil
default:
return fmt.Errorf("Invalid argument '%s' to freezer.state", string(cgroup.Resources.Freezer))
}
return nil
}
func (s *FreezerGroupV2) Remove(d *cgroupData) error {
return removePath(d.path("freezer"))
}
func (s *FreezerGroupV2) GetStats(path string, stats *cgroups.Stats) error {
return nil
}

View File

@@ -0,0 +1,191 @@
// +build linux
package fs
import (
"bufio"
"os"
"path/filepath"
"strconv"
"strings"
"github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/configs"
)
type IOGroupV2 struct {
}
func (s *IOGroupV2) Name() string {
return "blkio"
}
func (s *IOGroupV2) Apply(d *cgroupData) error {
_, err := d.join("blkio")
if err != nil && !cgroups.IsNotFound(err) {
return err
}
return nil
}
func (s *IOGroupV2) Set(path string, cgroup *configs.Cgroup) error {
cgroupsv2 := cgroups.IsCgroup2UnifiedMode()
if cgroup.Resources.BlkioWeight != 0 {
filename := "blkio.weight"
if cgroupsv2 {
filename = "io.bfq.weight"
}
if err := writeFile(path, filename, strconv.FormatUint(uint64(cgroup.Resources.BlkioWeight), 10)); err != nil {
return err
}
}
if cgroup.Resources.BlkioLeafWeight != 0 {
if err := writeFile(path, "blkio.leaf_weight", strconv.FormatUint(uint64(cgroup.Resources.BlkioLeafWeight), 10)); err != nil {
return err
}
}
for _, wd := range cgroup.Resources.BlkioWeightDevice {
if err := writeFile(path, "blkio.weight_device", wd.WeightString()); err != nil {
return err
}
if err := writeFile(path, "blkio.leaf_weight_device", wd.LeafWeightString()); err != nil {
return err
}
}
for _, td := range cgroup.Resources.BlkioThrottleReadBpsDevice {
if cgroupsv2 {
if err := writeFile(path, "io.max", td.StringName("rbps")); err != nil {
return err
}
} else {
if err := writeFile(path, "blkio.throttle.read_bps_device", td.String()); err != nil {
return err
}
}
}
for _, td := range cgroup.Resources.BlkioThrottleWriteBpsDevice {
if cgroupsv2 {
if err := writeFile(path, "io.max", td.StringName("wbps")); err != nil {
return err
}
} else {
if err := writeFile(path, "blkio.throttle.write_bps_device", td.String()); err != nil {
return err
}
}
}
for _, td := range cgroup.Resources.BlkioThrottleReadIOPSDevice {
if cgroupsv2 {
if err := writeFile(path, "io.max", td.StringName("riops")); err != nil {
return err
}
} else {
if err := writeFile(path, "blkio.throttle.read_iops_device", td.String()); err != nil {
return err
}
}
}
for _, td := range cgroup.Resources.BlkioThrottleWriteIOPSDevice {
if cgroupsv2 {
if err := writeFile(path, "io.max", td.StringName("wiops")); err != nil {
return err
}
} else {
if err := writeFile(path, "blkio.throttle.write_iops_device", td.String()); err != nil {
return err
}
}
}
return nil
}
func (s *IOGroupV2) Remove(d *cgroupData) error {
return removePath(d.path("blkio"))
}
func readCgroup2MapFile(path string, name string) (map[string][]string, error) {
ret := map[string][]string{}
p := filepath.Join("/sys/fs/cgroup", path, name)
f, err := os.Open(p)
if err != nil {
if os.IsNotExist(err) {
return ret, nil
}
return nil, err
}
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
line := scanner.Text()
parts := strings.Fields(line)
if len(parts) < 2 {
continue
}
ret[parts[0]] = parts[1:]
}
if err := scanner.Err(); err != nil {
return nil, err
}
return ret, nil
}
func (s *IOGroupV2) getCgroupV2Stats(path string, stats *cgroups.Stats) error {
// more details on the io.stat file format: https://www.kernel.org/doc/Documentation/cgroup-v2.txt
var ioServiceBytesRecursive []cgroups.BlkioStatEntry
values, err := readCgroup2MapFile(path, "io.stat")
if err != nil {
return err
}
for k, v := range values {
d := strings.Split(k, ":")
if len(d) != 2 {
continue
}
minor, err := strconv.ParseUint(d[0], 10, 0)
if err != nil {
return err
}
major, err := strconv.ParseUint(d[1], 10, 0)
if err != nil {
return err
}
for _, item := range v {
d := strings.Split(item, "=")
if len(d) != 2 {
continue
}
op := d[0]
// Accommodate the cgroup v1 naming
switch op {
case "rbytes":
op = "read"
case "wbytes":
op = "write"
}
value, err := strconv.ParseUint(d[1], 10, 0)
if err != nil {
return err
}
entry := cgroups.BlkioStatEntry{
Op: op,
Major: major,
Minor: minor,
Value: value,
}
ioServiceBytesRecursive = append(ioServiceBytesRecursive, entry)
}
}
stats.BlkioStats = cgroups.BlkioStats{IoServiceBytesRecursive: ioServiceBytesRecursive}
return nil
}
func (s *IOGroupV2) GetStats(path string, stats *cgroups.Stats) error {
return s.getCgroupV2Stats(path, stats)
}

View File

@@ -0,0 +1,164 @@
// +build linux
package fs
import (
"bufio"
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
"github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/configs"
)
type MemoryGroupV2 struct {
}
func (s *MemoryGroupV2) Name() string {
return "memory"
}
func (s *MemoryGroupV2) Apply(d *cgroupData) (err error) {
path, err := d.path("memory")
if err != nil && !cgroups.IsNotFound(err) {
return err
} else if path == "" {
return nil
}
if memoryAssigned(d.config) {
if _, err := os.Stat(path); os.IsNotExist(err) {
if err := os.MkdirAll(path, 0755); err != nil {
return err
}
// Only enable kernel memory accouting when this cgroup
// is created by libcontainer, otherwise we might get
// error when people use `cgroupsPath` to join an existed
// cgroup whose kernel memory is not initialized.
if err := EnableKernelMemoryAccounting(path); err != nil {
return err
}
}
}
defer func() {
if err != nil {
os.RemoveAll(path)
}
}()
// 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
}
func setMemoryAndSwapCgroups(path string, cgroup *configs.Cgroup) error {
if cgroup.Resources.MemorySwap != 0 {
if err := writeFile(path, "memory.swap.max", strconv.FormatInt(cgroup.Resources.MemorySwap, 10)); err != nil {
return err
}
}
if cgroup.Resources.Memory != 0 {
if err := writeFile(path, "memory.max", strconv.FormatInt(cgroup.Resources.Memory, 10)); err != nil {
return err
}
}
return nil
}
func (s *MemoryGroupV2) Set(path string, cgroup *configs.Cgroup) error {
if err := setMemoryAndSwapCgroups(path, cgroup); err != nil {
return err
}
if cgroup.Resources.KernelMemory != 0 {
if err := setKernelMemory(path, cgroup.Resources.KernelMemory); err != nil {
return err
}
}
if cgroup.Resources.MemoryReservation != 0 {
if err := writeFile(path, "memory.high", strconv.FormatInt(cgroup.Resources.MemoryReservation, 10)); err != nil {
return err
}
}
return nil
}
func (s *MemoryGroupV2) Remove(d *cgroupData) error {
return removePath(d.path("memory"))
}
func (s *MemoryGroupV2) GetStats(path string, stats *cgroups.Stats) error {
// Set stats from memory.stat.
statsFile, err := os.Open(filepath.Join(path, "memory.stat"))
if err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}
defer statsFile.Close()
sc := bufio.NewScanner(statsFile)
for sc.Scan() {
t, v, err := getCgroupParamKeyValue(sc.Text())
if err != nil {
return fmt.Errorf("failed to parse memory.stat (%q) - %v", sc.Text(), err)
}
stats.MemoryStats.Stats[t] = v
}
stats.MemoryStats.Cache = stats.MemoryStats.Stats["cache"]
memoryUsage, err := getMemoryDataV2(path, "")
if err != nil {
return err
}
stats.MemoryStats.Usage = memoryUsage
swapUsage, err := getMemoryDataV2(path, "swap")
if err != nil {
return err
}
stats.MemoryStats.SwapUsage = swapUsage
stats.MemoryStats.UseHierarchy = true
return nil
}
func getMemoryDataV2(path, name string) (cgroups.MemoryData, error) {
memoryData := cgroups.MemoryData{}
moduleName := "memory"
if name != "" {
moduleName = strings.Join([]string{"memory", name}, ".")
}
usage := strings.Join([]string{moduleName, "current"}, ".")
limit := strings.Join([]string{moduleName, "max"}, ".")
value, err := getCgroupParamUint(path, usage)
if err != nil {
if moduleName != "memory" && os.IsNotExist(err) {
return cgroups.MemoryData{}, nil
}
return cgroups.MemoryData{}, fmt.Errorf("failed to parse %s - %v", usage, err)
}
memoryData.Usage = value
value, err = getCgroupParamUint(path, limit)
if err != nil {
if moduleName != "memory" && os.IsNotExist(err) {
return cgroups.MemoryData{}, nil
}
return cgroups.MemoryData{}, fmt.Errorf("failed to parse %s - %v", limit, err)
}
memoryData.Limit = value
return memoryData, nil
}

View File

@@ -0,0 +1,107 @@
// +build linux
package fs
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/configs"
"golang.org/x/sys/unix"
)
type PidsGroupV2 struct {
}
func (s *PidsGroupV2) Name() string {
return "pids"
}
func (s *PidsGroupV2) Apply(d *cgroupData) error {
_, err := d.join("pids")
if err != nil && !cgroups.IsNotFound(err) {
return err
}
return nil
}
func (s *PidsGroupV2) Set(path 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 := writeFile(path, "pids.max", limit); err != nil {
return err
}
}
return nil
}
func (s *PidsGroupV2) Remove(d *cgroupData) error {
return removePath(d.path("pids"))
}
func isNOTSUP(err error) bool {
switch err := err.(type) {
case *os.PathError:
return err.Err == unix.ENOTSUP
default:
return false
}
}
func (s *PidsGroupV2) GetStats(path string, stats *cgroups.Stats) error {
current, err := getCgroupParamUint(path, "pids.current")
if os.IsNotExist(err) {
// if the controller is not enabled, let's read the list
// PIDs (or threads if cgroup.threads is enabled)
contents, err := ioutil.ReadFile(filepath.Join(path, "cgroup.procs"))
if err != nil && isNOTSUP(err) {
contents, err = ioutil.ReadFile(filepath.Join(path, "cgroup.threads"))
}
if err != nil {
return err
}
pids := make(map[string]string)
for _, i := range strings.Split(string(contents), "\n") {
if i != "" {
pids[i] = i
}
}
stats.PidsStats.Current = uint64(len(pids))
stats.PidsStats.Limit = 0
return nil
}
if err != nil {
return fmt.Errorf("failed to parse pids.current - %s", err)
}
maxString, err := getCgroupParamString(path, "pids.max")
if err != nil {
return fmt.Errorf("failed to parse pids.max - %s", err)
}
// Default if pids.max == "max" is 0 -- which represents "no limit".
var max uint64
if maxString != "max" {
max, err = parseUint(maxString, 10, 64)
if err != nil {
return fmt.Errorf("failed to parse pids.max - unable to parse %q as a uint from Cgroup file %q", maxString, filepath.Join(path, "pids.max"))
}
}
stats.PidsStats.Current = current
stats.PidsStats.Limit = max
return nil
}

View File

@@ -6,6 +6,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"math"
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
@@ -59,8 +60,12 @@ func getCgroupParamUint(cgroupPath, cgroupFile string) (uint64, error) {
if err != nil { if err != nil {
return 0, err return 0, err
} }
trimmed := strings.TrimSpace(string(contents))
if trimmed == "max" {
return math.MaxUint64, nil
}
res, err := parseUint(strings.TrimSpace(string(contents)), 10, 64) res, err := parseUint(trimmed, 10, 64)
if err != nil { if err != nil {
return res, fmt.Errorf("unable to parse %q as a uint from Cgroup file %q", string(contents), fileName) return res, fmt.Errorf("unable to parse %q as a uint from Cgroup file %q", string(contents), fileName)
} }

View File

@@ -5,6 +5,7 @@ go_library(
srcs = [ srcs = [
"apply_nosystemd.go", "apply_nosystemd.go",
"apply_systemd.go", "apply_systemd.go",
"unified_hierarchy.go",
], ],
importmap = "k8s.io/kubernetes/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd", importmap = "k8s.io/kubernetes/vendor/github.com/opencontainers/runc/libcontainer/cgroups/systemd",
importpath = "github.com/opencontainers/runc/libcontainer/cgroups/systemd", importpath = "github.com/opencontainers/runc/libcontainer/cgroups/systemd",
@@ -28,7 +29,6 @@ go_library(
], ],
"@io_bazel_rules_go//go/platform:linux": [ "@io_bazel_rules_go//go/platform:linux": [
"//vendor/github.com/coreos/go-systemd/dbus:go_default_library", "//vendor/github.com/coreos/go-systemd/dbus:go_default_library",
"//vendor/github.com/coreos/go-systemd/util:go_default_library",
"//vendor/github.com/godbus/dbus:go_default_library", "//vendor/github.com/godbus/dbus:go_default_library",
"//vendor/github.com/opencontainers/runc/libcontainer/cgroups:go_default_library", "//vendor/github.com/opencontainers/runc/libcontainer/cgroups:go_default_library",
"//vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs:go_default_library", "//vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs:go_default_library",

View File

@@ -14,7 +14,6 @@ import (
"time" "time"
systemdDbus "github.com/coreos/go-systemd/dbus" systemdDbus "github.com/coreos/go-systemd/dbus"
systemdUtil "github.com/coreos/go-systemd/util"
"github.com/godbus/dbus" "github.com/godbus/dbus"
"github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/cgroups/fs" "github.com/opencontainers/runc/libcontainer/cgroups/fs"
@@ -22,7 +21,7 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
type Manager struct { type LegacyManager struct {
mu sync.Mutex mu sync.Mutex
Cgroups *configs.Cgroup Cgroups *configs.Cgroup
Paths map[string]string Paths map[string]string
@@ -50,7 +49,7 @@ func (s subsystemSet) Get(name string) (subsystem, error) {
return nil, errSubsystemDoesNotExist return nil, errSubsystemDoesNotExist
} }
var subsystems = subsystemSet{ var legacySubsystems = subsystemSet{
&fs.CpusetGroup{}, &fs.CpusetGroup{},
&fs.DevicesGroup{}, &fs.DevicesGroup{},
&fs.MemoryGroup{}, &fs.MemoryGroup{},
@@ -74,9 +73,6 @@ const (
var ( var (
connLock sync.Mutex connLock sync.Mutex
theConn *systemdDbus.Conn theConn *systemdDbus.Conn
hasStartTransientUnit bool
hasStartTransientSliceUnit bool
hasDelegateSlice bool
) )
func newProp(name string, units interface{}) systemdDbus.Property { func newProp(name string, units interface{}) systemdDbus.Property {
@@ -86,8 +82,23 @@ func newProp(name string, units interface{}) systemdDbus.Property {
} }
} }
// 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 { func UseSystemd() bool {
if !systemdUtil.IsRunningSystemd() { if !isRunningSystemd() {
return false return false
} }
@@ -100,82 +111,31 @@ func UseSystemd() bool {
if err != nil { if err != nil {
return false return false
} }
// Assume we have StartTransientUnit
hasStartTransientUnit = true
// But if we get UnknownMethod error we don't
if _, err := theConn.StartTransientUnit("test.scope", "invalid", nil, nil); err != nil {
if dbusError, ok := err.(dbus.Error); ok {
if dbusError.Name == "org.freedesktop.DBus.Error.UnknownMethod" {
hasStartTransientUnit = false
return hasStartTransientUnit
} }
} return true
}
// Assume we have the ability to start a transient unit as a slice
// This was broken until systemd v229, but has been back-ported on RHEL environments >= 219
// For details, see: https://bugzilla.redhat.com/show_bug.cgi?id=1370299
hasStartTransientSliceUnit = true
// To ensure simple clean-up, we create a slice off the root with no hierarchy
slice := fmt.Sprintf("libcontainer_%d_systemd_test_default.slice", os.Getpid())
if _, err := theConn.StartTransientUnit(slice, "replace", nil, nil); err != nil {
if _, ok := err.(dbus.Error); ok {
hasStartTransientSliceUnit = false
}
}
for i := 0; i <= testSliceWait; i++ {
if _, err := theConn.StopUnit(slice, "replace", nil); err != nil {
if dbusError, ok := err.(dbus.Error); ok {
if strings.Contains(dbusError.Name, "org.freedesktop.systemd1.NoSuchUnit") {
hasStartTransientSliceUnit = false
break
}
}
} else {
break
}
time.Sleep(time.Millisecond)
}
// Not critical because of the stop unit logic above.
theConn.StopUnit(slice, "replace", nil)
// Assume StartTransientUnit on a slice allows Delegate
hasDelegateSlice = true
dlSlice := newProp("Delegate", true)
if _, err := theConn.StartTransientUnit(slice, "replace", []systemdDbus.Property{dlSlice}, nil); err != nil {
if dbusError, ok := err.(dbus.Error); ok {
// Starting with systemd v237, Delegate is not even a property of slices anymore,
// so the D-Bus call fails with "InvalidArgs" error.
if strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.PropertyReadOnly") || strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.InvalidArgs") {
hasDelegateSlice = false
}
}
}
// Not critical because of the stop unit logic above.
theConn.StopUnit(slice, "replace", nil)
}
return hasStartTransientUnit
} }
func NewSystemdCgroupsManager() (func(config *configs.Cgroup, paths map[string]string) cgroups.Manager, error) { func NewSystemdCgroupsManager() (func(config *configs.Cgroup, paths map[string]string) cgroups.Manager, error) {
if !systemdUtil.IsRunningSystemd() { if !isRunningSystemd() {
return nil, fmt.Errorf("systemd not running on this host, can't use systemd as a cgroups.Manager") 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 func(config *configs.Cgroup, paths map[string]string) cgroups.Manager {
return &Manager{ return &UnifiedManager{
Cgroups: config,
Paths: paths,
}
}, nil
}
return func(config *configs.Cgroup, paths map[string]string) cgroups.Manager {
return &LegacyManager{
Cgroups: config, Cgroups: config,
Paths: paths, Paths: paths,
} }
}, nil }, nil
} }
func (m *Manager) Apply(pid int) error { func (m *LegacyManager) Apply(pid int) error {
var ( var (
c = m.Cgroups c = m.Cgroups
unitName = getUnitName(c) unitName = getUnitName(c)
@@ -208,10 +168,6 @@ func (m *Manager) Apply(pid int) error {
// if we create a slice, the parent is defined via a Wants= // if we create a slice, the parent is defined via a Wants=
if strings.HasSuffix(unitName, ".slice") { if strings.HasSuffix(unitName, ".slice") {
// This was broken until systemd v229, but has been back-ported on RHEL environments >= 219
if !hasStartTransientSliceUnit {
return fmt.Errorf("systemd version does not support ability to start a slice as transient unit")
}
properties = append(properties, systemdDbus.PropWants(slice)) properties = append(properties, systemdDbus.PropWants(slice))
} else { } else {
// otherwise, we use Slice= // otherwise, we use Slice=
@@ -224,12 +180,7 @@ func (m *Manager) Apply(pid int) error {
} }
// Check if we can delegate. This is only supported on systemd versions 218 and above. // Check if we can delegate. This is only supported on systemd versions 218 and above.
if strings.HasSuffix(unitName, ".slice") { if !strings.HasSuffix(unitName, ".slice") {
if hasDelegateSlice {
// systemd 237 and above no longer allows delegation on a slice
properties = append(properties, newProp("Delegate", true))
}
} else {
// Assume scopes always support delegation. // Assume scopes always support delegation.
properties = append(properties, newProp("Delegate", true)) properties = append(properties, newProp("Delegate", true))
} }
@@ -310,7 +261,7 @@ func (m *Manager) Apply(pid int) error {
} }
paths := make(map[string]string) paths := make(map[string]string)
for _, s := range subsystems { for _, s := range legacySubsystems {
subsystemPath, err := getSubsystemPath(m.Cgroups, s.Name()) subsystemPath, err := getSubsystemPath(m.Cgroups, s.Name())
if err != nil { if err != nil {
// Don't fail if a cgroup hierarchy was not found, just skip this subsystem // Don't fail if a cgroup hierarchy was not found, just skip this subsystem
@@ -325,7 +276,7 @@ func (m *Manager) Apply(pid int) error {
return nil return nil
} }
func (m *Manager) Destroy() error { func (m *LegacyManager) Destroy() error {
if m.Cgroups.Paths != nil { if m.Cgroups.Paths != nil {
return nil return nil
} }
@@ -339,7 +290,7 @@ func (m *Manager) Destroy() error {
return nil return nil
} }
func (m *Manager) GetPaths() map[string]string { func (m *LegacyManager) GetPaths() map[string]string {
m.mu.Lock() m.mu.Lock()
paths := m.Paths paths := m.Paths
m.mu.Unlock() m.mu.Unlock()
@@ -351,6 +302,7 @@ func join(c *configs.Cgroup, subsystem string, pid int) (string, error) {
if err != nil { if err != nil {
return "", err return "", err
} }
if err := os.MkdirAll(path, 0755); err != nil { if err := os.MkdirAll(path, 0755); err != nil {
return "", err return "", err
} }
@@ -361,7 +313,7 @@ func join(c *configs.Cgroup, subsystem string, pid int) (string, error) {
} }
func joinCgroups(c *configs.Cgroup, pid int) error { func joinCgroups(c *configs.Cgroup, pid int) error {
for _, sys := range subsystems { for _, sys := range legacySubsystems {
name := sys.Name() name := sys.Name()
switch name { switch name {
case "name=systemd": case "name=systemd":
@@ -456,14 +408,14 @@ func getSubsystemPath(c *configs.Cgroup, subsystem string) (string, error) {
return filepath.Join(mountpoint, initPath, slice, getUnitName(c)), nil return filepath.Join(mountpoint, initPath, slice, getUnitName(c)), nil
} }
func (m *Manager) Freeze(state configs.FreezerState) error { func (m *LegacyManager) Freeze(state configs.FreezerState) error {
path, err := getSubsystemPath(m.Cgroups, "freezer") path, err := getSubsystemPath(m.Cgroups, "freezer")
if err != nil { if err != nil {
return err return err
} }
prevState := m.Cgroups.Resources.Freezer prevState := m.Cgroups.Resources.Freezer
m.Cgroups.Resources.Freezer = state m.Cgroups.Resources.Freezer = state
freezer, err := subsystems.Get("freezer") freezer, err := legacySubsystems.Get("freezer")
if err != nil { if err != nil {
return err return err
} }
@@ -475,7 +427,7 @@ func (m *Manager) Freeze(state configs.FreezerState) error {
return nil return nil
} }
func (m *Manager) GetPids() ([]int, error) { func (m *LegacyManager) GetPids() ([]int, error) {
path, err := getSubsystemPath(m.Cgroups, "devices") path, err := getSubsystemPath(m.Cgroups, "devices")
if err != nil { if err != nil {
return nil, err return nil, err
@@ -483,7 +435,7 @@ func (m *Manager) GetPids() ([]int, error) {
return cgroups.GetPids(path) return cgroups.GetPids(path)
} }
func (m *Manager) GetAllPids() ([]int, error) { func (m *LegacyManager) GetAllPids() ([]int, error) {
path, err := getSubsystemPath(m.Cgroups, "devices") path, err := getSubsystemPath(m.Cgroups, "devices")
if err != nil { if err != nil {
return nil, err return nil, err
@@ -491,12 +443,12 @@ func (m *Manager) GetAllPids() ([]int, error) {
return cgroups.GetAllPids(path) return cgroups.GetAllPids(path)
} }
func (m *Manager) GetStats() (*cgroups.Stats, error) { func (m *LegacyManager) GetStats() (*cgroups.Stats, error) {
m.mu.Lock() m.mu.Lock()
defer m.mu.Unlock() defer m.mu.Unlock()
stats := cgroups.NewStats() stats := cgroups.NewStats()
for name, path := range m.Paths { for name, path := range m.Paths {
sys, err := subsystems.Get(name) sys, err := legacySubsystems.Get(name)
if err == errSubsystemDoesNotExist || !cgroups.PathExists(path) { if err == errSubsystemDoesNotExist || !cgroups.PathExists(path) {
continue continue
} }
@@ -508,13 +460,13 @@ func (m *Manager) GetStats() (*cgroups.Stats, error) {
return stats, nil return stats, nil
} }
func (m *Manager) Set(container *configs.Config) error { func (m *LegacyManager) Set(container *configs.Config) error {
// If Paths are set, then we are just joining cgroups paths // If Paths are set, then we are just joining cgroups paths
// and there is no need to set any values. // and there is no need to set any values.
if m.Cgroups.Paths != nil { if m.Cgroups.Paths != nil {
return nil return nil
} }
for _, sys := range subsystems { for _, sys := range legacySubsystems {
// Get the subsystem path, but don't error out for not found cgroups. // Get the subsystem path, but don't error out for not found cgroups.
path, err := getSubsystemPath(container.Cgroups, sys.Name()) path, err := getSubsystemPath(container.Cgroups, sys.Name())
if err != nil && !cgroups.IsNotFound(err) { if err != nil && !cgroups.IsNotFound(err) {

View File

@@ -0,0 +1,329 @@
// +build linux,!static_build
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/fs"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/sirupsen/logrus"
)
type UnifiedManager struct {
mu sync.Mutex
Cgroups *configs.Cgroup
Paths map[string]string
}
var unifiedSubsystems = subsystemSet{
&fs.CpusetGroupV2{},
&fs.FreezerGroupV2{},
&fs.CpuGroupV2{},
&fs.MemoryGroupV2{},
&fs.IOGroupV2{},
&fs.PidsGroupV2{},
}
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
}
paths := make(map[string]string)
for _, s := range unifiedSubsystems {
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 *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 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) 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 := unifiedSubsystems.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 *UnifiedManager) GetPids() ([]int, error) {
path, err := getSubsystemPath(m.Cgroups, "devices")
if err != nil {
return nil, err
}
return cgroups.GetPids(path)
}
func (m *UnifiedManager) GetAllPids() ([]int, error) {
path, err := getSubsystemPath(m.Cgroups, "devices")
if err != nil {
return nil, err
}
return cgroups.GetAllPids(path)
}
func (m *UnifiedManager) GetStats() (*cgroups.Stats, error) {
m.mu.Lock()
defer m.mu.Unlock()
stats := cgroups.NewStats()
for name, path := range m.Paths {
sys, err := unifiedSubsystems.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 *UnifiedManager) 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 unifiedSubsystems {
// 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
}

View File

@@ -11,6 +11,8 @@ import (
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
"sync"
"syscall"
"time" "time"
units "github.com/docker/go-units" units "github.com/docker/go-units"
@@ -22,6 +24,11 @@ const (
CgroupProcesses = "cgroup.procs" CgroupProcesses = "cgroup.procs"
) )
var (
isUnifiedOnce sync.Once
isUnified bool
)
// HugePageSizeUnitList is a list of the units used by the linux kernel when // HugePageSizeUnitList is a list of the units used by the linux kernel when
// naming the HugePage control files. // naming the HugePage control files.
// https://www.kernel.org/doc/Documentation/cgroup-v1/hugetlb.txt // https://www.kernel.org/doc/Documentation/cgroup-v1/hugetlb.txt
@@ -29,6 +36,18 @@ const (
// depends on https://github.com/docker/go-units/commit/a09cd47f892041a4fac473133d181f5aea6fa393 // depends on https://github.com/docker/go-units/commit/a09cd47f892041a4fac473133d181f5aea6fa393
var HugePageSizeUnitList = []string{"B", "KB", "MB", "GB", "TB", "PB"} 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("/sys/fs/cgroup", &st); err != nil {
panic("cannot statfs cgroup root")
}
isUnified = st.Type == unix.CGROUP2_SUPER_MAGIC
})
return isUnified
}
// https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt // https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt
func FindCgroupMountpoint(cgroupPath, subsystem string) (string, error) { func FindCgroupMountpoint(cgroupPath, subsystem string) (string, error) {
mnt, _, err := FindCgroupMountpointAndRoot(cgroupPath, subsystem) mnt, _, err := FindCgroupMountpointAndRoot(cgroupPath, subsystem)
@@ -49,6 +68,10 @@ func FindCgroupMountpointAndRoot(cgroupPath, subsystem string) (string, string,
} }
defer f.Close() defer f.Close()
if IsCgroup2UnifiedMode() {
subsystem = ""
}
return findCgroupMountpointAndRootFromReader(f, cgroupPath, subsystem) return findCgroupMountpointAndRootFromReader(f, cgroupPath, subsystem)
} }
@@ -57,12 +80,12 @@ func findCgroupMountpointAndRootFromReader(reader io.Reader, cgroupPath, subsyst
for scanner.Scan() { for scanner.Scan() {
txt := scanner.Text() txt := scanner.Text()
fields := strings.Fields(txt) fields := strings.Fields(txt)
if len(fields) < 5 { if len(fields) < 9 {
continue continue
} }
if strings.HasPrefix(fields[4], cgroupPath) { if strings.HasPrefix(fields[4], cgroupPath) {
for _, opt := range strings.Split(fields[len(fields)-1], ",") { for _, opt := range strings.Split(fields[len(fields)-1], ",") {
if opt == subsystem { if (subsystem == "" && fields[9] == "cgroup2") || opt == subsystem {
return fields[4], fields[3], nil return fields[4], fields[3], nil
} }
} }
@@ -76,6 +99,19 @@ func findCgroupMountpointAndRootFromReader(reader io.Reader, cgroupPath, subsyst
} }
func isSubsystemAvailable(subsystem string) bool { 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") cgroups, err := ParseCgroupFile("/proc/self/cgroup")
if err != nil { if err != nil {
return false return false
@@ -120,7 +156,7 @@ func FindCgroupMountpointDir() (string, error) {
return "", fmt.Errorf("Found no fields post '-' in %q", text) return "", fmt.Errorf("Found no fields post '-' in %q", text)
} }
if postSeparatorFields[0] == "cgroup" { if postSeparatorFields[0] == "cgroup" || postSeparatorFields[0] == "cgroup2" {
// Check that the mount is properly formatted. // Check that the mount is properly formatted.
if numPostFields < 3 { if numPostFields < 3 {
return "", fmt.Errorf("Error found less than 3 fields post '-' in %q", text) return "", fmt.Errorf("Error found less than 3 fields post '-' in %q", text)
@@ -193,6 +229,19 @@ func getCgroupMountsHelper(ss map[string]bool, mi io.Reader, all bool) ([]Mount,
// GetCgroupMounts returns the mounts for the cgroup subsystems. // GetCgroupMounts returns the mounts for the cgroup subsystems.
// all indicates whether to return just the first instance or all the mounts. // all indicates whether to return just the first instance or all the mounts.
func GetCgroupMounts(all bool) ([]Mount, error) { func GetCgroupMounts(all bool) ([]Mount, error) {
if IsCgroup2UnifiedMode() {
availableControllers, err := GetAllSubsystems()
if err != nil {
return nil, err
}
m := Mount{
Mountpoint: "/sys/fs/cgroup",
Root: "/sys/fs/cgroup",
Subsystems: availableControllers,
}
return []Mount{m}, nil
}
f, err := os.Open("/proc/self/mountinfo") f, err := os.Open("/proc/self/mountinfo")
if err != nil { if err != nil {
return nil, err return nil, err
@@ -356,6 +405,9 @@ func parseCgroupFromReader(r io.Reader) (map[string]string, error) {
} }
func getControllerPath(subsystem string, cgroups map[string]string) (string, error) { func getControllerPath(subsystem string, cgroups map[string]string) (string, error) {
if IsCgroup2UnifiedMode() {
return "/", nil
}
if p, ok := cgroups[subsystem]; ok { if p, ok := cgroups[subsystem]; ok {
return p, nil return p, nil

View File

@@ -5,7 +5,7 @@ go_library(
srcs = [ srcs = [
"blkio_device.go", "blkio_device.go",
"cgroup_linux.go", "cgroup_linux.go",
"cgroup_windows.go", "cgroup_unsupported.go",
"config.go", "config.go",
"config_linux.go", "config_linux.go",
"device.go", "device.go",

View File

@@ -59,3 +59,8 @@ func NewThrottleDevice(major, minor int64, rate uint64) *ThrottleDevice {
func (td *ThrottleDevice) String() string { func (td *ThrottleDevice) String() string {
return fmt.Sprintf("%d:%d %d", td.Major, td.Minor, td.Rate) return fmt.Sprintf("%d:%d %d", td.Major, td.Minor, td.Rate)
} }
// StringName formats the struct to be writable to the cgroup specific file
func (td *ThrottleDevice) StringName(name string) string {
return fmt.Sprintf("%d:%d %s=%d", td.Major, td.Minor, name, td.Rate)
}

View File

@@ -119,4 +119,12 @@ type Resources struct {
// Set class identifier for container's network packets // Set class identifier for container's network packets
NetClsClassid uint32 `json:"net_cls_classid_u"` NetClsClassid uint32 `json:"net_cls_classid_u"`
// Used on cgroups v2:
// 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"`
} }

View File

@@ -1,3 +1,5 @@
// +build !linux
package configs package configs
// TODO Windows: This can ultimately be entirely factored out on Windows as // TODO Windows: This can ultimately be entirely factored out on Windows as

View File

@@ -44,6 +44,7 @@ const (
Trap Trap
Allow Allow
Trace Trace
Log
) )
// Operator is a comparison operator to be used when matching syscall arguments in Seccomp // Operator is a comparison operator to be used when matching syscall arguments in Seccomp

View File

@@ -19,7 +19,7 @@ import (
"syscall" // only for SysProcAttr and Signal "syscall" // only for SysProcAttr and Signal
"time" "time"
"github.com/cyphar/filepath-securejoin" securejoin "github.com/cyphar/filepath-securejoin"
"github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runc/libcontainer/intelrdt" "github.com/opencontainers/runc/libcontainer/intelrdt"
@@ -1176,7 +1176,7 @@ func (c *linuxContainer) makeCriuRestoreMountpoints(m *configs.Mount) error {
if err != nil { if err != nil {
return err return err
} }
if err := checkMountDestination(c.config.Rootfs, dest); err != nil { if err := checkProcMount(c.config.Rootfs, dest, ""); err != nil {
return err return err
} }
m.Destination = dest m.Destination = dest
@@ -1814,7 +1814,14 @@ func (c *linuxContainer) isPaused() (bool, error) {
// A container doesn't have a freezer cgroup // A container doesn't have a freezer cgroup
return false, nil return false, nil
} }
data, err := ioutil.ReadFile(filepath.Join(fcg, "freezer.state")) pausedState := "FROZEN"
filename := "freezer.state"
if cgroups.IsCgroup2UnifiedMode() {
filename = "cgroup.freeze"
pausedState = "1"
}
data, err := ioutil.ReadFile(filepath.Join(fcg, filename))
if err != nil { if err != nil {
// If freezer cgroup is not mounted, the container would just be not paused. // If freezer cgroup is not mounted, the container would just be not paused.
if os.IsNotExist(err) { if os.IsNotExist(err) {
@@ -1822,7 +1829,7 @@ func (c *linuxContainer) isPaused() (bool, error) {
} }
return false, newSystemErrorWithCause(err, "checking if container is paused") return false, newSystemErrorWithCause(err, "checking if container is paused")
} }
return bytes.Equal(bytes.TrimSpace(data), []byte("FROZEN")), nil return bytes.Equal(bytes.TrimSpace(data), []byte(pausedState)), nil
} }
func (c *linuxContainer) currentState() (*State, error) { func (c *linuxContainer) currentState() (*State, error) {

View File

@@ -13,7 +13,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/cyphar/filepath-securejoin" securejoin "github.com/cyphar/filepath-securejoin"
"github.com/mrunalp/fileutils" "github.com/mrunalp/fileutils"
"github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/configs"
@@ -197,7 +197,7 @@ func prepareBindMount(m *configs.Mount, rootfs string) error {
if dest, err = securejoin.SecureJoin(rootfs, m.Destination); err != nil { if dest, err = securejoin.SecureJoin(rootfs, m.Destination); err != nil {
return err return err
} }
if err := checkMountDestination(rootfs, dest); err != nil { if err := checkProcMount(rootfs, dest, m.Source); err != nil {
return err return err
} }
// update the mount with the correct dest after symlinks are resolved. // update the mount with the correct dest after symlinks are resolved.
@@ -209,6 +209,80 @@ func prepareBindMount(m *configs.Mount, rootfs string) error {
return nil return nil
} }
func mountCgroupV1(m *configs.Mount, rootfs, mountLabel string, enableCgroupns bool) error {
binds, err := getCgroupMounts(m)
if err != nil {
return err
}
var merged []string
for _, b := range binds {
ss := filepath.Base(b.Destination)
if strings.Contains(ss, ",") {
merged = append(merged, ss)
}
}
tmpfs := &configs.Mount{
Source: "tmpfs",
Device: "tmpfs",
Destination: m.Destination,
Flags: defaultMountFlags,
Data: "mode=755",
PropagationFlags: m.PropagationFlags,
}
if err := mountToRootfs(tmpfs, rootfs, mountLabel, enableCgroupns); err != nil {
return err
}
for _, b := range binds {
if enableCgroupns {
subsystemPath := filepath.Join(rootfs, b.Destination)
if err := os.MkdirAll(subsystemPath, 0755); err != nil {
return err
}
flags := defaultMountFlags
if m.Flags&unix.MS_RDONLY != 0 {
flags = flags | unix.MS_RDONLY
}
cgroupmount := &configs.Mount{
Source: "cgroup",
Device: "cgroup",
Destination: subsystemPath,
Flags: flags,
Data: filepath.Base(subsystemPath),
}
if err := mountNewCgroup(cgroupmount); err != nil {
return err
}
} else {
if err := mountToRootfs(b, rootfs, mountLabel, enableCgroupns); err != nil {
return err
}
}
}
for _, mc := range merged {
for _, ss := range strings.Split(mc, ",") {
// symlink(2) is very dumb, it will just shove the path into
// the link and doesn't do any checks or relative path
// conversion. Also, don't error out if the cgroup already exists.
if err := os.Symlink(mc, filepath.Join(rootfs, m.Destination, ss)); err != nil && !os.IsExist(err) {
return err
}
}
}
return nil
}
func mountCgroupV2(m *configs.Mount, rootfs, mountLabel string, enableCgroupns bool) error {
cgroupPath, err := securejoin.SecureJoin(rootfs, m.Destination)
if err != nil {
return err
}
if err := os.MkdirAll(cgroupPath, 0755); err != nil {
return err
}
return unix.Mount(m.Source, cgroupPath, "cgroup2", uintptr(m.Flags), m.Data)
}
func mountToRootfs(m *configs.Mount, rootfs, mountLabel string, enableCgroupns bool) error { func mountToRootfs(m *configs.Mount, rootfs, mountLabel string, enableCgroupns bool) error {
var ( var (
dest = m.Destination dest = m.Destination
@@ -309,64 +383,16 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string, enableCgroupns b
} }
} }
case "cgroup": case "cgroup":
binds, err := getCgroupMounts(m) if cgroups.IsCgroup2UnifiedMode() {
if err != nil { if err := mountCgroupV2(m, rootfs, mountLabel, enableCgroupns); err != nil {
return err
}
var merged []string
for _, b := range binds {
ss := filepath.Base(b.Destination)
if strings.Contains(ss, ",") {
merged = append(merged, ss)
}
}
tmpfs := &configs.Mount{
Source: "tmpfs",
Device: "tmpfs",
Destination: m.Destination,
Flags: defaultMountFlags,
Data: "mode=755",
PropagationFlags: m.PropagationFlags,
}
if err := mountToRootfs(tmpfs, rootfs, mountLabel, enableCgroupns); err != nil {
return err
}
for _, b := range binds {
if enableCgroupns {
subsystemPath := filepath.Join(rootfs, b.Destination)
if err := os.MkdirAll(subsystemPath, 0755); err != nil {
return err
}
flags := defaultMountFlags
if m.Flags&unix.MS_RDONLY != 0 {
flags = flags | unix.MS_RDONLY
}
cgroupmount := &configs.Mount{
Source: "cgroup",
Device: "cgroup",
Destination: subsystemPath,
Flags: flags,
Data: filepath.Base(subsystemPath),
}
if err := mountNewCgroup(cgroupmount); err != nil {
return err return err
} }
} else { } else {
if err := mountToRootfs(b, rootfs, mountLabel, enableCgroupns); err != nil {
if err := mountCgroupV1(m, rootfs, mountLabel, enableCgroupns); err != nil {
return err return err
} }
} }
}
for _, mc := range merged {
for _, ss := range strings.Split(mc, ",") {
// symlink(2) is very dumb, it will just shove the path into
// the link and doesn't do any checks or relative path
// conversion. Also, don't error out if the cgroup already exists.
if err := os.Symlink(mc, filepath.Join(rootfs, m.Destination, ss)); err != nil && !os.IsExist(err) {
return err
}
}
}
if m.Flags&unix.MS_RDONLY != 0 { if m.Flags&unix.MS_RDONLY != 0 {
// remount cgroup root as readonly // remount cgroup root as readonly
mcgrouproot := &configs.Mount{ mcgrouproot := &configs.Mount{
@@ -388,7 +414,7 @@ func mountToRootfs(m *configs.Mount, rootfs, mountLabel string, enableCgroupns b
if dest, err = securejoin.SecureJoin(rootfs, m.Destination); err != nil { if dest, err = securejoin.SecureJoin(rootfs, m.Destination); err != nil {
return err return err
} }
if err := checkMountDestination(rootfs, dest); err != nil { if err := checkProcMount(rootfs, dest, m.Source); err != nil {
return err return err
} }
// update the mount with the correct dest after symlinks are resolved. // update the mount with the correct dest after symlinks are resolved.
@@ -435,12 +461,12 @@ func getCgroupMounts(m *configs.Mount) ([]*configs.Mount, error) {
return binds, nil return binds, nil
} }
// checkMountDestination checks to ensure that the mount destination is not over the top of /proc. // checkProcMount checks to ensure that the mount destination is not over the top of /proc.
// dest is required to be an abs path and have any symlinks resolved before calling this function. // dest is required to be an abs path and have any symlinks resolved before calling this function.
func checkMountDestination(rootfs, dest string) error { //
invalidDestinations := []string{ // if source is nil, don't stat the filesystem. This is used for restore of a checkpoint.
"/proc", func checkProcMount(rootfs, dest, source string) error {
} const procPath = "/proc"
// White list, it should be sub directories of invalid destinations // White list, it should be sub directories of invalid destinations
validDestinations := []string{ validDestinations := []string{
// These entries can be bind mounted by files emulated by fuse, // These entries can be bind mounted by files emulated by fuse,
@@ -463,16 +489,40 @@ func checkMountDestination(rootfs, dest string) error {
return nil return nil
} }
} }
for _, invalid := range invalidDestinations { path, err := filepath.Rel(filepath.Join(rootfs, procPath), dest)
path, err := filepath.Rel(filepath.Join(rootfs, invalid), dest)
if err != nil { if err != nil {
return err return err
} }
if path != "." && !strings.HasPrefix(path, "..") { // pass if the mount path is located outside of /proc
return fmt.Errorf("%q cannot be mounted because it is located inside %q", dest, invalid) if strings.HasPrefix(path, "..") {
}
}
return nil return nil
}
if path == "." {
// an empty source is pasted on restore
if source == "" {
return nil
}
// only allow a mount on-top of proc if it's source is "proc"
isproc, err := isProc(source)
if err != nil {
return err
}
// pass if the mount is happening on top of /proc and the source of
// the mount is a proc filesystem
if isproc {
return nil
}
return fmt.Errorf("%q cannot be mounted because it is not of type proc", dest)
}
return fmt.Errorf("%q cannot be mounted because it is inside /proc", dest)
}
func isProc(path string) (bool, error) {
var s unix.Statfs_t
if err := unix.Statfs(path, &s); err != nil {
return false, err
}
return s.Type == unix.PROC_SUPER_MAGIC, nil
} }
func setupDevSymlinks(rootfs string) error { func setupDevSymlinks(rootfs string) error {

View File

@@ -22,6 +22,7 @@ var actions = map[string]configs.Action{
"SCMP_ACT_TRAP": configs.Trap, "SCMP_ACT_TRAP": configs.Trap,
"SCMP_ACT_ALLOW": configs.Allow, "SCMP_ACT_ALLOW": configs.Allow,
"SCMP_ACT_TRACE": configs.Trace, "SCMP_ACT_TRACE": configs.Trace,
"SCMP_ACT_LOG": configs.Log,
} }
var archs = map[string]string{ var archs = map[string]string{

View File

@@ -19,6 +19,7 @@ var (
actTrap = libseccomp.ActTrap actTrap = libseccomp.ActTrap
actKill = libseccomp.ActKill actKill = libseccomp.ActKill
actTrace = libseccomp.ActTrace.SetReturnCode(int16(unix.EPERM)) actTrace = libseccomp.ActTrace.SetReturnCode(int16(unix.EPERM))
actLog = libseccomp.ActLog
actErrno = libseccomp.ActErrno.SetReturnCode(int16(unix.EPERM)) actErrno = libseccomp.ActErrno.SetReturnCode(int16(unix.EPERM))
) )
@@ -112,6 +113,8 @@ func getAction(act configs.Action) (libseccomp.ScmpAction, error) {
return actAllow, nil return actAllow, nil
case configs.Trace: case configs.Trace:
return actTrace, nil return actTrace, nil
case configs.Log:
return actLog, nil
default: default:
return libseccomp.ActInvalid, fmt.Errorf("invalid action, cannot use in rule") return libseccomp.ActInvalid, fmt.Errorf("invalid action, cannot use in rule")
} }

View File

@@ -1,5 +1,5 @@
// +build linux // +build linux
// +build arm64 amd64 mips mipsle mips64 mips64le ppc ppc64 ppc64le s390x // +build arm64 amd64 mips mipsle mips64 mips64le ppc ppc64 ppc64le riscv64 s390x
package system package system

View File

@@ -3,33 +3,57 @@
package utils package utils
import ( import (
"io/ioutil" "fmt"
"os" "os"
"strconv" "strconv"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
// EnsureProcHandle returns whether or not the given file handle is on procfs.
func EnsureProcHandle(fh *os.File) error {
var buf unix.Statfs_t
if err := unix.Fstatfs(int(fh.Fd()), &buf); err != nil {
return fmt.Errorf("ensure %s is on procfs: %v", fh.Name(), err)
}
if buf.Type != unix.PROC_SUPER_MAGIC {
return fmt.Errorf("%s is not on procfs", fh.Name())
}
return nil
}
// CloseExecFrom applies O_CLOEXEC to all file descriptors currently open for
// the process (except for those below the given fd value).
func CloseExecFrom(minFd int) error { func CloseExecFrom(minFd int) error {
fdList, err := ioutil.ReadDir("/proc/self/fd") fdDir, err := os.Open("/proc/self/fd")
if err != nil { if err != nil {
return err return err
} }
for _, fi := range fdList { defer fdDir.Close()
fd, err := strconv.Atoi(fi.Name())
if err := EnsureProcHandle(fdDir); err != nil {
return err
}
fdList, err := fdDir.Readdirnames(-1)
if err != nil {
return err
}
for _, fdStr := range fdList {
fd, err := strconv.Atoi(fdStr)
// Ignore non-numeric file names.
if err != nil { if err != nil {
// ignore non-numeric file names
continue continue
} }
// Ignore descriptors lower than our specified minimum.
if fd < minFd { if fd < minFd {
// ignore descriptors lower than our specified minimum
continue continue
} }
// Intentionally ignore errors from unix.CloseOnExec -- the cases where
// intentionally ignore errors from unix.CloseOnExec // this might fail are basically file descriptors that have already
// been closed (including and especially the one that was created when
// ioutil.ReadDir did the "opendir" syscall).
unix.CloseOnExec(fd) unix.CloseOnExec(fd)
// the cases where this might fail are basically file descriptors that have already been closed (including and especially the one that was created when ioutil.ReadDir did the "opendir" syscall)
} }
return nil return nil
} }

View File

@@ -15,6 +15,7 @@ import (
var validOptions = map[string]bool{ var validOptions = map[string]bool{
"disable": true, "disable": true,
"type": true, "type": true,
"filetype": true,
"user": true, "user": true,
"role": true, "role": true,
"level": true, "level": true,
@@ -51,13 +52,16 @@ func InitLabels(options []string) (plabel string, mlabel string, Err error) {
return "", mountLabel, nil return "", mountLabel, nil
} }
if i := strings.Index(opt, ":"); i == -1 { if i := strings.Index(opt, ":"); i == -1 {
return "", "", fmt.Errorf("Bad label option %q, valid options 'disable' or \n'user, role, level, type' followed by ':' and a value", opt) return "", "", fmt.Errorf("Bad label option %q, valid options 'disable' or \n'user, role, level, type, filetype' followed by ':' and a value", opt)
} }
con := strings.SplitN(opt, ":", 2) con := strings.SplitN(opt, ":", 2)
if !validOptions[con[0]] { if !validOptions[con[0]] {
return "", "", fmt.Errorf("Bad label option %q, valid options 'disable, user, role, level, type'", con[0]) return "", "", fmt.Errorf("Bad label option %q, valid options 'disable, user, role, level, type, filetype'", con[0])
} }
if con[0] == "filetype" {
mcon["type"] = con[1]
}
pcon[con[0]] = con[1] pcon[con[0]] = con[1]
if con[0] == "level" || con[0] == "user" { if con[0] == "level" || con[0] == "user" {
mcon[con[0]] = con[1] mcon[con[0]] = con[1]

View File

@@ -18,6 +18,8 @@ import (
"strings" "strings"
"sync" "sync"
"syscall" "syscall"
"golang.org/x/sys/unix"
) )
const ( const (
@@ -252,6 +254,12 @@ func getSELinuxPolicyRoot() string {
return filepath.Join(selinuxDir, readConfig(selinuxTypeTag)) return filepath.Join(selinuxDir, readConfig(selinuxTypeTag))
} }
func isProcHandle(fh *os.File) (bool, error) {
var buf unix.Statfs_t
err := unix.Fstatfs(int(fh.Fd()), &buf)
return buf.Type == unix.PROC_SUPER_MAGIC, err
}
func readCon(fpath string) (string, error) { func readCon(fpath string) (string, error) {
if fpath == "" { if fpath == "" {
return "", ErrEmptyPath return "", ErrEmptyPath
@@ -263,6 +271,12 @@ func readCon(fpath string) (string, error) {
} }
defer in.Close() defer in.Close()
if ok, err := isProcHandle(in); err != nil {
return "", err
} else if !ok {
return "", fmt.Errorf("%s not on procfs", fpath)
}
var retval string var retval string
if _, err := fmt.Fscanf(in, "%s", &retval); err != nil { if _, err := fmt.Fscanf(in, "%s", &retval); err != nil {
return "", err return "", err
@@ -345,6 +359,12 @@ func writeCon(fpath string, val string) error {
} }
defer out.Close() defer out.Close()
if ok, err := isProcHandle(out); err != nil {
return err
} else if !ok {
return fmt.Errorf("%s not on procfs", fpath)
}
if val != "" { if val != "" {
_, err = out.Write([]byte(val)) _, err = out.Write([]byte(val))
} else { } else {
@@ -392,6 +412,14 @@ func SetExecLabel(label string) error {
return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid()), label) return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid()), label)
} }
/*
SetTaskLabel sets the SELinux label for the current thread, or an error.
This requires the dyntransition permission.
*/
func SetTaskLabel(label string) error {
return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/current", syscall.Gettid()), 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 // label to the next socket that gets created
func SetSocketLabel(label string) error { func SetSocketLabel(label string) error {
@@ -403,6 +431,11 @@ func SocketLabel() (string, error) {
return readCon(fmt.Sprintf("/proc/self/task/%d/attr/sockcreate", syscall.Gettid())) return readCon(fmt.Sprintf("/proc/self/task/%d/attr/sockcreate", syscall.Gettid()))
} }
// 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), syscall.SOL_SOCKET, syscall.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 // label to the next kernel keyring that gets created
func SetKeyLabel(label string) error { func SetKeyLabel(label string) error {

View File

@@ -96,6 +96,14 @@ func SetExecLabel(label string) error {
return nil 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 SetSocketLabel sets the SELinux label that the kernel will use for any programs
that are executed by the current process thread, or an error. that are executed by the current process thread, or an error.
@@ -109,6 +117,11 @@ func SocketLabel() (string, error) {
return "", nil 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 // SetKeyLabel takes a process label and tells the kernel to assign the
// label to the next kernel keyring that gets created // label to the next kernel keyring that gets created
func SetKeyLabel(label string) error { func SetKeyLabel(label string) error {

View File

@@ -60,13 +60,74 @@ type Capabilities interface {
Apply(kind CapType) error Apply(kind CapType) error
} }
// NewPid create new initialized Capabilities object for given pid when it // NewPid initializes a new Capabilities object for given pid when
// is nonzero, or for the current pid if pid is 0 // it is nonzero, or for the current process if pid is 0.
//
// Deprecated: Replace with NewPid2. For example, replace:
//
// c, err := NewPid(0)
// if err != nil {
// return err
// }
//
// with:
//
// c, err := NewPid2(0)
// if err != nil {
// return err
// }
// err = c.Load()
// if err != nil {
// return err
// }
func NewPid(pid int) (Capabilities, error) { func NewPid(pid int) (Capabilities, error) {
c, err := newPid(pid)
if err != nil {
return c, err
}
err = c.Load()
return c, err
}
// NewPid2 initializes a new Capabilities object for given pid when
// it is nonzero, or for the current process if pid is 0. This
// does not load the process's current capabilities; to do that you
// must call Load explicitly.
func NewPid2(pid int) (Capabilities, error) {
return newPid(pid) return newPid(pid)
} }
// NewFile create new initialized Capabilities object for given named file. // NewFile initializes a new Capabilities object for given file path.
func NewFile(name string) (Capabilities, error) { //
return newFile(name) // Deprecated: Replace with NewFile2. For example, replace:
//
// c, err := NewFile(path)
// if err != nil {
// return err
// }
//
// with:
//
// c, err := NewFile2(path)
// if err != nil {
// return err
// }
// err = c.Load()
// if err != nil {
// return err
// }
func NewFile(path string) (Capabilities, error) {
c, err := newFile(path)
if err != nil {
return c, err
}
err = c.Load()
return c, err
}
// NewFile2 creates a new initialized Capabilities object for given
// file path. This does not load the process's current capabilities;
// to do that you must call Load explicitly.
func NewFile2(path string) (Capabilities, error) {
return newFile(path)
} }

View File

@@ -103,21 +103,17 @@ func newPid(pid int) (c Capabilities, err error) {
case linuxCapVer1: case linuxCapVer1:
p := new(capsV1) p := new(capsV1)
p.hdr.version = capVers p.hdr.version = capVers
p.hdr.pid = pid p.hdr.pid = int32(pid)
c = p c = p
case linuxCapVer2, linuxCapVer3: case linuxCapVer2, linuxCapVer3:
p := new(capsV3) p := new(capsV3)
p.hdr.version = capVers p.hdr.version = capVers
p.hdr.pid = pid p.hdr.pid = int32(pid)
c = p c = p
default: default:
err = errUnknownVers err = errUnknownVers
return return
} }
err = c.Load()
if err != nil {
c = nil
}
return return
} }
@@ -428,11 +424,11 @@ func (c *capsV3) Load() (err error) {
} }
if strings.HasPrefix(line, "CapB") { if strings.HasPrefix(line, "CapB") {
fmt.Sscanf(line[4:], "nd: %08x%08x", &c.bounds[1], &c.bounds[0]) fmt.Sscanf(line[4:], "nd: %08x%08x", &c.bounds[1], &c.bounds[0])
break continue
} }
if strings.HasPrefix(line, "CapA") { if strings.HasPrefix(line, "CapA") {
fmt.Sscanf(line[4:], "mb: %08x%08x", &c.ambient[1], &c.ambient[0]) fmt.Sscanf(line[4:], "mb: %08x%08x", &c.ambient[1], &c.ambient[0])
break continue
} }
} }
f.Close() f.Close()
@@ -492,10 +488,6 @@ func (c *capsV3) Apply(kind CapType) (err error) {
func newFile(path string) (c Capabilities, err error) { func newFile(path string) (c Capabilities, err error) {
c = &capsFile{path: path} c = &capsFile{path: path}
err = c.Load()
if err != nil {
c = nil
}
return return
} }

View File

@@ -13,7 +13,7 @@ import (
type capHeader struct { type capHeader struct {
version uint32 version uint32
pid int pid int32
} }
type capData struct { type capData struct {

12
vendor/modules.txt vendored
View File

@@ -278,7 +278,7 @@ github.com/coreos/etcd/wal/walpb
github.com/coreos/go-oidc github.com/coreos/go-oidc
# github.com/coreos/go-semver v0.3.0 => github.com/coreos/go-semver v0.3.0 # github.com/coreos/go-semver v0.3.0 => github.com/coreos/go-semver v0.3.0
github.com/coreos/go-semver/semver github.com/coreos/go-semver/semver
# github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 => github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 # github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e => github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e
github.com/coreos/go-systemd/daemon github.com/coreos/go-systemd/daemon
github.com/coreos/go-systemd/dbus github.com/coreos/go-systemd/dbus
github.com/coreos/go-systemd/journal github.com/coreos/go-systemd/journal
@@ -388,7 +388,7 @@ github.com/go-openapi/validate
# github.com/go-ozzo/ozzo-validation v3.5.0+incompatible => github.com/go-ozzo/ozzo-validation v3.5.0+incompatible # github.com/go-ozzo/ozzo-validation v3.5.0+incompatible => github.com/go-ozzo/ozzo-validation v3.5.0+incompatible
github.com/go-ozzo/ozzo-validation github.com/go-ozzo/ozzo-validation
github.com/go-ozzo/ozzo-validation/is github.com/go-ozzo/ozzo-validation/is
# github.com/godbus/dbus v4.1.0+incompatible => github.com/godbus/dbus v4.1.0+incompatible # github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f => github.com/godbus/dbus v0.0.0-20181101234600-2ff6f7ffd60f
github.com/godbus/dbus github.com/godbus/dbus
# github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d => github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d # github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d => github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d
github.com/gogo/protobuf/gogoproto github.com/gogo/protobuf/gogoproto
@@ -625,7 +625,7 @@ github.com/modern-go/reflect2
github.com/mohae/deepcopy github.com/mohae/deepcopy
# github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c => github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c # github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c => github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c
github.com/morikuni/aec github.com/morikuni/aec
# github.com/mrunalp/fileutils v0.0.0-20160930181131-4ee1cc9a8058 => github.com/mrunalp/fileutils v0.0.0-20160930181131-4ee1cc9a8058 # github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618 => github.com/mrunalp/fileutils v0.0.0-20171103030105-7d4729fb3618
github.com/mrunalp/fileutils github.com/mrunalp/fileutils
# github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d => github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d # github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d => github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d
github.com/munnerz/goautoneg github.com/munnerz/goautoneg
@@ -679,7 +679,7 @@ github.com/opencontainers/go-digest
# github.com/opencontainers/image-spec v1.0.1 => github.com/opencontainers/image-spec v1.0.1 # github.com/opencontainers/image-spec v1.0.1 => github.com/opencontainers/image-spec v1.0.1
github.com/opencontainers/image-spec/specs-go github.com/opencontainers/image-spec/specs-go
github.com/opencontainers/image-spec/specs-go/v1 github.com/opencontainers/image-spec/specs-go/v1
# github.com/opencontainers/runc v1.0.0-rc2.0.20190611121236-6cc515888830 => github.com/opencontainers/runc v1.0.0-rc2.0.20190611121236-6cc515888830 # github.com/opencontainers/runc v1.0.0-rc9 => github.com/opencontainers/runc v1.0.0-rc9
github.com/opencontainers/runc/libcontainer github.com/opencontainers/runc/libcontainer
github.com/opencontainers/runc/libcontainer/apparmor github.com/opencontainers/runc/libcontainer/apparmor
github.com/opencontainers/runc/libcontainer/cgroups github.com/opencontainers/runc/libcontainer/cgroups
@@ -698,7 +698,7 @@ github.com/opencontainers/runc/libcontainer/user
github.com/opencontainers/runc/libcontainer/utils github.com/opencontainers/runc/libcontainer/utils
# github.com/opencontainers/runtime-spec v1.0.0 => github.com/opencontainers/runtime-spec v1.0.0 # github.com/opencontainers/runtime-spec v1.0.0 => github.com/opencontainers/runtime-spec v1.0.0
github.com/opencontainers/runtime-spec/specs-go github.com/opencontainers/runtime-spec/specs-go
# github.com/opencontainers/selinux v1.2.2 => github.com/opencontainers/selinux v1.2.2 # github.com/opencontainers/selinux v1.3.1-0.20190929122143-5215b1806f52 => github.com/opencontainers/selinux v1.3.1-0.20190929122143-5215b1806f52
github.com/opencontainers/selinux/go-selinux github.com/opencontainers/selinux/go-selinux
github.com/opencontainers/selinux/go-selinux/label github.com/opencontainers/selinux/go-selinux/label
# github.com/pborman/uuid v1.2.0 => github.com/pborman/uuid v1.2.0 # github.com/pborman/uuid v1.2.0 => github.com/pborman/uuid v1.2.0
@@ -769,7 +769,7 @@ github.com/stretchr/objx
github.com/stretchr/testify/assert github.com/stretchr/testify/assert
github.com/stretchr/testify/mock github.com/stretchr/testify/mock
github.com/stretchr/testify/require github.com/stretchr/testify/require
# github.com/syndtr/gocapability v0.0.0-20160928074757-e7cb7fa329f4 => github.com/syndtr/gocapability v0.0.0-20160928074757-e7cb7fa329f4 # github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2 => github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2
github.com/syndtr/gocapability/capability github.com/syndtr/gocapability/capability
# github.com/thecodeteam/goscaleio v0.1.0 => github.com/thecodeteam/goscaleio v0.1.0 # github.com/thecodeteam/goscaleio v0.1.0 => github.com/thecodeteam/goscaleio v0.1.0
github.com/thecodeteam/goscaleio github.com/thecodeteam/goscaleio