Skip to content

Commit

Permalink
Refactor flags handling, add 'ls', 'cat', 'unpack' subcommands
Browse files Browse the repository at this point in the history
Closes #11
  • Loading branch information
anatol committed Nov 2, 2021
1 parent 2e5f782 commit 0096a57
Show file tree
Hide file tree
Showing 15 changed files with 381 additions and 53 deletions.
14 changes: 14 additions & 0 deletions contrib/completion/bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
_completion_booster() {
# All arguments except the first one
args=("${COMP_WORDS[@]:1:$COMP_CWORD}")

# Only split on newlines
local IFS=$'\n'

# Call completion (note that the first element of COMP_WORDS is
# the executable itself)
COMPREPLY=($(GO_FLAGS_COMPLETION=1 ${COMP_WORDS[0]} "${args[@]}"))
return 0
}

complete -F _completion_booster booster
43 changes: 28 additions & 15 deletions docs/manpage.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,32 @@ Once you are done modifying your config file and want to regenerate booster imag
It is a convenience script that performs the same type of image regeneration as if you installed `booster` with your package manager.

## COMMAND-LINE FLAGS
`booster` command accepts following flags:

* `-config` config file to use. Default value is `/etc/booster.yaml`.
* `-universal` generate a universal image
* `-kernelVersion` use modules for the given kernel version. If the flag is not specified then the current kernel is used (as reported by "uname -r").
* `-output` output file, by default booster.img used
* `-compression` output file compression. Currently supported compression algorithms are "zstd" (default), "gzip" and "none".
* `-strip` strip ELF files (binaries, shared libraries and kernel modules) before adding it to the image
* `-force` overwrite output file if it exists
### Application Options

* `-v`, `--verbose` Enable verbose output

### SUBCOMMANDS

### build
Build initrd image. Usage: `booster [OPTIONS] build [build-OPTIONS] output`

* `-f`, `--force` Overwrite existing initrd file.
* `--init-binary` <default: _/usr/lib/booster/init_> Booster 'init' binary location.
* `--compression` <default: _zstd_> Output file compression. Possible values: _zstd_, _gzip_, _xz_, _lz4_, _none_.
* `--kernel-version` Linux kernel version to generate initramfs for.
* `--config` <default: _/etc/booster.yaml_> Configuration file path.
* `--universal` Add wide range of modules/tools to allow this image boot at different machines.
* `--strip` Strip ELF files (binaries, shared libraries and kernel modules) before adding it to the image.

### cat
Show content of the file inside the image. Usage: `booster [OPTIONS] cat image file-in-image`

### ls
List content of the image. Usage: `booster [OPTIONS] ls image`

### unpack
Unpack image. Usage: `booster [OPTIONS] unpack image output-dir`

## BOOT TIME KERNEL PARAMETERS
Some parts of booster boot functionality can be modified with kernel boot parameters. These parameters are usually set through bootloader config. Booster boot uses following kernel parameters:
Expand Down Expand Up @@ -167,19 +184,15 @@ provide additional logs.
## EXAMPLES
Create an initramfs file specific for the current kernel/host. The output file is booster.img:

$ booster

The same as above but output image to /tmp/foobar.img:

$ booster /tmp/foobar.img
$ booster build booster.img

Create an universal image with many modules (such as SATA/TPM/NVME/... drivers) included:

$ booster -universal
$ booster build --universal booster.img

Create an initramfs for kernel version 5.4.91-1-lts and copy it to /boot/booster-lts.img:

$ booster -kernelVersion 5.4.91-1-lts -output /boot/booster-lts.img
$ booster build --kernel-kersion 5.4.91-1-lts /boot/booster-lts.img

Here is a `systemd-boot` configuration stored at /boot/loader/entries/booster.conf. In this example e122d09e-87a9-4b35-83f7-2592ef40cefa is a UUID for the LUKS partition and 08684949-bcbb-47bb-1c17-089aaa59e17e is a UUID for the encrypted filesystem (e.g. ext4). Please refer to your bootloader documentation for more info about its configuration.

Expand Down
20 changes: 10 additions & 10 deletions generator/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func readGeneratorConfig(file string) (*generatorConfig, error) {
}
}
}
conf.universal = u.Universal || *universal
conf.universal = u.Universal || opts.BuildCommand.Universal
if u.Modules != "" {
conf.modules = strings.Split(u.Modules, ",")
}
Expand All @@ -112,17 +112,17 @@ func readGeneratorConfig(file string) (*generatorConfig, error) {
}

// now check command line flags
conf.output = *outputFile
conf.forceOverwrite = *forceOverwriteFile
conf.initBinary = *initBinary
if *compression != "" {
conf.compression = *compression
conf.output = opts.BuildCommand.Args.Output
conf.forceOverwrite = opts.BuildCommand.Force
conf.initBinary = opts.BuildCommand.InitBinary
if opts.BuildCommand.Compression != "" {
conf.compression = opts.BuildCommand.Compression
}
if conf.compression == "" {
conf.compression = "zstd"
}
if *kernelVersion != "" {
conf.kernelVersion = *kernelVersion
if opts.BuildCommand.KernelVersion != "" {
conf.kernelVersion = opts.BuildCommand.KernelVersion
} else {
ver, err := readKernelVersion()
if err != nil {
Expand All @@ -131,11 +131,11 @@ func readGeneratorConfig(file string) (*generatorConfig, error) {
conf.kernelVersion = ver
}
conf.modulesDir = path.Join("/usr/lib/modules", conf.kernelVersion)
conf.debug = *debugEnabled
conf.debug = opts.Verbose
conf.readDeviceAliases = readDeviceAliases
conf.readHostModules = readHostModules
conf.readModprobeOptions = readModprobeOptions
conf.stripBinaries = u.StripBinaries || *strip
conf.stripBinaries = u.StripBinaries || opts.BuildCommand.Strip
conf.enableLVM = u.EnableLVM
conf.enableMdraid = u.EnableMdraid
conf.mdraidConfigPath = u.MdraidConfigPath
Expand Down
68 changes: 68 additions & 0 deletions generator/filetype.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package main

import (
"bytes"
"io"
"os"
)

type matcher func(seeker io.ReadSeeker) (bool, error)

var matchers = map[string]matcher{
"zstd": matchZstd,
"gzip": matchGzip,
"xz": matchXz,
"lz4": matchLz4,
"cpio": matchCpio,
}

func matchBytes(f io.ReadSeeker, offset int64, marker []byte) (bool, error) {
if _, err := f.Seek(offset, io.SeekStart); err != nil {
return false, err
}
buff := make([]byte, len(marker))
if _, err := io.ReadFull(f, buff); err != nil {
return false, nil
}
return bytes.Equal(marker, buff), nil
}

func matchCpio(f io.ReadSeeker) (bool, error) {
return matchBytes(f, 0, []byte{'0', '7', '0', '7', '0', '1'}) // "new" cpio format
}

func matchLz4(f io.ReadSeeker) (bool, error) {
return matchBytes(f, 0, []byte{0x02, 0x21, 0x4c, 0x18}) // legacy format used by linux loader
}

func matchXz(f io.ReadSeeker) (bool, error) {
return matchBytes(f, 0, []byte{0xfd, '7', 'z', 'X', 'Z', 0x00})
}

func matchGzip(f io.ReadSeeker) (bool, error) {
return matchBytes(f, 0, []byte{0x1f, 0x8b})
}

func matchZstd(f io.ReadSeeker) (bool, error) {
return matchBytes(f, 0, []byte{0x28, 0xb5, 0x2f, 0xfd})
}

func filetype(r *os.File) (string, error) {
loc, err := r.Seek(0, io.SeekCurrent)
if err != nil {
return "", err
}
defer r.Seek(loc, io.SeekStart)

for name, match := range matchers {
ok, err := match(r)
if err != nil {
return "", err
}
if ok {
return name, nil
}
}

return "", nil
}
35 changes: 35 additions & 0 deletions generator/filetype_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package main

import (
"os"
"testing"

"github.com/cavaliercoder/go-cpio"
"github.com/stretchr/testify/require"
)

func TestFileType(t *testing.T) {
dir := t.TempDir()
check := func(compression, expectedType string) {
fileName := dir + "/" + compression
img, err := NewImage(fileName, compression, false)
require.NoError(t, err)

require.NoError(t, img.AppendEntry("foo.txt", cpio.ModeRegular, []byte("hello, world!")))
require.NoError(t, img.Close())

f, err := os.Open(fileName)
require.NoError(t, err)

kind, err := filetype(f)
require.NoError(t, err)

require.Equal(t, expectedType, kind)
}

check("zstd", "zstd")
check("gzip", "gzip")
check("xz", "xz")
check("lz4", "lz4")
check("none", "cpio")
}
2 changes: 1 addition & 1 deletion generator/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ var defaultModulesList = []string{

func generateInitRamfs(conf *generatorConfig) error {
if _, err := os.Stat(conf.output); (err == nil || !os.IsNotExist(err)) && !conf.forceOverwrite {
return fmt.Errorf("File %v exists, please specify -force if you want to overwrite it", conf.output)
return fmt.Errorf("File %v exists, please specify --force if you want to overwrite it", conf.output)
}

img, err := NewImage(conf.output, conf.compression, conf.stripBinaries)
Expand Down
2 changes: 1 addition & 1 deletion generator/generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ func testModprobeOptions(t *testing.T) {
}

func TestGenerator(t *testing.T) {
*debugEnabled = testing.Verbose()
opts.Verbose = testing.Verbose()

prepareAssets(t)

Expand Down
3 changes: 2 additions & 1 deletion generator/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ go 1.17

require (
github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e
github.com/frankban/quicktest v1.11.3 // indirect
github.com/google/renameio v1.0.1
github.com/jessevdk/go-flags v1.5.0
github.com/klauspost/compress v1.13.6
github.com/pierrec/lz4 v2.6.1+incompatible
github.com/stretchr/testify v1.7.0
Expand All @@ -17,5 +17,6 @@ require (

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/frankban/quicktest v1.11.3 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
)
3 changes: 3 additions & 0 deletions generator/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/renameio v1.0.1 h1:Lh/jXZmvZxb0BBeSY5VKEfidcbcbenKjZFzM/q0fSeU=
github.com/google/renameio v1.0.1/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk=
github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc=
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
Expand All @@ -27,6 +29,7 @@ github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 h1:2B5p2L5IfGiD7+b9BOoRMC6DgObAVZV+Fsp050NqXik=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
Expand Down

0 comments on commit 0096a57

Please sign in to comment.