aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/rosa/etc.go
blob: 11687295a43d679fefae5a836dfa849a048e5c36 (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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package rosa

import (
	"errors"
	"io"
	"os"
	"syscall"

	"hakurei.app/internal/pkg"
)

// cureEtc contains deterministic elements of /etc, made available as part of
// [Toolchain]. This silences test suites expecting certain standard files to be
// available in /etc.
type cureEtc struct {
	// Optional via newIANAEtc.
	iana pkg.Artifact
}

// Cure writes hardcoded configuration to files under etc.
func (a cureEtc) Cure(t *pkg.FContext) (err error) {
	etc := t.GetWorkDir().Append("etc")
	if err = os.MkdirAll(etc.String(), 0700); err != nil {
		return
	}
	for _, f := range [][2]string{
		{"hosts", "127.0.0.1 localhost cure cure-net\n"},
		{"passwd", `root:x:0:0:System administrator:/proc/nonexistent:/bin/sh
cure:x:1023:1023:Cure:/usr/src:/bin/sh
nobody:x:65534:65534:Overflow user:/proc/nonexistent:/system/bin/false
`},
		{"group", `root:x:0:
cure:x:1023:
nobody:x:65534:
`},
	} {
		if err = os.WriteFile(
			etc.Append(f[0]).String(),
			[]byte(f[1]),
			0400,
		); err != nil {
			return
		}
	}

	if a.iana != nil {
		iana, _ := t.GetArtifact(a.iana)

		buf := make([]byte, syscall.Getpagesize()<<3)
		for _, name := range []string{
			"protocols",
			"services",
		} {
			var dst, src *os.File
			if dst, err = os.OpenFile(
				etc.Append(name).String(),
				syscall.O_CREAT|syscall.O_EXCL|syscall.O_WRONLY,
				0400,
			); err != nil {
				return
			}

			if src, err = os.Open(
				iana.Append(name).String(),
			); err != nil {
				_ = dst.Close()
				return
			}

			_, err = io.CopyBuffer(dst, src, buf)
			closeErrs := [...]error{
				dst.Close(),
				src.Close(),
			}
			if err != nil {
				return
			} else if err = errors.Join(closeErrs[:]...); err != nil {
				return
			}
		}
	}

	return os.Chmod(etc.String(), 0500)
}

// Kind returns the hardcoded [pkg.Kind] value.
func (cureEtc) Kind() pkg.Kind { return kindEtc }

// Params is a noop.
func (cureEtc) Params(*pkg.IContext) {}

// IsExclusive returns false: Cure performs a few trivial filesystem writes.
func (cureEtc) IsExclusive() bool { return false }

// Dependencies returns a slice containing the backing iana-etc release.
func (a cureEtc) Dependencies() []pkg.Artifact {
	if a.iana != nil {
		return []pkg.Artifact{a.iana}
	}
	return nil
}

// String returns a hardcoded reporting name.
func (a cureEtc) String() string {
	if a.iana == nil {
		return "cure-etc-minimal"
	}
	return "cure-etc"
}

// newIANAEtc returns an unpacked iana-etc release.
func newIANAEtc() pkg.Artifact {
	const (
		version  = "20251215"
		checksum = "kvKz0gW_rGG5QaNK9ZWmWu1IEgYAdmhj_wR7DYrh3axDfIql_clGRHmelP7525NJ"
	)
	return pkg.NewHTTPGetTar(
		nil, "https://github.com/Mic92/iana-etc/releases/download/"+
			version+"/iana-etc-"+version+".tar.gz",
		mustDecode(checksum),
		pkg.TarGzip,
	)
}