forked from rosa/hakurei
df0bb877db
This is useful for external container tooling. Signed-off-by: Ophestra <cat@gensokyo.uk>
164 lines
3.4 KiB
Go
164 lines
3.4 KiB
Go
package rosa
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
"os"
|
|
"sync"
|
|
"syscall"
|
|
|
|
"hakurei.app/fhs"
|
|
"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 {
|
|
// Whether to exclude ianaEtc.
|
|
minimal bool
|
|
}
|
|
|
|
// NewEtc returns a [pkg.Artifact] containing deterministic elements of /etc.
|
|
func NewEtc(minimal bool) pkg.Artifact {
|
|
return cureEtc{minimal}
|
|
}
|
|
|
|
// 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 []KV{
|
|
{"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.minimal {
|
|
iana, _ := t.GetArtifact(ianaEtc)
|
|
|
|
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 writes whether iana-etc is populated.
|
|
func (a cureEtc) Params(ctx *pkg.IContext) {
|
|
if !a.minimal {
|
|
ctx.WriteUint32(1)
|
|
} else {
|
|
ctx.WriteUint32(0)
|
|
}
|
|
}
|
|
|
|
func init() {
|
|
pkg.Register(kindEtc, func(r *pkg.IRReader) pkg.Artifact {
|
|
a := cureEtc{}
|
|
if r.ReadUint32() == 0 {
|
|
a.minimal = true
|
|
}
|
|
if _, ok := r.Finalise(); ok {
|
|
panic(pkg.ErrUnexpectedChecksum)
|
|
}
|
|
return a
|
|
})
|
|
}
|
|
|
|
// 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.minimal {
|
|
return []pkg.Artifact{ianaEtc}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// String returns a hardcoded reporting name.
|
|
func (a cureEtc) String() string {
|
|
if a.minimal {
|
|
return "cure-etc-minimal"
|
|
}
|
|
return "cure-etc"
|
|
}
|
|
|
|
// ianaEtc is an unpacked iana-etc release.
|
|
var ianaEtc = newFromGitHubRelease(
|
|
"Mic92/iana-etc",
|
|
"20251215",
|
|
"iana-etc-20251215.tar.gz",
|
|
"kvKz0gW_rGG5QaNK9ZWmWu1IEgYAdmhj_wR7DYrh3axDfIql_clGRHmelP7525NJ",
|
|
pkg.Gzip,
|
|
)
|
|
|
|
var (
|
|
resolvconfPath pkg.ExecPath
|
|
resolvconfOnce sync.Once
|
|
)
|
|
|
|
// resolvconf returns a hardcoded /etc/resolv.conf file.
|
|
func resolvconf() pkg.ExecPath {
|
|
resolvconfOnce.Do(func() {
|
|
resolvconfPath = pkg.Path(
|
|
fhs.AbsEtc.Append("resolv.conf"), false,
|
|
pkg.NewFile("resolv.conf", []byte(`
|
|
nameserver 1.1.1.1
|
|
nameserver 1.0.0.1
|
|
`)),
|
|
)
|
|
})
|
|
return resolvconfPath
|
|
}
|