prepare boot v2
This commit is contained in:
parent
a794bb3887
commit
8e86579004
3
.gitignore
vendored
3
.gitignore
vendored
@ -1 +1,4 @@
|
|||||||
.*.sw[po]
|
.*.sw[po]
|
||||||
|
/dist
|
||||||
|
/qemu.pid
|
||||||
|
/test-initrd.cpio
|
||||||
|
19
Dockerfile
19
Dockerfile
@ -1,19 +1,18 @@
|
|||||||
# ------------------------------------------------------------------------
|
# ------------------------------------------------------------------------
|
||||||
from mcluseau/golang-builder:1.15.5 as build
|
from alpine:3.15
|
||||||
|
|
||||||
# ------------------------------------------------------------------------
|
add alpine/alpine-minirootfs-3.15.0-x86_64.tar.gz /layer/
|
||||||
from alpine:3.12
|
|
||||||
|
|
||||||
env busybox_v=1.28.1-defconfig-multiarch \
|
run apk update
|
||||||
arch=x86_64
|
run apk add -p /layer lvm2-static
|
||||||
|
|
||||||
run apk add --update curl
|
|
||||||
|
|
||||||
workdir /layer
|
workdir /layer
|
||||||
|
|
||||||
add build-layer /
|
run rm -rf usr/share/apk var/cache/apk
|
||||||
run /build-layer
|
|
||||||
|
|
||||||
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"]
|
entrypoint ["sh","-c","find |cpio -H newc -o |base64"]
|
||||||
|
BIN
alpine/alpine-minirootfs-3.15.0-x86_64.tar.gz
Normal file
BIN
alpine/alpine-minirootfs-3.15.0-x86_64.tar.gz
Normal file
Binary file not shown.
147
boot-v1.go
Normal file
147
boot-v1.go
Normal 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
5
boot-v2.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
func bootV2() {
|
||||||
|
fatal("boot v2 not finished")
|
||||||
|
}
|
@ -1,14 +1,6 @@
|
|||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
set -ex
|
set -ex
|
||||||
|
|
||||||
mkdir dev
|
|
||||||
mknod dev/null -m 0666 c 1 3
|
mknod dev/null -m 0666 c 1 3
|
||||||
mknod dev/tty -m 0666 c 5 0
|
mknod dev/tty -m 0666 c 5 0
|
||||||
mknod dev/console -m 0600 c 5 1
|
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
67
cpiocat/cpiocat.go
Normal 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
22
go.mod
@ -1,10 +1,24 @@
|
|||||||
module novit.nc/direktil/initrd
|
module novit.nc/direktil/initrd
|
||||||
|
|
||||||
require (
|
require (
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect
|
github.com/cavaliergopher/cpio v1.0.1
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
|
||||||
gopkg.in/yaml.v2 v2.3.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
novit.nc/direktil/pkg v0.0.0-20191211161950-96b0448b84c2
|
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
35
go.sum
@ -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 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
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/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 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
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=
|
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 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
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 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
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 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-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 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 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
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.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
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.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 h1:LN3K19gAJ1GamJXkzXAQmjbl8xCV7utqdxTTrM89MMc=
|
||||||
novit.nc/direktil/pkg v0.0.0-20191211161950-96b0448b84c2/go.mod h1:zwTVO6U0tXFEaga73megQIBK7yVIKZJVePaIh/UtdfU=
|
novit.nc/direktil/pkg v0.0.0-20191211161950-96b0448b84c2/go.mod h1:zwTVO6U0tXFEaga73megQIBK7yVIKZJVePaIh/UtdfU=
|
||||||
|
149
main.go
149
main.go
@ -3,24 +3,19 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/term"
|
"golang.org/x/term"
|
||||||
yaml "gopkg.in/yaml.v2"
|
|
||||||
"novit.nc/direktil/pkg/sysfs"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// VERSION is the current version of init
|
// VERSION is the current version of init
|
||||||
VERSION = "Direktil init v1.0"
|
VERSION = "Direktil init v2.0"
|
||||||
|
|
||||||
rootMountFlags = 0
|
rootMountFlags = 0
|
||||||
bootMountFlags = syscall.MS_NOEXEC | syscall.MS_NODEV | syscall.MS_NOSUID | syscall.MS_RDONLY
|
bootMountFlags = syscall.MS_NOEXEC | syscall.MS_NODEV | syscall.MS_NOSUID | syscall.MS_RDONLY
|
||||||
@ -45,135 +40,16 @@ func main() {
|
|||||||
bootVersion = param("version", "current")
|
bootVersion = param("version", "current")
|
||||||
log.Printf("booting system %q", bootVersion)
|
log.Printf("booting system %q", bootVersion)
|
||||||
|
|
||||||
// find and mount /boot
|
_, err := os.Stat("/config.yaml")
|
||||||
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 {
|
if err != nil {
|
||||||
fatalf("failed to read %s: %v", cfgPath, err)
|
if os.IsNotExist(err) {
|
||||||
|
bootV1()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fatal("stat failed: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := &config{}
|
bootV2()
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func layerPath(name string) string {
|
func layerPath(name string) string {
|
||||||
@ -193,7 +69,7 @@ func fatalf(pattern string, v ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func die() {
|
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)
|
deadline := time.Now().Add(time.Minute)
|
||||||
|
|
||||||
@ -207,11 +83,18 @@ func die() {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(b))
|
||||||
|
|
||||||
switch b[0] {
|
switch b[0] {
|
||||||
case 'o':
|
case 'o':
|
||||||
syscall.Reboot(syscall.LINUX_REBOOT_CMD_POWER_OFF)
|
syscall.Reboot(syscall.LINUX_REBOOT_CMD_POWER_OFF)
|
||||||
case 'r':
|
case 'r':
|
||||||
syscall.Reboot(syscall.LINUX_REBOOT_CMD_RESTART)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
15
modd.conf
15
modd.conf
@ -1,6 +1,13 @@
|
|||||||
go.??? *.go {
|
modd.conf {}
|
||||||
|
|
||||||
|
go.??? **/*.go {
|
||||||
prep: go test ./...
|
prep: go test ./...
|
||||||
prep: dockb -t dkl-initrd .
|
prep: mkdir -p dist
|
||||||
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: go build -o dist/init -trimpath -ldflags "-extldflags '-static -pthread'" .
|
||||||
prep: curl -H'Autorization: Bearer adm1n' localhost:7606/hosts/m1/boot.iso >/tmp/m1-boot.iso
|
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
8
modd.test.conf
Normal 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
6
run-test.sh
Executable 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
43
test-initrd/config.yaml
Normal 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
2
test-initrd/env
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
gateway=192.168.1.1/24
|
||||||
|
address=192.168.1.27/24
|
BIN
test-initrd/modules.sqfs
Normal file
BIN
test-initrd/modules.sqfs
Normal file
Binary file not shown.
BIN
test-kernel
Normal file
BIN
test-kernel
Normal file
Binary file not shown.
14
tools/cpiocat/main.go
Normal file
14
tools/cpiocat/main.go
Normal 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())
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user