24 Commits

Author SHA1 Message Date
Caleb Connolly
b54044a605 hookscripts: glob hook directories 2023-04-18 17:53:37 +01:00
Caleb Connolly
f0544999db filelist/hookfiles: encapsulate dir searching out of slurpFiles
Move the directory searching / globbing code out of slurpFiles and into
the filelist module so it can be used elsewhere.
2023-04-07 02:56:38 +01:00
Clayton Craft
8fac3004a6 archive: fix up documentation for AddItems 2023-03-19 23:14:18 -07:00
Clayton Craft
a15a3ad781 filelist/modules: don't print "skipping..." when dir not found
I think this was still causing some confusion, since it *might* look
like a failure when in reality it's not. I think it's important that
mkinitfs prints when it is adding something, and doesn't print when it
is *not* adding something, so that it should be clear if something
expected is missing and when something unexpected is included... without
having to sort out which is which every time the output is read.
2023-03-19 23:06:09 -07:00
Clayton Craft
1e8580a0a1 archive: New() can't fail, so don't return an error type
It could fail if the system can't allocate memory or something
undeterministic like that, but in that case it's best to just let the
runtime panic.
2023-03-19 22:05:55 -07:00
Clayton Craft
e6ee43826d doc/mkinitfs: add section on boot-deploy 2023-03-19 16:36:11 -07:00
Clayton Craft
7bdd68800d doc/mkinitfs.1: add design goals 2023-03-19 16:35:51 -07:00
Clayton Craft
80098d29c6 misc:TimeFunc: reduce printed time precision
Now:
        10:57:41.737665 initramfs-extra completed in: 0.33s
        ...
        10:57:42.008587 boot-deploy completed in: 0.27s
        10:57:42.012973 mkinitfs completed in: 0.90s

Times is just truncated, not rounding, since it's simpler (no dependency
on the math module), and I'm not sure if anyone cares for what this
function prints. If there is a desire to return to higher precision
later, it could be enabled by a new flag.

fixes https://gitlab.com/postmarketOS/postmarketos-mkinitfs/-/issues/25
2023-03-13 11:03:48 -07:00
Clayton Craft
67f1839ddc filelist/modules: fix order of struct items to reduce memory
Another one found by fieldalignment:
        modules.go:18:14: struct with 32 pointer bytes could be 24

Probably not going to matter much... but let's just get rid of the
warning.
2023-03-12 20:39:01 -07:00
Clayton Craft
baf76ed614 archive: fix order of struct items to reduce memory usage
Found by fieldalignment:
        archive.go:46:14: struct with 88 pointer bytes could be 56
        archive.go:66:18: struct with 24 pointer bytes could be 16

The first one probably doesn't matter that much, there's only like 2 of
those objects that are instantiated at runtime. However, there are many
ArchiveItems (hundreds or more depending on the archives compositions)
2023-03-12 20:37:10 -07:00
Clayton Craft
27e271b904 filelist/modules: print a message when including modules from deviceinfo
fixes https://gitlab.com/postmarketOS/postmarketos-mkinitfs/-/issues/24
2023-03-12 20:36:29 -07:00
Clayton Craft
1ac85b12fe filelist/modules: print search dir before searching dir
This will allow printing status for deviceinfo modules earlier in the
function, in a way that makes more sense.
2023-03-12 20:36:24 -07:00
Clayton Craft
f7f42bc2d4 filelist/modules: handle errors from filepath.Walk 2023-03-12 20:18:51 -07:00
Clayton Craft
c62a1f9ddb filelist/modules: remove outdated reference in error message 2023-03-12 20:05:55 -07:00
Clayton Craft
c9de619f98 filelist/hookscripts: use the correct path for scripts 2023-03-10 23:23:53 -08:00
Clayton Craft
a519769979 filelist/*: use "searching" instead of "including" in top-level msg
When this is printed, it's about to search the given path for stuff to
slurp up, but it hasn't actually included anything yet. Using
"Including" here was kinda confusing, so this changes it to use
"Searching for." Hopefully that's better!
2023-03-10 22:33:32 -08:00
Clayton Craft
128a48dd24 cmd/mkinitfs: re-add support for setting initramfs-extra compression 2023-03-10 22:22:51 -08:00
Clayton Craft
499136e83a cmd/mkinitfs: move printing compression info to generateArchive 2023-03-10 22:22:51 -08:00
Clayton Craft
78f8fa32fb deviceinfo: add initfs_extra_compression
For configuring the archive compression parameters for the
initramfs-extra archive.
2023-03-10 22:22:50 -08:00
Clayton Craft
d03257981f bootdeploy: add context to kernel copy fd close error (MR 33) 2023-03-06 22:20:11 -08:00
Clayton Craft
307fb1889f bootdeploy: use original kernel filename when calling boot-deploy (MR 33)
fixes #21
2023-03-06 22:20:07 -08:00
Clayton Craft
fa3d3268d7 bootdeploy: catch any errors when closing kernel file copy fd 2023-03-05 23:56:58 -08:00
Clayton Craft
8b67848d5c filelist/modules: print search path for modules
By doing so, it adds more useful context to this:

         - Including kernel modules
         -- Unable to find dir, skipping...
         - Including kernel modules
         -- Unable to find dir, skipping...
2023-03-05 23:54:15 -08:00
Clayton Craft
31ab72edbc cmd/mkinitfs: configure log to print milliseconds
Useful for timing each step of generating the initramfs without having
to add a bunch of calls to the "time func" function
2023-03-01 22:57:53 -08:00
12 changed files with 140 additions and 66 deletions

View File

@@ -47,6 +47,8 @@ func main() {
return
}
log.Default().SetFlags(log.Lmicroseconds)
deviceinfoFile := "/etc/deviceinfo"
if exists, err := misc.Exists(deviceinfoFile); !exists {
log.Printf("NOTE: %q not found, this file is required by mkinitfs.\n", deviceinfoFile)
@@ -63,10 +65,6 @@ func main() {
return
}
// deviceinfo.InitfsCompression needs a little more post-processing
compressionFormat, compressionLevel := archive.ExtractFormatLevel(devinfo.InitfsCompression)
log.Printf("Using compression format %s with level %q\n", compressionFormat, compressionLevel)
defer misc.TimeFunc(time.Now(), "mkinitfs")
kernVer, err := osutil.GetKernelVersion()
@@ -95,13 +93,15 @@ func main() {
log.Print("Generating for kernel version: ", kernVer)
log.Print("Output directory: ", *outDir)
// deviceinfo.InitfsCompression needs a little more post-processing
compressionFormat, compressionLevel := archive.ExtractFormatLevel(devinfo.InitfsCompression)
if err := generateArchive("initramfs", compressionFormat, compressionLevel, workDir, []filelist.FileLister{
hookdirs.New("/usr/share/mkinitfs/dirs"),
hookdirs.New("/etc/mkinitfs/dirs"),
hookfiles.New("/usr/share/mkinitfs/files"),
hookfiles.New("/etc/mkinitfs/files"),
hookscripts.New("/usr/share/mkinitfs/hooks"),
hookscripts.New("/etc/mkinitfs/hooks"),
hookscripts.New("/usr/share/mkinitfs/hooks", "/hooks"),
hookscripts.New("/etc/mkinitfs/hooks", "/hooks"),
modules.New(strings.Fields(devinfo.ModulesInitfs), "/usr/share/mkinitfs/modules"),
modules.New([]string{}, "/etc/mkinitfs/modules"),
}); err != nil {
@@ -111,14 +111,13 @@ func main() {
return
}
// Note: compression disabled for initramfs-extra, since it slows down boot
// and can add more requirements to the initramfs (e.g. need to add support
// for extracting zstd)
if err := generateArchive("initramfs-extra", archive.FormatNone, archive.LevelDefault, workDir, []filelist.FileLister{
// deviceinfo.InitfsExtraCompression needs a little more post-processing
compressionFormat, compressionLevel = archive.ExtractFormatLevel(devinfo.InitfsExtraCompression)
if err := generateArchive("initramfs-extra", compressionFormat, compressionLevel, 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"),
hookscripts.New("/usr/share/mkinitfs/hooks-extra", "/hooks-extra"),
hookscripts.New("/etc/mkinitfs/hooks-extra", "/hooks-extra"),
modules.New([]string{}, "/usr/share/mkinitfs/modules-extra"),
modules.New([]string{}, "/etc/mkinitfs/modules-extra"),
osksdl.New(devinfo.MesaDriver),
@@ -150,11 +149,10 @@ func bootDeploy(workDir, outDir, ubootBoardname string) error {
func generateArchive(name string, format archive.CompressFormat, level archive.CompressLevel, path string, features []filelist.FileLister) error {
log.Printf("== Generating %s ==\n", name)
log.Printf("- Using compression format %s with level %q\n", format, level)
defer misc.TimeFunc(time.Now(), name)
a, err := archive.New(format, level)
if err != nil {
return err
}
a := archive.New(format, level)
fs := initramfs.New(features)
if err := a.AddItems(fs); err != nil {

View File

@@ -24,6 +24,15 @@ is purely to generate the archive(s). mkinitfs does call *boot-deploy* after
creating the archive(s), in order to install/deploy them and any other relevant
boot-related items onto the system.
Design goals of this project are:
- Support as many distros as possible
- Simplify configuration, while still giving multiple opportunities to set or override defaults
- Execute an external app to do any boot install/setup finalization
- One such app is here: https://gitlab.com/postmarketOS/boot-deploy
- But implementation can be anything, see the section on *BOOT-DEPLOY*
for more info
# DEVICEINFO
The canonical deviceinfo "specification" is at
@@ -33,6 +42,7 @@ mkinitfs reads deviceinfo values from */etc/deviceinfo*. The following variables
are *required* by mkinitfs:
- deviceinfo_initfs_compression
- deviceinfo_initfs_extra_compression
- deviceinfo_mesa_driver
- deviceinfo_modules_initfs
- deviceinfo_uboot_boardname
@@ -40,6 +50,10 @@ are *required* by mkinitfs:
It is a design goal to keep the number of required variables from deviceinfo to
a bare minimum, and to require only variables that don't hold lists of things.
*NOTE*: When deviceinfo_initfs_extra_compression is set, make sure that the
necessary tools to extract the configured archive format are in the initramfs
archive.
# DIRECTORIES
The following directories are used by mkinitfs to generate the initramfs and
@@ -112,6 +126,30 @@ create/manage. mkinitfs reads configuration from */usr/share/mkinitfs* first, an
directories to create within the initramfs. There is no *-extra* variant,
since directories are of negligible size.
# BOOT-DEPLOY
After generating archives, mkinitfs will execute *boot-deploy*, using *$PATH* to
search for the app. The following commandline options are passed to it:
*-i* <initramfs filename>
Currently this is hardcoded to be "initramfs"
*-k* <kernel filename>
*-d* <work directory>
Path to the directory containing the build artifacts from mkinitfs.
*-o* <destination directory>
Path to the directory that boot-deploy should use as its root when
installing files.
*initramfs-extra*
This string is the filename of the initramfs-extra archive.
# AUTHORS
*Clayton Craft* <clayton@craftyguy.net>

View File

@@ -44,14 +44,14 @@ const (
)
type Archive struct {
items archiveItems
cpioWriter *cpio.Writer
buf *bytes.Buffer
compress_format CompressFormat
compress_level CompressLevel
items archiveItems
}
func New(format CompressFormat, level CompressLevel) (*Archive, error) {
func New(format CompressFormat, level CompressLevel) *Archive {
buf := new(bytes.Buffer)
archive := &Archive{
cpioWriter: cpio.NewWriter(buf),
@@ -60,12 +60,12 @@ func New(format CompressFormat, level CompressLevel) (*Archive, error) {
compress_level: level,
}
return archive, nil
return archive
}
type archiveItem struct {
sourcePath string
header *cpio.Header
sourcePath string
}
type archiveItems struct {
@@ -184,10 +184,11 @@ func (archive *Archive) Write(path string, mode os.FileMode) error {
return nil
}
// Adds the given items in the map to the archive. The map format is {source path:dest path}.
// Internally this just calls AddItem on each key,value pair in the map.
func (archive *Archive) AddItems(f filelist.FileLister) error {
list, err := f.List()
// AddItems adds the given items in the map to the archive. The map format is
// {source path:dest path}. Internally this just calls AddItem on each
// key,value pair in the map.
func (archive *Archive) AddItems(flister filelist.FileLister) error {
list, err := flister.List()
if err != nil {
return err
}

View File

@@ -2,10 +2,12 @@ package bootdeploy
import (
"errors"
"fmt"
"io"
"log"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
)
@@ -68,7 +70,8 @@ func bootDeploy(workDir string, outDir string) error {
}
defer kernFd.Close()
kernFileCopy, err := os.Create(filepath.Join(workDir, "vmlinuz"))
kernFilename := path.Base(kernFile)
kernFileCopy, err := os.Create(filepath.Join(workDir, kernFilename))
if err != nil {
return err
}
@@ -76,12 +79,14 @@ func bootDeploy(workDir string, outDir string) error {
if _, err = io.Copy(kernFileCopy, kernFd); err != nil {
return err
}
kernFileCopy.Close()
if err := kernFileCopy.Close(); err != nil {
return fmt.Errorf("error closing %s: %w", kernFilename, err)
}
// 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",
"-k", kernFilename,
"-d", workDir,
"-o", outDir,
"initramfs-extra")

View File

@@ -1,6 +1,12 @@
package filelist
import "sync"
import (
"fmt"
"path/filepath"
"sync"
"gitlab.com/postmarketOS/postmarketos-mkinitfs/internal/misc"
)
type FileLister interface {
List() (*FileList, error)
@@ -45,6 +51,26 @@ func (f *FileList) Import(src *FileList) {
}
}
func (f *FileList) AddGlobbed(src string, dest string) error {
fFiles, err := misc.GetFiles([]string{src}, true)
if err != nil {
return fmt.Errorf("unable to add %q: %w", src, err)
}
// loop over all returned files from GetFile
for _, file := range fFiles {
if len(fFiles) > 1 {
// Glob with arbitrary subdirectories, so we need to
// remove the src path and prepend the dest path
f.Add(file, filepath.Join(dest, file[len(src):]))
} else {
// dest path specified, and only 1 file
f.Add(file, dest)
}
}
return nil
}
// iterate through the list and and send each one as a new File over the
// returned channel
func (f *FileList) IterItems() <-chan File {

View File

@@ -23,7 +23,7 @@ func New(path string) *HookDirs {
}
func (h *HookDirs) List() (*filelist.FileList, error) {
log.Printf("- Creating directories specified in %s", h.path)
log.Printf("- Searching for directories specified in %s", h.path)
files := filelist.NewFileList()
fileInfo, err := os.ReadDir(h.path)

View File

@@ -10,7 +10,6 @@ import (
"strings"
"gitlab.com/postmarketOS/postmarketos-mkinitfs/internal/filelist"
"gitlab.com/postmarketOS/postmarketos-mkinitfs/internal/misc"
)
type HookFiles struct {
@@ -26,7 +25,7 @@ func New(filePath string) *HookFiles {
}
func (h *HookFiles) List() (*filelist.FileList, error) {
log.Printf("- Including file lists from %s", h.filePath)
log.Printf("- Searching for file lists from %s", h.filePath)
files := filelist.NewFileList()
fileInfo, err := os.ReadDir(h.filePath)
@@ -60,22 +59,13 @@ func slurpFiles(fd io.Reader) (*filelist.FileList, error) {
for s.Scan() {
src, dest, has_dest := strings.Cut(s.Text(), ":")
fFiles, err := misc.GetFiles([]string{src}, true)
if err != nil {
return nil, fmt.Errorf("unable to add %q: %w", src, err)
if !has_dest {
dest = src
}
// loop over all returned files from GetFile
for _, file := range fFiles {
if !has_dest {
files.Add(file, file)
} else if len(fFiles) > 1 {
// Don't support specifying dest if src was a glob
// NOTE: this could support this later...
files.Add(file, file)
} else {
// dest path specified, and only 1 file
files.Add(file, dest)
}
err := files.AddGlobbed(src, dest)
if err != nil {
return nil, err
}
}

View File

@@ -9,19 +9,22 @@ import (
)
type HookScripts struct {
destPath string
scriptsDir string
}
// New returns a new HookScripts that will use the given path to provide a list
// of script files.
func New(scriptsDir string) *HookScripts {
// of script files. The destination for each script it set to destPath, using
// the original file name.
func New(scriptsDir string, destPath string) *HookScripts {
return &HookScripts{
destPath: destPath,
scriptsDir: scriptsDir,
}
}
func (h *HookScripts) List() (*filelist.FileList, error) {
log.Printf("- Including hook scripts from %s", h.scriptsDir)
log.Printf("- Searching for hook scripts from %s", h.scriptsDir)
files := filelist.NewFileList()
@@ -32,7 +35,13 @@ func (h *HookScripts) List() (*filelist.FileList, error) {
}
for _, file := range fileInfo {
path := filepath.Join(h.scriptsDir, file.Name())
files.Add(path, path)
if file.IsDir() {
log.Printf("-- Including dir %s\n", path)
files.AddGlobbed(filepath.Join(path, "*"), filepath.Join(h.destPath, file.Name()))
} else {
log.Printf("-- Including script: %s\n", path)
files.Add(path, filepath.Join(h.destPath, file.Name()))
}
}
return files, nil
}

View File

@@ -16,8 +16,8 @@ import (
)
type Modules struct {
modulesList []string
modulesListPath string
modulesList []string
}
// New returns a new Modules that will use the given moduleto provide a list
@@ -30,8 +30,6 @@ func New(modulesList []string, modulesListPath string) *Modules {
}
func (m *Modules) List() (*filelist.FileList, error) {
log.Println("- Including kernel modules")
kernVer, err := osutil.GetKernelVersion()
if err != nil {
return nil, err
@@ -55,20 +53,23 @@ func (m *Modules) List() (*filelist.FileList, error) {
}
// slurp up given list of modules
for _, module := range m.modulesList {
if modFilelist, err := getModule(module, modDir); err != nil {
return nil, fmt.Errorf("getInitfsModules: unable to get modules from deviceinfo: %w", err)
} else {
for _, file := range modFilelist {
files.Add(file, file)
if len(m.modulesList) > 0 {
log.Printf("-- Including kernel modules from deviceinfo")
for _, module := range m.modulesList {
if modFilelist, err := getModule(module, modDir); err != nil {
return nil, fmt.Errorf("unable to get modules from deviceinfo: %w", err)
} else {
for _, file := range modFilelist {
files.Add(file, file)
}
}
}
}
// slurp up modules from lists in modulesListPath
log.Printf("- Searching for kernel modules from %s", m.modulesListPath)
fileInfo, err := os.ReadDir(m.modulesListPath)
if err != nil {
log.Println("-- Unable to find dir, skipping...")
return files, nil
}
for _, file := range fileInfo {
@@ -126,7 +127,11 @@ func slurpModules(fd io.Reader, modDir string) (*filelist.FileList, error) {
}
func getModulesInDir(modPath string) (files []string, err error) {
err = filepath.Walk(modPath, func(path string, f os.FileInfo, err error) error {
err = filepath.Walk(modPath, func(path string, _ os.FileInfo, err error) error {
if err != nil {
// Unable to walk path
return err
}
if filepath.Ext(path) != ".ko" && filepath.Ext(path) != ".xz" {
return nil
}

View File

@@ -45,7 +45,7 @@ func RemoveDuplicates(in []string) (out []string) {
// defer misc.TimeFunc(time.Now(), "foo")
func TimeFunc(start time.Time, name string) {
elapsed := time.Since(start)
log.Printf("%s completed in: %s", name, elapsed)
log.Printf("%s completed in: %.2fs", name, elapsed.Seconds())
}
// Exists tests if the given file/dir exists or not. Returns any errors related

View File

@@ -14,10 +14,11 @@ import (
)
type DeviceInfo struct {
InitfsCompression string
MesaDriver string
ModulesInitfs string
UbootBoardname string
InitfsCompression string
InitfsExtraCompression string
MesaDriver string
ModulesInitfs string
UbootBoardname string
}
func ReadDeviceinfo(file string) (DeviceInfo, error) {

View File

@@ -21,6 +21,7 @@ func TestNameToField(t *testing.T) {
{"deviceinfo_modules_initfs", "ModulesInitfs"},
{"modules_initfs", "ModulesInitfs"},
{"deviceinfo_modules_initfs___", "ModulesInitfs"},
{"deviceinfo_initfs_extra_compression", "InitfsExtraCompression"},
}
for _, table := range tables {