aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/sys/std.go
blob: 24b36fa2442beefa93ef8acdba3154a605f940be (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package sys

import (
	"errors"
	"io/fs"
	"log"
	"os"
	"os/exec"
	"os/user"
	"path/filepath"
	"sync"

	"hakurei.app/container"
	"hakurei.app/hst"
	"hakurei.app/internal"
	"hakurei.app/internal/hlog"
)

// Std implements System using the standard library.
type Std struct {
	paths     hst.Paths
	pathsOnce sync.Once
	Hsu
}

func (s *Std) Getuid() int                                  { return os.Getuid() }
func (s *Std) Getgid() int                                  { return os.Getgid() }
func (s *Std) LookupEnv(key string) (string, bool)          { return os.LookupEnv(key) }
func (s *Std) TempDir() string                              { return os.TempDir() }
func (s *Std) LookPath(file string) (string, error)         { return exec.LookPath(file) }
func (s *Std) MustExecutable() string                       { return container.MustExecutable() }
func (s *Std) LookupGroup(name string) (*user.Group, error) { return user.LookupGroup(name) }
func (s *Std) ReadDir(name string) ([]os.DirEntry, error)   { return os.ReadDir(name) }
func (s *Std) Stat(name string) (fs.FileInfo, error)        { return os.Stat(name) }
func (s *Std) Open(name string) (fs.File, error)            { return os.Open(name) }
func (s *Std) EvalSymlinks(path string) (string, error)     { return filepath.EvalSymlinks(path) }
func (s *Std) Exit(code int)                                { internal.Exit(code) }
func (s *Std) Println(v ...any)                             { hlog.Verbose(v...) }
func (s *Std) Printf(format string, v ...any)               { hlog.Verbosef(format, v...) }

const xdgRuntimeDir = "XDG_RUNTIME_DIR"

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
			hlog.BeforeExit()
			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
}