aboutsummaryrefslogtreecommitdiffhomepage
path: root/container/autoetc.go
blob: 0334ad14d76365acc4e97b5582e83a85212943da (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
package container

import (
	"encoding/gob"
	"fmt"
	"os"
	"syscall"
)

func init() { gob.Register(new(AutoEtcOp)) }

// Etc appends an [Op] that expands host /etc into a toplevel symlink mirror with /etc semantics.
// This is not a generic setup op. It is implemented here to reduce ipc overhead.
func (f *Ops) Etc(host *Absolute, prefix string) *Ops {
	e := &AutoEtcOp{prefix}
	f.Mkdir(AbsFHSEtc, 0755)
	f.Bind(host, e.hostPath(), 0)
	*f = append(*f, e)
	return f
}

type AutoEtcOp struct{ Prefix string }

func (e *AutoEtcOp) Valid() bool             { return e != nil }
func (e *AutoEtcOp) early(*setupState) error { return nil }
func (e *AutoEtcOp) apply(state *setupState) error {
	if state.nonrepeatable&nrAutoEtc != 0 {
		return msg.WrapErr(syscall.EINVAL, "autoetc is not repeatable")
	}
	state.nonrepeatable |= nrAutoEtc

	const target = sysrootPath + FHSEtc
	rel := e.hostRel() + "/"

	if err := os.MkdirAll(target, 0755); err != nil {
		return wrapErrSelf(err)
	}
	if d, err := os.ReadDir(toSysroot(e.hostPath().String())); err != nil {
		return wrapErrSelf(err)
	} else {
		for _, ent := range d {
			n := ent.Name()
			switch n {
			case ".host":

			case "passwd":
			case "group":

			case "mtab":
				if err = os.Symlink(FHSProc+"mounts", target+n); err != nil {
					return wrapErrSelf(err)
				}

			default:
				if err = os.Symlink(rel+n, target+n); err != nil {
					return wrapErrSelf(err)
				}
			}
		}
	}

	return nil
}

func (e *AutoEtcOp) hostPath() *Absolute { return AbsFHSEtc.Append(e.hostRel()) }
func (e *AutoEtcOp) hostRel() string     { return ".host/" + e.Prefix }

func (e *AutoEtcOp) Is(op Op) bool {
	ve, ok := op.(*AutoEtcOp)
	return ok && e.Valid() && ve.Valid() && *e == *ve
}
func (*AutoEtcOp) prefix() string   { return "setting up" }
func (e *AutoEtcOp) String() string { return fmt.Sprintf("auto etc %s", e.Prefix) }