From 7330cf70eac2e320bef27e86b82ffcf713fe388a Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Fri, 3 Jul 2020 23:05:46 +0200 Subject: [PATCH] feat: add IsTooManyError helper Signed-off-by: Manfred Touron <94029+moul@users.noreply.github.com> --- Makefile | 33 +++++++++++++++++++++++++++++++++ openfiles.go | 27 ++++++++++++++++++++++++--- openfiles_linux.go | 22 +++++++++++++++++++--- openfiles_test.go | 23 +++++++++++++++++++++++ 4 files changed, 99 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index edb0a8f..078aa6f 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,36 @@ GOPKG ?= moul.io/openfiles +.PHONY: test-archs +test-archs: + GOOS=darwin GOARCH=386 go test -v -c -o /dev/null + GOOS=darwin GOARCH=amd64 go test -v -c -o /dev/null + GOOS=linux GOARCH=386 go test -v -c -o /dev/null + GOOS=linux GOARCH=amd64 go test -v -c -o /dev/null + GOOS=linux GOARCH=arm go test -v -c -o /dev/null + GOOS=linux GOARCH=arm64 go test -v -c -o /dev/null + GOOS=linux GOARCH=ppc64 go test -v -c -o /dev/null + GOOS=linux GOARCH=ppc64le go test -v -c -o /dev/null + GOOS=linux GOARCH=mips go test -v -c -o /dev/null + GOOS=linux GOARCH=mipsle go test -v -c -o /dev/null + GOOS=linux GOARCH=mips64 go test -v -c -o /dev/null + GOOS=linux GOARCH=mips64le go test -v -c -o /dev/null + GOOS=linux GOARCH=s390x go test -v -c -o /dev/null + GOOS=js GOARCH=wasm go test -v -c -o /dev/null + GOOS=dragonfly GOARCH=amd64 go test -v -c -o /dev/null + GOOS=freebsd GOARCH=386 go test -v -c -o /dev/null + GOOS=freebsd GOARCH=amd64 go test -v -c -o /dev/null + GOOS=freebsd GOARCH=arm go test -v -c -o /dev/null + GOOS=netbsd GOARCH=386 go test -v -c -o /dev/null + GOOS=netbsd GOARCH=amd64 go test -v -c -o /dev/null + GOOS=netbsd GOARCH=arm go test -v -c -o /dev/null + GOOS=openbsd GOARCH=386 go test -v -c -o /dev/null + GOOS=openbsd GOARCH=amd64 go test -v -c -o /dev/null + GOOS=openbsd GOARCH=arm go test -v -c -o /dev/null + GOOS=plan9 GOARCH=386 go test -v -c -o /dev/null + GOOS=plan9 GOARCH=amd64 go test -v -c -o /dev/null + GOOS=plan9 GOARCH=arm go test -v -c -o /dev/null + GOOS=solaris GOARCH=amd64 go test -v -c -o /dev/null + GOOS=windows GOARCH=386 go test -v -c -o /dev/null + GOOS=windows GOARCH=amd64 go test -v -c -o /dev/null + include rules.mk diff --git a/openfiles.go b/openfiles.go index 7283369..1109809 100644 --- a/openfiles.go +++ b/openfiles.go @@ -1,6 +1,27 @@ package openfiles -import "errors" +import ( + "errors" + "os" + "syscall" +) -// ErrNotSupported indicates an unsupported GOOS or GOARCH -var ErrNotSupported = errors.New("not supported environment") +var ( + // ErrNotSupported is raised on an unsupported GOOS or GOARCH + ErrNotSupported = errors.New("moul.io/openfiles: not supported environment") + + // ErrInternal represents an internal error + ErrInternal = errors.New("moul.io/openfiles: internal error") +) + +func IsTooManyError(err error) bool { + if err == syscall.EMFILE { + return true + } + + if err, isPathError := err.(*os.PathError); isPathError { + return err.Err == syscall.EMFILE + } + + return false +} diff --git a/openfiles_linux.go b/openfiles_linux.go index 4d94406..2467bf9 100644 --- a/openfiles_linux.go +++ b/openfiles_linux.go @@ -5,14 +5,30 @@ package openfiles import ( "fmt" "os" - "path/filepath" ) func Count() (int64, error) { pid := os.Getpid() - m, err := filepath.Glob(fmt.Sprintf("/proc/%d/fd/*", pid)) + dir := fmt.Sprintf("/proc/%d/fd", pid) + fi, err := os.Stat(dir) if err != nil { return -1, err } - return int64(len(m)), nil + + if !fi.IsDir() { + return -1, ErrInternal + } + + d, err := os.Open(dir) // guardrails-disable-line + if err != nil { + return -1, err + } + defer d.Close() + + fds, err := d.Readdirnames(-1) + if err != nil { + return -1, err + } + + return int64(len(fds)), nil } diff --git a/openfiles_test.go b/openfiles_test.go index 498b4ec..7f3a597 100644 --- a/openfiles_test.go +++ b/openfiles_test.go @@ -1,6 +1,10 @@ package openfiles_test import ( + "errors" + "fmt" + "os" + "syscall" "testing" "moul.io/openfiles" @@ -19,3 +23,22 @@ func TestCount(t *testing.T) { } t.Logf("nofile: %d", nofile) } + +func TestIsTooManyError(t *testing.T) { + cases := []struct { + input error + isTooMany bool + }{ + {errors.New("blah"), false}, + {errors.New("too many open files"), false}, + {syscall.EMFILE, true}, + {&os.PathError{Err: syscall.EMFILE}, true}, + } + + for _, tt := range cases { + k := fmt.Sprintf("%v", tt.input) + t.Run(k, func(t *testing.T) { + + }) + } +}