Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Mike Brown 2021-05-10 16:25:23 -05:00
commit d024133308
70 changed files with 2085 additions and 639 deletions

View File

@ -20,7 +20,7 @@ jobs:
strategy: strategy:
matrix: matrix:
go-version: [1.16.3] go-version: [1.16.4]
os: [ubuntu-18.04, macos-10.15, windows-2019] os: [ubuntu-18.04, macos-10.15, windows-2019]
steps: steps:
@ -73,7 +73,7 @@ jobs:
steps: steps:
- uses: actions/setup-go@v2 - uses: actions/setup-go@v2
with: with:
go-version: '1.16.3' go-version: '1.16.4'
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
@ -106,7 +106,7 @@ jobs:
steps: steps:
- uses: actions/setup-go@v2 - uses: actions/setup-go@v2
with: with:
go-version: '1.16.3' go-version: '1.16.4'
- name: Set env - name: Set env
shell: bash shell: bash
@ -152,7 +152,7 @@ jobs:
steps: steps:
- uses: actions/setup-go@v2 - uses: actions/setup-go@v2
with: with:
go-version: '1.16.3' go-version: '1.16.4'
- name: Set env - name: Set env
shell: bash shell: bash
run: | run: |
@ -217,7 +217,7 @@ jobs:
strategy: strategy:
matrix: matrix:
os: [ubuntu-18.04, macos-10.15, windows-2019] os: [ubuntu-18.04, macos-10.15, windows-2019]
go-version: ['1.16.3'] go-version: ['1.16.4']
include: include:
# Go 1.13.x is still used by Docker/Moby # Go 1.13.x is still used by Docker/Moby
- go-version: '1.13.x' - go-version: '1.13.x'
@ -263,7 +263,7 @@ jobs:
steps: steps:
- uses: actions/setup-go@v2 - uses: actions/setup-go@v2
with: with:
go-version: '1.16.3' go-version: '1.16.4'
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
@ -344,7 +344,7 @@ jobs:
steps: steps:
- uses: actions/setup-go@v2 - uses: actions/setup-go@v2
with: with:
go-version: '1.16.3' go-version: '1.16.4'
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
@ -496,7 +496,7 @@ jobs:
steps: steps:
- uses: actions/setup-go@v2 - uses: actions/setup-go@v2
with: with:
go-version: '1.16.3' go-version: '1.16.4'
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:

View File

@ -18,7 +18,7 @@ jobs:
steps: steps:
- uses: actions/setup-go@v2 - uses: actions/setup-go@v2
with: with:
go-version: '1.16.3' go-version: '1.16.4'
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
@ -135,7 +135,7 @@ jobs:
steps: steps:
- uses: actions/setup-go@v2 - uses: actions/setup-go@v2
with: with:
go-version: '1.16.3' go-version: '1.16.4'
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:

View File

@ -62,7 +62,7 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: '1.16.3' go-version: '1.16.4'
- name: Set env - name: Set env
shell: bash shell: bash

View File

@ -2,7 +2,7 @@
become: yes become: yes
roles: roles:
- role: config-golang - role: config-golang
go_version: '1.16.3' go_version: '1.16.4'
arch: arm64 arch: arm64
tasks: tasks:
- name: Build containerd - name: Build containerd

View File

@ -13,6 +13,9 @@
# limitations under the License. # limitations under the License.
# Go command to use for build
GO ?= go
# Root directory of the project (absolute path). # Root directory of the project (absolute path).
ROOTDIR=$(dir $(abspath $(lastword $(MAKEFILE_LIST)))) ROOTDIR=$(dir $(abspath $(lastword $(MAKEFILE_LIST))))
@ -26,9 +29,9 @@ REVISION=$(shell git rev-parse HEAD)$(shell if ! git diff --no-ext-diff --quiet
PACKAGE=github.com/containerd/containerd PACKAGE=github.com/containerd/containerd
SHIM_CGO_ENABLED ?= 0 SHIM_CGO_ENABLED ?= 0
ifneq "$(strip $(shell command -v go 2>/dev/null))" "" ifneq "$(strip $(shell command -v $(GO) 2>/dev/null))" ""
GOOS ?= $(shell go env GOOS) GOOS ?= $(shell $(GO) env GOOS)
GOARCH ?= $(shell go env GOARCH) GOARCH ?= $(shell $(GO) env GOARCH)
else else
ifeq ($(GOOS),) ifeq ($(GOOS),)
# approximate GOOS for the platform if we don't have Go and GOOS isn't # approximate GOOS for the platform if we don't have Go and GOOS isn't
@ -85,7 +88,7 @@ GO_LDFLAGS=-ldflags '-X $(PKG)/version.Version=$(VERSION) -X $(PKG)/version.Revi
SHIM_GO_LDFLAGS=-ldflags '-X $(PKG)/version.Version=$(VERSION) -X $(PKG)/version.Revision=$(REVISION) -X $(PKG)/version.Package=$(PACKAGE) -extldflags "-static" $(EXTRA_LDFLAGS)' SHIM_GO_LDFLAGS=-ldflags '-X $(PKG)/version.Version=$(VERSION) -X $(PKG)/version.Revision=$(REVISION) -X $(PKG)/version.Package=$(PACKAGE) -extldflags "-static" $(EXTRA_LDFLAGS)'
# Project packages. # Project packages.
PACKAGES=$(shell go list ${GO_TAGS} ./... | grep -v /vendor/ | grep -v /integration) PACKAGES=$(shell $(GO) list ${GO_TAGS} ./... | grep -v /vendor/ | grep -v /integration)
TEST_REQUIRES_ROOT_PACKAGES=$(filter \ TEST_REQUIRES_ROOT_PACKAGES=$(filter \
${PACKAGES}, \ ${PACKAGES}, \
$(shell \ $(shell \
@ -122,7 +125,7 @@ TESTFLAGS ?= $(TESTFLAGS_RACE) $(EXTRA_TESTFLAGS)
TESTFLAGS_PARALLEL ?= 8 TESTFLAGS_PARALLEL ?= 8
# Use this to replace `go test` with, for instance, `gotestsum` # Use this to replace `go test` with, for instance, `gotestsum`
GOTEST ?= go test GOTEST ?= $(GO) test
OUTPUTDIR = $(join $(ROOTDIR), _output) OUTPUTDIR = $(join $(ROOTDIR), _output)
CRIDIR=$(OUTPUTDIR)/cri CRIDIR=$(OUTPUTDIR)/cri
@ -143,7 +146,7 @@ AUTHORS: .mailmap .git/HEAD
generate: protos generate: protos
@echo "$(WHALE) $@" @echo "$(WHALE) $@"
@PATH="${ROOTDIR}/bin:${PATH}" go generate -x ${PACKAGES} @PATH="${ROOTDIR}/bin:${PATH}" $(GO) generate -x ${PACKAGES}
protos: bin/protoc-gen-gogoctrd ## generate protobuf protos: bin/protoc-gen-gogoctrd ## generate protobuf
@echo "$(WHALE) $@" @echo "$(WHALE) $@"
@ -170,7 +173,7 @@ proto-fmt: ## check format of proto files
build: ## build the go packages build: ## build the go packages
@echo "$(WHALE) $@" @echo "$(WHALE) $@"
@go build ${DEBUG_GO_GCFLAGS} ${GO_GCFLAGS} ${GO_BUILD_FLAGS} ${EXTRA_FLAGS} ${GO_LDFLAGS} ${PACKAGES} @$(GO) build ${DEBUG_GO_GCFLAGS} ${GO_GCFLAGS} ${GO_BUILD_FLAGS} ${EXTRA_FLAGS} ${GO_LDFLAGS} ${PACKAGES}
test: ## run tests, except integration tests and tests that require root test: ## run tests, except integration tests and tests that require root
@echo "$(WHALE) $@" @echo "$(WHALE) $@"
@ -182,12 +185,12 @@ root-test: ## run tests, except integration tests
integration: ## run integration tests integration: ## run integration tests
@echo "$(WHALE) $@" @echo "$(WHALE) $@"
@cd "${ROOTDIR}/integration/client" && go mod download && $(GOTEST) -v ${TESTFLAGS} -test.root -parallel ${TESTFLAGS_PARALLEL} . @cd "${ROOTDIR}/integration/client" && $(GO) mod download && $(GOTEST) -v ${TESTFLAGS} -test.root -parallel ${TESTFLAGS_PARALLEL} .
# TODO integrate cri integration bucket with coverage # TODO integrate cri integration bucket with coverage
bin/cri-integration.test: bin/cri-integration.test:
@echo "$(WHALE) $@" @echo "$(WHALE) $@"
@go test -c ./integration -o bin/cri-integration.test @$(GO) test -c ./integration -o bin/cri-integration.test
cri-integration: binaries bin/cri-integration.test ## run cri integration tests cri-integration: binaries bin/cri-integration.test ## run cri integration tests
@echo "$(WHALE) $@" @echo "$(WHALE) $@"
@ -196,13 +199,13 @@ cri-integration: binaries bin/cri-integration.test ## run cri integration tests
benchmark: ## run benchmarks tests benchmark: ## run benchmarks tests
@echo "$(WHALE) $@" @echo "$(WHALE) $@"
@go test ${TESTFLAGS} -bench . -run Benchmark -test.root @$(GO) test ${TESTFLAGS} -bench . -run Benchmark -test.root
FORCE: FORCE:
define BUILD_BINARY define BUILD_BINARY
@echo "$(WHALE) $@" @echo "$(WHALE) $@"
@go build ${DEBUG_GO_GCFLAGS} ${GO_GCFLAGS} ${GO_BUILD_FLAGS} -o $@ ${GO_LDFLAGS} ${GO_TAGS} ./$< @$(GO) build ${DEBUG_GO_GCFLAGS} ${GO_GCFLAGS} ${GO_BUILD_FLAGS} -o $@ ${GO_LDFLAGS} ${GO_TAGS} ./$<
endef endef
# Build a binary from a cmd. # Build a binary from a cmd.
@ -211,15 +214,15 @@ bin/%: cmd/% FORCE
bin/containerd-shim: cmd/containerd-shim FORCE # set !cgo and omit pie for a static shim build: https://github.com/golang/go/issues/17789#issuecomment-258542220 bin/containerd-shim: cmd/containerd-shim FORCE # set !cgo and omit pie for a static shim build: https://github.com/golang/go/issues/17789#issuecomment-258542220
@echo "$(WHALE) bin/containerd-shim" @echo "$(WHALE) bin/containerd-shim"
@CGO_ENABLED=${SHIM_CGO_ENABLED} go build ${GO_BUILD_FLAGS} -o bin/containerd-shim ${SHIM_GO_LDFLAGS} ${GO_TAGS} ./cmd/containerd-shim @CGO_ENABLED=${SHIM_CGO_ENABLED} $(GO) build ${GO_BUILD_FLAGS} -o bin/containerd-shim ${SHIM_GO_LDFLAGS} ${GO_TAGS} ./cmd/containerd-shim
bin/containerd-shim-runc-v1: cmd/containerd-shim-runc-v1 FORCE # set !cgo and omit pie for a static shim build: https://github.com/golang/go/issues/17789#issuecomment-258542220 bin/containerd-shim-runc-v1: cmd/containerd-shim-runc-v1 FORCE # set !cgo and omit pie for a static shim build: https://github.com/golang/go/issues/17789#issuecomment-258542220
@echo "$(WHALE) bin/containerd-shim-runc-v1" @echo "$(WHALE) bin/containerd-shim-runc-v1"
@CGO_ENABLED=${SHIM_CGO_ENABLED} go build ${GO_BUILD_FLAGS} -o bin/containerd-shim-runc-v1 ${SHIM_GO_LDFLAGS} ${GO_TAGS} ./cmd/containerd-shim-runc-v1 @CGO_ENABLED=${SHIM_CGO_ENABLED} $(GO) build ${GO_BUILD_FLAGS} -o bin/containerd-shim-runc-v1 ${SHIM_GO_LDFLAGS} ${GO_TAGS} ./cmd/containerd-shim-runc-v1
bin/containerd-shim-runc-v2: cmd/containerd-shim-runc-v2 FORCE # set !cgo and omit pie for a static shim build: https://github.com/golang/go/issues/17789#issuecomment-258542220 bin/containerd-shim-runc-v2: cmd/containerd-shim-runc-v2 FORCE # set !cgo and omit pie for a static shim build: https://github.com/golang/go/issues/17789#issuecomment-258542220
@echo "$(WHALE) bin/containerd-shim-runc-v2" @echo "$(WHALE) bin/containerd-shim-runc-v2"
@CGO_ENABLED=${SHIM_CGO_ENABLED} go build ${GO_BUILD_FLAGS} -o bin/containerd-shim-runc-v2 ${SHIM_GO_LDFLAGS} ${GO_TAGS} ./cmd/containerd-shim-runc-v2 @CGO_ENABLED=${SHIM_CGO_ENABLED} $(GO) build ${GO_BUILD_FLAGS} -o bin/containerd-shim-runc-v2 ${SHIM_GO_LDFLAGS} ${GO_TAGS} ./cmd/containerd-shim-runc-v2
binaries: $(BINARIES) ## build binaries binaries: $(BINARIES) ## build binaries
@echo "$(WHALE) $@" @echo "$(WHALE) $@"
@ -235,11 +238,11 @@ genman: man/containerd.8 man/ctr.8
man/containerd.8: FORCE man/containerd.8: FORCE
@echo "$(WHALE) $@" @echo "$(WHALE) $@"
go run cmd/gen-manpages/main.go $(@F) $(@D) $(GO) run cmd/gen-manpages/main.go $(@F) $(@D)
man/ctr.8: FORCE man/ctr.8: FORCE
@echo "$(WHALE) $@" @echo "$(WHALE) $@"
go run cmd/gen-manpages/main.go $(@F) $(@D) $(GO) run cmd/gen-manpages/main.go $(@F) $(@D)
man/%: docs/man/%.md FORCE man/%: docs/man/%.md FORCE
@echo "$(WHALE) $@" @echo "$(WHALE) $@"
@ -365,9 +368,9 @@ endif
coverage: ## generate coverprofiles from the unit tests, except tests that require root coverage: ## generate coverprofiles from the unit tests, except tests that require root
@echo "$(WHALE) $@" @echo "$(WHALE) $@"
@rm -f coverage.txt @rm -f coverage.txt
@go test -i ${TESTFLAGS} ${PACKAGES} 2> /dev/null @$(GO) test -i ${TESTFLAGS} ${PACKAGES} 2> /dev/null
@( for pkg in ${PACKAGES}; do \ @( for pkg in ${PACKAGES}; do \
go test ${TESTFLAGS} \ $(GO) test ${TESTFLAGS} \
-cover \ -cover \
-coverprofile=profile.out \ -coverprofile=profile.out \
-covermode=atomic $$pkg || exit; \ -covermode=atomic $$pkg || exit; \
@ -379,9 +382,9 @@ coverage: ## generate coverprofiles from the unit tests, except tests that requi
root-coverage: ## generate coverage profiles for unit tests that require root root-coverage: ## generate coverage profiles for unit tests that require root
@echo "$(WHALE) $@" @echo "$(WHALE) $@"
@go test -i ${TESTFLAGS} ${TEST_REQUIRES_ROOT_PACKAGES} 2> /dev/null @$(GO) test -i ${TESTFLAGS} ${TEST_REQUIRES_ROOT_PACKAGES} 2> /dev/null
@( for pkg in ${TEST_REQUIRES_ROOT_PACKAGES}; do \ @( for pkg in ${TEST_REQUIRES_ROOT_PACKAGES}; do \
go test ${TESTFLAGS} \ $(GO) test ${TESTFLAGS} \
-cover \ -cover \
-coverprofile=profile.out \ -coverprofile=profile.out \
-covermode=atomic $$pkg -test.root || exit; \ -covermode=atomic $$pkg -test.root || exit; \
@ -393,8 +396,8 @@ root-coverage: ## generate coverage profiles for unit tests that require root
vendor: ## vendor vendor: ## vendor
@echo "$(WHALE) $@" @echo "$(WHALE) $@"
@go mod tidy @$(GO) mod tidy
@go mod vendor @$(GO) mod vendor
help: ## this help help: ## this help
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) | sort @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) | sort

View File

@ -100,8 +100,9 @@ The current state is available in the following table:
| [1.1](https://github.com/containerd/containerd/releases/tag/v1.1.8) | End of Life | April 23, 2018 | October 23, 2019 | | [1.1](https://github.com/containerd/containerd/releases/tag/v1.1.8) | End of Life | April 23, 2018 | October 23, 2019 |
| [1.2](https://github.com/containerd/containerd/releases/tag/v1.2.13) | End of Life | October 24, 2018 | October 15, 2020 | | [1.2](https://github.com/containerd/containerd/releases/tag/v1.2.13) | End of Life | October 24, 2018 | October 15, 2020 |
| [1.3](https://github.com/containerd/containerd/releases/tag/v1.3.10) | End of Life | September 26, 2019 | March 4, 2021 | | [1.3](https://github.com/containerd/containerd/releases/tag/v1.3.10) | End of Life | September 26, 2019 | March 4, 2021 |
| [1.4](https://github.com/containerd/containerd/releases/tag/v1.4.4) | Active | August 17, 2020 | max(August 17, 2021, release of 1.5.0 + 6 months) | | [1.4](https://github.com/containerd/containerd/releases/tag/v1.4.4) | Active | August 17, 2020 | November 3, 2021 (Active), February 3, 2022 (Extended) |
| [1.5](https://github.com/containerd/containerd/milestone/30) | Next | TBD | max(TBD+1 year, release of 1.6.0 + 6 months) | | [1.5](https://github.com/containerd/containerd/releases/tag/v1.5.0) | Active | May 3, 2021 | max(May 3, 2022, release of 1.6.0 + 6 months) |
| [1.6](https://github.com/containerd/containerd/milestone/34) | Next | TBD | max(TBD+1 year, release of 1.7.0 or 2.0.0 + 6 months) |
Note that branches and release from before 1.0 may not follow these rules. Note that branches and release from before 1.0 may not follow these rules.

2
Vagrantfile vendored
View File

@ -77,7 +77,7 @@ Vagrant.configure("2") do |config|
config.vm.provision "install-golang", type: "shell", run: "once" do |sh| config.vm.provision "install-golang", type: "shell", run: "once" do |sh|
sh.upload_path = "/tmp/vagrant-install-golang" sh.upload_path = "/tmp/vagrant-install-golang"
sh.env = { sh.env = {
'GO_VERSION': ENV['GO_VERSION'] || "1.16.3", 'GO_VERSION': ENV['GO_VERSION'] || "1.16.4",
} }
sh.inline = <<~SHELL sh.inline = <<~SHELL
#!/usr/bin/env bash #!/usr/bin/env bash

View File

@ -164,6 +164,7 @@ var diffCommand = cli.Command{
if err != nil { if err != nil {
return err return err
} }
defer ra.Close()
_, err = io.Copy(os.Stdout, content.NewReader(ra)) _, err = io.Copy(os.Stdout, content.NewReader(ra))
return err return err

89
content/adaptor_test.go Normal file
View File

@ -0,0 +1,89 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package content
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestAdaptInfo(t *testing.T) {
tests := []struct {
name string
info Info
fieldpath []string
wantValue string
wantPresent bool
}{
{
"empty fieldpath",
Info{},
[]string{},
"",
false,
},
{
"digest fieldpath",
Info{
Digest: "foo",
},
[]string{"digest"},
"foo",
true,
},
{
"size fieldpath",
Info{},
[]string{"size"},
"",
false,
},
{
"labels fieldpath",
Info{
Labels: map[string]string{
"foo": "bar",
},
},
[]string{"labels", "foo"},
"bar",
true,
},
{
"labels join fieldpath",
Info{
Labels: map[string]string{
"foo.bar.qux": "quux",
},
},
[]string{"labels", "foo", "bar", "qux"},
"quux",
true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
adaptInfo := AdaptInfo(tt.info)
value, present := adaptInfo.Field(tt.fieldpath)
assert.Equal(t, tt.wantValue, value)
assert.Equal(t, tt.wantPresent, present)
})
}
}

View File

@ -780,6 +780,7 @@ func checkSmallBlob(ctx context.Context, t *testing.T, store content.Store) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer ra.Close()
r := io.NewSectionReader(ra, 0, readSize) r := io.NewSectionReader(ra, 0, readSize)
b, err := ioutil.ReadAll(r) b, err := ioutil.ReadAll(r)
if err != nil { if err != nil {

View File

@ -6,11 +6,11 @@
# 3.) $ make binaries install test # 3.) $ make binaries install test
# #
# Use the RUNC_VERSION build-arg to build with a custom version of runc, for example, # Use the RUNC_VERSION build-arg to build with a custom version of runc, for example,
# to build runc v1.0.0-rc93, use: # to build runc v1.0.0-rc94, use:
# #
# docker build -t containerd-test --build-arg RUNC_VERSION=v1.0.0-rc93 -f Dockerfile.test ../ # docker build -t containerd-test --build-arg RUNC_VERSION=v1.0.0-rc94 -f Dockerfile.test ../
ARG GOLANG_VERSION=1.16.3 ARG GOLANG_VERSION=1.16.4
FROM golang:${GOLANG_VERSION} AS golang-base FROM golang:${GOLANG_VERSION} AS golang-base
RUN mkdir -p /go/src/github.com/containerd/containerd RUN mkdir -p /go/src/github.com/containerd/containerd

6
go.mod
View File

@ -19,7 +19,7 @@ require (
github.com/containerd/typeurl v1.0.2 github.com/containerd/typeurl v1.0.2
github.com/containerd/zfs v1.0.0 github.com/containerd/zfs v1.0.0
github.com/containernetworking/plugins v0.9.1 github.com/containernetworking/plugins v0.9.1
github.com/coreos/go-systemd/v22 v22.1.0 github.com/coreos/go-systemd/v22 v22.3.1
github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew v1.1.1
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c
github.com/docker/go-metrics v0.0.1 github.com/docker/go-metrics v0.0.1
@ -40,8 +40,8 @@ require (
github.com/moby/sys/symlink v0.1.0 github.com/moby/sys/symlink v0.1.0
github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.0.1 github.com/opencontainers/image-spec v1.0.1
github.com/opencontainers/runc v1.0.0-rc93 github.com/opencontainers/runc v1.0.0-rc94
github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
github.com/opencontainers/selinux v1.8.0 github.com/opencontainers/selinux v1.8.0
github.com/pelletier/go-toml v1.8.1 github.com/pelletier/go-toml v1.8.1
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1

21
go.sum
View File

@ -64,13 +64,14 @@ github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
github.com/cilium/ebpf v0.4.0 h1:QlHdikaxALkqWasW8hAC1mfR0jdmvbfaBdBPFmRSglA=
github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
github.com/cilium/ebpf v0.5.0 h1:E1KshmrMEtkMP2UjlWzfmUV1owWY+BnbL5FxxuatnrU=
github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/containerd/aufs v1.0.0 h1:2oeJiwX5HstO7shSrPZjrohJZLzK36wvpdmzDRkL/LY= github.com/containerd/aufs v1.0.0 h1:2oeJiwX5HstO7shSrPZjrohJZLzK36wvpdmzDRkL/LY=
github.com/containerd/aufs v1.0.0/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= github.com/containerd/aufs v1.0.0/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU=
@ -119,8 +120,9 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 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 h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd/v22 v22.1.0 h1:kq/SbG2BCKLkDKkjQf5OWwKWUKj1lgs3lFI4PxnR5lg=
github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/coreos/go-systemd/v22 v22.3.1 h1:7OO2CXWMYNDdaAzP51t4lCCZWwpQHmvPbm9sxWjm3So=
github.com/coreos/go-systemd/v22 v22.3.1/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
@ -185,8 +187,9 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
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 v0.0.0-20180201030542-885f9cc04c9c h1:RBUpb2b14UnmRHNd2uHz20ZHLDK+SW5Us/vWF5IHRaY= github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c h1:RBUpb2b14UnmRHNd2uHz20ZHLDK+SW5Us/vWF5IHRaY=
github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/googleapis v1.3.2 h1:kX1es4djPJrsDhY7aZKJy7aZasdcB5oSOEphMjSB53c= github.com/gogo/googleapis v1.3.2 h1:kX1es4djPJrsDhY7aZKJy7aZasdcB5oSOEphMjSB53c=
github.com/gogo/googleapis v1.3.2/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/googleapis v1.3.2/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@ -306,7 +309,6 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
github.com/moby/sys/mountinfo v0.4.1 h1:1O+1cHA1aujwEwwVMa2Xm2l+gIpUHyd3+D+d7LZh1kM= github.com/moby/sys/mountinfo v0.4.1 h1:1O+1cHA1aujwEwwVMa2Xm2l+gIpUHyd3+D+d7LZh1kM=
github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
github.com/moby/sys/symlink v0.1.0 h1:MTFZ74KtNI6qQQpuBxU+uKCim4WtOMokr03hCfJcazE= github.com/moby/sys/symlink v0.1.0 h1:MTFZ74KtNI6qQQpuBxU+uKCim4WtOMokr03hCfJcazE=
@ -342,11 +344,12 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
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-rc93 h1:x2UMpOOVf3kQ8arv/EsDGwim8PTNqzL1/EYDr/+scOM= github.com/opencontainers/runc v1.0.0-rc94 h1:atqAFoBGp+Wkh9HKpYN3g/8NCbMzYG6SJrr+YgwamgM=
github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0= github.com/opencontainers/runc v1.0.0-rc94/go.mod h1:z+bZxa/+Tz/FmYVWkhUajJdzFeOqjc5vrqskhVyHGUM=
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d h1:pNa8metDkwZjb9g4T8s+krQ+HRgZAkqnXml+wNir/+s=
github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc=
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/selinux v1.8.0 h1:+77ba4ar4jsCbL1GLbFL8fFM57w6suPfSS9PDLDY7KM= github.com/opencontainers/selinux v1.8.0 h1:+77ba4ar4jsCbL1GLbFL8fFM57w6suPfSS9PDLDY7KM=
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
@ -593,7 +596,6 @@ golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210324051608-47abb6519492 h1:Paq34FxTluEPvVyayQqMPgHm+vTOrIifmcYxFBx9TLg=
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -670,6 +672,7 @@ google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63 h1:YzfoEYWbODU5Fbt
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=

View File

@ -281,6 +281,7 @@ func resolveLayers(ctx context.Context, store content.Store, layerFiles []string
} }
s, err := compression.DecompressStream(content.NewReader(ra)) s, err := compression.DecompressStream(content.NewReader(ra))
if err != nil { if err != nil {
ra.Close()
return nil, errors.Wrapf(err, "failed to detect compression for %q", layerFiles[i]) return nil, errors.Wrapf(err, "failed to detect compression for %q", layerFiles[i])
} }
if s.GetCompression() == compression.Uncompressed { if s.GetCompression() == compression.Uncompressed {
@ -292,6 +293,7 @@ func resolveLayers(ctx context.Context, store content.Store, layerFiles []string
layers[i], err = compressBlob(ctx, store, s, ref, content.WithLabels(labels)) layers[i], err = compressBlob(ctx, store, s, ref, content.WithLabels(labels))
if err != nil { if err != nil {
s.Close() s.Close()
ra.Close()
return nil, err return nil, err
} }
layers[i].MediaType = images.MediaTypeDockerSchema2LayerGzip layers[i].MediaType = images.MediaTypeDockerSchema2LayerGzip
@ -302,7 +304,7 @@ func resolveLayers(ctx context.Context, store content.Store, layerFiles []string
layers[i].MediaType = images.MediaTypeDockerSchema2LayerGzip layers[i].MediaType = images.MediaTypeDockerSchema2LayerGzip
} }
s.Close() s.Close()
ra.Close()
} }
return layers, nil return layers, nil
} }

View File

@ -66,6 +66,7 @@ func (c *Client) Install(ctx context.Context, image Image, opts ...InstallOpts)
cr := content.NewReader(ra) cr := content.NewReader(ra)
r, err := compression.DecompressStream(cr) r, err := compression.DecompressStream(cr)
if err != nil { if err != nil {
ra.Close()
return err return err
} }
if _, err := archive.Apply(ctx, path, r, archive.WithFilter(func(hdr *tar.Header) (bool, error) { if _, err := archive.Apply(ctx, path, r, archive.WithFilter(func(hdr *tar.Header) (bool, error) {
@ -87,9 +88,11 @@ func (c *Client) Install(ctx context.Context, image Image, opts ...InstallOpts)
return result, nil return result, nil
})); err != nil { })); err != nil {
r.Close() r.Close()
ra.Close()
return err return err
} }
r.Close() r.Close()
ra.Close()
} }
return nil return nil
} }

View File

@ -32,9 +32,9 @@ git clone https://github.com/kubernetes-sigs/cri-tools.git "${TMPROOT}"/cri-tool
pushd "${TMPROOT}"/cri-tools pushd "${TMPROOT}"/cri-tools
git checkout "$CRITEST_COMMIT" git checkout "$CRITEST_COMMIT"
make make
make install -e BINDIR=${DESTDIR:=''}/usr/local/bin make install -e DESTDIR=${DESTDIR:=''} BINDIR=/usr/local/bin
cat << EOF | tee ${DESTDIR}/etc/crictl.yaml cat << EOF | tee ${DESTDIR:=''}/etc/crictl.yaml
runtime-endpoint: unix:///run/containerd/containerd.sock runtime-endpoint: unix:///run/containerd/containerd.sock
EOF EOF

View File

@ -1 +1 @@
v1.0.0-rc93 v1.0.0-rc94

29
vendor/github.com/cilium/ebpf/.golangci.yaml generated vendored Normal file
View File

@ -0,0 +1,29 @@
---
issues:
exclude-rules:
# syscall param structs will have unused fields in Go code.
- path: syscall.*.go
linters:
- structcheck
linters:
disable-all: true
enable:
- deadcode
- errcheck
- goimports
- gosimple
- govet
- ineffassign
- misspell
- staticcheck
- structcheck
- typecheck
- unused
- varcheck
# Could be enabled later:
# - gocyclo
# - prealloc
# - maligned
# - gosec

View File

@ -13,7 +13,7 @@ be used in long running processes.
* [perf](https://pkg.go.dev/github.com/cilium/ebpf/perf) allows reading from a * [perf](https://pkg.go.dev/github.com/cilium/ebpf/perf) allows reading from a
`PERF_EVENT_ARRAY` `PERF_EVENT_ARRAY`
* [cmd/bpf2go](https://pkg.go.dev/github.com/cilium/ebpf/cmd/bpf2go) allows * [cmd/bpf2go](https://pkg.go.dev/github.com/cilium/ebpf/cmd/bpf2go) allows
embedding eBPF in Go compiling and embedding eBPF programs in Go code
The library is maintained by [Cloudflare](https://www.cloudflare.com) and The library is maintained by [Cloudflare](https://www.cloudflare.com) and
[Cilium](https://www.cilium.io). Feel free to [Cilium](https://www.cilium.io). Feel free to
@ -25,6 +25,14 @@ The library is maintained by [Cloudflare](https://www.cloudflare.com) and
The package is production ready, but **the API is explicitly unstable right The package is production ready, but **the API is explicitly unstable right
now**. Expect to update your code if you want to follow along. now**. Expect to update your code if you want to follow along.
## Getting Started
A small collection of Go and eBPF programs that serve as examples for building
your own tools can be found under [examples/](examples/).
Contributions are highly encouraged, as they highlight certain use cases of
eBPF and the library, and help shape the future of the project.
## Requirements ## Requirements
* A version of Go that is [supported by * A version of Go that is [supported by

View File

@ -7,7 +7,7 @@ type BuiltinFunc int32
// eBPF built-in functions // eBPF built-in functions
// //
// You can renegerate this list using the following gawk script: // You can regenerate this list using the following gawk script:
// //
// /FN\(.+\),/ { // /FN\(.+\),/ {
// match($1, /\((.+)\)/, r) // match($1, /\((.+)\)/, r)

View File

@ -337,7 +337,7 @@ func (insns Instructions) ReferenceOffsets() map[string][]int {
// You can control indentation of symbols by // You can control indentation of symbols by
// specifying a width. Setting a precision controls the indentation of // specifying a width. Setting a precision controls the indentation of
// instructions. // instructions.
// The default character is a tab, which can be overriden by specifying // The default character is a tab, which can be overridden by specifying
// the ' ' space flag. // the ' ' space flag.
func (insns Instructions) Format(f fmt.State, c rune) { func (insns Instructions) Format(f fmt.State, c rune) {
if c != 's' && c != 'v' { if c != 's' && c != 'v' {
@ -382,8 +382,6 @@ func (insns Instructions) Format(f fmt.State, c rune) {
} }
fmt.Fprintf(f, "%s%*d: %v\n", indent, offsetWidth, iter.Offset, iter.Ins) fmt.Fprintf(f, "%s%*d: %v\n", indent, offsetWidth, iter.Offset, iter.Ins)
} }
return
} }
// Marshal encodes a BPF program into the kernel format. // Marshal encodes a BPF program into the kernel format.

View File

@ -272,11 +272,12 @@ func (ec *elfCode) loadPrograms() (map[string]*ProgramSpec, error) {
return nil, fmt.Errorf("program %s: %w", funcSym.Name, err) return nil, fmt.Errorf("program %s: %w", funcSym.Name, err)
} }
progType, attachType, attachTo := getProgType(sec.Name) progType, attachType, progFlags, attachTo := getProgType(sec.Name)
spec := &ProgramSpec{ spec := &ProgramSpec{
Name: funcSym.Name, Name: funcSym.Name,
Type: progType, Type: progType,
Flags: progFlags,
AttachType: attachType, AttachType: attachType,
AttachTo: attachTo, AttachTo: attachTo,
License: ec.license, License: ec.license,
@ -533,28 +534,25 @@ func (ec *elfCode) loadBTFMaps(maps map[string]*MapSpec) error {
return fmt.Errorf("missing BTF") return fmt.Errorf("missing BTF")
} }
if len(sec.symbols) == 0 {
return fmt.Errorf("section %v: no symbols", sec.Name)
}
_, err := io.Copy(internal.DiscardZeroes{}, bufio.NewReader(sec.Open())) _, err := io.Copy(internal.DiscardZeroes{}, bufio.NewReader(sec.Open()))
if err != nil { if err != nil {
return fmt.Errorf("section %v: initializing BTF map definitions: %w", sec.Name, internal.ErrNotSupported) return fmt.Errorf("section %v: initializing BTF map definitions: %w", sec.Name, internal.ErrNotSupported)
} }
for _, sym := range sec.symbols { var ds btf.Datasec
name := sym.Name if err := ec.btf.FindType(sec.Name, &ds); err != nil {
if maps[name] != nil { return fmt.Errorf("cannot find section '%s' in BTF: %w", sec.Name, err)
return fmt.Errorf("section %v: map %v already exists", sec.Name, sym) }
}
// A global Var is created by declaring a struct with a 'structure variable', for _, vs := range ds.Vars {
// as is common in eBPF C to declare eBPF maps. For example, v, ok := vs.Type.(*btf.Var)
// `struct { ... } map_name ...;` emits a global variable `map_name` if !ok {
// with the type of said struct (which can be anonymous). return fmt.Errorf("section %v: unexpected type %s", sec.Name, vs.Type)
var v btf.Var }
if err := ec.btf.FindType(name, &v); err != nil { name := string(v.Name)
return fmt.Errorf("cannot find global variable '%s' in BTF: %w", name, err)
if maps[name] != nil {
return fmt.Errorf("section %v: map %s already exists", sec.Name, name)
} }
mapStruct, ok := v.Type.(*btf.Struct) mapStruct, ok := v.Type.(*btf.Struct)
@ -834,56 +832,61 @@ func (ec *elfCode) loadDataSections(maps map[string]*MapSpec) error {
return nil return nil
} }
func getProgType(sectionName string) (ProgramType, AttachType, string) { func getProgType(sectionName string) (ProgramType, AttachType, uint32, string) {
types := map[string]struct { types := map[string]struct {
progType ProgramType progType ProgramType
attachType AttachType attachType AttachType
progFlags uint32
}{ }{
// From https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/lib/bpf/libbpf.c // From https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/lib/bpf/libbpf.c
"socket": {SocketFilter, AttachNone}, "socket": {SocketFilter, AttachNone, 0},
"seccomp": {SocketFilter, AttachNone}, "seccomp": {SocketFilter, AttachNone, 0},
"kprobe/": {Kprobe, AttachNone}, "kprobe/": {Kprobe, AttachNone, 0},
"uprobe/": {Kprobe, AttachNone}, "uprobe/": {Kprobe, AttachNone, 0},
"kretprobe/": {Kprobe, AttachNone}, "kretprobe/": {Kprobe, AttachNone, 0},
"uretprobe/": {Kprobe, AttachNone}, "uretprobe/": {Kprobe, AttachNone, 0},
"tracepoint/": {TracePoint, AttachNone}, "tracepoint/": {TracePoint, AttachNone, 0},
"raw_tracepoint/": {RawTracepoint, AttachNone}, "raw_tracepoint/": {RawTracepoint, AttachNone, 0},
"xdp": {XDP, AttachNone}, "xdp": {XDP, AttachNone, 0},
"perf_event": {PerfEvent, AttachNone}, "perf_event": {PerfEvent, AttachNone, 0},
"lwt_in": {LWTIn, AttachNone}, "lwt_in": {LWTIn, AttachNone, 0},
"lwt_out": {LWTOut, AttachNone}, "lwt_out": {LWTOut, AttachNone, 0},
"lwt_xmit": {LWTXmit, AttachNone}, "lwt_xmit": {LWTXmit, AttachNone, 0},
"lwt_seg6local": {LWTSeg6Local, AttachNone}, "lwt_seg6local": {LWTSeg6Local, AttachNone, 0},
"sockops": {SockOps, AttachCGroupSockOps}, "sockops": {SockOps, AttachCGroupSockOps, 0},
"sk_skb/stream_parser": {SkSKB, AttachSkSKBStreamParser}, "sk_skb/stream_parser": {SkSKB, AttachSkSKBStreamParser, 0},
"sk_skb/stream_verdict": {SkSKB, AttachSkSKBStreamParser}, "sk_skb/stream_verdict": {SkSKB, AttachSkSKBStreamParser, 0},
"sk_msg": {SkMsg, AttachSkSKBStreamVerdict}, "sk_msg": {SkMsg, AttachSkSKBStreamVerdict, 0},
"lirc_mode2": {LircMode2, AttachLircMode2}, "lirc_mode2": {LircMode2, AttachLircMode2, 0},
"flow_dissector": {FlowDissector, AttachFlowDissector}, "flow_dissector": {FlowDissector, AttachFlowDissector, 0},
"iter/": {Tracing, AttachTraceIter}, "iter/": {Tracing, AttachTraceIter, 0},
"sk_lookup/": {SkLookup, AttachSkLookup}, "fentry.s/": {Tracing, AttachTraceFEntry, unix.BPF_F_SLEEPABLE},
"lsm/": {LSM, AttachLSMMac}, "fmod_ret.s/": {Tracing, AttachModifyReturn, unix.BPF_F_SLEEPABLE},
"fexit.s/": {Tracing, AttachTraceFExit, unix.BPF_F_SLEEPABLE},
"sk_lookup/": {SkLookup, AttachSkLookup, 0},
"lsm/": {LSM, AttachLSMMac, 0},
"lsm.s/": {LSM, AttachLSMMac, unix.BPF_F_SLEEPABLE},
"cgroup_skb/ingress": {CGroupSKB, AttachCGroupInetIngress}, "cgroup_skb/ingress": {CGroupSKB, AttachCGroupInetIngress, 0},
"cgroup_skb/egress": {CGroupSKB, AttachCGroupInetEgress}, "cgroup_skb/egress": {CGroupSKB, AttachCGroupInetEgress, 0},
"cgroup/dev": {CGroupDevice, AttachCGroupDevice}, "cgroup/dev": {CGroupDevice, AttachCGroupDevice, 0},
"cgroup/skb": {CGroupSKB, AttachNone}, "cgroup/skb": {CGroupSKB, AttachNone, 0},
"cgroup/sock": {CGroupSock, AttachCGroupInetSockCreate}, "cgroup/sock": {CGroupSock, AttachCGroupInetSockCreate, 0},
"cgroup/post_bind4": {CGroupSock, AttachCGroupInet4PostBind}, "cgroup/post_bind4": {CGroupSock, AttachCGroupInet4PostBind, 0},
"cgroup/post_bind6": {CGroupSock, AttachCGroupInet6PostBind}, "cgroup/post_bind6": {CGroupSock, AttachCGroupInet6PostBind, 0},
"cgroup/bind4": {CGroupSockAddr, AttachCGroupInet4Bind}, "cgroup/bind4": {CGroupSockAddr, AttachCGroupInet4Bind, 0},
"cgroup/bind6": {CGroupSockAddr, AttachCGroupInet6Bind}, "cgroup/bind6": {CGroupSockAddr, AttachCGroupInet6Bind, 0},
"cgroup/connect4": {CGroupSockAddr, AttachCGroupInet4Connect}, "cgroup/connect4": {CGroupSockAddr, AttachCGroupInet4Connect, 0},
"cgroup/connect6": {CGroupSockAddr, AttachCGroupInet6Connect}, "cgroup/connect6": {CGroupSockAddr, AttachCGroupInet6Connect, 0},
"cgroup/sendmsg4": {CGroupSockAddr, AttachCGroupUDP4Sendmsg}, "cgroup/sendmsg4": {CGroupSockAddr, AttachCGroupUDP4Sendmsg, 0},
"cgroup/sendmsg6": {CGroupSockAddr, AttachCGroupUDP6Sendmsg}, "cgroup/sendmsg6": {CGroupSockAddr, AttachCGroupUDP6Sendmsg, 0},
"cgroup/recvmsg4": {CGroupSockAddr, AttachCGroupUDP4Recvmsg}, "cgroup/recvmsg4": {CGroupSockAddr, AttachCGroupUDP4Recvmsg, 0},
"cgroup/recvmsg6": {CGroupSockAddr, AttachCGroupUDP6Recvmsg}, "cgroup/recvmsg6": {CGroupSockAddr, AttachCGroupUDP6Recvmsg, 0},
"cgroup/sysctl": {CGroupSysctl, AttachCGroupSysctl}, "cgroup/sysctl": {CGroupSysctl, AttachCGroupSysctl, 0},
"cgroup/getsockopt": {CGroupSockopt, AttachCGroupGetsockopt}, "cgroup/getsockopt": {CGroupSockopt, AttachCGroupGetsockopt, 0},
"cgroup/setsockopt": {CGroupSockopt, AttachCGroupSetsockopt}, "cgroup/setsockopt": {CGroupSockopt, AttachCGroupSetsockopt, 0},
"classifier": {SchedCLS, AttachNone}, "classifier": {SchedCLS, AttachNone, 0},
"action": {SchedACT, AttachNone}, "action": {SchedACT, AttachNone, 0},
} }
for prefix, t := range types { for prefix, t := range types {
@ -892,13 +895,13 @@ func getProgType(sectionName string) (ProgramType, AttachType, string) {
} }
if !strings.HasSuffix(prefix, "/") { if !strings.HasSuffix(prefix, "/") {
return t.progType, t.attachType, "" return t.progType, t.attachType, t.progFlags, ""
} }
return t.progType, t.attachType, sectionName[len(prefix):] return t.progType, t.attachType, t.progFlags, sectionName[len(prefix):]
} }
return UnspecifiedProgram, AttachNone, "" return UnspecifiedProgram, AttachNone, 0, ""
} }
func (ec *elfCode) loadRelocations(sec *elf.Section, symbols []elf.Symbol) (map[uint64]elf.Symbol, error) { func (ec *elfCode) loadRelocations(sec *elf.Section, symbols []elf.Symbol) (map[uint64]elf.Symbol, error) {

View File

@ -31,12 +31,14 @@ const (
kindDatasec kindDatasec
) )
// btfFuncLinkage describes BTF function linkage metadata.
type btfFuncLinkage uint8 type btfFuncLinkage uint8
// Equivalent of enum btf_func_linkage.
const ( const (
linkageStatic btfFuncLinkage = iota linkageStatic btfFuncLinkage = iota
linkageGlobal linkageGlobal
linkageExtern // linkageExtern // Currently unused in libbpf.
) )
const ( const (

View File

@ -98,41 +98,3 @@ func FeatureTest(name, version string, fn FeatureTestFn) func() error {
return ft.result return ft.result
} }
} }
// A Version in the form Major.Minor.Patch.
type Version [3]uint16
// NewVersion creates a version from a string like "Major.Minor.Patch".
//
// Patch is optional.
func NewVersion(ver string) (Version, error) {
var major, minor, patch uint16
n, _ := fmt.Sscanf(ver, "%d.%d.%d", &major, &minor, &patch)
if n < 2 {
return Version{}, fmt.Errorf("invalid version: %s", ver)
}
return Version{major, minor, patch}, nil
}
func (v Version) String() string {
if v[2] == 0 {
return fmt.Sprintf("v%d.%d", v[0], v[1])
}
return fmt.Sprintf("v%d.%d.%d", v[0], v[1], v[2])
}
// Less returns true if the version is less than another version.
func (v Version) Less(other Version) bool {
for i, a := range v {
if a == other[i] {
continue
}
return a < other[i]
}
return false
}
// Unspecified returns true if the version is all zero.
func (v Version) Unspecified() bool {
return v[0] == 0 && v[1] == 0 && v[2] == 0
}

View File

@ -1,36 +1,38 @@
package ebpf package internal
import ( import (
"errors" "errors"
"fmt" "fmt"
"os" "os"
"github.com/cilium/ebpf/internal" "github.com/cilium/ebpf/internal/unix"
) )
func pin(currentPath, newPath string, fd *internal.FD) error { func Pin(currentPath, newPath string, fd *FD) error {
if newPath == "" { if newPath == "" {
return errors.New("given pinning path cannot be empty") return errors.New("given pinning path cannot be empty")
} }
if currentPath == "" {
return internal.BPFObjPin(newPath, fd)
}
if currentPath == newPath { if currentPath == newPath {
return nil return nil
} }
if currentPath == "" {
return BPFObjPin(newPath, fd)
}
var err error var err error
// Object is now moved to the new pinning path. // Renameat2 is used instead of os.Rename to disallow the new path replacing
if err = os.Rename(currentPath, newPath); err == nil { // an existing path.
if err = unix.Renameat2(unix.AT_FDCWD, currentPath, unix.AT_FDCWD, newPath, unix.RENAME_NOREPLACE); err == nil {
// Object is now moved to the new pinning path.
return nil return nil
} }
if !os.IsNotExist(err) { if !os.IsNotExist(err) {
return fmt.Errorf("unable to move pinned object to new path %v: %w", newPath, err) return fmt.Errorf("unable to move pinned object to new path %v: %w", newPath, err)
} }
// Internal state not in sync with the file system so let's fix it. // Internal state not in sync with the file system so let's fix it.
return internal.BPFObjPin(newPath, fd) return BPFObjPin(newPath, fd)
} }
func unpin(pinnedPath string) error { func Unpin(pinnedPath string) error {
if pinnedPath == "" { if pinnedPath == "" {
return nil return nil
} }

View File

@ -1,6 +1,10 @@
package internal package internal
import "unsafe" import (
"unsafe"
"github.com/cilium/ebpf/internal/unix"
)
// NewPointer creates a 64-bit pointer from an unsafe Pointer. // NewPointer creates a 64-bit pointer from an unsafe Pointer.
func NewPointer(ptr unsafe.Pointer) Pointer { func NewPointer(ptr unsafe.Pointer) Pointer {
@ -22,9 +26,10 @@ func NewStringPointer(str string) Pointer {
return Pointer{} return Pointer{}
} }
// The kernel expects strings to be zero terminated p, err := unix.BytePtrFromString(str)
buf := make([]byte, len(str)+1) if err != nil {
copy(buf, str) return Pointer{}
}
return Pointer{ptr: unsafe.Pointer(&buf[0])} return Pointer{ptr: unsafe.Pointer(p)}
} }

View File

@ -140,9 +140,10 @@ func BPFObjPin(fileName string, fd *FD) error {
} }
// BPFObjGet wraps BPF_OBJ_GET. // BPFObjGet wraps BPF_OBJ_GET.
func BPFObjGet(fileName string) (*FD, error) { func BPFObjGet(fileName string, flags uint32) (*FD, error) {
attr := bpfObjAttr{ attr := bpfObjAttr{
fileName: NewStringPointer(fileName), fileName: NewStringPointer(fileName),
fileFlags: flags,
} }
ptr, err := BPF(BPF_OBJ_GET, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) ptr, err := BPF(BPF_OBJ_GET, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
if err != nil { if err != nil {

View File

@ -26,8 +26,11 @@ const (
EBADF = linux.EBADF EBADF = linux.EBADF
BPF_F_NO_PREALLOC = linux.BPF_F_NO_PREALLOC BPF_F_NO_PREALLOC = linux.BPF_F_NO_PREALLOC
BPF_F_NUMA_NODE = linux.BPF_F_NUMA_NODE BPF_F_NUMA_NODE = linux.BPF_F_NUMA_NODE
BPF_F_RDONLY = linux.BPF_F_RDONLY
BPF_F_WRONLY = linux.BPF_F_WRONLY
BPF_F_RDONLY_PROG = linux.BPF_F_RDONLY_PROG BPF_F_RDONLY_PROG = linux.BPF_F_RDONLY_PROG
BPF_F_WRONLY_PROG = linux.BPF_F_WRONLY_PROG BPF_F_WRONLY_PROG = linux.BPF_F_WRONLY_PROG
BPF_F_SLEEPABLE = linux.BPF_F_SLEEPABLE
BPF_OBJ_NAME_LEN = linux.BPF_OBJ_NAME_LEN BPF_OBJ_NAME_LEN = linux.BPF_OBJ_NAME_LEN
BPF_TAG_SIZE = linux.BPF_TAG_SIZE BPF_TAG_SIZE = linux.BPF_TAG_SIZE
SYS_BPF = linux.SYS_BPF SYS_BPF = linux.SYS_BPF
@ -40,13 +43,21 @@ const (
PROT_WRITE = linux.PROT_WRITE PROT_WRITE = linux.PROT_WRITE
MAP_SHARED = linux.MAP_SHARED MAP_SHARED = linux.MAP_SHARED
PERF_TYPE_SOFTWARE = linux.PERF_TYPE_SOFTWARE PERF_TYPE_SOFTWARE = linux.PERF_TYPE_SOFTWARE
PERF_TYPE_TRACEPOINT = linux.PERF_TYPE_TRACEPOINT
PERF_COUNT_SW_BPF_OUTPUT = linux.PERF_COUNT_SW_BPF_OUTPUT PERF_COUNT_SW_BPF_OUTPUT = linux.PERF_COUNT_SW_BPF_OUTPUT
PERF_EVENT_IOC_DISABLE = linux.PERF_EVENT_IOC_DISABLE
PERF_EVENT_IOC_ENABLE = linux.PERF_EVENT_IOC_ENABLE
PERF_EVENT_IOC_SET_BPF = linux.PERF_EVENT_IOC_SET_BPF
PerfBitWatermark = linux.PerfBitWatermark PerfBitWatermark = linux.PerfBitWatermark
PERF_SAMPLE_RAW = linux.PERF_SAMPLE_RAW PERF_SAMPLE_RAW = linux.PERF_SAMPLE_RAW
PERF_FLAG_FD_CLOEXEC = linux.PERF_FLAG_FD_CLOEXEC PERF_FLAG_FD_CLOEXEC = linux.PERF_FLAG_FD_CLOEXEC
RLIM_INFINITY = linux.RLIM_INFINITY RLIM_INFINITY = linux.RLIM_INFINITY
RLIMIT_MEMLOCK = linux.RLIMIT_MEMLOCK RLIMIT_MEMLOCK = linux.RLIMIT_MEMLOCK
BPF_STATS_RUN_TIME = linux.BPF_STATS_RUN_TIME BPF_STATS_RUN_TIME = linux.BPF_STATS_RUN_TIME
PERF_RECORD_LOST = linux.PERF_RECORD_LOST
PERF_RECORD_SAMPLE = linux.PERF_RECORD_SAMPLE
AT_FDCWD = linux.AT_FDCWD
RENAME_NOREPLACE = linux.RENAME_NOREPLACE
) )
// Statfs_t is a wrapper // Statfs_t is a wrapper
@ -70,6 +81,11 @@ func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
return linux.FcntlInt(fd, cmd, arg) return linux.FcntlInt(fd, cmd, arg)
} }
// IoctlSetInt is a wrapper
func IoctlSetInt(fd int, req uint, value int) error {
return linux.IoctlSetInt(fd, req, value)
}
// Statfs is a wrapper // Statfs is a wrapper
func Statfs(path string, buf *Statfs_t) (err error) { func Statfs(path string, buf *Statfs_t) (err error) {
return linux.Statfs(path, buf) return linux.Statfs(path, buf)
@ -157,6 +173,21 @@ func Tgkill(tgid int, tid int, sig syscall.Signal) (err error) {
return linux.Tgkill(tgid, tid, sig) return linux.Tgkill(tgid, tid, sig)
} }
// BytePtrFromString is a wrapper
func BytePtrFromString(s string) (*byte, error) {
return linux.BytePtrFromString(s)
}
// ByteSliceToString is a wrapper
func ByteSliceToString(s []byte) string {
return linux.ByteSliceToString(s)
}
// Renameat2 is a wrapper
func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) error {
return linux.Renameat2(olddirfd, oldpath, newdirfd, newpath, flags)
}
func KernelRelease() (string, error) { func KernelRelease() (string, error) {
var uname Utsname var uname Utsname
err := Uname(&uname) err := Uname(&uname)

View File

@ -26,8 +26,11 @@ const (
BPF_F_NO_PREALLOC = 0 BPF_F_NO_PREALLOC = 0
BPF_F_NUMA_NODE = 0 BPF_F_NUMA_NODE = 0
BPF_F_RDONLY = 0
BPF_F_WRONLY = 0
BPF_F_RDONLY_PROG = 0 BPF_F_RDONLY_PROG = 0
BPF_F_WRONLY_PROG = 0 BPF_F_WRONLY_PROG = 0
BPF_F_SLEEPABLE = 0
BPF_OBJ_NAME_LEN = 0x10 BPF_OBJ_NAME_LEN = 0x10
BPF_TAG_SIZE = 0x8 BPF_TAG_SIZE = 0x8
SYS_BPF = 321 SYS_BPF = 321
@ -41,13 +44,21 @@ const (
PROT_WRITE = 0x2 PROT_WRITE = 0x2
MAP_SHARED = 0x1 MAP_SHARED = 0x1
PERF_TYPE_SOFTWARE = 0x1 PERF_TYPE_SOFTWARE = 0x1
PERF_TYPE_TRACEPOINT = 0
PERF_COUNT_SW_BPF_OUTPUT = 0xa PERF_COUNT_SW_BPF_OUTPUT = 0xa
PERF_EVENT_IOC_DISABLE = 0
PERF_EVENT_IOC_ENABLE = 0
PERF_EVENT_IOC_SET_BPF = 0
PerfBitWatermark = 0x4000 PerfBitWatermark = 0x4000
PERF_SAMPLE_RAW = 0x400 PERF_SAMPLE_RAW = 0x400
PERF_FLAG_FD_CLOEXEC = 0x8 PERF_FLAG_FD_CLOEXEC = 0x8
RLIM_INFINITY = 0x7fffffffffffffff RLIM_INFINITY = 0x7fffffffffffffff
RLIMIT_MEMLOCK = 8 RLIMIT_MEMLOCK = 8
BPF_STATS_RUN_TIME = 0 BPF_STATS_RUN_TIME = 0
PERF_RECORD_LOST = 2
PERF_RECORD_SAMPLE = 9
AT_FDCWD = -0x2
RENAME_NOREPLACE = 0x1
) )
// Statfs_t is a wrapper // Statfs_t is a wrapper
@ -87,6 +98,11 @@ func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
return -1, errNonLinux return -1, errNonLinux
} }
// IoctlSetInt is a wrapper
func IoctlSetInt(fd int, req uint, value int) error {
return errNonLinux
}
// Statfs is a wrapper // Statfs is a wrapper
func Statfs(path string, buf *Statfs_t) error { func Statfs(path string, buf *Statfs_t) error {
return errNonLinux return errNonLinux
@ -201,6 +217,7 @@ func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int
// Utsname is a wrapper // Utsname is a wrapper
type Utsname struct { type Utsname struct {
Release [65]byte Release [65]byte
Version [65]byte
} }
// Uname is a wrapper // Uname is a wrapper
@ -223,6 +240,21 @@ func Tgkill(tgid int, tid int, sig syscall.Signal) (err error) {
return errNonLinux return errNonLinux
} }
// BytePtrFromString is a wrapper
func BytePtrFromString(s string) (*byte, error) {
return nil, errNonLinux
}
// ByteSliceToString is a wrapper
func ByteSliceToString(s []byte) string {
return ""
}
// Renameat2 is a wrapper
func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) error {
return errNonLinux
}
func KernelRelease() (string, error) { func KernelRelease() (string, error) {
return "", errNonLinux return "", errNonLinux
} }

163
vendor/github.com/cilium/ebpf/internal/version.go generated vendored Normal file
View File

@ -0,0 +1,163 @@
package internal
import (
"fmt"
"io/ioutil"
"regexp"
"sync"
"github.com/cilium/ebpf/internal/unix"
)
const (
// Version constant used in ELF binaries indicating that the loader needs to
// substitute the eBPF program's version with the value of the kernel's
// KERNEL_VERSION compile-time macro. Used for compatibility with BCC, gobpf
// and RedSift.
MagicKernelVersion = 0xFFFFFFFE
)
var (
// Match between one and three decimals separated by dots, with the last
// segment (patch level) being optional on some kernels.
// The x.y.z string must appear at the start of a string or right after
// whitespace to prevent sequences like 'x.y.z-a.b.c' from matching 'a.b.c'.
rgxKernelVersion = regexp.MustCompile(`(?:\A|\s)\d{1,3}\.\d{1,3}(?:\.\d{1,3})?`)
kernelVersion = struct {
once sync.Once
version Version
err error
}{}
)
// A Version in the form Major.Minor.Patch.
type Version [3]uint16
// NewVersion creates a version from a string like "Major.Minor.Patch".
//
// Patch is optional.
func NewVersion(ver string) (Version, error) {
var major, minor, patch uint16
n, _ := fmt.Sscanf(ver, "%d.%d.%d", &major, &minor, &patch)
if n < 2 {
return Version{}, fmt.Errorf("invalid version: %s", ver)
}
return Version{major, minor, patch}, nil
}
func (v Version) String() string {
if v[2] == 0 {
return fmt.Sprintf("v%d.%d", v[0], v[1])
}
return fmt.Sprintf("v%d.%d.%d", v[0], v[1], v[2])
}
// Less returns true if the version is less than another version.
func (v Version) Less(other Version) bool {
for i, a := range v {
if a == other[i] {
continue
}
return a < other[i]
}
return false
}
// Unspecified returns true if the version is all zero.
func (v Version) Unspecified() bool {
return v[0] == 0 && v[1] == 0 && v[2] == 0
}
// Kernel implements the kernel's KERNEL_VERSION macro from linux/version.h.
// It represents the kernel version and patch level as a single value.
func (v Version) Kernel() uint32 {
// Kernels 4.4 and 4.9 have their SUBLEVEL clamped to 255 to avoid
// overflowing into PATCHLEVEL.
// See kernel commit 9b82f13e7ef3 ("kbuild: clamp SUBLEVEL to 255").
s := v[2]
if s > 255 {
s = 255
}
// Truncate members to uint8 to prevent them from spilling over into
// each other when overflowing 8 bits.
return uint32(uint8(v[0]))<<16 | uint32(uint8(v[1]))<<8 | uint32(uint8(s))
}
// KernelVersion returns the version of the currently running kernel.
func KernelVersion() (Version, error) {
kernelVersion.once.Do(func() {
kernelVersion.version, kernelVersion.err = detectKernelVersion()
})
if kernelVersion.err != nil {
return Version{}, kernelVersion.err
}
return kernelVersion.version, nil
}
// detectKernelVersion returns the version of the running kernel. It scans the
// following sources in order: /proc/version_signature, uname -v, uname -r.
// In each of those locations, the last-appearing x.y(.z) value is selected
// for parsing. The first location that yields a usable version number is
// returned.
func detectKernelVersion() (Version, error) {
// Try reading /proc/version_signature for Ubuntu compatibility.
// Example format: Ubuntu 4.15.0-91.92-generic 4.15.18
// This method exists in the kernel itself, see d18acd15c
// ("perf tools: Fix kernel version error in ubuntu").
if pvs, err := ioutil.ReadFile("/proc/version_signature"); err == nil {
// If /proc/version_signature exists, failing to parse it is an error.
// It only exists on Ubuntu, where the real patch level is not obtainable
// through any other method.
v, err := findKernelVersion(string(pvs))
if err != nil {
return Version{}, err
}
return v, nil
}
var uname unix.Utsname
if err := unix.Uname(&uname); err != nil {
return Version{}, fmt.Errorf("calling uname: %w", err)
}
// Debian puts the version including the patch level in uname.Version.
// It is not an error if there's no version number in uname.Version,
// as most distributions don't use it. Parsing can continue on uname.Release.
// Example format: #1 SMP Debian 4.19.37-5+deb10u2 (2019-08-08)
if v, err := findKernelVersion(unix.ByteSliceToString(uname.Version[:])); err == nil {
return v, nil
}
// Most other distributions have the full kernel version including patch
// level in uname.Release.
// Example format: 4.19.0-5-amd64, 5.5.10-arch1-1
v, err := findKernelVersion(unix.ByteSliceToString(uname.Release[:]))
if err != nil {
return Version{}, err
}
return v, nil
}
// findKernelVersion matches s against rgxKernelVersion and parses the result
// into a Version. If s contains multiple matches, the last entry is selected.
func findKernelVersion(s string) (Version, error) {
m := rgxKernelVersion.FindAllString(s, -1)
if m == nil {
return Version{}, fmt.Errorf("no kernel version in string: %s", s)
}
// Pick the last match of the string in case there are multiple.
s = m[len(m)-1]
v, err := NewVersion(s)
if err != nil {
return Version{}, fmt.Errorf("parsing version string %s: %w", s, err)
}
return v, nil
}

View File

@ -57,13 +57,13 @@ func AttachCgroup(opts CgroupOptions) (Link, error) {
} }
// LoadPinnedCgroup loads a pinned cgroup from a bpffs. // LoadPinnedCgroup loads a pinned cgroup from a bpffs.
func LoadPinnedCgroup(fileName string) (Link, error) { func LoadPinnedCgroup(fileName string, opts *ebpf.LoadPinOptions) (Link, error) {
link, err := LoadPinnedRawLink(fileName) link, err := LoadPinnedRawLink(fileName, CgroupType, opts)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &linkCgroup{link}, nil return &linkCgroup{*link}, nil
} }
type progAttachCgroup struct { type progAttachCgroup struct {
@ -147,14 +147,16 @@ func (cg *progAttachCgroup) Pin(string) error {
return fmt.Errorf("can't pin cgroup: %w", ErrNotSupported) return fmt.Errorf("can't pin cgroup: %w", ErrNotSupported)
} }
func (cg *progAttachCgroup) Unpin() error {
return fmt.Errorf("can't pin cgroup: %w", ErrNotSupported)
}
type linkCgroup struct { type linkCgroup struct {
*RawLink RawLink
} }
var _ Link = (*linkCgroup)(nil) var _ Link = (*linkCgroup)(nil)
func (cg *linkCgroup) isLink() {}
func newLinkCgroup(cgroup *os.File, attach ebpf.AttachType, prog *ebpf.Program) (*linkCgroup, error) { func newLinkCgroup(cgroup *os.File, attach ebpf.AttachType, prog *ebpf.Program) (*linkCgroup, error) {
link, err := AttachRawLink(RawLinkOptions{ link, err := AttachRawLink(RawLinkOptions{
Target: int(cgroup.Fd()), Target: int(cgroup.Fd()),
@ -165,5 +167,5 @@ func newLinkCgroup(cgroup *os.File, attach ebpf.AttachType, prog *ebpf.Program)
return nil, err return nil, err
} }
return &linkCgroup{link}, err return &linkCgroup{*link}, err
} }

View File

@ -27,53 +27,29 @@ func AttachIter(opts IterOptions) (*Iter, error) {
return nil, fmt.Errorf("can't link iterator: %w", err) return nil, fmt.Errorf("can't link iterator: %w", err)
} }
return &Iter{link}, err return &Iter{*link}, err
} }
// LoadPinnedIter loads a pinned iterator from a bpffs. // LoadPinnedIter loads a pinned iterator from a bpffs.
func LoadPinnedIter(fileName string) (*Iter, error) { func LoadPinnedIter(fileName string, opts *ebpf.LoadPinOptions) (*Iter, error) {
link, err := LoadPinnedRawLink(fileName) link, err := LoadPinnedRawLink(fileName, IterType, opts)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &Iter{link}, err return &Iter{*link}, err
} }
// Iter represents an attached bpf_iter. // Iter represents an attached bpf_iter.
type Iter struct { type Iter struct {
link *RawLink RawLink
}
var _ Link = (*Iter)(nil)
func (it *Iter) isLink() {}
// FD returns the underlying file descriptor.
func (it *Iter) FD() int {
return it.link.FD()
}
// Close implements Link.
func (it *Iter) Close() error {
return it.link.Close()
}
// Pin implements Link.
func (it *Iter) Pin(fileName string) error {
return it.link.Pin(fileName)
}
// Update implements Link.
func (it *Iter) Update(new *ebpf.Program) error {
return it.link.Update(new)
} }
// Open creates a new instance of the iterator. // Open creates a new instance of the iterator.
// //
// Reading from the returned reader triggers the BPF program. // Reading from the returned reader triggers the BPF program.
func (it *Iter) Open() (io.ReadCloser, error) { func (it *Iter) Open() (io.ReadCloser, error) {
linkFd, err := it.link.fd.Value() linkFd, err := it.fd.Value()
if err != nil { if err != nil {
return nil, err return nil, err
} }

296
vendor/github.com/cilium/ebpf/link/kprobe.go generated vendored Normal file
View File

@ -0,0 +1,296 @@
package link
import (
"crypto/rand"
"errors"
"fmt"
"os"
"path/filepath"
"runtime"
"github.com/cilium/ebpf"
"github.com/cilium/ebpf/internal"
"github.com/cilium/ebpf/internal/unix"
)
var (
kprobeEventsPath = filepath.Join(tracefsPath, "kprobe_events")
)
// Kprobe attaches the given eBPF program to a perf event that fires when the
// given kernel symbol starts executing. See /proc/kallsyms for available
// symbols. For example, printk():
//
// Kprobe("printk")
//
// The resulting Link must be Closed during program shutdown to avoid leaking
// system resources.
func Kprobe(symbol string, prog *ebpf.Program) (Link, error) {
k, err := kprobe(symbol, prog, false)
if err != nil {
return nil, err
}
err = k.attach(prog)
if err != nil {
k.Close()
return nil, err
}
return k, nil
}
// Kretprobe attaches the given eBPF program to a perf event that fires right
// before the given kernel symbol exits, with the function stack left intact.
// See /proc/kallsyms for available symbols. For example, printk():
//
// Kretprobe("printk")
//
// The resulting Link must be Closed during program shutdown to avoid leaking
// system resources.
func Kretprobe(symbol string, prog *ebpf.Program) (Link, error) {
k, err := kprobe(symbol, prog, true)
if err != nil {
return nil, err
}
err = k.attach(prog)
if err != nil {
k.Close()
return nil, err
}
return k, nil
}
// kprobe opens a perf event on the given symbol and attaches prog to it.
// If ret is true, create a kretprobe.
func kprobe(symbol string, prog *ebpf.Program, ret bool) (*perfEvent, error) {
if symbol == "" {
return nil, fmt.Errorf("symbol name cannot be empty: %w", errInvalidInput)
}
if prog == nil {
return nil, fmt.Errorf("prog cannot be nil: %w", errInvalidInput)
}
if !rgxTraceEvent.MatchString(symbol) {
return nil, fmt.Errorf("symbol '%s' must be alphanumeric or underscore: %w", symbol, errInvalidInput)
}
if prog.Type() != ebpf.Kprobe {
return nil, fmt.Errorf("eBPF program type %s is not a Kprobe: %w", prog.Type(), errInvalidInput)
}
// Use kprobe PMU if the kernel has it available.
tp, err := pmuKprobe(symbol, ret)
if err == nil {
return tp, nil
}
if err != nil && !errors.Is(err, ErrNotSupported) {
return nil, fmt.Errorf("creating perf_kprobe PMU: %w", err)
}
// Use tracefs if kprobe PMU is missing.
tp, err = tracefsKprobe(symbol, ret)
if err != nil {
return nil, fmt.Errorf("creating trace event '%s' in tracefs: %w", symbol, err)
}
return tp, nil
}
// pmuKprobe opens a perf event based on a Performance Monitoring Unit.
// Requires at least 4.17 (e12f03d7031a "perf/core: Implement the
// 'perf_kprobe' PMU").
// Returns ErrNotSupported if the kernel doesn't support perf_kprobe PMU,
// or os.ErrNotExist if the given symbol does not exist in the kernel.
func pmuKprobe(symbol string, ret bool) (*perfEvent, error) {
// Getting the PMU type will fail if the kernel doesn't support
// the perf_kprobe PMU.
et, err := getPMUEventType("kprobe")
if err != nil {
return nil, err
}
// Create a pointer to a NUL-terminated string for the kernel.
sp, err := unsafeStringPtr(symbol)
if err != nil {
return nil, err
}
// TODO: Parse the position of the bit from /sys/bus/event_source/devices/%s/format/retprobe.
config := 0
if ret {
config = 1
}
attr := unix.PerfEventAttr{
Type: uint32(et), // PMU event type read from sysfs
Ext1: uint64(uintptr(sp)), // Kernel symbol to trace
Config: uint64(config), // perf_kprobe PMU treats config as flags
}
fd, err := unix.PerfEventOpen(&attr, perfAllThreads, 0, -1, unix.PERF_FLAG_FD_CLOEXEC)
// Since commit 97c753e62e6c, ENOENT is correctly returned instead of EINVAL
// when trying to create a kretprobe for a missing symbol. Make sure ENOENT
// is returned to the caller.
if errors.Is(err, os.ErrNotExist) || errors.Is(err, unix.EINVAL) {
return nil, fmt.Errorf("symbol '%s' not found: %w", symbol, os.ErrNotExist)
}
if err != nil {
return nil, fmt.Errorf("opening perf event: %w", err)
}
// Ensure the string pointer is not collected before PerfEventOpen returns.
runtime.KeepAlive(sp)
// Kernel has perf_kprobe PMU available, initialize perf event.
return &perfEvent{
fd: internal.NewFD(uint32(fd)),
pmuID: et,
name: symbol,
ret: ret,
progType: ebpf.Kprobe,
}, nil
}
// tracefsKprobe creates a trace event by writing an entry to <tracefs>/kprobe_events.
// A new trace event group name is generated on every call to support creating
// multiple trace events for the same kernel symbol. A perf event is then opened
// on the newly-created trace event and returned to the caller.
func tracefsKprobe(symbol string, ret bool) (*perfEvent, error) {
// Generate a random string for each trace event we attempt to create.
// This value is used as the 'group' token in tracefs to allow creating
// multiple kprobe trace events with the same name.
group, err := randomGroup("ebpf")
if err != nil {
return nil, fmt.Errorf("randomizing group name: %w", err)
}
// Before attempting to create a trace event through tracefs,
// check if an event with the same group and name already exists.
// Kernels 4.x and earlier don't return os.ErrExist on writing a duplicate
// entry, so we need to rely on reads for detecting uniqueness.
_, err = getTraceEventID(group, symbol)
if err == nil {
return nil, fmt.Errorf("trace event already exists: %s/%s", group, symbol)
}
// The read is expected to fail with ErrNotSupported due to a non-existing event.
if err != nil && !errors.Is(err, ErrNotSupported) {
return nil, fmt.Errorf("checking trace event %s/%s: %w", group, symbol, err)
}
// Create the kprobe trace event using tracefs.
if err := createTraceFSKprobeEvent(group, symbol, ret); err != nil {
return nil, fmt.Errorf("creating kprobe event on tracefs: %w", err)
}
// Get the newly-created trace event's id.
tid, err := getTraceEventID(group, symbol)
if err != nil {
return nil, fmt.Errorf("getting trace event id: %w", err)
}
// Kprobes are ephemeral tracepoints and share the same perf event type.
fd, err := openTracepointPerfEvent(tid)
if err != nil {
return nil, err
}
return &perfEvent{
fd: fd,
group: group,
name: symbol,
ret: ret,
tracefsID: tid,
progType: ebpf.Kprobe, // kernel only allows attaching kprobe programs to kprobe events
}, nil
}
// createTraceFSKprobeEvent creates a new ephemeral trace event by writing to
// <tracefs>/kprobe_events. Returns ErrNotSupported if symbol is not a valid
// kernel symbol, or if it is not traceable with kprobes.
func createTraceFSKprobeEvent(group, symbol string, ret bool) error {
// Open the kprobe_events file in tracefs.
f, err := os.OpenFile(kprobeEventsPath, os.O_APPEND|os.O_WRONLY, 0666)
if err != nil {
return fmt.Errorf("error opening kprobe_events: %w", err)
}
defer f.Close()
// The kprobe_events syntax is as follows (see Documentation/trace/kprobetrace.txt):
// p[:[GRP/]EVENT] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS] : Set a probe
// r[MAXACTIVE][:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS] : Set a return probe
// -:[GRP/]EVENT : Clear a probe
//
// Some examples:
// r:ebpf_1234/r_my_kretprobe nf_conntrack_destroy
// p:ebpf_5678/p_my_kprobe __x64_sys_execve
//
// Leaving the kretprobe's MAXACTIVE set to 0 (or absent) will make the
// kernel default to NR_CPUS. This is desired in most eBPF cases since
// subsampling or rate limiting logic can be more accurately implemented in
// the eBPF program itself. See Documentation/kprobes.txt for more details.
pe := fmt.Sprintf("%s:%s/%s %s", kprobePrefix(ret), group, symbol, symbol)
_, err = f.WriteString(pe)
// Since commit 97c753e62e6c, ENOENT is correctly returned instead of EINVAL
// when trying to create a kretprobe for a missing symbol. Make sure ENOENT
// is returned to the caller.
if errors.Is(err, os.ErrNotExist) || errors.Is(err, unix.EINVAL) {
return fmt.Errorf("kernel symbol %s not found: %w", symbol, os.ErrNotExist)
}
if err != nil {
return fmt.Errorf("writing '%s' to kprobe_events: %w", pe, err)
}
return nil
}
// closeTraceFSKprobeEvent removes the kprobe with the given group, symbol and kind
// from <tracefs>/kprobe_events.
func closeTraceFSKprobeEvent(group, symbol string) error {
f, err := os.OpenFile(kprobeEventsPath, os.O_APPEND|os.O_WRONLY, 0666)
if err != nil {
return fmt.Errorf("error opening kprobe_events: %w", err)
}
defer f.Close()
// See kprobe_events syntax above. Kprobe type does not need to be specified
// for removals.
pe := fmt.Sprintf("-:%s/%s", group, symbol)
if _, err = f.WriteString(pe); err != nil {
return fmt.Errorf("writing '%s' to kprobe_events: %w", pe, err)
}
return nil
}
// randomGroup generates a pseudorandom string for use as a tracefs group name.
// Returns an error when the output string would exceed 63 characters (kernel
// limitation), when rand.Read() fails or when prefix contains characters not
// allowed by rgxTraceEvent.
func randomGroup(prefix string) (string, error) {
if !rgxTraceEvent.MatchString(prefix) {
return "", fmt.Errorf("prefix '%s' must be alphanumeric or underscore: %w", prefix, errInvalidInput)
}
b := make([]byte, 8)
if _, err := rand.Read(b); err != nil {
return "", fmt.Errorf("reading random bytes: %w", err)
}
group := fmt.Sprintf("%s_%x", prefix, b)
if len(group) > 63 {
return "", fmt.Errorf("group name '%s' cannot be longer than 63 characters: %w", group, errInvalidInput)
}
return group, nil
}
func kprobePrefix(ret bool) string {
if ret {
return "r"
}
return "p"
}

View File

@ -22,6 +22,11 @@ type Link interface {
// May return an error wrapping ErrNotSupported. // May return an error wrapping ErrNotSupported.
Pin(string) error Pin(string) error
// Undo a previous call to Pin.
//
// May return an error wrapping ErrNotSupported.
Unpin() error
// Close frees resources. // Close frees resources.
// //
// The link will be broken unless it has been pinned. A link // The link will be broken unless it has been pinned. A link
@ -58,7 +63,8 @@ type RawLinkInfo struct {
// You should consider using the higher level interfaces in this // You should consider using the higher level interfaces in this
// package instead. // package instead.
type RawLink struct { type RawLink struct {
fd *internal.FD fd *internal.FD
pinnedPath string
} }
// AttachRawLink creates a raw link. // AttachRawLink creates a raw link.
@ -86,22 +92,21 @@ func AttachRawLink(opts RawLinkOptions) (*RawLink, error) {
return nil, fmt.Errorf("can't create link: %s", err) return nil, fmt.Errorf("can't create link: %s", err)
} }
return &RawLink{fd}, nil return &RawLink{fd, ""}, nil
} }
// LoadPinnedRawLink loads a persisted link from a bpffs. // LoadPinnedRawLink loads a persisted link from a bpffs.
func LoadPinnedRawLink(fileName string) (*RawLink, error) { //
return loadPinnedRawLink(fileName, UnspecifiedType) // Returns an error if the pinned link type doesn't match linkType. Pass
} // UnspecifiedType to disable this behaviour.
func LoadPinnedRawLink(fileName string, linkType Type, opts *ebpf.LoadPinOptions) (*RawLink, error) {
func loadPinnedRawLink(fileName string, typ Type) (*RawLink, error) { fd, err := internal.BPFObjGet(fileName, opts.Marshal())
fd, err := internal.BPFObjGet(fileName)
if err != nil { if err != nil {
return nil, fmt.Errorf("load pinned link: %s", err) return nil, fmt.Errorf("load pinned link: %w", err)
} }
link := &RawLink{fd} link := &RawLink{fd, fileName}
if typ == UnspecifiedType { if linkType == UnspecifiedType {
return link, nil return link, nil
} }
@ -111,9 +116,9 @@ func loadPinnedRawLink(fileName string, typ Type) (*RawLink, error) {
return nil, fmt.Errorf("get pinned link info: %s", err) return nil, fmt.Errorf("get pinned link info: %s", err)
} }
if info.Type != typ { if info.Type != linkType {
link.Close() link.Close()
return nil, fmt.Errorf("link type %v doesn't match %v", info.Type, typ) return nil, fmt.Errorf("link type %v doesn't match %v", info.Type, linkType)
} }
return link, nil return link, nil
@ -142,13 +147,23 @@ func (l *RawLink) Close() error {
// Calling Close on a pinned Link will not break the link // Calling Close on a pinned Link will not break the link
// until the pin is removed. // until the pin is removed.
func (l *RawLink) Pin(fileName string) error { func (l *RawLink) Pin(fileName string) error {
if err := internal.BPFObjPin(fileName, l.fd); err != nil { if err := internal.Pin(l.pinnedPath, fileName, l.fd); err != nil {
return fmt.Errorf("can't pin link: %s", err) return err
} }
l.pinnedPath = fileName
return nil return nil
} }
// Update implements Link. // Unpin implements the Link interface.
func (l *RawLink) Unpin() error {
if err := internal.Unpin(l.pinnedPath); err != nil {
return err
}
l.pinnedPath = ""
return nil
}
// Update implements the Link interface.
func (l *RawLink) Update(new *ebpf.Program) error { func (l *RawLink) Update(new *ebpf.Program) error {
return l.UpdateArgs(RawLinkUpdateOptions{ return l.UpdateArgs(RawLinkUpdateOptions{
New: new, New: new,

View File

@ -41,8 +41,8 @@ func AttachNetNs(ns int, prog *ebpf.Program) (*NetNsLink, error) {
} }
// LoadPinnedNetNs loads a network namespace link from bpffs. // LoadPinnedNetNs loads a network namespace link from bpffs.
func LoadPinnedNetNs(fileName string) (*NetNsLink, error) { func LoadPinnedNetNs(fileName string, opts *ebpf.LoadPinOptions) (*NetNsLink, error) {
link, err := loadPinnedRawLink(fileName, NetNsType) link, err := LoadPinnedRawLink(fileName, NetNsType, opts)
if err != nil { if err != nil {
return nil, err return nil, err
} }

253
vendor/github.com/cilium/ebpf/link/perf_event.go generated vendored Normal file
View File

@ -0,0 +1,253 @@
package link
import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"runtime"
"strconv"
"strings"
"unsafe"
"github.com/cilium/ebpf"
"github.com/cilium/ebpf/internal"
"github.com/cilium/ebpf/internal/unix"
)
// Getting the terminology right is usually the hardest part. For posterity and
// for staying sane during implementation:
//
// - trace event: Representation of a kernel runtime hook. Filesystem entries
// under <tracefs>/events. Can be tracepoints (static), kprobes or uprobes.
// Can be instantiated into perf events (see below).
// - tracepoint: A predetermined hook point in the kernel. Exposed as trace
// events in (sub)directories under <tracefs>/events. Cannot be closed or
// removed, they are static.
// - k(ret)probe: Ephemeral trace events based on entry or exit points of
// exported kernel symbols. kprobe-based (tracefs) trace events can be
// created system-wide by writing to the <tracefs>/kprobe_events file, or
// they can be scoped to the current process by creating PMU perf events.
// - perf event: An object instantiated based on an existing trace event or
// kernel symbol. Referred to by fd in userspace.
// Exactly one eBPF program can be attached to a perf event. Multiple perf
// events can be created from a single trace event. Closing a perf event
// stops any further invocations of the attached eBPF program.
var (
tracefsPath = "/sys/kernel/debug/tracing"
// Trace event groups, names and kernel symbols must adhere to this set
// of characters. Non-empty, first character must not be a number, all
// characters must be alphanumeric or underscore.
rgxTraceEvent = regexp.MustCompile("^[a-zA-Z_][0-9a-zA-Z_]*$")
errInvalidInput = errors.New("invalid input")
)
const (
perfAllThreads = -1
)
// A perfEvent represents a perf event kernel object. Exactly one eBPF program
// can be attached to it. It is created based on a tracefs trace event or a
// Performance Monitoring Unit (PMU).
type perfEvent struct {
// Group and name of the tracepoint/kprobe/uprobe.
group string
name string
// PMU event ID read from sysfs. Valid IDs are non-zero.
pmuID uint64
// ID of the trace event read from tracefs. Valid IDs are non-zero.
tracefsID uint64
// True for kretprobes/uretprobes.
ret bool
fd *internal.FD
progType ebpf.ProgramType
}
func (pe *perfEvent) isLink() {}
func (pe *perfEvent) Pin(string) error {
return fmt.Errorf("pin perf event: %w", ErrNotSupported)
}
func (pe *perfEvent) Unpin() error {
return fmt.Errorf("unpin perf event: %w", ErrNotSupported)
}
// Since 4.15 (e87c6bc3852b "bpf: permit multiple bpf attachments for a single perf event"),
// calling PERF_EVENT_IOC_SET_BPF appends the given program to a prog_array
// owned by the perf event, which means multiple programs can be attached
// simultaneously.
//
// Before 4.15, calling PERF_EVENT_IOC_SET_BPF more than once on a perf event
// returns EEXIST.
//
// Detaching a program from a perf event is currently not possible, so a
// program replacement mechanism cannot be implemented for perf events.
func (pe *perfEvent) Update(prog *ebpf.Program) error {
return fmt.Errorf("can't replace eBPF program in perf event: %w", ErrNotSupported)
}
func (pe *perfEvent) Close() error {
if pe.fd == nil {
return nil
}
pfd, err := pe.fd.Value()
if err != nil {
return fmt.Errorf("getting perf event fd: %w", err)
}
err = unix.IoctlSetInt(int(pfd), unix.PERF_EVENT_IOC_DISABLE, 0)
if err != nil {
return fmt.Errorf("disabling perf event: %w", err)
}
err = pe.fd.Close()
if err != nil {
return fmt.Errorf("closing perf event fd: %w", err)
}
switch t := pe.progType; t {
case ebpf.Kprobe:
// For kprobes created using tracefs, clean up the <tracefs>/kprobe_events entry.
if pe.tracefsID != 0 {
return closeTraceFSKprobeEvent(pe.group, pe.name)
}
case ebpf.TracePoint:
// Tracepoint trace events don't hold any extra resources.
return nil
}
return nil
}
// attach the given eBPF prog to the perf event stored in pe.
// pe must contain a valid perf event fd.
// prog's type must match the program type stored in pe.
func (pe *perfEvent) attach(prog *ebpf.Program) error {
if prog == nil {
return errors.New("cannot attach a nil program")
}
if pe.fd == nil {
return errors.New("cannot attach to nil perf event")
}
if t := prog.Type(); t != pe.progType {
return fmt.Errorf("invalid program type (expected %s): %s", pe.progType, t)
}
if prog.FD() < 0 {
return fmt.Errorf("invalid program: %w", internal.ErrClosedFd)
}
// The ioctl below will fail when the fd is invalid.
kfd, _ := pe.fd.Value()
// Assign the eBPF program to the perf event.
err := unix.IoctlSetInt(int(kfd), unix.PERF_EVENT_IOC_SET_BPF, prog.FD())
if err != nil {
return fmt.Errorf("setting perf event bpf program: %w", err)
}
// PERF_EVENT_IOC_ENABLE and _DISABLE ignore their given values.
if err := unix.IoctlSetInt(int(kfd), unix.PERF_EVENT_IOC_ENABLE, 0); err != nil {
return fmt.Errorf("enable perf event: %s", err)
}
// Close the perf event when its reference is lost to avoid leaking system resources.
runtime.SetFinalizer(pe, (*perfEvent).Close)
return nil
}
// unsafeStringPtr returns an unsafe.Pointer to a NUL-terminated copy of str.
func unsafeStringPtr(str string) (unsafe.Pointer, error) {
p, err := unix.BytePtrFromString(str)
if err != nil {
return nil, err
}
return unsafe.Pointer(p), nil
}
// getTraceEventID reads a trace event's ID from tracefs given its group and name.
// group and name must be alphanumeric or underscore, as required by the kernel.
func getTraceEventID(group, name string) (uint64, error) {
tid, err := uint64FromFile(tracefsPath, "events", group, name, "id")
if errors.Is(err, ErrNotSupported) {
return 0, fmt.Errorf("trace event %s/%s: %w", group, name, ErrNotSupported)
}
if err != nil {
return 0, fmt.Errorf("reading trace event ID of %s/%s: %w", group, name, err)
}
return tid, nil
}
// getPMUEventType reads a Performance Monitoring Unit's type (numeric identifier)
// from /sys/bus/event_source/devices/<pmu>/type.
func getPMUEventType(pmu string) (uint64, error) {
et, err := uint64FromFile("/sys/bus/event_source/devices", pmu, "type")
if errors.Is(err, ErrNotSupported) {
return 0, fmt.Errorf("pmu type %s: %w", pmu, ErrNotSupported)
}
if err != nil {
return 0, fmt.Errorf("reading pmu type %s: %w", pmu, err)
}
return et, nil
}
// openTracepointPerfEvent opens a tracepoint-type perf event. System-wide
// kprobes created by writing to <tracefs>/kprobe_events are tracepoints
// behind the scenes, and can be attached to using these perf events.
func openTracepointPerfEvent(tid uint64) (*internal.FD, error) {
attr := unix.PerfEventAttr{
Type: unix.PERF_TYPE_TRACEPOINT,
Config: tid,
Sample_type: unix.PERF_SAMPLE_RAW,
Sample: 1,
Wakeup: 1,
}
fd, err := unix.PerfEventOpen(&attr, perfAllThreads, 0, -1, unix.PERF_FLAG_FD_CLOEXEC)
if err != nil {
return nil, fmt.Errorf("opening tracepoint perf event: %w", err)
}
return internal.NewFD(uint32(fd)), nil
}
// uint64FromFile reads a uint64 from a file. All elements of path are sanitized
// and joined onto base. Returns error if base no longer prefixes the path after
// joining all components.
func uint64FromFile(base string, path ...string) (uint64, error) {
// Resolve leaf path separately for error feedback. Makes the join onto
// base more readable (can't mix with variadic args).
l := filepath.Join(path...)
p := filepath.Join(base, l)
if !strings.HasPrefix(p, base) {
return 0, fmt.Errorf("path '%s' attempts to escape base path '%s': %w", l, base, errInvalidInput)
}
data, err := ioutil.ReadFile(p)
if os.IsNotExist(err) {
// Only echo leaf path, the base path can be prepended at the call site
// if more verbosity is required.
return 0, fmt.Errorf("symbol %s: %w", l, ErrNotSupported)
}
if err != nil {
return 0, fmt.Errorf("reading file %s: %w", p, err)
}
et := bytes.TrimSpace(data)
return strconv.ParseUint(string(et), 10, 64)
}

View File

@ -55,3 +55,7 @@ func (rt *progAttachRawTracepoint) Update(_ *ebpf.Program) error {
func (rt *progAttachRawTracepoint) Pin(_ string) error { func (rt *progAttachRawTracepoint) Pin(_ string) error {
return fmt.Errorf("can't pin raw_tracepoint: %w", ErrNotSupported) return fmt.Errorf("can't pin raw_tracepoint: %w", ErrNotSupported)
} }
func (rt *progAttachRawTracepoint) Unpin() error {
return fmt.Errorf("unpin raw_tracepoint: %w", ErrNotSupported)
}

56
vendor/github.com/cilium/ebpf/link/tracepoint.go generated vendored Normal file
View File

@ -0,0 +1,56 @@
package link
import (
"fmt"
"github.com/cilium/ebpf"
)
// Tracepoint attaches the given eBPF program to the tracepoint with the given
// group and name. See /sys/kernel/debug/tracing/events to find available
// tracepoints. The top-level directory is the group, the event's subdirectory
// is the name. Example:
//
// Tracepoint("syscalls", "sys_enter_fork")
//
// Note that attaching eBPF programs to syscalls (sys_enter_*/sys_exit_*) is
// only possible as of kernel 4.14 (commit cf5f5ce).
func Tracepoint(group, name string, prog *ebpf.Program) (Link, error) {
if group == "" || name == "" {
return nil, fmt.Errorf("group and name cannot be empty: %w", errInvalidInput)
}
if prog == nil {
return nil, fmt.Errorf("prog cannot be nil: %w", errInvalidInput)
}
if !rgxTraceEvent.MatchString(group) || !rgxTraceEvent.MatchString(name) {
return nil, fmt.Errorf("group and name '%s/%s' must be alphanumeric or underscore: %w", group, name, errInvalidInput)
}
if prog.Type() != ebpf.TracePoint {
return nil, fmt.Errorf("eBPF program type %s is not a Tracepoint: %w", prog.Type(), errInvalidInput)
}
tid, err := getTraceEventID(group, name)
if err != nil {
return nil, err
}
fd, err := openTracepointPerfEvent(tid)
if err != nil {
return nil, err
}
pe := &perfEvent{
fd: fd,
tracefsID: tid,
group: group,
name: name,
progType: ebpf.TracePoint,
}
if err := pe.attach(prog); err != nil {
pe.Close()
return nil, err
}
return pe, nil
}

54
vendor/github.com/cilium/ebpf/map.go generated vendored
View File

@ -25,7 +25,8 @@ type MapOptions struct {
// The base path to pin maps in if requested via PinByName. // The base path to pin maps in if requested via PinByName.
// Existing maps will be re-used if they are compatible, otherwise an // Existing maps will be re-used if they are compatible, otherwise an
// error is returned. // error is returned.
PinPath string PinPath string
LoadPinOptions LoadPinOptions
} }
// MapID represents the unique ID of an eBPF map // MapID represents the unique ID of an eBPF map
@ -40,7 +41,10 @@ type MapSpec struct {
KeySize uint32 KeySize uint32
ValueSize uint32 ValueSize uint32
MaxEntries uint32 MaxEntries uint32
Flags uint32
// Flags is passed to the kernel and specifies additional map
// creation attributes.
Flags uint32
// Automatically pin and load a map from MapOptions.PinPath. // Automatically pin and load a map from MapOptions.PinPath.
// Generates an error if an existing pinned map is incompatible with the MapSpec. // Generates an error if an existing pinned map is incompatible with the MapSpec.
@ -174,23 +178,30 @@ func NewMapWithOptions(spec *MapSpec, opts MapOptions) (*Map, error) {
return newMapWithOptions(spec, opts, btfs) return newMapWithOptions(spec, opts, btfs)
} }
func newMapWithOptions(spec *MapSpec, opts MapOptions, btfs btfHandleCache) (*Map, error) { func newMapWithOptions(spec *MapSpec, opts MapOptions, btfs btfHandleCache) (_ *Map, err error) {
closeOnError := func(c io.Closer) {
if err != nil {
c.Close()
}
}
switch spec.Pinning { switch spec.Pinning {
case PinByName: case PinByName:
if spec.Name == "" || opts.PinPath == "" { if spec.Name == "" || opts.PinPath == "" {
return nil, fmt.Errorf("pin by name: missing Name or PinPath") return nil, fmt.Errorf("pin by name: missing Name or PinPath")
} }
m, err := LoadPinnedMap(filepath.Join(opts.PinPath, spec.Name)) path := filepath.Join(opts.PinPath, spec.Name)
m, err := LoadPinnedMap(path, &opts.LoadPinOptions)
if errors.Is(err, unix.ENOENT) { if errors.Is(err, unix.ENOENT) {
break break
} }
if err != nil { if err != nil {
return nil, fmt.Errorf("load pinned map: %s", err) return nil, fmt.Errorf("load pinned map: %w", err)
} }
defer closeOnError(m)
if err := spec.checkCompatibility(m); err != nil { if err := spec.checkCompatibility(m); err != nil {
m.Close()
return nil, fmt.Errorf("use pinned map %s: %s", spec.Name, err) return nil, fmt.Errorf("use pinned map %s: %s", spec.Name, err)
} }
@ -226,10 +237,11 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions, btfs btfHandleCache) (*Ma
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer closeOnError(m)
if spec.Pinning == PinByName { if spec.Pinning == PinByName {
if err := m.Pin(filepath.Join(opts.PinPath, spec.Name)); err != nil { path := filepath.Join(opts.PinPath, spec.Name)
m.Close() if err := m.Pin(path); err != nil {
return nil, fmt.Errorf("pin map: %s", err) return nil, fmt.Errorf("pin map: %s", err)
} }
} }
@ -805,12 +817,13 @@ func (m *Map) Clone() (*Map, error) {
// Pin persists the map on the BPF virtual file system past the lifetime of // Pin persists the map on the BPF virtual file system past the lifetime of
// the process that created it . // the process that created it .
// //
// Calling Pin on a previously pinned map will override the path. // Calling Pin on a previously pinned map will overwrite the path, except when
// the new path already exists. Re-pinning across filesystems is not supported.
// You can Clone a map to pin it to a different path. // You can Clone a map to pin it to a different path.
// //
// This requires bpffs to be mounted above fileName. See https://docs.cilium.io/en/k8s-doc/admin/#admin-mount-bpffs // This requires bpffs to be mounted above fileName. See https://docs.cilium.io/en/k8s-doc/admin/#admin-mount-bpffs
func (m *Map) Pin(fileName string) error { func (m *Map) Pin(fileName string) error {
if err := pin(m.pinnedPath, fileName, m.fd); err != nil { if err := internal.Pin(m.pinnedPath, fileName, m.fd); err != nil {
return err return err
} }
m.pinnedPath = fileName m.pinnedPath = fileName
@ -823,7 +836,7 @@ func (m *Map) Pin(fileName string) error {
// //
// Unpinning an unpinned Map returns nil. // Unpinning an unpinned Map returns nil.
func (m *Map) Unpin() error { func (m *Map) Unpin() error {
if err := unpin(m.pinnedPath); err != nil { if err := internal.Unpin(m.pinnedPath); err != nil {
return err return err
} }
m.pinnedPath = "" m.pinnedPath = ""
@ -832,10 +845,7 @@ func (m *Map) Unpin() error {
// IsPinned returns true if the map has a non-empty pinned path. // IsPinned returns true if the map has a non-empty pinned path.
func (m *Map) IsPinned() bool { func (m *Map) IsPinned() bool {
if m.pinnedPath == "" { return m.pinnedPath != ""
return false
}
return true
} }
// Freeze prevents a map to be modified from user space. // Freeze prevents a map to be modified from user space.
@ -937,7 +947,9 @@ func (m *Map) unmarshalValue(value interface{}, buf []byte) error {
return err return err
} }
(*value).Close() // The caller might close the map externally, so ignore errors.
_ = (*value).Close()
*value = other *value = other
return nil return nil
@ -957,7 +969,9 @@ func (m *Map) unmarshalValue(value interface{}, buf []byte) error {
return err return err
} }
(*value).Close() // The caller might close the program externally, so ignore errors.
_ = (*value).Close()
*value = other *value = other
return nil return nil
@ -971,9 +985,9 @@ func (m *Map) unmarshalValue(value interface{}, buf []byte) error {
return unmarshalBytes(value, buf) return unmarshalBytes(value, buf)
} }
// LoadPinnedMap load a Map from a BPF file. // LoadPinnedMap loads a Map from a BPF file.
func LoadPinnedMap(fileName string) (*Map, error) { func LoadPinnedMap(fileName string, opts *LoadPinOptions) (*Map, error) {
fd, err := internal.BPFObjGet(fileName) fd, err := internal.BPFObjGet(fileName, opts.Marshal())
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -84,7 +84,9 @@ func makeBuffer(dst interface{}, length int) (internal.Pointer, []byte) {
func unmarshalBytes(data interface{}, buf []byte) error { func unmarshalBytes(data interface{}, buf []byte) error {
switch value := data.(type) { switch value := data.(type) {
case unsafe.Pointer: case unsafe.Pointer:
sh := &reflect.SliceHeader{ // This could be solved in Go 1.17 by unsafe.Slice instead. (https://github.com/golang/go/issues/19367)
// We could opt for removing unsafe.Pointer support in the lib as well.
sh := &reflect.SliceHeader{ //nolint:govet
Data: uintptr(value), Data: uintptr(value),
Len: len(buf), Len: len(buf),
Cap: len(buf), Cap: len(buf),

View File

@ -55,16 +55,19 @@ type ProgramSpec struct {
// depends on Type and AttachType. // depends on Type and AttachType.
AttachTo string AttachTo string
Instructions asm.Instructions Instructions asm.Instructions
// Flags is passed to the kernel and specifies additional program
// load attributes.
Flags uint32
// License of the program. Some helpers are only available if // License of the program. Some helpers are only available if
// the license is deemed compatible with the GPL. // the license is deemed compatible with the GPL.
// //
// See https://www.kernel.org/doc/html/latest/process/license-rules.html#id1 // See https://www.kernel.org/doc/html/latest/process/license-rules.html#id1
License string License string
// Version used by tracing programs. // Version used by Kprobe programs.
// //
// Deprecated: superseded by BTF. // Deprecated on kernels 5.0 and later. Leave empty to let the library
// detect this value automatically.
KernelVersion uint32 KernelVersion uint32
// The BTF associated with this program. Changing Instructions // The BTF associated with this program. Changing Instructions
@ -141,6 +144,19 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, btfs btfHandl
return nil, fmt.Errorf("can't load %s program on %s", spec.ByteOrder, internal.NativeEndian) return nil, fmt.Errorf("can't load %s program on %s", spec.ByteOrder, internal.NativeEndian)
} }
// Kernels before 5.0 (6c4fc209fcf9 "bpf: remove useless version check for prog load")
// require the version field to be set to the value of the KERNEL_VERSION
// macro for kprobe-type programs.
// Overwrite Kprobe program version if set to zero or the magic version constant.
kv := spec.KernelVersion
if spec.Type == Kprobe && (kv == 0 || kv == internal.MagicKernelVersion) {
v, err := internal.KernelVersion()
if err != nil {
return nil, fmt.Errorf("detecting kernel version: %w", err)
}
kv = v.Kernel()
}
insns := make(asm.Instructions, len(spec.Instructions)) insns := make(asm.Instructions, len(spec.Instructions))
copy(insns, spec.Instructions) copy(insns, spec.Instructions)
@ -158,11 +174,12 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions, btfs btfHandl
insCount := uint32(len(bytecode) / asm.InstructionSize) insCount := uint32(len(bytecode) / asm.InstructionSize)
attr := &bpfProgLoadAttr{ attr := &bpfProgLoadAttr{
progType: spec.Type, progType: spec.Type,
progFlags: spec.Flags,
expectedAttachType: spec.AttachType, expectedAttachType: spec.AttachType,
insCount: insCount, insCount: insCount,
instructions: internal.NewSlicePointer(bytecode), instructions: internal.NewSlicePointer(bytecode),
license: internal.NewStringPointer(spec.License), license: internal.NewStringPointer(spec.License),
kernelVersion: spec.KernelVersion, kernelVersion: kv,
} }
if haveObjName() == nil { if haveObjName() == nil {
@ -345,9 +362,12 @@ func (p *Program) Clone() (*Program, error) {
// Pin persists the Program on the BPF virtual file system past the lifetime of // Pin persists the Program on the BPF virtual file system past the lifetime of
// the process that created it // the process that created it
// //
// Calling Pin on a previously pinned program will overwrite the path, except when
// the new path already exists. Re-pinning across filesystems is not supported.
//
// This requires bpffs to be mounted above fileName. See https://docs.cilium.io/en/k8s-doc/admin/#admin-mount-bpffs // This requires bpffs to be mounted above fileName. See https://docs.cilium.io/en/k8s-doc/admin/#admin-mount-bpffs
func (p *Program) Pin(fileName string) error { func (p *Program) Pin(fileName string) error {
if err := pin(p.pinnedPath, fileName, p.fd); err != nil { if err := internal.Pin(p.pinnedPath, fileName, p.fd); err != nil {
return err return err
} }
p.pinnedPath = fileName p.pinnedPath = fileName
@ -360,7 +380,7 @@ func (p *Program) Pin(fileName string) error {
// //
// Unpinning an unpinned Program returns nil. // Unpinning an unpinned Program returns nil.
func (p *Program) Unpin() error { func (p *Program) Unpin() error {
if err := unpin(p.pinnedPath); err != nil { if err := internal.Unpin(p.pinnedPath); err != nil {
return err return err
} }
p.pinnedPath = "" p.pinnedPath = ""
@ -369,10 +389,7 @@ func (p *Program) Unpin() error {
// IsPinned returns true if the Program has a non-empty pinned path. // IsPinned returns true if the Program has a non-empty pinned path.
func (p *Program) IsPinned() bool { func (p *Program) IsPinned() bool {
if p.pinnedPath == "" { return p.pinnedPath != ""
return false
}
return true
} }
// Close unloads the program from the kernel. // Close unloads the program from the kernel.
@ -597,8 +614,8 @@ func (p *Program) Detach(fd int, typ AttachType, flags AttachFlags) error {
// LoadPinnedProgram loads a Program from a BPF file. // LoadPinnedProgram loads a Program from a BPF file.
// //
// Requires at least Linux 4.11. // Requires at least Linux 4.11.
func LoadPinnedProgram(fileName string) (*Program, error) { func LoadPinnedProgram(fileName string, opts *LoadPinOptions) (*Program, error) {
fd, err := internal.BPFObjGet(fileName) fd, err := internal.BPFObjGet(fileName, opts.Marshal())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -609,7 +626,7 @@ func LoadPinnedProgram(fileName string) (*Program, error) {
return nil, fmt.Errorf("info for %s: %w", fileName, err) return nil, fmt.Errorf("info for %s: %w", fileName, err)
} }
return &Program{"", fd, filepath.Base(fileName), "", info.Type}, nil return &Program{"", fd, filepath.Base(fileName), fileName, info.Type}, nil
} }
// SanitizeName replaces all invalid characters in name with replacement. // SanitizeName replaces all invalid characters in name with replacement.

View File

@ -9,6 +9,7 @@ if [[ "${1:-}" = "--in-vm" ]]; then
shift shift
mount -t bpf bpf /sys/fs/bpf mount -t bpf bpf /sys/fs/bpf
mount -t tracefs tracefs /sys/kernel/debug/tracing
export CGO_ENABLED=0 export CGO_ENABLED=0
export GOFLAGS=-mod=readonly export GOFLAGS=-mod=readonly
export GOPATH=/run/go-path export GOPATH=/run/go-path

View File

@ -383,7 +383,7 @@ func wrapMapError(err error) error {
return ErrNotSupported return ErrNotSupported
} }
return errors.New(err.Error()) return err
} }
func bpfMapFreeze(m *internal.FD) error { func bpfMapFreeze(m *internal.FD) error {

View File

@ -1,5 +1,9 @@
package ebpf package ebpf
import (
"github.com/cilium/ebpf/internal/unix"
)
//go:generate stringer -output types_string.go -type=MapType,ProgramType,AttachType,PinType //go:generate stringer -output types_string.go -type=MapType,ProgramType,AttachType,PinType
// MapType indicates the type map structure // MapType indicates the type map structure
@ -202,6 +206,33 @@ const (
PinByName PinByName
) )
// LoadPinOptions control how a pinned object is loaded.
type LoadPinOptions struct {
// Request a read-only or write-only object. The default is a read-write
// object. Only one of the flags may be set.
ReadOnly bool
WriteOnly bool
// Raw flags for the syscall. Other fields of this struct take precedence.
Flags uint32
}
// Marshal returns a value suitable for BPF_OBJ_GET syscall file_flags parameter.
func (lpo *LoadPinOptions) Marshal() uint32 {
if lpo == nil {
return 0
}
flags := lpo.Flags
if lpo.ReadOnly {
flags |= unix.BPF_F_RDONLY
}
if lpo.WriteOnly {
flags |= unix.BPF_F_WRONLY
}
return flags
}
// BatchOptions batch map operations options // BatchOptions batch map operations options
// //
// Mirrors libbpf struct bpf_map_batch_opts // Mirrors libbpf struct bpf_map_batch_opts

View File

@ -16,6 +16,7 @@
package dbus package dbus
import ( import (
"context"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"os" "os"
@ -112,39 +113,63 @@ type Conn struct {
// New establishes a connection to any available bus and authenticates. // New establishes a connection to any available bus and authenticates.
// Callers should call Close() when done with the connection. // Callers should call Close() when done with the connection.
// Deprecated: use NewWithContext instead
func New() (*Conn, error) { func New() (*Conn, error) {
conn, err := NewSystemConnection() return NewWithContext(context.Background())
}
// NewWithContext same as New with context
func NewWithContext(ctx context.Context) (*Conn, error) {
conn, err := NewSystemConnectionContext(ctx)
if err != nil && os.Geteuid() == 0 { if err != nil && os.Geteuid() == 0 {
return NewSystemdConnection() return NewSystemdConnectionContext(ctx)
} }
return conn, err return conn, err
} }
// NewSystemConnection establishes a connection to the system bus and authenticates. // NewSystemConnection establishes a connection to the system bus and authenticates.
// Callers should call Close() when done with the connection // Callers should call Close() when done with the connection
// Deprecated: use NewSystemConnectionContext instead
func NewSystemConnection() (*Conn, error) { func NewSystemConnection() (*Conn, error) {
return NewSystemConnectionContext(context.Background())
}
// NewSystemConnectionContext same as NewSystemConnection with context
func NewSystemConnectionContext(ctx context.Context) (*Conn, error) {
return NewConnection(func() (*dbus.Conn, error) { return NewConnection(func() (*dbus.Conn, error) {
return dbusAuthHelloConnection(dbus.SystemBusPrivate) return dbusAuthHelloConnection(ctx, dbus.SystemBusPrivate)
}) })
} }
// NewUserConnection establishes a connection to the session bus and // NewUserConnection establishes a connection to the session bus and
// authenticates. This can be used to connect to systemd user instances. // authenticates. This can be used to connect to systemd user instances.
// Callers should call Close() when done with the connection. // Callers should call Close() when done with the connection.
// Deprecated: use NewUserConnectionContext instead
func NewUserConnection() (*Conn, error) { func NewUserConnection() (*Conn, error) {
return NewUserConnectionContext(context.Background())
}
// NewUserConnectionContext same as NewUserConnection with context
func NewUserConnectionContext(ctx context.Context) (*Conn, error) {
return NewConnection(func() (*dbus.Conn, error) { return NewConnection(func() (*dbus.Conn, error) {
return dbusAuthHelloConnection(dbus.SessionBusPrivate) return dbusAuthHelloConnection(ctx, dbus.SessionBusPrivate)
}) })
} }
// NewSystemdConnection establishes a private, direct connection to systemd. // NewSystemdConnection establishes a private, direct connection to systemd.
// This can be used for communicating with systemd without a dbus daemon. // This can be used for communicating with systemd without a dbus daemon.
// Callers should call Close() when done with the connection. // Callers should call Close() when done with the connection.
// Deprecated: use NewSystemdConnectionContext instead
func NewSystemdConnection() (*Conn, error) { func NewSystemdConnection() (*Conn, error) {
return NewSystemdConnectionContext(context.Background())
}
// NewSystemdConnectionContext same as NewSystemdConnection with context
func NewSystemdConnectionContext(ctx context.Context) (*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(opts ...dbus.ConnOption) (*dbus.Conn, error) { return dbusAuthConnection(ctx, func(opts ...dbus.ConnOption) (*dbus.Conn, error) {
return dbus.Dial("unix:path=/run/systemd/private") return dbus.Dial("unix:path=/run/systemd/private", opts...)
}) })
}) })
} }
@ -201,8 +226,8 @@ func (c *Conn) GetManagerProperty(prop string) (string, error) {
return variant.String(), nil return variant.String(), nil
} }
func dbusAuthConnection(createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) { func dbusAuthConnection(ctx context.Context, createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) {
conn, err := createBus() conn, err := createBus(dbus.WithContext(ctx))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -221,8 +246,8 @@ func dbusAuthConnection(createBus func(opts ...dbus.ConnOption) (*dbus.Conn, err
return conn, nil return conn, nil
} }
func dbusAuthHelloConnection(createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) { func dbusAuthHelloConnection(ctx context.Context, createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) {
conn, err := dbusAuthConnection(createBus) conn, err := dbusAuthConnection(ctx, createBus)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -15,6 +15,7 @@
package dbus package dbus
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"path" "path"
@ -23,6 +24,18 @@ import (
"github.com/godbus/dbus/v5" "github.com/godbus/dbus/v5"
) )
// Who can be used to specify which process to kill in the unit via the KillUnitWithTarget API
type Who string
const (
// All sends the signal to all processes in the unit
All Who = "all"
// Main sends the signal to the main process of the unit
Main Who = "main"
// Control sends the signal to the control process of the unit
Control Who = "control"
)
func (c *Conn) jobComplete(signal *dbus.Signal) { func (c *Conn) jobComplete(signal *dbus.Signal) {
var id uint32 var id uint32
var job dbus.ObjectPath var job dbus.ObjectPath
@ -38,14 +51,14 @@ func (c *Conn) jobComplete(signal *dbus.Signal) {
c.jobListener.Unlock() c.jobListener.Unlock()
} }
func (c *Conn) startJob(ch chan<- string, job string, args ...interface{}) (int, error) { func (c *Conn) startJob(ctx context.Context, ch chan<- string, job string, args ...interface{}) (int, error) {
if ch != nil { if ch != nil {
c.jobListener.Lock() c.jobListener.Lock()
defer c.jobListener.Unlock() defer c.jobListener.Unlock()
} }
var p dbus.ObjectPath var p dbus.ObjectPath
err := c.sysobj.Call(job, 0, args...).Store(&p) err := c.sysobj.CallWithContext(ctx, job, 0, args...).Store(&p)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -90,43 +103,85 @@ func (c *Conn) startJob(ch chan<- string, job string, args ...interface{}) (int,
// should not be considered authoritative. // should not be considered authoritative.
// //
// If an error does occur, it will be returned to the user alongside a job ID of 0. // If an error does occur, it will be returned to the user alongside a job ID of 0.
// Deprecated: use StartUnitContext instead
func (c *Conn) StartUnit(name string, mode string, ch chan<- string) (int, error) { func (c *Conn) StartUnit(name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ch, "org.freedesktop.systemd1.Manager.StartUnit", name, mode) return c.StartUnitContext(context.Background(), name, mode, ch)
}
// StartUnitContext same as StartUnit with context
func (c *Conn) StartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.StartUnit", name, mode)
} }
// StopUnit is similar to StartUnit but stops the specified unit rather // StopUnit is similar to StartUnit but stops the specified unit rather
// than starting it. // than starting it.
// Deprecated: use StopUnitContext instead
func (c *Conn) StopUnit(name string, mode string, ch chan<- string) (int, error) { func (c *Conn) StopUnit(name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ch, "org.freedesktop.systemd1.Manager.StopUnit", name, mode) return c.StopUnitContext(context.Background(), name, mode, ch)
}
// StopUnitContext same as StopUnit with context
func (c *Conn) StopUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.StopUnit", name, mode)
} }
// ReloadUnit reloads a unit. Reloading is done only if the unit is already running and fails otherwise. // ReloadUnit reloads a unit. Reloading is done only if the unit is already running and fails otherwise.
// Deprecated: use ReloadUnitContext instead
func (c *Conn) ReloadUnit(name string, mode string, ch chan<- string) (int, error) { func (c *Conn) ReloadUnit(name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ch, "org.freedesktop.systemd1.Manager.ReloadUnit", name, mode) return c.ReloadUnitContext(context.Background(), name, mode, ch)
}
// ReloadUnitContext same as ReloadUnit with context
func (c *Conn) ReloadUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.ReloadUnit", name, mode)
} }
// RestartUnit restarts a service. If a service is restarted that isn't // RestartUnit restarts a service. If a service is restarted that isn't
// running it will be started. // running it will be started.
// Deprecated: use RestartUnitContext instead
func (c *Conn) RestartUnit(name string, mode string, ch chan<- string) (int, error) { func (c *Conn) RestartUnit(name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ch, "org.freedesktop.systemd1.Manager.RestartUnit", name, mode) return c.RestartUnitContext(context.Background(), name, mode, ch)
}
// RestartUnitContext same as RestartUnit with context
func (c *Conn) RestartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.RestartUnit", name, mode)
} }
// TryRestartUnit is like RestartUnit, except that a service that isn't running // TryRestartUnit is like RestartUnit, except that a service that isn't running
// is not affected by the restart. // is not affected by the restart.
// Deprecated: use TryRestartUnitContext instead
func (c *Conn) TryRestartUnit(name string, mode string, ch chan<- string) (int, error) { func (c *Conn) TryRestartUnit(name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ch, "org.freedesktop.systemd1.Manager.TryRestartUnit", name, mode) return c.TryRestartUnitContext(context.Background(), name, mode, ch)
}
// TryRestartUnitContext same as TryRestartUnit with context
func (c *Conn) TryRestartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.TryRestartUnit", name, mode)
} }
// ReloadOrRestartUnit 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.
// Deprecated: use ReloadOrRestartUnitContext instead
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.ReloadOrRestartUnitContext(context.Background(), name, mode, ch)
}
// ReloadOrRestartUnitContext same as ReloadOrRestartUnit with context
func (c *Conn) ReloadOrRestartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.ReloadOrRestartUnit", name, mode)
} }
// ReloadOrTryRestartUnit 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.
// Deprecated: use ReloadOrTryRestartUnitContext instead
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.ReloadOrTryRestartUnitContext(context.Background(), name, mode, ch)
}
// ReloadOrTryRestartUnitContext same as ReloadOrTryRestartUnit with context
func (c *Conn) ReloadOrTryRestartUnitContext(ctx context.Context, name string, mode string, ch chan<- string) (int, error) {
return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.ReloadOrTryRestartUnit", name, mode)
} }
// StartTransientUnit() may be used to create and start a transient unit, which // StartTransientUnit() may be used to create and start a transient unit, which
@ -134,28 +189,57 @@ func (c *Conn) ReloadOrTryRestartUnit(name string, mode string, ch chan<- string
// system is rebooted. name is the unit name including suffix, and must be // system is rebooted. name is the unit name including suffix, and must be
// unique. mode is the same as in StartUnit(), properties contains properties // unique. mode is the same as in StartUnit(), properties contains properties
// of the unit. // of the unit.
// Deprecated: use StartTransientUnitContext instead
func (c *Conn) StartTransientUnit(name string, mode string, properties []Property, ch chan<- string) (int, error) { func (c *Conn) StartTransientUnit(name string, mode string, properties []Property, ch chan<- string) (int, error) {
return c.startJob(ch, "org.freedesktop.systemd1.Manager.StartTransientUnit", name, mode, properties, make([]PropertyCollection, 0)) return c.StartTransientUnitContext(context.Background(), name, mode, properties, ch)
}
// StartTransientUnitContext same as StartTransientUnit with context
func (c *Conn) StartTransientUnitContext(ctx context.Context, name string, mode string, properties []Property, ch chan<- string) (int, error) {
return c.startJob(ctx, ch, "org.freedesktop.systemd1.Manager.StartTransientUnit", name, mode, properties, make([]PropertyCollection, 0))
} }
// KillUnit takes the unit name and a UNIX signal number to send. All of the unit's // KillUnit takes the unit name and a UNIX signal number to send. All of the unit's
// processes are killed. // processes are killed.
// Deprecated: use KillUnitContext instead
func (c *Conn) KillUnit(name string, signal int32) { func (c *Conn) KillUnit(name string, signal int32) {
c.sysobj.Call("org.freedesktop.systemd1.Manager.KillUnit", 0, name, "all", signal).Store() c.KillUnitContext(context.Background(), name, signal)
}
// KillUnitContext same as KillUnit with context
func (c *Conn) KillUnitContext(ctx context.Context, name string, signal int32) {
c.KillUnitWithTarget(ctx, name, All, signal)
}
// KillUnitWithTarget is like KillUnitContext, but allows you to specify which process in the unit to send the signal to
func (c *Conn) KillUnitWithTarget(ctx context.Context, name string, target Who, signal int32) error {
return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.KillUnit", 0, name, string(target), signal).Store()
} }
// ResetFailedUnit resets the "failed" state of a specific unit. // ResetFailedUnit resets the "failed" state of a specific unit.
// Deprecated: use ResetFailedUnitContext instead
func (c *Conn) ResetFailedUnit(name string) error { func (c *Conn) ResetFailedUnit(name string) error {
return c.sysobj.Call("org.freedesktop.systemd1.Manager.ResetFailedUnit", 0, name).Store() return c.ResetFailedUnitContext(context.Background(), name)
}
// ResetFailedUnitContext same as ResetFailedUnit with context
func (c *Conn) ResetFailedUnitContext(ctx context.Context, name string) error {
return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ResetFailedUnit", 0, name).Store()
} }
// SystemState returns the systemd state. Equivalent to `systemctl is-system-running`. // SystemState returns the systemd state. Equivalent to `systemctl is-system-running`.
// Deprecated: use SystemStateContext instead
func (c *Conn) SystemState() (*Property, error) { func (c *Conn) SystemState() (*Property, error) {
return c.SystemStateContext(context.Background())
}
// SystemStateContext same as SystemState with context
func (c *Conn) SystemStateContext(ctx context.Context) (*Property, error) {
var err error var err error
var prop dbus.Variant var prop dbus.Variant
obj := c.sysconn.Object("org.freedesktop.systemd1", "/org/freedesktop/systemd1") obj := c.sysconn.Object("org.freedesktop.systemd1", "/org/freedesktop/systemd1")
err = obj.Call("org.freedesktop.DBus.Properties.Get", 0, "org.freedesktop.systemd1.Manager", "SystemState").Store(&prop) err = obj.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, "org.freedesktop.systemd1.Manager", "SystemState").Store(&prop)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -164,7 +248,7 @@ func (c *Conn) SystemState() (*Property, error) {
} }
// getProperties takes the unit path and returns all of its dbus object properties, for the given dbus interface // getProperties takes the unit path and returns all of its dbus object properties, for the given dbus interface
func (c *Conn) getProperties(path dbus.ObjectPath, dbusInterface string) (map[string]interface{}, error) { func (c *Conn) getProperties(ctx context.Context, path dbus.ObjectPath, dbusInterface string) (map[string]interface{}, error) {
var err error var err error
var props map[string]dbus.Variant var props map[string]dbus.Variant
@ -173,7 +257,7 @@ func (c *Conn) getProperties(path dbus.ObjectPath, dbusInterface string) (map[st
} }
obj := c.sysconn.Object("org.freedesktop.systemd1", path) obj := c.sysconn.Object("org.freedesktop.systemd1", path)
err = obj.Call("org.freedesktop.DBus.Properties.GetAll", 0, dbusInterface).Store(&props) err = obj.CallWithContext(ctx, "org.freedesktop.DBus.Properties.GetAll", 0, dbusInterface).Store(&props)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -187,23 +271,41 @@ func (c *Conn) getProperties(path dbus.ObjectPath, dbusInterface string) (map[st
} }
// GetUnitProperties takes the (unescaped) unit name and returns all of its dbus object properties. // GetUnitProperties takes the (unescaped) unit name and returns all of its dbus object properties.
// Deprecated: use GetUnitPropertiesContext instead
func (c *Conn) GetUnitProperties(unit string) (map[string]interface{}, error) { func (c *Conn) GetUnitProperties(unit string) (map[string]interface{}, error) {
return c.GetUnitPropertiesContext(context.Background(), unit)
}
// GetUnitPropertiesContext same as GetUnitPropertiesContext with context
func (c *Conn) GetUnitPropertiesContext(ctx context.Context, unit string) (map[string]interface{}, error) {
path := unitPath(unit) path := unitPath(unit)
return c.getProperties(path, "org.freedesktop.systemd1.Unit") return c.getProperties(ctx, path, "org.freedesktop.systemd1.Unit")
} }
// GetUnitPathProperties 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.
// Deprecated: use GetUnitPathPropertiesContext instead
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.GetUnitPathPropertiesContext(context.Background(), path)
}
// GetUnitPathPropertiesContext same as GetUnitPathProperties with context
func (c *Conn) GetUnitPathPropertiesContext(ctx context.Context, path dbus.ObjectPath) (map[string]interface{}, error) {
return c.getProperties(ctx, path, "org.freedesktop.systemd1.Unit")
} }
// GetAllProperties takes the (unescaped) unit name and returns all of its dbus object properties. // GetAllProperties takes the (unescaped) unit name and returns all of its dbus object properties.
// Deprecated: use GetAllPropertiesContext instead
func (c *Conn) GetAllProperties(unit string) (map[string]interface{}, error) { func (c *Conn) GetAllProperties(unit string) (map[string]interface{}, error) {
path := unitPath(unit) return c.GetAllPropertiesContext(context.Background(), unit)
return c.getProperties(path, "")
} }
func (c *Conn) getProperty(unit string, dbusInterface string, propertyName string) (*Property, error) { // GetAllPropertiesContext same as GetAllProperties with context
func (c *Conn) GetAllPropertiesContext(ctx context.Context, unit string) (map[string]interface{}, error) {
path := unitPath(unit)
return c.getProperties(ctx, path, "")
}
func (c *Conn) getProperty(ctx context.Context, unit string, dbusInterface string, propertyName string) (*Property, error) {
var err error var err error
var prop dbus.Variant var prop dbus.Variant
@ -213,7 +315,7 @@ func (c *Conn) getProperty(unit string, dbusInterface string, propertyName strin
} }
obj := c.sysconn.Object("org.freedesktop.systemd1", path) obj := c.sysconn.Object("org.freedesktop.systemd1", path)
err = obj.Call("org.freedesktop.DBus.Properties.Get", 0, dbusInterface, propertyName).Store(&prop) err = obj.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, dbusInterface, propertyName).Store(&prop)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -221,21 +323,39 @@ func (c *Conn) getProperty(unit string, dbusInterface string, propertyName strin
return &Property{Name: propertyName, Value: prop}, nil return &Property{Name: propertyName, Value: prop}, nil
} }
// Deprecated: use GetUnitPropertyContext instead
func (c *Conn) GetUnitProperty(unit string, propertyName string) (*Property, error) { func (c *Conn) GetUnitProperty(unit string, propertyName string) (*Property, error) {
return c.getProperty(unit, "org.freedesktop.systemd1.Unit", propertyName) return c.GetUnitPropertyContext(context.Background(), unit, propertyName)
}
// GetUnitPropertyContext same as GetUnitProperty with context
func (c *Conn) GetUnitPropertyContext(ctx context.Context, unit string, propertyName string) (*Property, error) {
return c.getProperty(ctx, unit, "org.freedesktop.systemd1.Unit", propertyName)
} }
// GetServiceProperty returns property for given service name and property name // GetServiceProperty returns property for given service name and property name
// Deprecated: use GetServicePropertyContext instead
func (c *Conn) GetServiceProperty(service string, propertyName string) (*Property, error) { func (c *Conn) GetServiceProperty(service string, propertyName string) (*Property, error) {
return c.getProperty(service, "org.freedesktop.systemd1.Service", propertyName) return c.GetServicePropertyContext(context.Background(), service, propertyName)
}
// GetServicePropertyContext same as GetServiceProperty with context
func (c *Conn) GetServicePropertyContext(ctx context.Context, service string, propertyName string) (*Property, error) {
return c.getProperty(ctx, service, "org.freedesktop.systemd1.Service", propertyName)
} }
// GetUnitTypeProperties returns the extra properties for a unit, specific to the unit type. // GetUnitTypeProperties returns the extra properties for a unit, specific to the unit type.
// Valid values for unitType: Service, Socket, Target, Device, Mount, Automount, Snapshot, Timer, Swap, Path, Slice, Scope // Valid values for unitType: Service, Socket, Target, Device, Mount, Automount, Snapshot, Timer, Swap, Path, Slice, Scope
// return "dbus.Error: Unknown interface" if the unitType is not the correct type of the unit // return "dbus.Error: Unknown interface" if the unitType is not the correct type of the unit
// Deprecated: use GetUnitTypePropertiesContext instead
func (c *Conn) GetUnitTypeProperties(unit string, unitType string) (map[string]interface{}, error) { func (c *Conn) GetUnitTypeProperties(unit string, unitType string) (map[string]interface{}, error) {
return c.GetUnitTypePropertiesContext(context.Background(), unit, unitType)
}
// GetUnitTypePropertiesContext same as GetUnitTypeProperties with context
func (c *Conn) GetUnitTypePropertiesContext(ctx context.Context, unit string, unitType string) (map[string]interface{}, error) {
path := unitPath(unit) path := unitPath(unit)
return c.getProperties(path, "org.freedesktop.systemd1."+unitType) return c.getProperties(ctx, path, "org.freedesktop.systemd1."+unitType)
} }
// SetUnitProperties() may be used to modify certain unit properties at runtime. // SetUnitProperties() may be used to modify certain unit properties at runtime.
@ -245,12 +365,24 @@ func (c *Conn) GetUnitTypeProperties(unit string, unitType string) (map[string]i
// case the settings only apply until the next reboot. name is the name of the unit // case the settings only apply until the next reboot. name is the name of the unit
// to modify. properties are the settings to set, encoded as an array of property // to modify. properties are the settings to set, encoded as an array of property
// name and value pairs. // name and value pairs.
// Deprecated: use SetUnitPropertiesContext instead
func (c *Conn) SetUnitProperties(name string, runtime bool, properties ...Property) error { func (c *Conn) SetUnitProperties(name string, runtime bool, properties ...Property) error {
return c.sysobj.Call("org.freedesktop.systemd1.Manager.SetUnitProperties", 0, name, runtime, properties).Store() return c.SetUnitPropertiesContext(context.Background(), name, runtime, properties...)
} }
// SetUnitPropertiesContext same as SetUnitProperties with context
func (c *Conn) SetUnitPropertiesContext(ctx context.Context, name string, runtime bool, properties ...Property) error {
return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.SetUnitProperties", 0, name, runtime, properties).Store()
}
// Deprecated: use GetUnitTypePropertyContext instead
func (c *Conn) GetUnitTypeProperty(unit string, unitType string, propertyName string) (*Property, error) { func (c *Conn) GetUnitTypeProperty(unit string, unitType string, propertyName string) (*Property, error) {
return c.getProperty(unit, "org.freedesktop.systemd1."+unitType, propertyName) return c.GetUnitTypePropertyContext(context.Background(), unit, unitType, propertyName)
}
// GetUnitTypePropertyContext same as GetUnitTypeProperty with context
func (c *Conn) GetUnitTypePropertyContext(ctx context.Context, unit string, unitType string, propertyName string) (*Property, error) {
return c.getProperty(ctx, unit, "org.freedesktop.systemd1."+unitType, propertyName)
} }
type UnitStatus struct { type UnitStatus struct {
@ -299,22 +431,40 @@ func (c *Conn) listUnitsInternal(f storeFunc) ([]UnitStatus, error) {
// 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. // 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. // Units that are both disabled and inactive will thus not be returned.
// Deprecated: use ListUnitsContext instead
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.ListUnitsContext(context.Background())
}
// ListUnitsContext same as ListUnits with context
func (c *Conn) ListUnitsContext(ctx context.Context) ([]UnitStatus, error) {
return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnits", 0).Store)
} }
// ListUnitsFiltered returns an array with units filtered by state. // ListUnitsFiltered returns an array with units filtered by state.
// It takes a list of units' statuses to filter. // It takes a list of units' statuses to filter.
// Deprecated: use ListUnitsFilteredContext instead
func (c *Conn) ListUnitsFiltered(states []string) ([]UnitStatus, error) { func (c *Conn) ListUnitsFiltered(states []string) ([]UnitStatus, error) {
return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitsFiltered", 0, states).Store) return c.ListUnitsFilteredContext(context.Background(), states)
}
// ListUnitsFilteredContext same as ListUnitsFiltered with context
func (c *Conn) ListUnitsFilteredContext(ctx context.Context, states []string) ([]UnitStatus, error) {
return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitsFiltered", 0, states).Store)
} }
// ListUnitsByPatterns returns an array with units. // ListUnitsByPatterns returns an array with units.
// It takes a list of units' statuses and names to filter. // It takes a list of units' statuses and names to filter.
// Note that units may be known by multiple names at the same time, // Note that 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. // and hence there might be more unit names loaded than actual units behind them.
// Deprecated: use ListUnitsByPatternsContext instead
func (c *Conn) ListUnitsByPatterns(states []string, patterns []string) ([]UnitStatus, error) { func (c *Conn) ListUnitsByPatterns(states []string, patterns []string) ([]UnitStatus, error) {
return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitsByPatterns", 0, states, patterns).Store) return c.ListUnitsByPatternsContext(context.Background(), states, patterns)
}
// ListUnitsByPatternsContext same as ListUnitsByPatterns with context
func (c *Conn) ListUnitsByPatternsContext(ctx context.Context, states []string, patterns []string) ([]UnitStatus, error) {
return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitsByPatterns", 0, states, patterns).Store)
} }
// ListUnitsByNames returns an array with units. It takes a list of units' // ListUnitsByNames returns an array with units. It takes a list of units'
@ -322,8 +472,14 @@ func (c *Conn) ListUnitsByPatterns(states []string, patterns []string) ([]UnitSt
// method, this method returns statuses even for inactive or non-existing // method, this method returns statuses even for inactive or non-existing
// units. Input array should contain exact unit names, but not patterns. // units. Input array should contain exact unit names, but not patterns.
// Note: Requires systemd v230 or higher // Note: Requires systemd v230 or higher
// Deprecated: use ListUnitsByNamesContext instead
func (c *Conn) ListUnitsByNames(units []string) ([]UnitStatus, error) { func (c *Conn) ListUnitsByNames(units []string) ([]UnitStatus, error) {
return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitsByNames", 0, units).Store) return c.ListUnitsByNamesContext(context.Background(), units)
}
// ListUnitsByNamesContext same as ListUnitsByNames with context
func (c *Conn) ListUnitsByNamesContext(ctx context.Context, units []string) ([]UnitStatus, error) {
return c.listUnitsInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitsByNames", 0, units).Store)
} }
type UnitFile struct { type UnitFile struct {
@ -358,13 +514,25 @@ func (c *Conn) listUnitFilesInternal(f storeFunc) ([]UnitFile, error) {
} }
// ListUnitFiles returns an array of all available units on disk. // ListUnitFiles returns an array of all available units on disk.
// Deprecated: use ListUnitFilesContext instead
func (c *Conn) ListUnitFiles() ([]UnitFile, error) { func (c *Conn) ListUnitFiles() ([]UnitFile, error) {
return c.listUnitFilesInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitFiles", 0).Store) return c.ListUnitFilesContext(context.Background())
}
// ListUnitFilesContext same as ListUnitFiles with context
func (c *Conn) ListUnitFilesContext(ctx context.Context) ([]UnitFile, error) {
return c.listUnitFilesInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitFiles", 0).Store)
} }
// ListUnitFilesByPatterns returns an array of all available units on disk matched the patterns. // ListUnitFilesByPatterns returns an array of all available units on disk matched the patterns.
// Deprecated: use ListUnitFilesByPatternsContext instead
func (c *Conn) ListUnitFilesByPatterns(states []string, patterns []string) ([]UnitFile, error) { func (c *Conn) ListUnitFilesByPatterns(states []string, patterns []string) ([]UnitFile, error) {
return c.listUnitFilesInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitFilesByPatterns", 0, states, patterns).Store) return c.ListUnitFilesByPatternsContext(context.Background(), states, patterns)
}
// ListUnitFilesByPatternsContext same as ListUnitFilesByPatterns with context
func (c *Conn) ListUnitFilesByPatternsContext(ctx context.Context, states []string, patterns []string) ([]UnitFile, error) {
return c.listUnitFilesInternal(c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListUnitFilesByPatterns", 0, states, patterns).Store)
} }
type LinkUnitFileChange EnableUnitFileChange type LinkUnitFileChange EnableUnitFileChange
@ -383,9 +551,15 @@ type LinkUnitFileChange EnableUnitFileChange
// structures with three strings: the type of the change (one of symlink // structures with three strings: the type of the change (one of symlink
// or unlink), the file name of the symlink and the destination of the // or unlink), the file name of the symlink and the destination of the
// symlink. // symlink.
// Deprecated: use LinkUnitFilesContext instead
func (c *Conn) LinkUnitFiles(files []string, runtime bool, force bool) ([]LinkUnitFileChange, error) { func (c *Conn) LinkUnitFiles(files []string, runtime bool, force bool) ([]LinkUnitFileChange, error) {
return c.LinkUnitFilesContext(context.Background(), files, runtime, force)
}
// LinkUnitFilesContext same as LinkUnitFiles with context
func (c *Conn) LinkUnitFilesContext(ctx context.Context, files []string, runtime bool, force bool) ([]LinkUnitFileChange, error) {
result := make([][]interface{}, 0) result := make([][]interface{}, 0)
err := c.sysobj.Call("org.freedesktop.systemd1.Manager.LinkUnitFiles", 0, files, runtime, force).Store(&result) err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.LinkUnitFiles", 0, files, runtime, force).Store(&result)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -425,11 +599,17 @@ func (c *Conn) LinkUnitFiles(files []string, runtime bool, force bool) ([]LinkUn
// structures with three strings: the type of the change (one of symlink // structures with three strings: the type of the change (one of symlink
// or unlink), the file name of the symlink and the destination of the // or unlink), the file name of the symlink and the destination of the
// symlink. // symlink.
// Deprecated: use EnableUnitFilesContext instead
func (c *Conn) EnableUnitFiles(files []string, runtime bool, force bool) (bool, []EnableUnitFileChange, error) { func (c *Conn) EnableUnitFiles(files []string, runtime bool, force bool) (bool, []EnableUnitFileChange, error) {
return c.EnableUnitFilesContext(context.Background(), files, runtime, force)
}
// EnableUnitFilesContext same as EnableUnitFiles with context
func (c *Conn) EnableUnitFilesContext(ctx context.Context, files []string, runtime bool, force bool) (bool, []EnableUnitFileChange, error) {
var carries_install_info bool var carries_install_info bool
result := make([][]interface{}, 0) result := make([][]interface{}, 0)
err := c.sysobj.Call("org.freedesktop.systemd1.Manager.EnableUnitFiles", 0, files, runtime, force).Store(&carries_install_info, &result) err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.EnableUnitFiles", 0, files, runtime, force).Store(&carries_install_info, &result)
if err != nil { if err != nil {
return false, nil, err return false, nil, err
} }
@ -471,9 +651,15 @@ type EnableUnitFileChange struct {
// consists of structures with three strings: the type of the change (one of // consists of structures with three strings: the type of the change (one of
// symlink or unlink), the file name of the symlink and the destination of the // symlink or unlink), the file name of the symlink and the destination of the
// symlink. // symlink.
// Deprecated: use DisableUnitFilesContext instead
func (c *Conn) DisableUnitFiles(files []string, runtime bool) ([]DisableUnitFileChange, error) { func (c *Conn) DisableUnitFiles(files []string, runtime bool) ([]DisableUnitFileChange, error) {
return c.DisableUnitFilesContext(context.Background(), files, runtime)
}
// DisableUnitFilesContext same as DisableUnitFiles with context
func (c *Conn) DisableUnitFilesContext(ctx context.Context, files []string, runtime bool) ([]DisableUnitFileChange, error) {
result := make([][]interface{}, 0) result := make([][]interface{}, 0)
err := c.sysobj.Call("org.freedesktop.systemd1.Manager.DisableUnitFiles", 0, files, runtime).Store(&result) err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.DisableUnitFiles", 0, files, runtime).Store(&result)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -512,9 +698,15 @@ type DisableUnitFileChange struct {
// * runtime to specify whether the unit was enabled for runtime // * runtime to specify whether the unit was enabled for runtime
// only (true, /run/systemd/..), or persistently (false, /etc/systemd/..) // only (true, /run/systemd/..), or persistently (false, /etc/systemd/..)
// * force flag // * force flag
// Deprecated: use MaskUnitFilesContext instead
func (c *Conn) MaskUnitFiles(files []string, runtime bool, force bool) ([]MaskUnitFileChange, error) { func (c *Conn) MaskUnitFiles(files []string, runtime bool, force bool) ([]MaskUnitFileChange, error) {
return c.MaskUnitFilesContext(context.Background(), files, runtime, force)
}
// MaskUnitFilesContext same as MaskUnitFiles with context
func (c *Conn) MaskUnitFilesContext(ctx context.Context, files []string, runtime bool, force bool) ([]MaskUnitFileChange, error) {
result := make([][]interface{}, 0) result := make([][]interface{}, 0)
err := c.sysobj.Call("org.freedesktop.systemd1.Manager.MaskUnitFiles", 0, files, runtime, force).Store(&result) err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.MaskUnitFiles", 0, files, runtime, force).Store(&result)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -552,9 +744,15 @@ type MaskUnitFileChange struct {
// the usual unit search paths) // the usual unit search paths)
// * runtime to specify whether the unit was enabled for runtime // * runtime to specify whether the unit was enabled for runtime
// only (true, /run/systemd/..), or persistently (false, /etc/systemd/..) // only (true, /run/systemd/..), or persistently (false, /etc/systemd/..)
// Deprecated: use UnmaskUnitFilesContext instead
func (c *Conn) UnmaskUnitFiles(files []string, runtime bool) ([]UnmaskUnitFileChange, error) { func (c *Conn) UnmaskUnitFiles(files []string, runtime bool) ([]UnmaskUnitFileChange, error) {
return c.UnmaskUnitFilesContext(context.Background(), files, runtime)
}
// UnmaskUnitFilesContext same as UnmaskUnitFiles with context
func (c *Conn) UnmaskUnitFilesContext(ctx context.Context, files []string, runtime bool) ([]UnmaskUnitFileChange, error) {
result := make([][]interface{}, 0) result := make([][]interface{}, 0)
err := c.sysobj.Call("org.freedesktop.systemd1.Manager.UnmaskUnitFiles", 0, files, runtime).Store(&result) err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.UnmaskUnitFiles", 0, files, runtime).Store(&result)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -586,8 +784,14 @@ type UnmaskUnitFileChange struct {
// Reload instructs systemd to scan for and reload unit files. This is // Reload instructs systemd to scan for and reload unit files. This is
// equivalent to a 'systemctl daemon-reload'. // equivalent to a 'systemctl daemon-reload'.
// Deprecated: use ReloadContext instead
func (c *Conn) Reload() error { func (c *Conn) Reload() error {
return c.sysobj.Call("org.freedesktop.systemd1.Manager.Reload", 0).Store() return c.ReloadContext(context.Background())
}
// ReloadContext same as Reload with context
func (c *Conn) ReloadContext(ctx context.Context) error {
return c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.Reload", 0).Store()
} }
func unitPath(name string) dbus.ObjectPath { func unitPath(name string) dbus.ObjectPath {
@ -598,3 +802,48 @@ func unitPath(name string) dbus.ObjectPath {
func unitName(dpath dbus.ObjectPath) string { func unitName(dpath dbus.ObjectPath) string {
return pathBusUnescape(path.Base(string(dpath))) return pathBusUnescape(path.Base(string(dpath)))
} }
// Currently queued job definition
type JobStatus struct {
Id uint32 // The numeric job id
Unit string // The primary unit name for this job
JobType string // The job type as string
Status string // The job state as string
JobPath dbus.ObjectPath // The job object path
UnitPath dbus.ObjectPath // The unit object path
}
// ListJobs returns an array with all currently queued jobs
// Deprecated: use ListJobsContext instead
func (c *Conn) ListJobs() ([]JobStatus, error) {
return c.ListJobsContext(context.Background())
}
// ListJobsContext same as ListJobs with context
func (c *Conn) ListJobsContext(ctx context.Context) ([]JobStatus, error) {
return c.listJobsInternal(ctx)
}
func (c *Conn) listJobsInternal(ctx context.Context) ([]JobStatus, error) {
result := make([][]interface{}, 0)
if err := c.sysobj.CallWithContext(ctx, "org.freedesktop.systemd1.Manager.ListJobs", 0).Store(&result); err != nil {
return nil, err
}
resultInterface := make([]interface{}, len(result))
for i := range result {
resultInterface[i] = result[i]
}
status := make([]JobStatus, len(result))
statusInterface := make([]interface{}, len(status))
for i := range status {
statusInterface[i] = &status[i]
}
if err := dbus.Store(resultInterface, statusInterface...); err != nil {
return nil, err
}
return status, nil
}

View File

@ -1,50 +0,0 @@
dist: bionic
language: go
go_import_path: github.com/godbus/dbus
go:
- 1.11.x
- 1.12.x
- 1.13.x
- tip
matrix:
fast_finish: true
allow_failures:
- go: tip
addons:
apt:
packages:
- dbus
- dbus-x11
before_install:
- export GO111MODULE=on
script:
- go test -v -race -mod=readonly ./... # Run all the tests with the race detector enabled
- go vet ./... # go vet is the official Go static analyzer
jobs:
include:
# The build matrix doesn't cover build stages, so manually expand
# the jobs with anchors
- &multiarch
stage: "Multiarch Test"
go: 1.11.x
env: TARGETS="386 arm arm64 ppc64le"
before_install:
- docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
script:
- |
set -e
for target in $TARGETS; do
printf "\e[1mRunning test suite under ${target}.\e[0m\n"
GOARCH="$target" go test -v ./...
printf "\n\n"
done
- <<: *multiarch
go: 1.12.x
- <<: *multiarch
go: 1.13.x

View File

@ -1,4 +1,4 @@
[![Build Status](https://travis-ci.org/godbus/dbus.svg?branch=master)](https://travis-ci.org/godbus/dbus) ![Build Status](https://github.com/godbus/dbus/workflows/Go/badge.svg)
dbus dbus
---- ----
@ -32,6 +32,8 @@ gives a short overview over the basic usage.
#### Projects using godbus #### Projects using godbus
- [notify](https://github.com/esiqveland/notify) provides desktop notifications over dbus into a library. - [notify](https://github.com/esiqveland/notify) provides desktop notifications over dbus into a library.
- [go-bluetooth](https://github.com/muka/go-bluetooth) provides a bluetooth client over bluez dbus API. - [go-bluetooth](https://github.com/muka/go-bluetooth) provides a bluetooth client over bluez dbus API.
- [playerbm](https://github.com/altdesktop/playerbm) a bookmark utility for media players.
- [iwd](https://github.com/shibumi/iwd) go bindings for the internet wireless daemon "iwd".
Please note that the API is considered unstable for now and may change without Please note that the API is considered unstable for now and may change without
further notice. further notice.

View File

@ -37,7 +37,7 @@ const (
// Auth defines the behaviour of an authentication mechanism. // Auth defines the behaviour of an authentication mechanism.
type Auth interface { type Auth interface {
// Return the name of the mechnism, the argument to the first AUTH command // Return the name of the mechanism, the argument to the first AUTH command
// and the next status. // and the next status.
FirstData() (name, resp []byte, status AuthStatus) FirstData() (name, resp []byte, status AuthStatus)

View File

@ -24,6 +24,15 @@ type Call struct {
// Holds the response once the call is done. // Holds the response once the call is done.
Body []interface{} Body []interface{}
// ResponseSequence stores the sequence number of the DBus message containing
// the call response (or error). This can be compared to the sequence number
// of other call responses and signals on this connection to determine their
// relative ordering on the underlying DBus connection.
// For errors, ResponseSequence is populated only if the error came from a
// DBusMessage that was received or if there was an error receiving. In case of
// failure to make the call, ResponseSequence will be NoSequence.
ResponseSequence Sequence
// tracks context and canceler // tracks context and canceler
ctx context.Context ctx context.Context
ctxCanceler context.CancelFunc ctxCanceler context.CancelFunc

View File

@ -45,6 +45,7 @@ type Conn struct {
serialGen SerialGenerator serialGen SerialGenerator
inInt Interceptor inInt Interceptor
outInt Interceptor outInt Interceptor
auth []Auth
names *nameTracker names *nameTracker
calls *callTracker calls *callTracker
@ -59,7 +60,8 @@ type Conn struct {
func SessionBus() (conn *Conn, err error) { func SessionBus() (conn *Conn, err error) {
sessionBusLck.Lock() sessionBusLck.Lock()
defer sessionBusLck.Unlock() defer sessionBusLck.Unlock()
if sessionBus != nil { if sessionBus != nil &&
sessionBus.Connected() {
return sessionBus, nil return sessionBus, nil
} }
defer func() { defer func() {
@ -67,19 +69,7 @@ func SessionBus() (conn *Conn, err error) {
sessionBus = conn sessionBus = conn
} }
}() }()
conn, err = SessionBusPrivate() conn, err = ConnectSessionBus()
if err != nil {
return
}
if err = conn.Auth(nil); err != nil {
conn.Close()
conn = nil
return
}
if err = conn.Hello(); err != nil {
conn.Close()
conn = nil
}
return return
} }
@ -116,7 +106,8 @@ func SessionBusPrivateHandler(handler Handler, signalHandler SignalHandler) (*Co
func SystemBus() (conn *Conn, err error) { func SystemBus() (conn *Conn, err error) {
systemBusLck.Lock() systemBusLck.Lock()
defer systemBusLck.Unlock() defer systemBusLck.Unlock()
if systemBus != nil { if systemBus != nil &&
systemBus.Connected() {
return systemBus, nil return systemBus, nil
} }
defer func() { defer func() {
@ -124,20 +115,42 @@ func SystemBus() (conn *Conn, err error) {
systemBus = conn systemBus = conn
} }
}() }()
conn, err = SystemBusPrivate() conn, err = ConnectSystemBus()
return
}
// ConnectSessionBus connects to the session bus.
func ConnectSessionBus(opts ...ConnOption) (*Conn, error) {
address, err := getSessionBusAddress()
if err != nil { if err != nil {
return return nil, err
} }
if err = conn.Auth(nil); err != nil { return Connect(address, opts...)
conn.Close() }
conn = nil
return // ConnectSystemBus connects to the system bus.
func ConnectSystemBus(opts ...ConnOption) (*Conn, error) {
return Connect(getSystemBusPlatformAddress(), opts...)
}
// Connect connects to the given address.
//
// Returned connection is ready to use and doesn't require calling
// Auth and Hello methods to make it usable.
func Connect(address string, opts ...ConnOption) (*Conn, error) {
conn, err := Dial(address, opts...)
if err != nil {
return nil, err
}
if err = conn.Auth(conn.auth); err != nil {
_ = conn.Close()
return nil, err
} }
if err = conn.Hello(); err != nil { if err = conn.Hello(); err != nil {
conn.Close() _ = conn.Close()
conn = nil return nil, err
} }
return return conn, nil
} }
// SystemBusPrivate returns a new private connection to the system bus. // SystemBusPrivate returns a new private connection to the system bus.
@ -197,6 +210,14 @@ func WithSerialGenerator(gen SerialGenerator) ConnOption {
} }
} }
// WithAuth sets authentication methods for the auth conversation.
func WithAuth(methods ...Auth) ConnOption {
return func(conn *Conn) error {
conn.auth = methods
return nil
}
}
// Interceptor intercepts incoming and outgoing messages. // Interceptor intercepts incoming and outgoing messages.
type Interceptor func(msg *Message) type Interceptor func(msg *Message)
@ -309,6 +330,11 @@ func (conn *Conn) Context() context.Context {
return conn.ctx return conn.ctx
} }
// Connected returns whether conn is connected
func (conn *Conn) Connected() bool {
return conn.ctx.Err() == nil
}
// Eavesdrop causes conn to send all incoming messages to the given channel // Eavesdrop causes conn to send all incoming messages to the given channel
// without further processing. Method replies, errors and signals will not be // without further processing. Method replies, errors and signals will not be
// sent to the appropriate channels and method calls will not be handled. If nil // sent to the appropriate channels and method calls will not be handled. If nil
@ -342,8 +368,9 @@ func (conn *Conn) Hello() error {
} }
// inWorker runs in an own goroutine, reading incoming messages from the // inWorker runs in an own goroutine, reading incoming messages from the
// transport and dispatching them appropiately. // transport and dispatching them appropriately.
func (conn *Conn) inWorker() { func (conn *Conn) inWorker() {
sequenceGen := newSequenceGenerator()
for { for {
msg, err := conn.ReadMessage() msg, err := conn.ReadMessage()
if err != nil { if err != nil {
@ -352,7 +379,7 @@ func (conn *Conn) inWorker() {
// anything but to shut down all stuff and returns errors to all // anything but to shut down all stuff and returns errors to all
// pending replies. // pending replies.
conn.Close() conn.Close()
conn.calls.finalizeAllWithError(err) conn.calls.finalizeAllWithError(sequenceGen, err)
return return
} }
// invalid messages are ignored // invalid messages are ignored
@ -381,13 +408,14 @@ func (conn *Conn) inWorker() {
if conn.inInt != nil { if conn.inInt != nil {
conn.inInt(msg) conn.inInt(msg)
} }
sequence := sequenceGen.next()
switch msg.Type { switch msg.Type {
case TypeError: case TypeError:
conn.serialGen.RetireSerial(conn.calls.handleDBusError(msg)) conn.serialGen.RetireSerial(conn.calls.handleDBusError(sequence, msg))
case TypeMethodReply: case TypeMethodReply:
conn.serialGen.RetireSerial(conn.calls.handleReply(msg)) conn.serialGen.RetireSerial(conn.calls.handleReply(sequence, msg))
case TypeSignal: case TypeSignal:
conn.handleSignal(msg) conn.handleSignal(sequence, msg)
case TypeMethodCall: case TypeMethodCall:
go conn.handleCall(msg) go conn.handleCall(msg)
} }
@ -395,7 +423,7 @@ func (conn *Conn) inWorker() {
} }
} }
func (conn *Conn) handleSignal(msg *Message) { func (conn *Conn) handleSignal(sequence Sequence, 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 ,
@ -421,10 +449,11 @@ func (conn *Conn) handleSignal(msg *Message) {
} }
} }
signal := &Signal{ signal := &Signal{
Sender: sender, Sender: sender,
Path: msg.Headers[FieldPath].value.(ObjectPath), Path: msg.Headers[FieldPath].value.(ObjectPath),
Name: iface + "." + member, Name: iface + "." + member,
Body: msg.Body, Body: msg.Body,
Sequence: sequence,
} }
conn.signalHandler.DeliverSignal(iface, member, signal) conn.signalHandler.DeliverSignal(iface, member, signal)
} }
@ -442,6 +471,9 @@ func (conn *Conn) Object(dest string, path ObjectPath) BusObject {
} }
func (conn *Conn) sendMessageAndIfClosed(msg *Message, ifClosed func()) { func (conn *Conn) sendMessageAndIfClosed(msg *Message, ifClosed func()) {
if msg.serial == 0 {
msg.serial = conn.getSerial()
}
if conn.outInt != nil { if conn.outInt != nil {
conn.outInt(msg) conn.outInt(msg)
} }
@ -473,16 +505,16 @@ func (conn *Conn) send(ctx context.Context, msg *Message, ch chan *Call) *Call {
if ctx == nil { if ctx == nil {
panic("nil context") panic("nil context")
} }
if ch == nil {
ch = make(chan *Call, 1)
} else if cap(ch) == 0 {
panic("dbus: unbuffered channel passed to (*Conn).Send")
}
var call *Call var call *Call
ctx, canceler := context.WithCancel(ctx) 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 {
ch = make(chan *Call, 5)
} else if cap(ch) == 0 {
panic("dbus: unbuffered channel passed to (*Conn).Send")
}
call = new(Call) call = new(Call)
call.Destination, _ = msg.Headers[FieldDestination].value.(string) call.Destination, _ = msg.Headers[FieldDestination].value.(string)
call.Path, _ = msg.Headers[FieldPath].value.(ObjectPath) call.Path, _ = msg.Headers[FieldPath].value.(ObjectPath)
@ -504,7 +536,8 @@ func (conn *Conn) send(ctx context.Context, msg *Message, ch chan *Call) *Call {
}) })
} else { } else {
canceler() canceler()
call = &Call{Err: nil} call = &Call{Err: nil, Done: ch}
ch <- call
conn.sendMessageAndIfClosed(msg, func() { conn.sendMessageAndIfClosed(msg, func() {
call = &Call{Err: ErrClosed} call = &Call{Err: ErrClosed}
}) })
@ -529,7 +562,6 @@ func (conn *Conn) sendError(err error, dest string, serial uint32) {
} }
msg := new(Message) msg := new(Message)
msg.Type = TypeError msg.Type = TypeError
msg.serial = conn.getSerial()
msg.Headers = make(map[HeaderField]Variant) msg.Headers = make(map[HeaderField]Variant)
if dest != "" { if dest != "" {
msg.Headers[FieldDestination] = MakeVariant(dest) msg.Headers[FieldDestination] = MakeVariant(dest)
@ -548,7 +580,6 @@ func (conn *Conn) sendError(err error, dest string, serial uint32) {
func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) { func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) {
msg := new(Message) msg := new(Message)
msg.Type = TypeMethodReply msg.Type = TypeMethodReply
msg.serial = conn.getSerial()
msg.Headers = make(map[HeaderField]Variant) msg.Headers = make(map[HeaderField]Variant)
if dest != "" { if dest != "" {
msg.Headers[FieldDestination] = MakeVariant(dest) msg.Headers[FieldDestination] = MakeVariant(dest)
@ -564,8 +595,14 @@ func (conn *Conn) sendReply(dest string, serial uint32, values ...interface{}) {
// AddMatchSignal registers the given match rule to receive broadcast // AddMatchSignal registers the given match rule to receive broadcast
// signals based on their contents. // signals based on their contents.
func (conn *Conn) AddMatchSignal(options ...MatchOption) error { func (conn *Conn) AddMatchSignal(options ...MatchOption) error {
return conn.AddMatchSignalContext(context.Background(), options...)
}
// AddMatchSignalContext acts like AddMatchSignal but takes a context.
func (conn *Conn) AddMatchSignalContext(ctx context.Context, options ...MatchOption) error {
options = append([]MatchOption{withMatchType("signal")}, options...) options = append([]MatchOption{withMatchType("signal")}, options...)
return conn.busObj.Call( return conn.busObj.CallWithContext(
ctx,
"org.freedesktop.DBus.AddMatch", 0, "org.freedesktop.DBus.AddMatch", 0,
formatMatchOptions(options), formatMatchOptions(options),
).Store() ).Store()
@ -573,8 +610,14 @@ func (conn *Conn) AddMatchSignal(options ...MatchOption) error {
// RemoveMatchSignal removes the first rule that matches previously registered with AddMatchSignal. // RemoveMatchSignal removes the first rule that matches previously registered with AddMatchSignal.
func (conn *Conn) RemoveMatchSignal(options ...MatchOption) error { func (conn *Conn) RemoveMatchSignal(options ...MatchOption) error {
return conn.RemoveMatchSignalContext(context.Background(), options...)
}
// RemoveMatchSignalContext acts like RemoveMatchSignal but takes a context.
func (conn *Conn) RemoveMatchSignalContext(ctx context.Context, options ...MatchOption) error {
options = append([]MatchOption{withMatchType("signal")}, options...) options = append([]MatchOption{withMatchType("signal")}, options...)
return conn.busObj.Call( return conn.busObj.CallWithContext(
ctx,
"org.freedesktop.DBus.RemoveMatch", 0, "org.freedesktop.DBus.RemoveMatch", 0,
formatMatchOptions(options), formatMatchOptions(options),
).Store() ).Store()
@ -639,10 +682,11 @@ func (e Error) Error() string {
// Signal represents a D-Bus message of type Signal. The name member is given in // Signal represents a D-Bus message of type Signal. The name member is given in
// "interface.member" notation, e.g. org.freedesktop.D-Bus.NameLost. // "interface.member" notation, e.g. org.freedesktop.D-Bus.NameLost.
type Signal struct { type Signal struct {
Sender string Sender string
Path ObjectPath Path ObjectPath
Name string Name string
Body []interface{} Body []interface{}
Sequence Sequence
} }
// transport is a D-Bus transport. // transport is a D-Bus transport.
@ -825,25 +869,25 @@ func (tracker *callTracker) track(sn uint32, call *Call) {
tracker.lck.Unlock() tracker.lck.Unlock()
} }
func (tracker *callTracker) handleReply(msg *Message) uint32 { func (tracker *callTracker) handleReply(sequence Sequence, msg *Message) uint32 {
serial := msg.Headers[FieldReplySerial].value.(uint32) serial := msg.Headers[FieldReplySerial].value.(uint32)
tracker.lck.RLock() tracker.lck.RLock()
_, ok := tracker.calls[serial] _, ok := tracker.calls[serial]
tracker.lck.RUnlock() tracker.lck.RUnlock()
if ok { if ok {
tracker.finalizeWithBody(serial, msg.Body) tracker.finalizeWithBody(serial, sequence, msg.Body)
} }
return serial return serial
} }
func (tracker *callTracker) handleDBusError(msg *Message) uint32 { func (tracker *callTracker) handleDBusError(sequence Sequence, msg *Message) uint32 {
serial := msg.Headers[FieldReplySerial].value.(uint32) serial := msg.Headers[FieldReplySerial].value.(uint32)
tracker.lck.RLock() tracker.lck.RLock()
_, ok := tracker.calls[serial] _, ok := tracker.calls[serial]
tracker.lck.RUnlock() tracker.lck.RUnlock()
if ok { if ok {
name, _ := msg.Headers[FieldErrorName].value.(string) name, _ := msg.Headers[FieldErrorName].value.(string)
tracker.finalizeWithError(serial, Error{name, msg.Body}) tracker.finalizeWithError(serial, sequence, Error{name, msg.Body})
} }
return serial return serial
} }
@ -856,7 +900,7 @@ func (tracker *callTracker) handleSendError(msg *Message, err error) {
_, ok := tracker.calls[msg.serial] _, ok := tracker.calls[msg.serial]
tracker.lck.RUnlock() tracker.lck.RUnlock()
if ok { if ok {
tracker.finalizeWithError(msg.serial, err) tracker.finalizeWithError(msg.serial, NoSequence, err)
} }
} }
@ -871,7 +915,7 @@ func (tracker *callTracker) finalize(sn uint32) {
} }
} }
func (tracker *callTracker) finalizeWithBody(sn uint32, body []interface{}) { func (tracker *callTracker) finalizeWithBody(sn uint32, sequence Sequence, body []interface{}) {
tracker.lck.Lock() tracker.lck.Lock()
c, ok := tracker.calls[sn] c, ok := tracker.calls[sn]
if ok { if ok {
@ -880,11 +924,12 @@ func (tracker *callTracker) finalizeWithBody(sn uint32, body []interface{}) {
tracker.lck.Unlock() tracker.lck.Unlock()
if ok { if ok {
c.Body = body c.Body = body
c.ResponseSequence = sequence
c.done() c.done()
} }
} }
func (tracker *callTracker) finalizeWithError(sn uint32, err error) { func (tracker *callTracker) finalizeWithError(sn uint32, sequence Sequence, err error) {
tracker.lck.Lock() tracker.lck.Lock()
c, ok := tracker.calls[sn] c, ok := tracker.calls[sn]
if ok { if ok {
@ -893,11 +938,12 @@ func (tracker *callTracker) finalizeWithError(sn uint32, err error) {
tracker.lck.Unlock() tracker.lck.Unlock()
if ok { if ok {
c.Err = err c.Err = err
c.ResponseSequence = sequence
c.done() c.done()
} }
} }
func (tracker *callTracker) finalizeAllWithError(err error) { func (tracker *callTracker) finalizeAllWithError(sequenceGen *sequenceGenerator, err error) {
tracker.lck.Lock() tracker.lck.Lock()
closedCalls := make([]*Call, 0, len(tracker.calls)) closedCalls := make([]*Call, 0, len(tracker.calls))
for sn := range tracker.calls { for sn := range tracker.calls {
@ -907,6 +953,7 @@ func (tracker *callTracker) finalizeAllWithError(err error) {
tracker.lck.Unlock() tracker.lck.Unlock()
for _, call := range closedCalls { for _, call := range closedCalls {
call.Err = err call.Err = err
call.ResponseSequence = sequenceGen.next()
call.done() call.done()
} }
} }

View File

@ -28,6 +28,7 @@ var (
interfaceType = reflect.TypeOf((*interface{})(nil)).Elem() interfaceType = reflect.TypeOf((*interface{})(nil)).Elem()
unixFDType = reflect.TypeOf(UnixFD(0)) unixFDType = reflect.TypeOf(UnixFD(0))
unixFDIndexType = reflect.TypeOf(UnixFDIndex(0)) unixFDIndexType = reflect.TypeOf(UnixFDIndex(0))
errType = reflect.TypeOf((*error)(nil)).Elem()
) )
// An InvalidTypeError signals that a value which cannot be represented in the // An InvalidTypeError signals that a value which cannot be represented in the
@ -63,6 +64,9 @@ func storeInterfaces(src, dest interface{}) error {
func store(dest, src reflect.Value) error { func store(dest, src reflect.Value) error {
if dest.Kind() == reflect.Ptr { if dest.Kind() == reflect.Ptr {
if dest.IsNil() {
dest.Set(reflect.New(dest.Type().Elem()))
}
return store(dest.Elem(), src) return store(dest.Elem(), src)
} }
switch src.Kind() { switch src.Kind() {

View File

@ -126,14 +126,28 @@ func (m exportedMethod) Call(args ...interface{}) ([]interface{}, error) {
} }
ret := m.Value.Call(params) ret := m.Value.Call(params)
var err error
err := ret[t.NumOut()-1].Interface().(*Error) nilErr := false // The reflection will find almost-nils, let's only pass back clean ones!
ret = ret[:t.NumOut()-1] if t.NumOut() > 0 {
if e, ok := ret[t.NumOut()-1].Interface().(*Error); ok { // godbus *Error
nilErr = ret[t.NumOut()-1].IsNil()
ret = ret[:t.NumOut()-1]
err = e
} else if ret[t.NumOut()-1].Type().Implements(errType) { // Go error
i := ret[t.NumOut()-1].Interface()
if i == nil {
nilErr = ret[t.NumOut()-1].IsNil()
} else {
err = i.(error)
}
ret = ret[:t.NumOut()-1]
}
}
out := make([]interface{}, len(ret)) out := make([]interface{}, len(ret))
for i, val := range ret { for i, val := range ret {
out[i] = val.Interface() out[i] = val.Interface()
} }
if err == nil { if nilErr || err == nil {
//concrete type to interface nil is a special case //concrete type to interface nil is a special case
return out, nil return out, nil
} }

View File

@ -69,6 +69,22 @@ func getMethods(in interface{}, mapping map[string]string) map[string]reflect.Va
return methods return methods
} }
func getAllMethods(in interface{}, mapping map[string]string) map[string]reflect.Value {
if in == nil {
return nil
}
methods := make(map[string]reflect.Value)
val := reflect.ValueOf(in)
typ := val.Type()
for i := 0; i < typ.NumMethod(); i++ {
methtype := typ.Method(i)
method := val.Method(i)
// map names while building table
methods[computeMethodName(methtype.Name, mapping)] = method
}
return methods
}
func standardMethodArgumentDecode(m Method, sender string, msg *Message, body []interface{}) ([]interface{}, error) { func standardMethodArgumentDecode(m Method, sender string, msg *Message, body []interface{}) ([]interface{}, error) {
pointers := make([]interface{}, m.NumArguments()) pointers := make([]interface{}, m.NumArguments())
decode := make([]interface{}, 0, len(body)) decode := make([]interface{}, 0, len(body))
@ -159,7 +175,6 @@ func (conn *Conn) handleCall(msg *Message) {
if msg.Flags&FlagNoReplyExpected == 0 { if msg.Flags&FlagNoReplyExpected == 0 {
reply := new(Message) reply := new(Message)
reply.Type = TypeMethodReply reply.Type = TypeMethodReply
reply.serial = conn.getSerial()
reply.Headers = make(map[HeaderField]Variant) reply.Headers = make(map[HeaderField]Variant)
if hasSender { if hasSender {
reply.Headers[FieldDestination] = msg.Headers[FieldSender] reply.Headers[FieldDestination] = msg.Headers[FieldSender]
@ -195,7 +210,6 @@ func (conn *Conn) Emit(path ObjectPath, name string, values ...interface{}) erro
} }
msg := new(Message) msg := new(Message)
msg.Type = TypeSignal msg.Type = TypeSignal
msg.serial = conn.getSerial()
msg.Headers = make(map[HeaderField]Variant) msg.Headers = make(map[HeaderField]Variant)
msg.Headers[FieldInterface] = MakeVariant(iface) msg.Headers[FieldInterface] = MakeVariant(iface)
msg.Headers[FieldMember] = MakeVariant(member) msg.Headers[FieldMember] = MakeVariant(member)
@ -247,6 +261,18 @@ func (conn *Conn) Export(v interface{}, path ObjectPath, iface string) error {
return conn.ExportWithMap(v, nil, path, iface) return conn.ExportWithMap(v, nil, path, iface)
} }
// ExportAll registers all exported methods defined by the given object on
// the message bus.
//
// Unlike Export there is no requirement to have the last parameter as type
// *Error. If you want to be able to return error then you can append an error
// type parameter to your method signature. If the error returned is not nil,
// it is sent back to the caller as an error. Otherwise, a method reply is
// sent with the other return values as its body.
func (conn *Conn) ExportAll(v interface{}, path ObjectPath, iface string) error {
return conn.export(getAllMethods(v, nil), path, iface, false)
}
// ExportWithMap works exactly like Export but provides the ability to remap // ExportWithMap works exactly like Export but provides the ability to remap
// method names (e.g. export a lower-case method). // method names (e.g. export a lower-case method).
// //
@ -299,19 +325,22 @@ func (conn *Conn) ExportSubtreeMethodTable(methods map[string]interface{}, path
} }
func (conn *Conn) exportMethodTable(methods map[string]interface{}, path ObjectPath, iface string, includeSubtree bool) error { func (conn *Conn) exportMethodTable(methods map[string]interface{}, path ObjectPath, iface string, includeSubtree bool) error {
out := make(map[string]reflect.Value) var out map[string]reflect.Value
for name, method := range methods { if methods != nil {
rval := reflect.ValueOf(method) out = make(map[string]reflect.Value)
if rval.Kind() != reflect.Func { for name, method := range methods {
continue rval := reflect.ValueOf(method)
if rval.Kind() != reflect.Func {
continue
}
t := rval.Type()
// only track valid methods must return *Error as last arg
if t.NumOut() == 0 ||
t.Out(t.NumOut()-1) != reflect.TypeOf(&ErrMsgInvalidArg) {
continue
}
out[name] = rval
} }
t := rval.Type()
// only track valid methods must return *Error as last arg
if t.NumOut() == 0 ||
t.Out(t.NumOut()-1) != reflect.TypeOf(&ErrMsgInvalidArg) {
continue
}
out[name] = rval
} }
return conn.export(out, path, iface, includeSubtree) return conn.export(out, path, iface, includeSubtree)
} }
@ -327,12 +356,12 @@ func (conn *Conn) unexport(h *defaultHandler, path ObjectPath, iface string) err
return nil return nil
} }
// exportWithMap is the worker function for all exports/registrations. // export is the worker function for all exports/registrations.
func (conn *Conn) export(methods map[string]reflect.Value, path ObjectPath, iface string, includeSubtree bool) error { func (conn *Conn) export(methods map[string]reflect.Value, path ObjectPath, iface string, includeSubtree bool) error {
h, ok := conn.handler.(*defaultHandler) h, ok := conn.handler.(*defaultHandler)
if !ok { if !ok {
return fmt.Errorf( return fmt.Errorf(
`dbus: export only allowed on the default hander handler have %T"`, `dbus: export only allowed on the default handler. Received: %T"`,
conn.handler) conn.handler)
} }

View File

@ -1,6 +1,7 @@
package dbus package dbus
import ( import (
"strconv"
"strings" "strings"
) )
@ -60,3 +61,29 @@ func WithMatchPathNamespace(namespace ObjectPath) MatchOption {
func WithMatchDestination(destination string) MatchOption { func WithMatchDestination(destination string) MatchOption {
return WithMatchOption("destination", destination) return WithMatchOption("destination", destination)
} }
// WithMatchArg sets argN match option, range of N is 0 to 63.
func WithMatchArg(argIdx int, value string) MatchOption {
if argIdx < 0 || argIdx > 63 {
panic("range of argument index is 0 to 63")
}
return WithMatchOption("arg"+strconv.Itoa(argIdx), value)
}
// WithMatchArgPath sets argN path match option, range of N is 0 to 63.
func WithMatchArgPath(argIdx int, path string) MatchOption {
if argIdx < 0 || argIdx > 63 {
panic("range of argument index is 0 to 63")
}
return WithMatchOption("arg"+strconv.Itoa(argIdx)+"path", path)
}
// WithMatchArg0Namespace sets arg0namespace match option.
func WithMatchArg0Namespace(arg0Namespace string) MatchOption {
return WithMatchOption("arg0namespace", arg0Namespace)
}
// WithMatchEavesdrop sets eavesdrop match option.
func WithMatchEavesdrop(eavesdrop bool) MatchOption {
return WithMatchOption("eavesdrop", strconv.FormatBool(eavesdrop))
}

View File

@ -16,6 +16,7 @@ type BusObject interface {
AddMatchSignal(iface, member string, options ...MatchOption) *Call AddMatchSignal(iface, member string, options ...MatchOption) *Call
RemoveMatchSignal(iface, member string, options ...MatchOption) *Call RemoveMatchSignal(iface, member string, options ...MatchOption) *Call
GetProperty(p string) (Variant, error) GetProperty(p string) (Variant, error)
StoreProperty(p string, value interface{}) error
SetProperty(p string, v interface{}) error SetProperty(p string, v interface{}) error
Destination() string Destination() string
Path() ObjectPath Path() ObjectPath
@ -109,7 +110,6 @@ func (o *Object) createCall(ctx context.Context, method string, flags Flags, ch
method = method[i+1:] method = method[i+1:]
msg := new(Message) msg := new(Message)
msg.Type = TypeMethodCall msg.Type = TypeMethodCall
msg.serial = o.conn.getSerial()
msg.Flags = flags & (FlagNoAutoStart | FlagNoReplyExpected) msg.Flags = flags & (FlagNoAutoStart | FlagNoReplyExpected)
msg.Headers = make(map[HeaderField]Variant) msg.Headers = make(map[HeaderField]Variant)
msg.Headers[FieldPath] = MakeVariant(o.path) msg.Headers[FieldPath] = MakeVariant(o.path)
@ -122,68 +122,31 @@ func (o *Object) createCall(ctx context.Context, method string, flags Flags, ch
if len(args) > 0 { if len(args) > 0 {
msg.Headers[FieldSignature] = MakeVariant(SignatureOf(args...)) msg.Headers[FieldSignature] = MakeVariant(SignatureOf(args...))
} }
if msg.Flags&FlagNoReplyExpected == 0 { return o.conn.SendWithContext(ctx, msg, ch)
if ch == nil {
ch = make(chan *Call, 1)
} else if cap(ch) == 0 {
panic("dbus: unbuffered channel passed to (*Object).Go")
}
ctx, cancel := context.WithCancel(ctx)
call := &Call{
Destination: o.dest,
Path: o.path,
Method: method,
Args: args,
Done: ch,
ctxCanceler: cancel,
ctx: ctx,
}
o.conn.calls.track(msg.serial, call)
o.conn.sendMessageAndIfClosed(msg, func() {
o.conn.calls.handleSendError(msg, ErrClosed)
cancel()
})
go func() {
<-ctx.Done()
o.conn.calls.handleSendError(msg, ctx.Err())
}()
return call
}
done := make(chan *Call, 1)
call := &Call{
Err: nil,
Done: done,
}
defer func() {
call.Done <- call
close(done)
}()
o.conn.sendMessageAndIfClosed(msg, func() {
call.Err = ErrClosed
})
return call
} }
// GetProperty calls org.freedesktop.DBus.Properties.Get on the given // GetProperty calls org.freedesktop.DBus.Properties.Get on the given
// object. The property name must be given in interface.member notation. // object. The property name must be given in interface.member notation.
func (o *Object) GetProperty(p string) (Variant, error) { func (o *Object) GetProperty(p string) (Variant, error) {
var result Variant
err := o.StoreProperty(p, &result)
return result, err
}
// StoreProperty calls org.freedesktop.DBus.Properties.Get on the given
// object. The property name must be given in interface.member notation.
// It stores the returned property into the provided value.
func (o *Object) StoreProperty(p string, value interface{}) error {
idx := strings.LastIndex(p, ".") idx := strings.LastIndex(p, ".")
if idx == -1 || idx+1 == len(p) { if idx == -1 || idx+1 == len(p) {
return Variant{}, errors.New("dbus: invalid property " + p) return errors.New("dbus: invalid property " + p)
} }
iface := p[:idx] iface := p[:idx]
prop := p[idx+1:] prop := p[idx+1:]
result := Variant{} return o.Call("org.freedesktop.DBus.Properties.Get", 0, iface, prop).
err := o.Call("org.freedesktop.DBus.Properties.Get", 0, iface, prop).Store(&result) Store(value)
if err != nil {
return Variant{}, err
}
return result, nil
} }
// SetProperty calls org.freedesktop.DBus.Properties.Set on the given // SetProperty calls org.freedesktop.DBus.Properties.Set on the given

24
vendor/github.com/godbus/dbus/v5/sequence.go generated vendored Normal file
View File

@ -0,0 +1,24 @@
package dbus
// Sequence represents the value of a monotonically increasing counter.
type Sequence uint64
const (
// NoSequence indicates the absence of a sequence value.
NoSequence Sequence = 0
)
// sequenceGenerator represents a monotonically increasing counter.
type sequenceGenerator struct {
nextSequence Sequence
}
func (generator *sequenceGenerator) next() Sequence {
result := generator.nextSequence
generator.nextSequence++
return result
}
func newSequenceGenerator() *sequenceGenerator {
return &sequenceGenerator{nextSequence: 1}
}

125
vendor/github.com/godbus/dbus/v5/sequential_handler.go generated vendored Normal file
View File

@ -0,0 +1,125 @@
package dbus
import (
"sync"
)
// NewSequentialSignalHandler returns an instance of a new
// signal handler that guarantees sequential processing of signals. It is a
// guarantee of this signal handler that signals will be written to
// channels in the order they are received on the DBus connection.
func NewSequentialSignalHandler() SignalHandler {
return &sequentialSignalHandler{}
}
type sequentialSignalHandler struct {
mu sync.RWMutex
closed bool
signals []*sequentialSignalChannelData
}
func (sh *sequentialSignalHandler) DeliverSignal(intf, name string, signal *Signal) {
sh.mu.RLock()
defer sh.mu.RUnlock()
if sh.closed {
return
}
for _, scd := range sh.signals {
scd.deliver(signal)
}
}
func (sh *sequentialSignalHandler) Terminate() {
sh.mu.Lock()
defer sh.mu.Unlock()
if sh.closed {
return
}
for _, scd := range sh.signals {
scd.close()
close(scd.ch)
}
sh.closed = true
sh.signals = nil
}
func (sh *sequentialSignalHandler) AddSignal(ch chan<- *Signal) {
sh.mu.Lock()
defer sh.mu.Unlock()
if sh.closed {
return
}
sh.signals = append(sh.signals, newSequentialSignalChannelData(ch))
}
func (sh *sequentialSignalHandler) RemoveSignal(ch chan<- *Signal) {
sh.mu.Lock()
defer sh.mu.Unlock()
if sh.closed {
return
}
for i := len(sh.signals) - 1; i >= 0; i-- {
if ch == sh.signals[i].ch {
sh.signals[i].close()
copy(sh.signals[i:], sh.signals[i+1:])
sh.signals[len(sh.signals)-1] = nil
sh.signals = sh.signals[:len(sh.signals)-1]
}
}
}
type sequentialSignalChannelData struct {
ch chan<- *Signal
in chan *Signal
done chan struct{}
}
func newSequentialSignalChannelData(ch chan<- *Signal) *sequentialSignalChannelData {
scd := &sequentialSignalChannelData{
ch: ch,
in: make(chan *Signal),
done: make(chan struct{}),
}
go scd.bufferSignals()
return scd
}
func (scd *sequentialSignalChannelData) bufferSignals() {
defer close(scd.done)
// Ensure that signals are delivered to scd.ch in the same
// order they are received from scd.in.
var queue []*Signal
for {
if len(queue) == 0 {
signal, ok := <- scd.in
if !ok {
return
}
queue = append(queue, signal)
}
select {
case scd.ch <- queue[0]:
copy(queue, queue[1:])
queue[len(queue)-1] = nil
queue = queue[:len(queue)-1]
case signal, ok := <-scd.in:
if !ok {
return
}
queue = append(queue, signal)
}
}
}
func (scd *sequentialSignalChannelData) deliver(signal *Signal) {
scd.in <- signal
}
func (scd *sequentialSignalChannelData) close() {
close(scd.in)
// Ensure that bufferSignals() has exited and won't attempt
// any future sends on scd.ch
<-scd.done
}

View File

@ -137,7 +137,7 @@ func ParseSignatureMust(s string) Signature {
return sig return sig
} }
// Empty retruns whether the signature is the empty signature. // Empty returns whether the signature is the empty signature.
func (s Signature) Empty() bool { func (s Signature) Empty() bool {
return s.str == "" return s.str == ""
} }

View File

@ -10,6 +10,7 @@ package dbus
/* /*
const int sizeofPtr = sizeof(void*); const int sizeofPtr = sizeof(void*);
#define _WANT_UCRED #define _WANT_UCRED
#include <sys/types.h>
#include <sys/ucred.h> #include <sys/ucred.h>
*/ */
import "C" import "C"

View File

@ -142,3 +142,9 @@ func (v Variant) String() string {
func (v Variant) Value() interface{} { func (v Variant) Value() interface{} {
return v.value return v.value
} }
// Store converts the variant into a native go type using the same
// mechanism as the "Store" function.
func (v Variant) Store(value interface{}) error {
return storeInterfaces(v.value, value)
}

View File

@ -1,2 +0,0 @@
Tianon Gravi <admwiggin@gmail.com> (@tianon)
Aleksa Sarai <cyphar@cyphar.com> (@cyphar)

View File

@ -1,41 +0,0 @@
package user
import (
"errors"
)
var (
// The current operating system does not provide the required data for user lookups.
ErrUnsupported = errors.New("user lookup: operating system does not provide passwd-formatted data")
// No matching entries found in file.
ErrNoPasswdEntries = errors.New("no matching entries in passwd file")
ErrNoGroupEntries = errors.New("no matching entries in group file")
)
// LookupUser looks up a user by their username in /etc/passwd. If the user
// cannot be found (or there is no /etc/passwd file on the filesystem), then
// LookupUser returns an error.
func LookupUser(username string) (User, error) {
return lookupUser(username)
}
// LookupUid looks up a user by their user id in /etc/passwd. If the user cannot
// be found (or there is no /etc/passwd file on the filesystem), then LookupId
// returns an error.
func LookupUid(uid int) (User, error) {
return lookupUid(uid)
}
// LookupGroup looks up a group by its name in /etc/group. If the group cannot
// be found (or there is no /etc/group file on the filesystem), then LookupGroup
// returns an error.
func LookupGroup(groupname string) (Group, error) {
return lookupGroup(groupname)
}
// LookupGid looks up a group by its group id in /etc/group. If the group cannot
// be found (or there is no /etc/group file on the filesystem), then LookupGid
// returns an error.
func LookupGid(gid int) (Group, error) {
return lookupGid(gid)
}

View File

@ -16,13 +16,19 @@ const (
unixGroupPath = "/etc/group" unixGroupPath = "/etc/group"
) )
func lookupUser(username string) (User, error) { // LookupUser looks up a user by their username in /etc/passwd. If the user
// cannot be found (or there is no /etc/passwd file on the filesystem), then
// LookupUser returns an error.
func LookupUser(username string) (User, error) {
return lookupUserFunc(func(u User) bool { return lookupUserFunc(func(u User) bool {
return u.Name == username return u.Name == username
}) })
} }
func lookupUid(uid int) (User, error) { // LookupUid looks up a user by their user id in /etc/passwd. If the user cannot
// be found (or there is no /etc/passwd file on the filesystem), then LookupId
// returns an error.
func LookupUid(uid int) (User, error) {
return lookupUserFunc(func(u User) bool { return lookupUserFunc(func(u User) bool {
return u.Uid == uid return u.Uid == uid
}) })
@ -51,13 +57,19 @@ func lookupUserFunc(filter func(u User) bool) (User, error) {
return users[0], nil return users[0], nil
} }
func lookupGroup(groupname string) (Group, error) { // LookupGroup looks up a group by its name in /etc/group. If the group cannot
// be found (or there is no /etc/group file on the filesystem), then LookupGroup
// returns an error.
func LookupGroup(groupname string) (Group, error) {
return lookupGroupFunc(func(g Group) bool { return lookupGroupFunc(func(g Group) bool {
return g.Name == groupname return g.Name == groupname
}) })
} }
func lookupGid(gid int) (Group, error) { // LookupGid looks up a group by its group id in /etc/group. If the group cannot
// be found (or there is no /etc/group file on the filesystem), then LookupGid
// returns an error.
func LookupGid(gid int) (Group, error) {
return lookupGroupFunc(func(g Group) bool { return lookupGroupFunc(func(g Group) bool {
return g.Gid == gid return g.Gid == gid
}) })

View File

@ -1,40 +0,0 @@
// +build windows
package user
import (
"os/user"
"strconv"
)
func lookupUser(username string) (User, error) {
u, err := user.Lookup(username)
if err != nil {
return User{}, err
}
return userFromOS(u)
}
func lookupUid(uid int) (User, error) {
u, err := user.LookupId(strconv.Itoa(uid))
if err != nil {
return User{}, err
}
return userFromOS(u)
}
func lookupGroup(groupname string) (Group, error) {
g, err := user.LookupGroup(groupname)
if err != nil {
return Group{}, err
}
return groupFromOS(g)
}
func lookupGid(gid int) (Group, error) {
g, err := user.LookupGroupId(strconv.Itoa(gid))
if err != nil {
return Group{}, err
}
return groupFromOS(g)
}

View File

@ -2,10 +2,10 @@ package user
import ( import (
"bufio" "bufio"
"errors"
"fmt" "fmt"
"io" "io"
"os" "os"
"os/user"
"strconv" "strconv"
"strings" "strings"
) )
@ -16,6 +16,13 @@ const (
) )
var ( var (
// The current operating system does not provide the required data for user lookups.
ErrUnsupported = errors.New("user lookup: operating system does not provide passwd-formatted data")
// No matching entries found in file.
ErrNoPasswdEntries = errors.New("no matching entries in passwd file")
ErrNoGroupEntries = errors.New("no matching entries in group file")
ErrRange = fmt.Errorf("uids and gids must be in range %d-%d", minId, maxId) ErrRange = fmt.Errorf("uids and gids must be in range %d-%d", minId, maxId)
) )
@ -29,28 +36,6 @@ type User struct {
Shell string Shell string
} }
// userFromOS converts an os/user.(*User) to local User
//
// (This does not include Pass, Shell or Gecos)
func userFromOS(u *user.User) (User, error) {
newUser := User{
Name: u.Username,
Home: u.HomeDir,
}
id, err := strconv.Atoi(u.Uid)
if err != nil {
return newUser, err
}
newUser.Uid = id
id, err = strconv.Atoi(u.Gid)
if err != nil {
return newUser, err
}
newUser.Gid = id
return newUser, nil
}
type Group struct { type Group struct {
Name string Name string
Pass string Pass string
@ -58,23 +43,6 @@ type Group struct {
List []string List []string
} }
// groupFromOS converts an os/user.(*Group) to local Group
//
// (This does not include Pass or List)
func groupFromOS(g *user.Group) (Group, error) {
newGroup := Group{
Name: g.Name,
}
id, err := strconv.Atoi(g.Gid)
if err != nil {
return newGroup, err
}
newGroup.Gid = id
return newGroup, nil
}
// SubID represents an entry in /etc/sub{u,g}id // SubID represents an entry in /etc/sub{u,g}id
type SubID struct { type SubID struct {
Name string Name string

View File

@ -0,0 +1,42 @@
// +build gofuzz
package user
import (
"io"
"strings"
)
func IsDivisbleBy(n int, divisibleby int) bool {
return (n % divisibleby) == 0
}
func FuzzUser(data []byte) int {
if len(data) == 0 {
return -1
}
if !IsDivisbleBy(len(data), 5) {
return -1
}
var divided [][]byte
chunkSize := len(data) / 5
for i := 0; i < len(data); i += chunkSize {
end := i + chunkSize
divided = append(divided, data[i:end])
}
_, _ = ParsePasswdFilter(strings.NewReader(string(divided[0])), nil)
var passwd, group io.Reader
group = strings.NewReader(string(divided[1]))
_, _ = GetAdditionalGroups([]string{string(divided[2])}, group)
passwd = strings.NewReader(string(divided[3]))
_, _ = GetExecUser(string(divided[4]), nil, passwd, group)
return 1
}

View File

@ -598,10 +598,13 @@ type VMImage struct {
// LinuxSeccomp represents syscall restrictions // LinuxSeccomp represents syscall restrictions
type LinuxSeccomp struct { type LinuxSeccomp struct {
DefaultAction LinuxSeccompAction `json:"defaultAction"` DefaultAction LinuxSeccompAction `json:"defaultAction"`
Architectures []Arch `json:"architectures,omitempty"` DefaultErrnoRet *uint `json:"defaultErrnoRet,omitempty"`
Flags []LinuxSeccompFlag `json:"flags,omitempty"` Architectures []Arch `json:"architectures,omitempty"`
Syscalls []LinuxSyscall `json:"syscalls,omitempty"` Flags []LinuxSeccompFlag `json:"flags,omitempty"`
ListenerPath string `json:"listenerPath,omitempty"`
ListenerMetadata string `json:"listenerMetadata,omitempty"`
Syscalls []LinuxSyscall `json:"syscalls,omitempty"`
} }
// Arch used for additional architectures // Arch used for additional architectures
@ -641,11 +644,13 @@ type LinuxSeccompAction string
const ( const (
ActKill LinuxSeccompAction = "SCMP_ACT_KILL" ActKill LinuxSeccompAction = "SCMP_ACT_KILL"
ActKillProcess LinuxSeccompAction = "SCMP_ACT_KILL_PROCESS" ActKillProcess LinuxSeccompAction = "SCMP_ACT_KILL_PROCESS"
ActKillThread LinuxSeccompAction = "SCMP_ACT_KILL_THREAD"
ActTrap LinuxSeccompAction = "SCMP_ACT_TRAP" ActTrap LinuxSeccompAction = "SCMP_ACT_TRAP"
ActErrno LinuxSeccompAction = "SCMP_ACT_ERRNO" ActErrno LinuxSeccompAction = "SCMP_ACT_ERRNO"
ActTrace LinuxSeccompAction = "SCMP_ACT_TRACE" ActTrace LinuxSeccompAction = "SCMP_ACT_TRACE"
ActAllow LinuxSeccompAction = "SCMP_ACT_ALLOW" ActAllow LinuxSeccompAction = "SCMP_ACT_ALLOW"
ActLog LinuxSeccompAction = "SCMP_ACT_LOG" ActLog LinuxSeccompAction = "SCMP_ACT_LOG"
ActNotify LinuxSeccompAction = "SCMP_ACT_NOTIFY"
) )
// LinuxSeccompOperator used to match syscall arguments in Seccomp // LinuxSeccompOperator used to match syscall arguments in Seccomp

View File

@ -5,17 +5,17 @@ type ContainerState string
const ( const (
// StateCreating indicates that the container is being created // StateCreating indicates that the container is being created
StateCreating ContainerState = "creating" StateCreating ContainerState = "creating"
// StateCreated indicates that the runtime has finished the create operation // StateCreated indicates that the runtime has finished the create operation
StateCreated ContainerState = "created" StateCreated ContainerState = "created"
// StateRunning indicates that the container process has executed the // StateRunning indicates that the container process has executed the
// user-specified program but has not exited // user-specified program but has not exited
StateRunning ContainerState = "running" StateRunning ContainerState = "running"
// StateStopped indicates that the container process has exited // StateStopped indicates that the container process has exited
StateStopped ContainerState = "stopped" StateStopped ContainerState = "stopped"
) )
// State holds information about the runtime state of the container. // State holds information about the runtime state of the container.
@ -33,3 +33,24 @@ type State struct {
// Annotations are key values associated with the container. // Annotations are key values associated with the container.
Annotations map[string]string `json:"annotations,omitempty"` Annotations map[string]string `json:"annotations,omitempty"`
} }
const (
// SeccompFdName is the name of the seccomp notify file descriptor.
SeccompFdName string = "seccompFd"
)
// ContainerProcessState holds information about the state of a container process.
type ContainerProcessState struct {
// Version is the version of the specification that is supported.
Version string `json:"ociVersion"`
// Fds is a string array containing the names of the file descriptors passed.
// The index of the name in this array corresponds to index of the file
// descriptor in the `SCM_RIGHTS` array.
Fds []string `json:"fds"`
// Pid is the process ID as seen by the runtime.
Pid int `json:"pid"`
// Opaque metadata.
Metadata string `json:"metadata,omitempty"`
// State of the container.
State State `json:"state"`
}

10
vendor/modules.txt vendored
View File

@ -45,7 +45,7 @@ github.com/Microsoft/hcsshim/pkg/ociwclayer
github.com/beorn7/perks/quantile github.com/beorn7/perks/quantile
# github.com/cespare/xxhash/v2 v2.1.1 # github.com/cespare/xxhash/v2 v2.1.1
github.com/cespare/xxhash/v2 github.com/cespare/xxhash/v2
# github.com/cilium/ebpf v0.4.0 # github.com/cilium/ebpf v0.5.0
github.com/cilium/ebpf github.com/cilium/ebpf
github.com/cilium/ebpf/asm github.com/cilium/ebpf/asm
github.com/cilium/ebpf/internal github.com/cilium/ebpf/internal
@ -134,7 +134,7 @@ github.com/containers/ocicrypt/keywrap/pkcs7
github.com/containers/ocicrypt/spec github.com/containers/ocicrypt/spec
github.com/containers/ocicrypt/utils github.com/containers/ocicrypt/utils
github.com/containers/ocicrypt/utils/keyprovider github.com/containers/ocicrypt/utils/keyprovider
# github.com/coreos/go-systemd/v22 v22.1.0 # github.com/coreos/go-systemd/v22 v22.3.1
## explicit ## explicit
github.com/coreos/go-systemd/v22/daemon github.com/coreos/go-systemd/v22/daemon
github.com/coreos/go-systemd/v22/dbus github.com/coreos/go-systemd/v22/dbus
@ -164,7 +164,7 @@ github.com/emicklei/go-restful/log
github.com/fsnotify/fsnotify github.com/fsnotify/fsnotify
# github.com/go-logr/logr v0.2.0 # github.com/go-logr/logr v0.2.0
github.com/go-logr/logr github.com/go-logr/logr
# github.com/godbus/dbus/v5 v5.0.3 # github.com/godbus/dbus/v5 v5.0.4
github.com/godbus/dbus/v5 github.com/godbus/dbus/v5
# github.com/gogo/googleapis v1.4.0 => github.com/gogo/googleapis v1.3.2 # github.com/gogo/googleapis v1.4.0 => github.com/gogo/googleapis v1.3.2
## explicit ## explicit
@ -268,10 +268,10 @@ github.com/opencontainers/go-digest/digestset
github.com/opencontainers/image-spec/identity github.com/opencontainers/image-spec/identity
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-rc93 # github.com/opencontainers/runc v1.0.0-rc94
## explicit ## explicit
github.com/opencontainers/runc/libcontainer/user github.com/opencontainers/runc/libcontainer/user
# github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d # github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
## explicit ## explicit
github.com/opencontainers/runtime-spec/specs-go github.com/opencontainers/runtime-spec/specs-go
# github.com/opencontainers/selinux v1.8.0 # github.com/opencontainers/selinux v1.8.0