Files
postmarketos-mkinitfs/cmd/mkinitfs/main.go
Clayton Craft 6f05222018 filelist/modules: add support for directories in .modules files
This is kinda janky, passing both a list of modules and a directory path
is just because we support modules in deviceinfo and in directory file
lists... Maybe one day we can move away from having modules in the
deviceinfo...
2023-02-21 00:45:58 -08:00

217 lines
5.5 KiB
Go

// Copyright 2022 Clayton Craft <clayton@craftyguy.net>
// SPDX-License-Identifier: GPL-3.0-or-later
package main
import (
"errors"
"flag"
"io"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
"gitlab.com/postmarketOS/postmarketos-mkinitfs/internal/archive"
"gitlab.com/postmarketOS/postmarketos-mkinitfs/internal/filelist"
"gitlab.com/postmarketOS/postmarketos-mkinitfs/internal/filelist/hookfiles"
"gitlab.com/postmarketOS/postmarketos-mkinitfs/internal/filelist/hookscripts"
"gitlab.com/postmarketOS/postmarketos-mkinitfs/internal/filelist/initramfs"
"gitlab.com/postmarketOS/postmarketos-mkinitfs/internal/filelist/modules"
"gitlab.com/postmarketOS/postmarketos-mkinitfs/internal/filelist/osksdl"
"gitlab.com/postmarketOS/postmarketos-mkinitfs/internal/misc"
"gitlab.com/postmarketOS/postmarketos-mkinitfs/pkgs/deviceinfo"
)
func main() {
deviceinfoFile := "/etc/deviceinfo"
if !misc.Exists(deviceinfoFile) {
log.Print("NOTE: deviceinfo (from device package) not installed yet, " +
"not building the initramfs now (it should get built later " +
"automatically.)")
return
}
devinfo, err := deviceinfo.ReadDeviceinfo(deviceinfoFile)
if err != nil {
log.Fatal(err)
}
outDir := flag.String("d", "/boot", "Directory to output initfs(-extra) and other boot files")
flag.Parse()
defer misc.TimeFunc(time.Now(), "mkinitfs")
kernVer, err := misc.GetKernelVersion()
if err != nil {
log.Fatal(err)
}
// temporary working dir
workDir, err := os.MkdirTemp("", "mkinitfs")
if err != nil {
log.Fatal("Unable to create temporary work directory:", err)
}
defer os.RemoveAll(workDir)
log.Print("Generating for kernel version: ", kernVer)
log.Print("Output directory: ", *outDir)
log.Println("== Generating initramfs ==")
if err := generateArchive("initramfs", workDir, []filelist.FileLister{
hookfiles.New("/usr/share/mkinitfs/files"),
hookfiles.New("/etc/mkinitfs/files"),
hookscripts.New("/usr/share/mkinitfs/hooks"),
hookscripts.New("/etc/mkinitfs/hooks"),
modules.New(strings.Fields(devinfo.ModulesInitfs), "/usr/share/mkinitfs/modules"),
}); err != nil {
log.Fatalf("failed to generate %q: %s\n", "initramfs", err)
}
log.Println("== Generating initramfs-extra ==")
if err := generateArchive("initramfs-extra", workDir, []filelist.FileLister{
hookfiles.New("/usr/share/mkinitfs/files-extra"),
hookfiles.New("/etc/mkinitfs/files-extra"),
hookscripts.New("/usr/share/mkinitfs/hooks-extra"),
hookscripts.New("/etc/mkinitfs/hooks-extra"),
osksdl.New(devinfo.MesaDriver),
}); err != nil {
log.Fatalf("failed to generate %q: %s\n", "initramfs-extra", err)
}
if err := copyUbootFiles(workDir, devinfo); errors.Is(err, os.ErrNotExist) {
log.Println("u-boot files copying skipped: ", err)
} else {
if err != nil {
log.Fatal("copyUbootFiles: ", err)
}
}
// Final processing of initramfs / kernel is done by boot-deploy
if err := bootDeploy(workDir, *outDir); err != nil {
log.Fatal("bootDeploy: ", err)
}
}
func bootDeploy(workDir string, outDir string) error {
// boot-deploy expects the kernel to be in the same dir as initramfs.
// Assume that the kernel is in the output dir...
log.Print("== Using boot-deploy to finalize/install files ==")
kernels, _ := filepath.Glob(filepath.Join(outDir, "vmlinuz*"))
if len(kernels) == 0 {
return errors.New("Unable to find any kernels at " + filepath.Join(outDir, "vmlinuz*"))
}
// Pick a kernel that does not have suffixes added by boot-deploy
var kernFile string
for _, f := range kernels {
if strings.HasSuffix(f, "-dtb") || strings.HasSuffix(f, "-mtk") {
continue
}
kernFile = f
break
}
kernFd, err := os.Open(kernFile)
if err != nil {
return err
}
defer kernFd.Close()
kernFileCopy, err := os.Create(filepath.Join(workDir, "vmlinuz"))
if err != nil {
return err
}
if _, err = io.Copy(kernFileCopy, kernFd); err != nil {
return err
}
kernFileCopy.Close()
// boot-deploy -i initramfs -k vmlinuz-postmarketos-rockchip -d /tmp/cpio -o /tmp/foo initramfs-extra
cmd := exec.Command("boot-deploy",
"-i", "initramfs",
"-k", "vmlinuz",
"-d", workDir,
"-o", outDir,
"initramfs-extra")
if !misc.Exists(cmd.Path) {
return errors.New("boot-deploy command not found")
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
log.Print("'boot-deploy' command failed")
return err
}
return nil
}
func Copy(srcFile, dstFile string) error {
out, err := os.Create(dstFile)
if err != nil {
return err
}
defer out.Close()
in, err := os.Open(srcFile)
if err != nil {
return err
}
defer in.Close()
_, err = io.Copy(out, in)
if err != nil {
return err
}
return nil
}
func copyUbootFiles(path string, devinfo deviceinfo.DeviceInfo) error {
if devinfo.UbootBoardname == "" {
return nil
}
srcDir := filepath.Join("/usr/share/u-boot", devinfo.UbootBoardname)
entries, err := os.ReadDir(srcDir)
if err != nil {
return err
}
for _, entry := range entries {
sourcePath := filepath.Join(srcDir, entry.Name())
destPath := filepath.Join(path, entry.Name())
if err := Copy(sourcePath, destPath); err != nil {
return err
}
}
return nil
}
func generateArchive(name string, path string, features []filelist.FileLister) error {
a, err := archive.New()
if err != nil {
return err
}
fs := initramfs.New(features)
if err := a.AddItems(fs); err != nil {
return err
}
log.Println("- Writing and verifying archive: ", name)
if err := a.Write(filepath.Join(path, name), os.FileMode(0644)); err != nil {
return err
}
return nil
}