diff --git a/.gitignore b/.gitignore index 3aa6369..c8b9dc2 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ .*.sw[po] +/dist +/qemu.pid +/test-initrd.cpio diff --git a/Dockerfile b/Dockerfile index d253ffd..1344d08 100644 --- a/Dockerfile +++ b/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"] diff --git a/alpine/alpine-minirootfs-3.15.0-x86_64.tar.gz b/alpine/alpine-minirootfs-3.15.0-x86_64.tar.gz new file mode 100644 index 0000000..9f3091c Binary files /dev/null and b/alpine/alpine-minirootfs-3.15.0-x86_64.tar.gz differ diff --git a/boot-v1.go b/boot-v1.go new file mode 100644 index 0000000..d64caed --- /dev/null +++ b/boot-v1.go @@ -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) +} diff --git a/boot-v2.go b/boot-v2.go new file mode 100644 index 0000000..2600406 --- /dev/null +++ b/boot-v2.go @@ -0,0 +1,5 @@ +package main + +func bootV2() { + fatal("boot v2 not finished") +} diff --git a/build-layer b/build-layer index 296c18e..5a4e449 100755 --- a/build-layer +++ b/build-layer @@ -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 diff --git a/cpiocat/cpiocat.go b/cpiocat/cpiocat.go new file mode 100644 index 0000000..7a19509 --- /dev/null +++ b/cpiocat/cpiocat.go @@ -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 +} diff --git a/go.mod b/go.mod index 0cc4186..0e9be77 100644 --- a/go.mod +++ b/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 diff --git a/go.sum b/go.sum index 55c3d5e..2baf361 100644 --- a/go.sum +++ b/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= diff --git a/main.go b/main.go index 985fb64..d754da3 100644 --- a/main.go +++ b/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) + } } } diff --git a/modd.conf b/modd.conf index 5746255..40c9178 100644 --- a/modd.conf +++ b/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 } diff --git a/modd.test.conf b/modd.test.conf new file mode 100644 index 0000000..f7dd9d9 --- /dev/null +++ b/modd.test.conf @@ -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 $(