diff options
Diffstat (limited to 'container')
| -rw-r--r-- | container/dispatcher.go | 16 | ||||
| -rw-r--r-- | container/errors.go | 27 |
2 files changed, 39 insertions, 4 deletions
diff --git a/container/dispatcher.go b/container/dispatcher.go index 4636a469..1bad7527 100644 --- a/container/dispatcher.go +++ b/container/dispatcher.go @@ -228,11 +228,19 @@ func (direct) seccompLoad(rules []std.NativeRule, flags seccomp.ExportFlag) erro func (direct) notify(c chan<- os.Signal, sig ...os.Signal) { signal.Notify(c, sig...) } func (direct) start(c *exec.Cmd) error { return c.Start() } func (direct) signal(c *exec.Cmd, sig os.Signal) error { return c.Process.Signal(sig) } -func (direct) evalSymlinks(path string) (string, error) { return filepath.EvalSymlinks(path) } +func (direct) evalSymlinks(path string) (string, error) { + return retryExp(func() (string, error) { + return filepath.EvalSymlinks(path) + }, syscall.EACCES) +} -func (direct) exit(code int) { os.Exit(code) } -func (direct) getpid() int { return os.Getpid() } -func (direct) stat(name string) (os.FileInfo, error) { return os.Stat(name) } +func (direct) exit(code int) { os.Exit(code) } +func (direct) getpid() int { return os.Getpid() } +func (direct) stat(name string) (os.FileInfo, error) { + return retryExp(func() (os.FileInfo, error) { + return os.Stat(name) + }, syscall.EACCES) +} func (direct) mkdir(name string, perm os.FileMode) error { return os.Mkdir(name, perm) } func (direct) mkdirTemp(dir, pattern string) (string, error) { return os.MkdirTemp(dir, pattern) } func (direct) mkdirAll(path string, perm os.FileMode) error { return os.MkdirAll(path, perm) } diff --git a/container/errors.go b/container/errors.go index 053bdeb7..8975dec4 100644 --- a/container/errors.go +++ b/container/errors.go @@ -4,12 +4,39 @@ import ( "errors" "os" "syscall" + "time" "hakurei.app/check" "hakurei.app/message" "hakurei.app/vfs" ) +// retryExp retries f if the resulting error is equivalent to e according to +// [errors.Is], up to 8 times. +func retryExp[T any](f func() (T, error), e error) (v T, err error) { + const statRetry = 8 // 64 ms + var n int + d := 256 * time.Microsecond + +retry: + v, err = f() + if err != nil { + if !errors.Is(err, e) { + return + } + + n++ + if n == statRetry { + return + } + + time.Sleep(d) + d *= 2 + goto retry + } + return +} + // messageFromError returns a printable error message for a supported concrete type. func messageFromError(err error) (m string, ok bool) { if m, ok = messagePrefixP[MountError]("cannot ", err); ok { |
