Files
hakurei/internal/rosa/etc.go
Ophestra fa94155f42 internal/rosa/etc: resolv.conf
Required by programs that download from the internet in measured execArtifact.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-02-06 21:04:59 +09:00

164 lines
3.4 KiB
Go

package rosa
import (
"errors"
"io"
"os"
"sync"
"syscall"
"hakurei.app/container/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 {
// 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 writes whether iana-etc is populated.
func (a cureEtc) Params(ctx *pkg.IContext) {
if a.iana != nil {
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.iana = r.Next()
}
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.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,
)
}
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
}