carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1//go:build linux
2
3package hostfloor
4
5import (
6 "errors"
7 "fmt"
8 "path/filepath"
9
10 "golang.org/x/sys/unix"
11
12 "github.com/carlosframework/platform/internal/safefile"
13)
14
15// EnsureControllerDir creates <dataDir>/.hostexec, the claim controllers'
16// state directory (claim D6), and settles an existing one: a real directory
17// owned by uid:gid, mode 2770, like /data/hostguard. The floor-armed update
18// path refuses while the directory is missing (CheckControllersIdle), so
19// guard-arm creates it (Opus re-review M1-2).
20//
21// Neither dataDir nor .hostexec may be a symlink. Ownership and mode are set
22// through the opened descriptor, so a path swapped after the open changes
23// nothing but the directory that was checked. Existing records are kept.
24func EnsureControllerDir(dataDir string, uid, gid int) error {
25 if !filepath.IsAbs(dataDir) || filepath.Clean(dataDir) != dataDir {
26 return ErrFloor
27 }
28 parentDir, err := safefile.OpenDir(dataDir)
29 if err != nil {
30 return fmt.Errorf("open %s: %w", dataDir, err)
31 }
32 defer parentDir.Close()
33 parent := int(parentDir.Fd())
34 if err = unix.Mkdirat(parent, ".hostexec", 0o700); err != nil && !errors.Is(err, unix.EEXIST) {
35 return fmt.Errorf("create %s/.hostexec: %w", dataDir, err)
36 }
37 fd, err := unix.Openat(parent, ".hostexec", unix.O_RDONLY|unix.O_DIRECTORY|unix.O_NOFOLLOW|unix.O_CLOEXEC, 0)
38 if err != nil {
39 return fmt.Errorf("%w: %s/.hostexec is not a directory: %v", ErrFloor, dataDir, err)
40 }
41 defer unix.Close(fd)
42 var st unix.Stat_t
43 if err = unix.Fstat(fd, &st); err != nil {
44 return err
45 }
46 if st.Mode&unix.S_IFMT != unix.S_IFDIR {
47 return ErrFloor
48 }
49 if err = unix.Fchown(fd, uid, gid); err != nil {
50 return err
51 }
52 if err = unix.Fchmod(fd, 0o2770); err != nil {
53 return err
54 }
55 if err = unix.Fsync(fd); err != nil {
56 return err
57 }
58 return unix.Fsync(parent)
59}
60