From a2a291791c6447528d3b1abc1ec57c7b213730b6 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Mon, 15 Sep 2025 02:30:47 +0900 Subject: internal/sys: separate hsu uid cache This begins the effort of the removal of the sys package. Signed-off-by: Ophestra --- internal/sys/std.go | 99 ++++++++++------------------------------------------- 1 file changed, 18 insertions(+), 81 deletions(-) (limited to 'internal/sys/std.go') diff --git a/internal/sys/std.go b/internal/sys/std.go index c46bdd58..24b36fa2 100644 --- a/internal/sys/std.go +++ b/internal/sys/std.go @@ -2,16 +2,13 @@ package sys import ( "errors" - "fmt" "io/fs" "log" "os" "os/exec" "os/user" "path/filepath" - "strconv" "sync" - "syscall" "hakurei.app/container" "hakurei.app/hst" @@ -23,13 +20,7 @@ import ( type Std struct { paths hst.Paths pathsOnce sync.Once - - uidOnce sync.Once - uidCopy map[int]struct { - uid int - err error - } - uidMu sync.RWMutex + Hsu } func (s *Std) Getuid() int { return os.Getuid() } @@ -53,81 +44,27 @@ func (s *Std) Paths() hst.Paths { s.pathsOnce.Do(func() { if userid, err := GetUserID(s); err != nil { // TODO(ophestra): this duplicates code in cmd/hakurei/command.go, keep this up to date until removal - if m, ok := container.GetErrorMessage(err); ok { - if m != "\x00" { - log.Print(m) - } - } else { - log.Println("cannot obtain user id from hsu:", err) - } hlog.BeforeExit() - s.Exit(1) + const fallback = "cannot obtain user id from hsu:" + + // this indicates the error message has already reached stderr, outside the current process's control; + // this is only reached when hsu fails for any reason, as a second error message following hsu is confusing + if errors.Is(err, ErrHsuAccess) { + hlog.Verbose("*"+fallback, err) + os.Exit(1) + return + } + + m, ok := container.GetErrorMessage(err) + if !ok { + log.Fatalln(fallback, err) + return + } + + log.Fatal(m) } else { CopyPaths(s, &s.paths, userid) } }) return s.paths } - -// this is a temporary placeholder until this package is removed -type wrappedError struct { - Err error - Msg string -} - -func (e *wrappedError) Error() string { return e.Err.Error() } -func (e *wrappedError) Unwrap() error { return e.Err } -func (e *wrappedError) Message() string { return e.Msg } - -func (s *Std) Uid(identity int) (int, error) { - s.uidOnce.Do(func() { - s.uidCopy = make(map[int]struct { - uid int - err error - }) - }) - - { - s.uidMu.RLock() - u, ok := s.uidCopy[identity] - s.uidMu.RUnlock() - if ok { - return u.uid, u.err - } - } - - s.uidMu.Lock() - defer s.uidMu.Unlock() - - u := struct { - uid int - err error - }{} - defer func() { s.uidCopy[identity] = u }() - - u.uid = -1 - hsuPath := internal.MustHsuPath() - - cmd := exec.Command(hsuPath) - cmd.Path = hsuPath - cmd.Stderr = os.Stderr // pass through fatal messages - cmd.Env = []string{"HAKUREI_APP_ID=" + strconv.Itoa(identity)} - cmd.Dir = container.FHSRoot - var ( - p []byte - exitError *exec.ExitError - ) - - if p, u.err = cmd.Output(); u.err == nil { - u.uid, u.err = strconv.Atoi(string(p)) - if u.err != nil { - u.err = &wrappedError{u.err, "invalid uid string from hsu"} - } - } else if errors.As(u.err, &exitError) && exitError != nil && exitError.ExitCode() == 1 { - // hsu prints an error message in this case - u.err = &wrappedError{syscall.EACCES, "\x00"} // this drops the message, handled in cmd/hakurei/command.go - } else if os.IsNotExist(u.err) { - u.err = &wrappedError{os.ErrNotExist, fmt.Sprintf("the setuid helper is missing: %s", hsuPath)} - } - return u.uid, u.err -} -- cgit v1.3.1