Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions capability/capability.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ func NewFile2(path string) (Capabilities, error) {

// LastCap returns highest valid capability of the running kernel,
// or an error if it can not be obtained.
//
// See also: [ListSupported].
func LastCap() (Cap, error) {
return lastCap()
}
52 changes: 39 additions & 13 deletions capability/capability_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@ import (
"testing"
)

// Based on the fact Go 1.18+ supports Linux >= 2.6.32, and
// - CAP_MAC_ADMIN (33) was added in 2.6.25;
// - CAP_SYSLOG (34) was added in 2.6.38;
// - CAP_CHECKPOINT_RESTORE (40) was added in 5.9, and it is
// the last added capability as of today (July 2024);
//
// LastCap return value should be between minLastCap and maxLastCap.
const (
minLastCap = CAP_MAC_ADMIN
maxLastCap = CAP_CHECKPOINT_RESTORE
)

func TestLastCap(t *testing.T) {
last, err := LastCap()
switch runtime.GOOS {
Expand All @@ -24,21 +36,35 @@ func TestLastCap(t *testing.T) {
}

// Sanity checks (Linux only).
//
// Based on the fact Go 1.18+ supports Linux >= 2.6.32, and
// - CAP_MAC_ADMIN (33) was added in 2.6.25;
// - CAP_SYSLOG (34) was added in 2.6.38;
// - CAP_CHECKPOINT_RESTORE (40) was added in 5.9, and it is
// the last added capability as of today (July 2024);
// LastCap return value should be between minCap and maxCap.
minCap := CAP_MAC_ADMIN
maxCap := CAP_CHECKPOINT_RESTORE
if last < minCap {
if last < minLastCap {
t.Fatalf("LastCap returned %d (%s), expected >= %d (%s)",
last, last, minCap, minCap)
last, last, minLastCap, minLastCap)
}
if last > maxCap {
if last > maxLastCap {
t.Fatalf("LastCap returned %d, expected <= %d (%s). Package needs to be updated.",
last, maxCap, maxCap)
last, maxLastCap, maxLastCap)
}
}

func TestListSupported(t *testing.T) {
list, err := ListSupported()
switch runtime.GOOS {
case "linux":
if err != nil {
t.Fatal(err)
}
default:
if err == nil {
t.Fatal(runtime.GOOS, ": want error, got nil")
}
}
if runtime.GOOS != "linux" {
return
}
// Sanity check (Linux only).
t.Logf("got +%v (len %d)", list, len(list))
minLen := int(minLastCap) + 1
if len(list) < minLen {
t.Fatalf("result is too short (got %d, want %d): +%v", len(list), minLen, list)
}
}
27 changes: 27 additions & 0 deletions capability/enum.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

package capability

import "slices"

type CapType uint

func (c CapType) String() string {
Expand Down Expand Up @@ -301,3 +303,28 @@ const (
// Introduced in kernel 5.9
CAP_CHECKPOINT_RESTORE = Cap(40)
)

// List returns the list of all capabilities known to the package.
//
// Deprecated: use [ListKnown] or [ListSupported] instead.
func List() []Cap {
return ListKnown()
}

// ListKnown returns the list of all capabilities known to the package.
func ListKnown() []Cap {
return list()
}

// ListSupported retuns the list of all capabilities known to the package,
// except those that are not supported by the currently running Linux kernel.
func ListSupported() ([]Cap, error) {
last, err := LastCap()
if err != nil {
return nil, err
}
return slices.DeleteFunc(list(), func(c Cap) bool {
// Remove caps not supported by the kernel.
return c > last
}), nil
}
5 changes: 2 additions & 3 deletions capability/enum_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions capability/enumgen/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type generator struct {
}

func (g *generator) writeHeader() {
g.buf.WriteString("// generated file; DO NOT EDIT - use go generate in directory with source\n")
g.buf.WriteString("// Code generated by go generate; DO NOT EDIT.\n")
g.buf.WriteString("\n")
g.buf.WriteString("package capability")
}
Expand All @@ -43,8 +43,7 @@ func (g *generator) writeStringFunc() {

func (g *generator) writeListFunc() {
g.buf.WriteString("\n")
g.buf.WriteString("// List returns list of all supported capabilities\n")
g.buf.WriteString("func List() []Cap {\n")
g.buf.WriteString("func list() []Cap {\n")
g.buf.WriteString("return []Cap{\n")
for _, cap := range g.caps {
fmt.Fprintf(&g.buf, "%s,\n", cap)
Expand Down
Loading