diff --git a/proc_sys.go b/proc_sys.go new file mode 100644 index 000000000..d46533ebf --- /dev/null +++ b/proc_sys.go @@ -0,0 +1,51 @@ +// Copyright 2022 The Prometheus 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 procfs + +import ( + "fmt" + "strings" + + "github.com/prometheus/procfs/internal/util" +) + +func sysctlToPath(sysctl string) string { + return strings.Replace(sysctl, ".", "/", -1) +} + +func (fs FS) SysctlStrings(sysctl string) ([]string, error) { + value, err := util.SysReadFile(fs.proc.Path("sys", sysctlToPath(sysctl))) + if err != nil { + return nil, err + } + return strings.Fields(value), nil + +} + +func (fs FS) SysctlInts(sysctl string) ([]int, error) { + fields, err := fs.SysctlStrings(sysctl) + if err != nil { + return nil, err + } + + values := make([]int, len(fields)) + for i, f := range fields { + vp := util.NewValueParser(f) + values[i] = vp.Int() + if err := vp.Err(); err != nil { + return nil, fmt.Errorf("field %d in sysctl %s is not a valid int: %w", i, sysctl, err) + } + } + return values, nil +} diff --git a/proc_sys_test.go b/proc_sys_test.go new file mode 100644 index 000000000..2f8b867be --- /dev/null +++ b/proc_sys_test.go @@ -0,0 +1,84 @@ +// Copyright 2022 The Prometheus 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 procfs + +import ( + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestSysctlInts(t *testing.T) { + fs := getProcFixtures(t) + + for _, tc := range []struct { + sysctl string + want []int + }{ + {"kernel.random.entropy_avail", []int{3943}}, + {"vm.lowmem_reserve_ratio", []int{256, 256, 32, 0, 0}}, + } { + t.Run(tc.sysctl, func(t *testing.T) { + got, err := fs.SysctlInts(tc.sysctl) + if err != nil { + t.Fatal(err) + } + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Fatalf("unexpected syscall value(-want +got):\n%s", diff) + } + }) + } +} + +func TestSysctlStrings(t *testing.T) { + fs := getProcFixtures(t) + + for _, tc := range []struct { + sysctl string + want []string + }{ + {"kernel.seccomp.actions_avail", []string{"kill_process", "kill_thread", "trap", "errno", "trace", "log", "allow"}}, + } { + t.Run(tc.sysctl, func(t *testing.T) { + got, err := fs.SysctlStrings(tc.sysctl) + if err != nil { + t.Fatal(err) + } + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Fatalf("unexpected syscall value(-want +got):\n%s", diff) + } + }) + } +} + +func TestSysctlIntsError(t *testing.T) { + fs := getProcFixtures(t) + + for _, tc := range []struct { + sysctl string + want string + }{ + {"kernel.seccomp.actions_avail", "field 0 in sysctl kernel.seccomp.actions_avail is not a valid int: strconv.ParseInt: parsing \"kill_process\": invalid syntax"}, + } { + t.Run(tc.sysctl, func(t *testing.T) { + _, err := fs.SysctlInts(tc.sysctl) + if err == nil { + t.Fatal("expected error") + } + if diff := cmp.Diff(tc.want, err.Error()); diff != "" { + t.Fatalf("unexpected syscall value(-want +got):\n%s", diff) + } + }) + } +} diff --git a/testdata/fixtures.ttar b/testdata/fixtures.ttar index bd25048a5..40b630739 100644 --- a/testdata/fixtures.ttar +++ b/testdata/fixtures.ttar @@ -2873,6 +2873,14 @@ Lines: 1 3072 Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/proc/sys/kernel/seccomp +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/proc/sys/kernel/seccomp/actions_avail +Lines: 1 +kill_process kill_thread trap errno trace log allow +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Directory: fixtures/proc/sys/vm Mode: 775 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -