initramfs

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 15, 2024 License: MIT Imports: 12 Imported by: 5

README

initramfs

Read and write Linux kernel initramfs-style cpio "newc" formatted archives.

import "go.pdmccormick.com/initramfs"

This implementation follows the documented kernel buffer format. See also early userspace support for more information about how the kernel uses initramfs during the boot process.

See examples for demonstrations of how to use this package.

Documentation

Overview

Read and write Linux kernel initramfs-style cpio "newc" formatted archives.

This implementation follows the documented kernel buffer format. See also early userspace support for more information about how the kernel uses initramfs during the boot process.

See go.pdmccormick.com/initramfs/examples for demonstrations of how to use this package.

Index

Constants

View Source
const (
	MicrocodeX86Path           = "kernel/x86/microcode/"
	MicrocodePath_AuthenticAMD = "kernel/x86/microcode/AuthenticAMD.bin"
	MicrocodePath_GenuineIntel = "kernel/x86/microcode/GenuineIntel.bin"
)

The Linux kernel can load x86 microcode updates from an initramfs very early in the boot process. See The Linux Microcode Loader and the go.pdmccormick.com/initramfs/examples/earlyinitramfs example.

View Source
const (
	Magic_070701 = `070701`
	Magic_070702 = `070702`
)

Magic identifiers for cpio archive member file headers.

View Source
const HeaderSize = 110

The size of a member file header within a cpio archive.

View Source
const MicrocodeDataAlignment = 16

Current practise is to align Intel x86 kernel microcode update data to a 16 byte boundary, although this may only be necessary for older kernel versions.

Use with Writer.SetDataAlignment.

View Source
const StartCompressionAlignment = 512

Before the start of a compressed stream within an archive, the output will be padded to match this alignment.

View Source
const TrailerFilename = "TRAILER!!!"

The sentinel filename that indicates end-of-archive.

Variables

View Source
var (
	ErrMalformedFilename = errors.New("initramfs: filename field is missing trailing 0")
	ErrBadHeaderMagic    = errors.New("initramfs: header contains a bad magic value")
)

Errors related to Header.

View Source
var (
	ErrBadAlignment      = errors.New("initramfs: alignment must itself be a multiple of 4")
	ErrBadDataAlignment  = errors.New("initramfs: unable to align data as requested given the filename")
	ErrAlreadyCompressed = errors.New("initramfs: writer compression is already being applied")
)
View Source
var CompressReaders = CompressReaderMap{
	Gzip:  GzipReader,
	Bzip2: Bzip2Reader,
}

A global map of known compression readers.

The default only includes compressors that exist within the standard library. See go.pdmccormick.com/initramfs/examples for sample implementations of existing packages.

View Source
var ErrCompressedContentAhead = errors.New("initramfs: compressed content ahead")
View Source
var ErrNoCompressReader = errors.New("initramfs: no suitable CompressReader found")

Functions

func ComputeChecksum

func ComputeChecksum(data []byte) (sum uint32)

Compute the 32-bit unsigned sum of all the data bytes.

This is the simple algorithm as used by the kernel for calculating the value of the Header Checksum field, as noted in the buffer format documentation.

func ReaderChecksum

func ReaderChecksum(r io.Reader) (sum uint32, err error)

Computes the 32-bit unsigned sum of all the bytes from given reader. See ComputeChecksum for details.

Types

type CompressReader

type CompressReader func(input io.Reader) (io.Reader, error)

A CompressReader will decompress the given input.

type CompressReaderMap

type CompressReaderMap map[Lookahead]CompressReader

Use the Lookahead token to select a suitable CompressReader.

type CompressWriter

type CompressWriter func(output io.Writer) (io.Writer, error)

A CompressWriter will compress anything written to it and write the compressed data to the given output.

When compressing an initramfs archive using Xz, review the XZ compression options to ensure compatibility.

type Flusher

type Flusher interface {
	Flush() error
}

Any writer that supports flushing its output.

type Header struct {
	HeaderOffset int64
	DataOffset   int64

	// Fixed length fields
	Magic        string    // Either `070701` or `070702`
	Inode        uint32    // File inode number
	Mode         Mode      // File mode and permission bits
	Uid          uint32    // File owner user id
	Gid          uint32    // File owner group id
	NumLinks     uint32    // Number of hard links
	Mtime        time.Time // Modification time (seconds since Unix epoch)
	DataSize     uint32    // Size of file data following the header
	Major        uint32    // Major part of file device number
	Minor        uint32    // Minor part of file device number
	RMajor       uint32    // Major part of device node reference
	RMinor       uint32    // Minor part of device node reference
	FilenameSize uint32    // Length of filename field (including trailing 0)
	Checksum     uint32    // Checksum of data field (if magic is `070702`, otherwise 0)

	// Variable length field
	Filename string
}

Header for a file member within a cpio archive.

func (*Header) Bytes

func (hdr *Header) Bytes() []byte

Return the textual form of the header and filename fields.

func (*Header) ReadFrom

func (hdr *Header) ReadFrom(r io.Reader) (n int64, err error)

Read and convert the textual form of the header and filename fields.

Returns an InvalidByteError if an invalid hexadecimal byte value is encountered. Returns ErrMalformedFilename if the filename field is missing a trailing 0.

func (*Header) Size

func (hdr *Header) Size() int

The length of the textual form of the header and filename fields.

func (*Header) String

func (hdr *Header) String() string

Formats the header similarly to the long listing output of `ls -l`.

func (*Header) Trailer

func (hdr *Header) Trailer() bool

func (*Header) WriteTo

func (hdr *Header) WriteTo(w io.Writer) (n int64, err error)

Write the textual form of the header and filename fields.

type InvalidByteError

type InvalidByteError int

An invalid hexadecimal character was found at an offset relative to the start of a Header.

func (*InvalidByteError) Error

func (offs *InvalidByteError) Error() string

type Lookahead

type Lookahead int

Identify what kind of data comes next in a stream by looking ahead a few bytes and identifying magic values.

Recognizes the difference between cpio archive member file headers, zero padding and various compression schemes. See the RD_ and INITRAMFS_COMPRESSION_ config options in Linux kernel usr/Kconfig.

const (
	UnknownLookahead Lookahead = iota
	EOF                        // End of file
	Padding                    // Zero padding
	CpioFile                   // Start of cpio archive member file header
	Gzip                       // Start of Gzip compressed data
	Bzip2                      // Start of Bzip2 compressed data
	Lzma                       // Start of LZMA compressed data
	Xz                         // Start of XZ compressed data
	Lzo                        // Start of LZO compressed data
	Lz4                        // Start of LZ4 compressed data
	Zstd                       // Start of Zstd compressed data
)

func PeekLookahead

func PeekLookahead(br *bufio.Reader) (la Lookahead, err error)

Uses bufio.Reader.Peek to determine what kind of data follows. Does not consume the input. Only returns non-EOF errors.

func (Lookahead) Compression

func (la Lookahead) Compression() bool

Returns true if and only if the lookahead indicates the start of compressed data.

func (Lookahead) EOF

func (la Lookahead) EOF() bool

If the end of file was reached when looking ahead.

func (Lookahead) String

func (la Lookahead) String() string

type Magic

type Magic uint16

Magic byte values used to identify the start of various types of compressed data streams.

These match what the kernel uses, see Linux kernel lib/decompress.c.

const (
	CpioFileMagic Magic = 0x30_37 // A cpio archive member file header starts with "07" (either "070701" or "070702")
	GzipMagic1    Magic = 0x1F_8B
	GzipMagic2    Magic = 0x1F_9E
	Bzip2Magic    Magic = 0x42_5A
	LzmaMagic     Magic = 0x5D_00
	XzMagic       Magic = 0xFD_37
	LzoMagic      Magic = 0x89_4C
	Lz4Magic      Magic = 0x02_21
	ZstdMagic     Magic = 0x28_B5
)

func SniffMagic

func SniffMagic(peek [2]byte) (m Magic, ok bool)

Determine if the provided bytes are a recognized magic value.

func (Magic) Match

func (m Magic) Match(a [2]byte) bool

Returns true if the bytes match the magic value.

func (Magic) MatchBytes

func (m Magic) MatchBytes(p []byte) bool

type Mode

type Mode uint32

File mode and permission bits

const (
	Mode_FileTypeMask Mode = 0o170_000
	Mode_Socket       Mode = 0o140_000 // File type for sockets.
	Mode_Symlink      Mode = 0o120_000 // File type for symbolic links (file data is link target).
	Mode_File         Mode = 0o100_000 // File type for regular files.
	Mode_BlockDevice  Mode = 0o060_000 // File type for block devices.
	Mode_Dir          Mode = 0o040_000 // File type for directories.
	Mode_CharDevice   Mode = 0o020_000 // File type for character devices.
	Mode_FIFO         Mode = 0o010_000 // File type for named pipes or FIFO's.
	Mode_SUID         Mode = 0o004_000 // SUID bit. See https://man7.org/linux/man-pages/man2/setfsuid.2.html#DESCRIPTION
	Mode_SGID         Mode = 0o002_000 // SGID bit. See https://man7.org/linux/man-pages/man2/setfsgid.2.html#DESCRIPTION
	Mode_Sticky       Mode = 0o001_000 // Sticky bit. See https://www.man7.org/linux/man-pages/man1/chmod.1.html#RESTRICTED_DELETION_FLAG_OR_STICKY_BIT
	Mode_PermsMask    Mode = 0o000_777 // Permission bits (read/write/execute for user, group and other). See https://man7.org/linux/man-pages/man1/chmod.1.html#DESCRIPTION

	UserRead     Mode = 0o400
	UserWrite    Mode = 0o200
	UserExecute  Mode = 0o100
	GroupRead    Mode = 0o040
	GroupWrite   Mode = 0o020
	GroupExecute Mode = 0o010
	OtherRead    Mode = 0o004
	OtherWrite   Mode = 0o002
	OtherExecute Mode = 0o001
)
const DefaultMkdirPerm Mode = 0o700

Default permissions for directory entries

func (Mode) BlockDevice

func (m Mode) BlockDevice() bool

func (Mode) CharDevice

func (m Mode) CharDevice() bool

func (*Mode) ClearBits

func (m *Mode) ClearBits(bits int) Mode

func (Mode) Dir

func (m Mode) Dir() bool

func (Mode) FIFO

func (m Mode) FIFO() bool

func (Mode) File

func (m Mode) File() bool

func (Mode) FileType

func (m Mode) FileType() Mode

func (Mode) Perms

func (m Mode) Perms() int

func (Mode) SGID

func (m Mode) SGID() bool

func (Mode) SUID

func (m Mode) SUID() bool

func (*Mode) SetBits

func (m *Mode) SetBits(bits int) Mode

func (*Mode) SetFileType

func (m *Mode) SetFileType(ftype int) Mode

func (*Mode) SetPerms

func (m *Mode) SetPerms(perms int) Mode

func (Mode) Socket

func (m Mode) Socket() bool

func (Mode) Sticky

func (m Mode) Sticky() bool

func (Mode) String

func (m Mode) String() string
func (m Mode) Symlink() bool

func (Mode) WithPerms

func (m Mode) WithPerms(perms int) Mode

type Reader

type Reader struct {
	// contains filtered or unexported fields
}

func NewReader

func NewReader(r io.Reader) *Reader

func (*Reader) All

func (r *Reader) All() iter.Seq2[int, Header]

Provides a sequence iterator that is equivalent to calling Reader.Next until EOF.

func (*Reader) ContinueCompressed

func (r *Reader) ContinueCompressed(compressReaders CompressReaderMap) (isCompressed bool, compressType Lookahead, err error)

Attempt to continue reader into the start of a compressed data stream.

Returns ErrNoCompressReader if the CompressReaderMap does not contain a suitable reader for the encountered compression type.

func (*Reader) Next

func (r *Reader) Next() (*Header, error)

Consumes input looking for the next file entry. Returns ErrCompressedContentAhead if the start of compress data has been detected.

Check for compressed data by calling Reader.ContinueCompressed.

func (*Reader) Read

func (r *Reader) Read(buf []byte) (int, error)

Reads file data up to the length indicated by [Header.DataSize].

func (*Reader) WriteTo

func (r *Reader) WriteTo(w io.Writer) (n int64, err error)

Copy all remaining current file data to the writer.

type Writer

type Writer struct {
	// contains filtered or unexported fields
}

Writer

func NewWriter

func NewWriter(w io.Writer) *Writer

func (*Writer) Close

func (iw *Writer) Close() error

Flush and close the writer.

func (*Writer) Flush

func (iw *Writer) Flush() error

Flush any unwritten buffered output.

The base io.Writer or CompressWriter must implement the Flusher interface for this to be effective.

func (*Writer) MkdirAll

func (iw *Writer) MkdirAll(path string, perm Mode) error

Add a directory named path, along with any necessary parents, to the archive.

The writer tracks which directories have already been added, and will skip any that already exist.

func (*Writer) ReadFrom

func (iw *Writer) ReadFrom(r io.Reader) (n int64, err error)

Reads file data from r and writes to the archive.

func (*Writer) SetDataAlignment

func (iw *Writer) SetDataAlignment(alignTo int) error

Attempts to set the alignment of the file data by adjusting the amount of padding before the next header write. Value must itself be a multiple of 4.

If the length of the header (110 bytes, see HeaderSize), plus the length of the NUL-terminated filename, is itself not a multiple of 4, the call to Writer.WriteHeader will return ErrBadDataAlignment. In the case of filename MicrocodePath_GenuineIntel, this will work.

Only one of header or data alignment can be applied, and whichever is called last prior to calling Writer.WriteHeader will be applied. After every call to Writer.WriteHeader alignment is reset.

func (*Writer) SetHeaderAlignment

func (iw *Writer) SetHeaderAlignment(alignTo int) error

Sets the output alignment for the start of the next header write. Value must itself be a multiple of 4.

Only one of header or data alignment can be applied, and whichever is called last prior to calling Writer.WriteHeader will be applied. After every call to Writer.WriteHeader alignment is reset.

func (*Writer) StartCompression

func (iw *Writer) StartCompression(c CompressWriter) error

Switch the writer to a compressed output stream, according to the supplied CompressWriter. It is not possible to end a compressed stream other than by reaching the end of the file, so all remaining output from the writer will be compressed.

func (*Writer) Write

func (iw *Writer) Write(buf []byte) (n int, err error)

func (*Writer) WriteHeader

func (iw *Writer) WriteHeader(hdr *Header) error

Write the header in textual form, respecting output alignment requirements. The header will first be updated to ensure well-formedness:

  • If Magic is blank, it will be given a default value of Magic_070701
  • NumLinks will be minimum 1
  • If Inode is 0 and this is not a trailer, an inode number will be assigned
  • All leading slashes will be removed from the Filename
  • FilenameSize will be set to the length of Filename plus 1

func (*Writer) WriteTrailer

func (iw *Writer) WriteTrailer() error

Write the end-of-archive sentinel trailer entry.

Directories

Path Synopsis
examples module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL