prepare boot v2
This commit is contained in:
parent
a794bb3887
commit
8e86579004
3
.gitignore
vendored
3
.gitignore
vendored
@ -1 +1,4 @@
|
||||
.*.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
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
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"]
|
||||
|
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
|
||||
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
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
|
||||
|
||||
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
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/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
147
main.go
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
15
modd.conf
15
modd.conf
@ -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
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