mirror of
https://github.com/siderolabs/talos.git
synced 2025-10-28 15:01:13 +01:00
Initramfs and kernel are compressed with zstd. Extensions are compressed with zstd for Talos 1.8+. Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
171 lines
4.3 KiB
Go
171 lines
4.3 KiB
Go
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
package extensions
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"os/exec"
|
|
|
|
"github.com/siderolabs/talos/pkg/machinery/imager/quirks"
|
|
)
|
|
|
|
// rebuildInitramfs rebuilds finalized initramfs with extensions.
|
|
//
|
|
// If uncompressedListing is not empty, contents will be prepended to the initramfs uncompressed.
|
|
// Contents from compressedListing will be appended to the initramfs compressed (xz/zstd) as a second block.
|
|
// Original initramfs.xz contents will stay without changes.
|
|
func (builder *Builder) rebuildInitramfs(tempDir string, quirks quirks.Quirks) error {
|
|
compressedListing, uncompressedListing, err := buildInitramfsContents(tempDir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(uncompressedListing) > 0 {
|
|
if err = builder.prependUncompressedInitramfs(tempDir, uncompressedListing); err != nil {
|
|
return fmt.Errorf("error prepending uncompressed initramfs: %w", err)
|
|
}
|
|
}
|
|
|
|
if err = builder.appendCompressedInitramfs(tempDir, compressedListing, quirks); err != nil {
|
|
return fmt.Errorf("error appending compressed initramfs: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (builder *Builder) appendCompressedInitramfs(tempDir string, compressedListing []byte, quirks quirks.Quirks) error {
|
|
builder.Printf("creating system extensions initramfs archive and compressing it")
|
|
|
|
// the code below runs the equivalent of:
|
|
// find $tempDir -print | cpio -H newc --create --reproducible | { xz -v -C crc32 -0 -e -T 0 -z || zstd -T0 -18 -c --quiet }
|
|
|
|
pipeR, pipeW, err := os.Pipe()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer pipeR.Close() //nolint:errcheck
|
|
defer pipeW.Close() //nolint:errcheck
|
|
|
|
// build cpio image which contains .sqsh images and extensions.yaml
|
|
cmd1 := exec.Command("cpio", "-H", "newc", "--create", "--reproducible", "--quiet", "-R", "+0:+0")
|
|
cmd1.Dir = tempDir
|
|
cmd1.Stdin = bytes.NewReader(compressedListing)
|
|
cmd1.Stdout = pipeW
|
|
cmd1.Stderr = os.Stderr
|
|
|
|
if err = cmd1.Start(); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err = pipeW.Close(); err != nil {
|
|
return err
|
|
}
|
|
|
|
destination, err := os.OpenFile(builder.InitramfsPath, os.O_APPEND|os.O_WRONLY, 0)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer destination.Close() //nolint:errcheck
|
|
|
|
// append compressed initramfs.sysext to the original initramfs.xz, kernel can read such format
|
|
var cmd2 *exec.Cmd
|
|
|
|
if quirks.UseZSTDCompression() {
|
|
cmd2 = exec.Command("zstd", "-T0", "-18", "-c", "--quiet")
|
|
} else {
|
|
cmd2 = exec.Command("xz", "-v", "-C", "crc32", "-0", "-e", "-T", "0", "-z", "--quiet")
|
|
}
|
|
|
|
cmd2.Dir = tempDir
|
|
cmd2.Stdin = pipeR
|
|
cmd2.Stdout = destination
|
|
cmd2.Stderr = os.Stderr
|
|
|
|
if err = cmd2.Start(); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err = pipeR.Close(); err != nil {
|
|
return err
|
|
}
|
|
|
|
errCh := make(chan error, 1)
|
|
|
|
go func() {
|
|
errCh <- cmd1.Wait()
|
|
}()
|
|
|
|
go func() {
|
|
errCh <- cmd2.Wait()
|
|
}()
|
|
|
|
for range 2 {
|
|
if err = <-errCh; err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return destination.Sync()
|
|
}
|
|
|
|
func (builder *Builder) prependUncompressedInitramfs(tempDir string, uncompressedListing []byte) error {
|
|
builder.Printf("creating uncompressed initramfs archive")
|
|
|
|
// the code below runs the equivalent of:
|
|
// mv initramfs.xz initramfs.xz-old
|
|
// find $tempDir -print | cpio -H newc --create --reproducible > initramfs.xz
|
|
// cat initramfs.xz-old >> initramfs.xz
|
|
// rm initramfs.xz-old
|
|
|
|
initramfsOld := builder.InitramfsPath + "-old"
|
|
|
|
if err := os.Rename(builder.InitramfsPath, initramfsOld); err != nil {
|
|
return err
|
|
}
|
|
|
|
destination, err := os.OpenFile(builder.InitramfsPath, os.O_CREATE|os.O_WRONLY, 0o644)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer destination.Close() //nolint:errcheck
|
|
|
|
cmd := exec.Command("cpio", "-H", "newc", "--create", "--reproducible", "--quiet", "-R", "+0:+0")
|
|
cmd.Dir = tempDir
|
|
cmd.Stdin = bytes.NewReader(uncompressedListing)
|
|
cmd.Stdout = destination
|
|
cmd.Stderr = os.Stderr
|
|
|
|
if err = cmd.Run(); err != nil {
|
|
return err
|
|
}
|
|
|
|
old, err := os.Open(initramfsOld)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer old.Close() //nolint:errcheck
|
|
|
|
if _, err = io.Copy(destination, old); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err = destination.Close(); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err = old.Close(); err != nil {
|
|
return err
|
|
}
|
|
|
|
return os.Remove(initramfsOld)
|
|
}
|