prepare boot v2

This commit is contained in:
Mikaël Cluseau 2022-02-04 19:59:42 +01:00
parent a794bb3887
commit 8e86579004
18 changed files with 383 additions and 158 deletions

3
.gitignore vendored
View File

@ -1 +1,4 @@
.*.sw[po]
/dist
/qemu.pid
/test-initrd.cpio

View File

@ -1,19 +1,18 @@
# ------------------------------------------------------------------------
from mcluseau/golang-builder:1.15.5 as build
from alpine:3.15
# ------------------------------------------------------------------------
from alpine:3.12
add alpine/alpine-minirootfs-3.15.0-x86_64.tar.gz /layer/
env busybox_v=1.28.1-defconfig-multiarch \
arch=x86_64
run apk add --update curl
run apk update
run apk add -p /layer lvm2-static
workdir /layer
add build-layer /
run /build-layer
run rm -rf usr/share/apk var/cache/apk
copy --from=build /go/bin/initrd /layer/init
#add build-layer /
#run /build-layer
copy dist/init /layer/init
entrypoint ["sh","-c","find |cpio -H newc -o |base64"]

Binary file not shown.

147
boot-v1.go Normal file
View File

@ -0,0 +1,147 @@
package main
import (
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
"syscall"
"time"
yaml "gopkg.in/yaml.v2"
"novit.nc/direktil/pkg/sysfs"
)
func bootV1() {
// find and mount /boot
bootMatch := param("boot", "")
bootMounted := false
if bootMatch != "" {
bootFS := param("boot.fs", "vfat")
for i := 0; ; i++ {
devNames := sysfs.DeviceByProperty("block", bootMatch)
if len(devNames) == 0 {
if i > 30 {
fatal("boot partition not found after 30s")
}
log.Print("boot partition not found, retrying")
time.Sleep(1 * time.Second)
continue
}
devFile := filepath.Join("/dev", devNames[0])
log.Print("boot partition found: ", devFile)
mount(devFile, "/boot", bootFS, bootMountFlags, "")
bootMounted = true
break
}
} else {
log.Print("Assuming /boot is already populated.")
}
// load config
cfgPath := param("config", "/boot/config.yaml")
cfgBytes, err := ioutil.ReadFile(cfgPath)
if err != nil {
fatalf("failed to read %s: %v", cfgPath, err)
}
cfg := &config{}
if err := yaml.Unmarshal(cfgBytes, cfg); err != nil {
fatal("failed to load config: ", err)
}
// mount layers
if len(cfg.Layers) == 0 {
fatal("no layers configured!")
}
log.Printf("wanted layers: %q", cfg.Layers)
layersInMemory := paramBool("layers-in-mem", false)
const layersInMemDir = "/layers-in-mem"
if layersInMemory {
mkdir(layersInMemDir, 0700)
mount("layers-mem", layersInMemDir, "tmpfs", 0, "")
}
lowers := make([]string, len(cfg.Layers))
for i, layer := range cfg.Layers {
path := layerPath(layer)
info, err := os.Stat(path)
if err != nil {
fatal(err)
}
log.Printf("layer %s found (%d bytes)", layer, info.Size())
if layersInMemory {
log.Print(" copying to memory...")
targetPath := filepath.Join(layersInMemDir, layer)
cp(path, targetPath)
path = targetPath
}
dir := "/layers/" + layer
lowers[i] = dir
loopDev := fmt.Sprintf("/dev/loop%d", i)
losetup(loopDev, path)
mount(loopDev, dir, "squashfs", layerMountFlags, "")
}
// prepare system root
mount("mem", "/changes", "tmpfs", 0, "")
mkdir("/changes/workdir", 0755)
mkdir("/changes/upperdir", 0755)
mount("overlay", "/system", "overlay", rootMountFlags,
"lowerdir="+strings.Join(lowers, ":")+",upperdir=/changes/upperdir,workdir=/changes/workdir")
if bootMounted {
if layersInMemory {
if err := syscall.Unmount("/boot", 0); err != nil {
log.Print("WARNING: failed to unmount /boot: ", err)
time.Sleep(2 * time.Second)
}
} else {
mount("/boot", "/system/boot", "", syscall.MS_BIND, "")
}
}
// - write configuration
log.Print("writing /config.yaml")
if err := ioutil.WriteFile("/system/config.yaml", cfgBytes, 0600); err != nil {
fatal("failed: ", err)
}
// - write files
for _, fileDef := range cfg.Files {
log.Print("writing ", fileDef.Path)
filePath := filepath.Join("/system", fileDef.Path)
ioutil.WriteFile(filePath, []byte(fileDef.Content), fileDef.Mode)
}
// clean zombies
cleanZombies()
// switch root
log.Print("switching root")
err = syscall.Exec("/sbin/switch_root", []string{"switch_root",
"-c", "/dev/console", "/system", "/sbin/init"}, os.Environ())
fatal("switch_root failed: ", err)
}

5
boot-v2.go Normal file
View File

@ -0,0 +1,5 @@
package main
func bootV2() {
fatal("boot v2 not finished")
}

View File

@ -1,14 +1,6 @@
#! /bin/sh
set -ex
mkdir dev
mknod dev/null -m 0666 c 1 3
mknod dev/tty -m 0666 c 5 0
mknod dev/console -m 0600 c 5 1
mkdir sys proc bin sbin usr usr/bin usr/sbin
curl -L -o bin/busybox https://busybox.net/downloads/binaries/$busybox_v/busybox-$arch
chmod +x bin/busybox
chroot . /bin/busybox --install -s

67
cpiocat/cpiocat.go Normal file
View File

@ -0,0 +1,67 @@
package cpiocat
import (
"io"
"os"
"github.com/cavaliergopher/cpio"
)
func Append(out io.Writer, in io.Reader, filesToAppend []string) (err error) {
cout := cpio.NewWriter(out)
cin := cpio.NewReader(in)
for {
var hdr *cpio.Header
hdr, err = cin.Next()
if err != nil {
if err == io.EOF {
break
}
return
}
err = cout.WriteHeader(hdr)
if err != nil {
return
}
_, err = io.Copy(cout, cin)
if err != nil {
return
}
}
for _, file := range filesToAppend {
err = func() (err error) {
stat, err := os.Stat(file)
if err != nil {
return
}
hdr := &cpio.Header{
Name: file,
Size: stat.Size(),
Mode: cpio.FileMode(stat.Mode()),
}
cout.WriteHeader(hdr)
f, err := os.Open(file)
if err != nil {
return
}
defer f.Close()
_, err = io.Copy(cout, f)
return
}()
if err != nil {
return
}
}
err = cout.Close()
return
}

22
go.mod
View File

@ -1,10 +1,24 @@
module novit.nc/direktil/initrd
require (
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221
gopkg.in/yaml.v2 v2.3.0
github.com/cavaliergopher/cpio v1.0.1
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
gopkg.in/yaml.v2 v2.4.0
novit.nc/direktil/pkg v0.0.0-20191211161950-96b0448b84c2
)
go 1.13
require (
github.com/charmbracelet/bubbletea v0.19.3 // indirect
github.com/containerd/console v1.0.2 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.13 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b // indirect
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.9.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 // indirect
)
go 1.18

35
go.sum
View File

@ -1,15 +1,48 @@
github.com/cavaliergopher/cpio v1.0.1 h1:KQFSeKmZhv0cr+kawA3a0xTQCU4QxXF1vhU7P7av2KM=
github.com/cavaliergopher/cpio v1.0.1/go.mod h1:pBdaqQjnvXxdS/6CvNDwIANIFSP0xRKI16PX4xejRQc=
github.com/charmbracelet/bubbletea v0.19.3 h1:OKeO/Y13rQQqt4snX+lePB0QrnW80UdrMNolnCcmoAw=
github.com/charmbracelet/bubbletea v0.19.3/go.mod h1:VuXF2pToRxDUHcBUcPmCRUHRvFATM4Ckb/ql1rBl3KA=
github.com/containerd/console v1.0.2 h1:Pi6D+aZXM+oUw1czuKgH5IJ+y0jhYcwBJfx5/Ghn9dE=
github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA=
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34=
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho=
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
github.com/muesli/termenv v0.9.0 h1:wnbOaGz+LUR3jNT0zOzinPnyDaCZUQRZj9GxK8eRVl8=
github.com/muesli/termenv v0.9.0/go.mod h1:R/LzAKf+suGs4IsO95y7+7DpFHO0KABgnZqtlyx2mBw=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 h1:XDXtA5hveEEV8JB2l7nhMTp3t3cHp9ZpwcdjqyEWLlo=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20210422114643-f5beecf764ed h1:Ei4bQjjpYUsS4efOUz+5Nz++IVkHk87n2zBA0NxBWc0=
golang.org/x/term v0.0.0-20210422114643-f5beecf764ed/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@ -17,5 +50,7 @@ gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
novit.nc/direktil/pkg v0.0.0-20191211161950-96b0448b84c2 h1:LN3K19gAJ1GamJXkzXAQmjbl8xCV7utqdxTTrM89MMc=
novit.nc/direktil/pkg v0.0.0-20191211161950-96b0448b84c2/go.mod h1:zwTVO6U0tXFEaga73megQIBK7yVIKZJVePaIh/UtdfU=

147
main.go
View File

@ -3,24 +3,19 @@ package main
import (
"fmt"
"io"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"syscall"
"time"
"golang.org/x/term"
yaml "gopkg.in/yaml.v2"
"novit.nc/direktil/pkg/sysfs"
)
const (
// VERSION is the current version of init
VERSION = "Direktil init v1.0"
VERSION = "Direktil init v2.0"
rootMountFlags = 0
bootMountFlags = syscall.MS_NOEXEC | syscall.MS_NODEV | syscall.MS_NOSUID | syscall.MS_RDONLY
@ -45,135 +40,16 @@ func main() {
bootVersion = param("version", "current")
log.Printf("booting system %q", bootVersion)
// find and mount /boot
bootMatch := param("boot", "")
bootMounted := false
if bootMatch != "" {
bootFS := param("boot.fs", "vfat")
for i := 0; ; i++ {
devNames := sysfs.DeviceByProperty("block", bootMatch)
if len(devNames) == 0 {
if i > 30 {
fatal("boot partition not found after 30s")
}
log.Print("boot partition not found, retrying")
time.Sleep(1 * time.Second)
continue
}
devFile := filepath.Join("/dev", devNames[0])
log.Print("boot partition found: ", devFile)
mount(devFile, "/boot", bootFS, bootMountFlags, "")
bootMounted = true
break
}
} else {
log.Print("Assuming /boot is already populated.")
}
// load config
cfgPath := param("config", "/boot/config.yaml")
cfgBytes, err := ioutil.ReadFile(cfgPath)
_, err := os.Stat("/config.yaml")
if err != nil {
fatalf("failed to read %s: %v", cfgPath, err)
}
cfg := &config{}
if err := yaml.Unmarshal(cfgBytes, cfg); err != nil {
fatal("failed to load config: ", err)
}
// mount layers
if len(cfg.Layers) == 0 {
fatal("no layers configured!")
}
log.Printf("wanted layers: %q", cfg.Layers)
layersInMemory := paramBool("layers-in-mem", false)
const layersInMemDir = "/layers-in-mem"
if layersInMemory {
mkdir(layersInMemDir, 0700)
mount("layers-mem", layersInMemDir, "tmpfs", 0, "")
}
lowers := make([]string, len(cfg.Layers))
for i, layer := range cfg.Layers {
path := layerPath(layer)
info, err := os.Stat(path)
if err != nil {
fatal(err)
if os.IsNotExist(err) {
bootV1()
return
}
log.Printf("layer %s found (%d bytes)", layer, info.Size())
if layersInMemory {
log.Print(" copying to memory...")
targetPath := filepath.Join(layersInMemDir, layer)
cp(path, targetPath)
path = targetPath
}
dir := "/layers/" + layer
lowers[i] = dir
loopDev := fmt.Sprintf("/dev/loop%d", i)
losetup(loopDev, path)
mount(loopDev, dir, "squashfs", layerMountFlags, "")
fatal("stat failed: ", err)
}
// prepare system root
mount("mem", "/changes", "tmpfs", 0, "")
mkdir("/changes/workdir", 0755)
mkdir("/changes/upperdir", 0755)
mount("overlay", "/system", "overlay", rootMountFlags,
"lowerdir="+strings.Join(lowers, ":")+",upperdir=/changes/upperdir,workdir=/changes/workdir")
if bootMounted {
if layersInMemory {
if err := syscall.Unmount("/boot", 0); err != nil {
log.Print("WARNING: failed to unmount /boot: ", err)
time.Sleep(2 * time.Second)
}
} else {
mount("/boot", "/system/boot", "", syscall.MS_BIND, "")
}
}
// - write configuration
log.Print("writing /config.yaml")
if err := ioutil.WriteFile("/system/config.yaml", cfgBytes, 0600); err != nil {
fatal("failed: ", err)
}
// - write files
for _, fileDef := range cfg.Files {
log.Print("writing ", fileDef.Path)
filePath := filepath.Join("/system", fileDef.Path)
ioutil.WriteFile(filePath, []byte(fileDef.Content), fileDef.Mode)
}
// clean zombies
cleanZombies()
// switch root
log.Print("switching root")
err = syscall.Exec("/sbin/switch_root", []string{"switch_root",
"-c", "/dev/console", "/system", "/sbin/init"}, os.Environ())
fatal("switch_root failed: ", err)
bootV2()
}
func layerPath(name string) string {
@ -193,7 +69,7 @@ func fatalf(pattern string, v ...interface{}) {
}
func die() {
fmt.Println("\nwill reboot in 1 minute; press r to reboot now, o to power off")
fmt.Println("\nwill reboot in 1 minute; press r to reboot now, o to power off, s to get a shell")
deadline := time.Now().Add(time.Minute)
@ -207,11 +83,18 @@ func die() {
break
}
fmt.Println(string(b))
switch b[0] {
case 'o':
syscall.Reboot(syscall.LINUX_REBOOT_CMD_POWER_OFF)
case 'r':
syscall.Reboot(syscall.LINUX_REBOOT_CMD_RESTART)
case 's':
err = syscall.Exec("/bin/ash", []string{"/bin/ash"}, os.Environ())
if err != nil {
fmt.Println("failed to start the shell:", err)
}
}
}

View File

@ -1,6 +1,13 @@
go.??? *.go {
modd.conf {}
go.??? **/*.go {
prep: go test ./...
prep: dockb -t dkl-initrd .
prep: docker run dkl-initrd | docker exec -i dls sh -c "base64 -d >/var/lib/direktil/dist/initrd/1.0.7 && rm -rfv /var/lib/direktil/cache/*"
prep: curl -H'Autorization: Bearer adm1n' localhost:7606/hosts/m1/boot.iso >/tmp/m1-boot.iso
prep: mkdir -p dist
prep: go build -o dist/init -trimpath -ldflags "-extldflags '-static -pthread'" .
prep: go build -o dist/ ./tools/...
}
dist/init Dockerfile {
prep: docker build -t dkl-initrd .
prep: docker run dkl-initrd | base64 -d >dist/initrd
}

8
modd.test.conf Normal file
View File

@ -0,0 +1,8 @@
modd.test.conf {}
dist/initrd test-initrd/* {
prep: cp -f dist/initrd test-initrd.cpio
prep: cd test-initrd && ../dist/cpiocat <../dist/initrd >../test-initrd.cpio *
prep: if cpio -t -F test-initrd.cpio 2>&1 |grep bytes.of.junk; then echo "bad cpio archive"; exit 1; fi
prep: kill $(<qemu.pid)
}

6
run-test.sh Executable file
View File

@ -0,0 +1,6 @@
#! /bin/sh
exec qemu-system-x86_64 -pidfile qemu.pid -kernel test-kernel -initrd test-initrd.cpio \
-smp 2 -m 2048 \
-nographic -serial mon:stdio -append 'console=ttyS0'
# -display curses

43
test-initrd/config.yaml Normal file
View File

@ -0,0 +1,43 @@
---
# early system configuration
modules: /modules.sqfs
networks:
- name: main
ifaces:
- var: iface
n: 1
regexps:
- eth.*
- veth.*
- eno.*
- enp.*
script: |
# hello
. /env
ip a add $address dev $iface
ip route add default via $gateway
ip li set $iface up
lvm:
pvs:
n: 1
regexps:
- /dev/nvme[0-9]+n[0-9]+p[0-9]+
- /dev/vd[a-z]+[0-9]+
- /dev/sd[a-z]+[0-9]+
defaults:
fs: ext4
tags: [ encrypt ]
lvs:
- name: bootstrap
tags: [ bootstrap, -encrypt ]
size: 2g
- name: dls
mountPoint: /var/lib/direktil
size: 100%FREE

2
test-initrd/env Normal file
View File

@ -0,0 +1,2 @@
gateway=192.168.1.1/24
address=192.168.1.27/24

BIN
test-initrd/modules.sqfs Normal file

Binary file not shown.

BIN
test-kernel Normal file

Binary file not shown.

14
tools/cpiocat/main.go Normal file
View File

@ -0,0 +1,14 @@
package main
import (
"flag"
"os"
"novit.nc/direktil/initrd/cpiocat"
)
func main() {
flag.Parse()
cpiocat.Append(os.Stdout, os.Stdin, flag.Args())
}