aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/app/dispatcher.go
blob: deecfa920f9a80ae874452c1c0d9ec536eecb3a1 (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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package app

import (
	"log"
	"os"
	"os/exec"
	"os/user"
	"path/filepath"

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

// syscallDispatcher provides methods that make state-dependent system calls as part of their behaviour.
type syscallDispatcher interface {
	// new starts a goroutine with a new instance of syscallDispatcher.
	// A syscallDispatcher must never be used in any goroutine other than the one owning it,
	// just synchronising access is not enough, as this is for test instrumentation.
	new(f func(k syscallDispatcher))

	// getuid provides [os.Getuid].
	getuid() int
	// getgid provides [os.Getgid].
	getgid() int
	// lookupEnv provides [os.LookupEnv].
	lookupEnv(key string) (string, bool)
	// stat provides [os.Stat].
	stat(name string) (os.FileInfo, error)
	// readdir provides [os.ReadDir].
	readdir(name string) ([]os.DirEntry, error)
	// tempdir provides [os.TempDir].
	tempdir() string

	// evalSymlinks provides [filepath.EvalSymlinks].
	evalSymlinks(path string) (string, error)

	// lookPath provides exec.LookPath.
	lookPath(file string) (string, error)

	// lookupGroupId calls [user.LookupGroup] and returns the Gid field of the resulting [user.Group] struct.
	lookupGroupId(name string) (string, error)

	// cmdOutput provides the Output method of [exec.Cmd].
	cmdOutput(cmd *exec.Cmd) ([]byte, error)

	// overflowUid provides [container.OverflowUid].
	overflowUid() int
	// overflowGid provides [container.OverflowGid].
	overflowGid() int

	// mustHsuPath provides [internal.MustHsuPath].
	mustHsuPath() string

	// fatalf provides [log.Fatalf].
	fatalf(format string, v ...any)

	isVerbose() bool
	verbose(v ...any)
	verbosef(format string, v ...any)
}

// direct implements syscallDispatcher on the current kernel.
type direct struct{}

func (k direct) new(f func(k syscallDispatcher)) { go f(k) }

func (direct) getuid() int                                { return os.Getuid() }
func (direct) getgid() int                                { return os.Getgid() }
func (direct) lookupEnv(key string) (string, bool)        { return os.LookupEnv(key) }
func (direct) stat(name string) (os.FileInfo, error)      { return os.Stat(name) }
func (direct) readdir(name string) ([]os.DirEntry, error) { return os.ReadDir(name) }
func (direct) tempdir() string                            { return os.TempDir() }

func (direct) evalSymlinks(path string) (string, error) { return filepath.EvalSymlinks(path) }

func (direct) lookPath(file string) (string, error) { return exec.LookPath(file) }

func (direct) lookupGroupId(name string) (gid string, err error) {
	var group *user.Group
	group, err = user.LookupGroup(name)
	if group != nil {
		gid = group.Gid
	}
	return
}

func (direct) cmdOutput(cmd *exec.Cmd) ([]byte, error) { return cmd.Output() }

func (direct) overflowUid() int { return container.OverflowUid() }
func (direct) overflowGid() int { return container.OverflowGid() }

func (direct) mustHsuPath() string { return internal.MustHsuPath() }

func (direct) fatalf(format string, v ...any) { log.Fatalf(format, v...) }

func (k direct) isVerbose() bool                { return hlog.Load() }
func (direct) verbose(v ...any)                 { hlog.Verbose(v...) }
func (direct) verbosef(format string, v ...any) { hlog.Verbosef(format, v...) }