From b6d23acaa1647cc5cdefb2de21ec7ba8e626bb0d Mon Sep 17 00:00:00 2001 From: Chris Koch Date: Sun, 11 Feb 2024 03:32:56 +0000 Subject: [PATCH] New initramfs API Signed-off-by: Chris Koch --- cmd/mkuimage/main.go | 85 +++++++++------- uroot/initramfs/archive.go | 68 ++++--------- uroot/initramfs/cpio.go | 67 ++++++++----- uroot/initramfs/dir.go | 31 ++---- uroot/initramfs/files_test.go | 180 ++++++++++++++++------------------ uroot/uroot.go | 4 +- uroot/uroot_test.go | 14 +-- 7 files changed, 206 insertions(+), 243 deletions(-) diff --git a/cmd/mkuimage/main.go b/cmd/mkuimage/main.go index 4013a3c..c57bd25 100644 --- a/cmd/mkuimage/main.go +++ b/cmd/mkuimage/main.go @@ -47,15 +47,15 @@ var ( // Flags for u-root builder. var ( - build, format, tmpDir, base, outputPath *string - uinitCmd, initCmd *string - defaultShell *string - useExistingInit *bool - noCommands *bool - extraFiles multiFlag - statsOutputPath *string - statsLabel *string - shellbang *bool + build, format, tmpDir, basePath, outputPath *string + uinitCmd, initCmd *string + defaultShell *string + useExistingInit *bool + noCommands *bool + extraFiles multiFlag + statsOutputPath *string + statsLabel *string + shellbang *bool // For the new "filepath only" logic. urootSourceDir *string ) @@ -74,7 +74,7 @@ func init() { tmpDir = flag.String("tmpdir", "", "Temporary directory to put binaries in.") - base = flag.String("base", "", "Base archive to add files to. By default, this is a couple of directories like /bin, /etc, etc. u-root has a default internally supplied set of files; use base=/dev/null if you don't want any base files.") + basePath = flag.String("base", "", "Base archive to add files to. By default, this is a couple of directories like /bin, /etc, etc. u-root has a default internally supplied set of files; use base=/dev/null if you don't want any base files.") useExistingInit = flag.Bool("useinit", false, "Use existing init from base archive (only if --base was specified).") outputPath = flag.String("o", "", "Path to output initramfs file.") @@ -253,6 +253,33 @@ func isRecommendedVersion(v string) bool { return false } +func GetReader(format string, path string) initramfs.ReadOpener { + switch format { + case "cpio": + return &initramfs.CPIOFile{Path: path} + default: + return nil + } +} + +func GetWriter(format string, path string) initramfs.WriteOpener { + switch format { + case "cpio": + return &initramfs.CPIOFile{Path: path} + case "dir": + return &initramfs.Dir{Path: path} + default: + return nil + } +} + +func defaultFile(env *golang.Environ) string { + if len(env.GOOS) == 0 || len(env.GOARCH) == 0 { + return "/tmp/initramfs.cpio" + } + return fmt.Sprintf("/tmp/initramfs.%s_%s.cpio", env.GOOS, env.GOARCH) +} + // Main is a separate function so defers are run on return, which they wouldn't // on exit. func Main(l ulog.Logger, env *golang.Environ, buildOpts *golang.BuildOpts) error { @@ -269,34 +296,16 @@ func Main(l ulog.Logger, env *golang.Environ, buildOpts *golang.BuildOpts) error v, recommendedVersions, recommendedVersions[0]) } - archiver, err := initramfs.GetArchiver(*format) - if err != nil { - return err + var output initramfs.WriteOpener + output = &initramfs.CPIOFile{Path: defaultFile(env)} + if *outputPath != "" { + output = GetWriter(*format, *outputPath) } - // Open the target initramfs file. - if *outputPath == "" { - *outputPath, err = archiver.CreateDefault(env) - if err != nil { - return err - } - l.Printf("Output path is %v", *outputPath) - } - w, err := archiver.OpenWriter(*outputPath) - if err != nil { - return err - } - - var baseFile initramfs.Reader - if *base != "" { - bf, err := os.Open(*base) - if err != nil { - return err - } - defer bf.Close() - baseFile = archiver.Reader(bf) - } else { - baseFile = uroot.DefaultRamfs().Reader() + var base initramfs.ReadOpener + base = &initramfs.Archive{Archive: uroot.DefaultRamfs()} + if *basePath != "" { + base = GetReader(*format, *basePath) } tempDir := *tmpDir @@ -363,8 +372,8 @@ func Main(l ulog.Logger, env *golang.Environ, buildOpts *golang.BuildOpts) error UrootSource: *urootSourceDir, TempDir: tempDir, ExtraFiles: extraFiles, - OutputFile: w, - BaseArchive: baseFile, + OutputFile: output, + BaseArchive: base, UseExistingInit: *useExistingInit, InitCmd: initCommand, DefaultShell: *defaultShell, diff --git a/uroot/initramfs/archive.go b/uroot/initramfs/archive.go index 99576de..9d8f1a4 100644 --- a/uroot/initramfs/archive.go +++ b/uroot/initramfs/archive.go @@ -6,54 +6,19 @@ package initramfs import ( - "fmt" "io" - "github.com/u-root/gobusybox/src/pkg/golang" "github.com/u-root/mkuimage/cpio" ) -var ( - // CPIO creates files in a CPIO file. - CPIO = CPIOArchiver{ - RecordFormat: cpio.Newc, - } - - // Dir writes "archived" files to a directory. - Dir = DirArchiver{} - - // Archivers are the supported initramfs archivers at the moment. - // - // - cpio: writes the initramfs to a cpio. - // - dir: writes the initramfs relative to a specified directory. - Archivers = map[string]Archiver{ - "cpio": CPIO, - "dir": Dir, - } -) - -// Archiver is an archive format that builds an archive using a given set of -// files. -type Archiver interface { - // CreateDefault creates a default file that can be passed as path to OpenWriter. - CreateDefault(env *golang.Environ) (string, error) - - // OpenWriter opens an archive writer at `path`. - OpenWriter(path string) (Writer, error) - - // Reader returns a Reader that allows reading files from a file. - Reader(file io.ReaderAt) Reader +// ReadOpener opens a cpio.RecordReader. +type ReadOpener interface { + OpenReader() (cpio.RecordReader, error) } -// GetArchiver finds a registered initramfs archiver by name. -// -// Good to use with command-line arguments. -func GetArchiver(name string) (Archiver, error) { - archiver, ok := Archivers[name] - if !ok { - return nil, fmt.Errorf("couldn't find archival format %q", name) - } - return archiver, nil +// WriteOpener opens a Writer. +type WriteOpener interface { + OpenWriter() (Writer, error) } // Writer is an initramfs archive that files can be written to. @@ -64,9 +29,6 @@ type Writer interface { Finish() error } -// Reader is an object that files can be read from. -type Reader cpio.RecordReader - // Opts are options for building an initramfs archive. type Opts struct { // Files are the files to be included. @@ -76,12 +38,12 @@ type Opts struct { *Files // OutputFile is the file to write to. - OutputFile Writer + OutputFile WriteOpener // BaseArchive is an existing archive to add files to. // // BaseArchive may be nil. - BaseArchive Reader + BaseArchive ReadOpener // UseExistingInit determines whether the init from BaseArchive is used // or not, if BaseArchive is specified. @@ -96,6 +58,10 @@ type Opts struct { func Write(opts *Opts) error { // Write base archive. if opts.BaseArchive != nil { + base, err := opts.BaseArchive.OpenReader() + if err != nil { + return err + } transform := cpio.MakeReproducible // Rename init to inito if user doesn't want the existing init. @@ -114,7 +80,7 @@ func Write(opts *Opts) error { } for { - f, err := opts.BaseArchive.ReadRecord() + f, err := base.ReadRecord() if err == io.EOF { break } @@ -127,8 +93,12 @@ func Write(opts *Opts) error { } } - if err := opts.Files.WriteTo(opts.OutputFile); err != nil { + out, err := opts.OutputFile.OpenWriter() + if err != nil { + return err + } + if err := opts.Files.WriteTo(out); err != nil { return err } - return opts.OutputFile.Finish() + return out.Finish() } diff --git a/uroot/initramfs/cpio.go b/uroot/initramfs/cpio.go index 199308b..791354e 100644 --- a/uroot/initramfs/cpio.go +++ b/uroot/initramfs/cpio.go @@ -6,55 +6,72 @@ package initramfs import ( "fmt" - "io" "os" - "github.com/u-root/gobusybox/src/pkg/golang" "github.com/u-root/mkuimage/cpio" ) -// CPIOArchiver is an implementation of Archiver for the cpio format. -type CPIOArchiver struct { - cpio.RecordFormat +// CPIOFile opens a Reader or Writer that reads/writes files from/to a CPIO archive at the given path. +type CPIOFile struct { + Path string } -// CreateDefault chooses /tmp/initramfs.cpio or /tmp/initramfs.GOOS_GOARCH.cpio -// if available. -func (ca CPIOArchiver) CreateDefault(env *golang.Environ) (string, error) { - if len(env.GOOS) == 0 || len(env.GOARCH) == 0 { - return "/tmp/initramfs.cpio", nil +var _ ReadOpener = &CPIOFile{} +var _ WriteOpener = &CPIOFile{} + +// OpenWriter opens c.Path for writing. +func (c *CPIOFile) OpenWriter() (Writer, error) { + if len(c.Path) == 0 { + return nil, fmt.Errorf("path is required") + } + f, err := os.OpenFile(c.Path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644) + if err != nil { + return nil, err } - return fmt.Sprintf("/tmp/initramfs.%s_%s.cpio", env.GOOS, env.GOARCH), nil + return cpioWriter{cpio.Newc.Writer(f), f}, nil } -// OpenWriter opens `path` as the correct file type and returns an -// Writer pointing to `path`. -func (ca CPIOArchiver) OpenWriter(path string) (Writer, error) { - if len(path) == 0 { +// OpenReader opens c.Path for reading. +func (c *CPIOFile) OpenReader() (cpio.RecordReader, error) { + if len(c.Path) == 0 { return nil, fmt.Errorf("path is required") } - f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644) + f, err := os.Open(c.Path) if err != nil { return nil, err } - return osWriter{ca.RecordFormat.Writer(f), f}, nil + return cpio.Newc.Reader(f), nil +} + +// Archive opens a Reader that reads files from an in-memory archive. +type Archive struct { + *cpio.Archive +} + +var _ ReadOpener = &Archive{} + +// OpenWriter writes to the archive. +func (a *Archive) OpenWriter() (Writer, error) { + return cpioWriter{a.Archive, nil}, nil +} + +// OpenReader opens the archive for reading. +func (a *Archive) OpenReader() (cpio.RecordReader, error) { + return a.Archive.Reader(), nil } // osWriter implements Writer. -type osWriter struct { +type cpioWriter struct { cpio.RecordWriter f *os.File } // Finish implements Writer.Finish. -func (o osWriter) Finish() error { +func (o cpioWriter) Finish() error { err := cpio.WriteTrailer(o) - o.f.Close() + if o.f != nil { + o.f.Close() + } return err } - -// Reader implements Archiver.Reader. -func (ca CPIOArchiver) Reader(r io.ReaderAt) Reader { - return ca.RecordFormat.Reader(r) -} diff --git a/uroot/initramfs/dir.go b/uroot/initramfs/dir.go index 4317009..bc847c6 100644 --- a/uroot/initramfs/dir.go +++ b/uroot/initramfs/dir.go @@ -7,42 +7,27 @@ package initramfs import ( "errors" "fmt" - "io" "os" - "github.com/u-root/gobusybox/src/pkg/golang" "github.com/u-root/mkuimage/cpio" ) -// DirArchiver implements Archiver for a directory. -type DirArchiver struct{} - -// Reader implements Archiver.Reader. -// -// Currently unsupported for directories. -func (da DirArchiver) Reader(io.ReaderAt) Reader { - return nil +// Dir opens a Writer that writes all archive files to the given directory. +type Dir struct { + Path string } -// CreateDefault creates a tmpdir using os.MkdirTemp prefixed with mkuimage- or -// mkuimage-GOOS-GOARCH- if available. -func (da DirArchiver) CreateDefault(env *golang.Environ) (string, error) { - name := "mkuimage-" - if len(env.GOOS) != 0 && len(env.GOARCH) != 0 { - name = fmt.Sprintf("mkuimage-%s-%s-", env.GOOS, env.GOARCH) - } - return os.MkdirTemp("", name) -} +var _ WriteOpener = &Dir{} // OpenWriter implements Archiver.OpenWriter. -func (da DirArchiver) OpenWriter(path string) (Writer, error) { - if len(path) == 0 { +func (d *Dir) OpenWriter() (Writer, error) { + if len(d.Path) == 0 { return nil, fmt.Errorf("path is required") } - if err := os.MkdirAll(path, 0o755); err != nil && !errors.Is(err, os.ErrExist) { + if err := os.MkdirAll(d.Path, 0o755); err != nil && !errors.Is(err, os.ErrExist) { return nil, err } - return dirWriter{path}, nil + return dirWriter{d.Path}, nil } // dirWriter implements Writer. diff --git a/uroot/initramfs/files_test.go b/uroot/initramfs/files_test.go index 29d0db6..77c1c03 100644 --- a/uroot/initramfs/files_test.go +++ b/uroot/initramfs/files_test.go @@ -7,7 +7,6 @@ package initramfs import ( "errors" "fmt" - "io" "os" "path/filepath" "reflect" @@ -17,6 +16,15 @@ import ( "github.com/u-root/uio/uio" ) +func archive(tb testing.TB, rs ...cpio.Record) *cpio.Archive { + tb.Helper() + a, err := cpio.ArchiveFromRecords(rs) + if err != nil { + tb.Fatal(err) + } + return a +} + func TestFilesAddFileNoFollow(t *testing.T) { regularFile, err := os.CreateTemp("", "archive-files-add-file") if err != nil { @@ -403,37 +411,9 @@ func TestFilesfillInParent(t *testing.T) { } } -type MockArchiver struct { - Records Records - FinishCalled bool - BaseArchive []cpio.Record -} - -func (ma *MockArchiver) WriteRecord(r cpio.Record) error { - if _, ok := ma.Records[r.Name]; ok { - return fmt.Errorf("file exists") - } - ma.Records[r.Name] = r - return nil -} - -func (ma *MockArchiver) Finish() error { - ma.FinishCalled = true - return nil -} - -func (ma *MockArchiver) ReadRecord() (cpio.Record, error) { - if len(ma.BaseArchive) > 0 { - next := ma.BaseArchive[0] - ma.BaseArchive = ma.BaseArchive[1:] - return next, nil - } - return cpio.Record{}, io.EOF -} - type Records map[string]cpio.Record -func RecordsEqual(r1, r2 Records, recordEqual func(cpio.Record, cpio.Record) bool) bool { +func recordsEqual(r1, r2 Records, recordEqual func(cpio.Record, cpio.Record) bool) bool { for name, s1 := range r1 { s2, ok := r2[name] if !ok { @@ -460,11 +440,11 @@ func sameNameModeContent(r1 cpio.Record, r2 cpio.Record) bool { func TestOptsWrite(t *testing.T) { for i, tt := range []struct { - desc string - opts *Opts - ma *MockArchiver - want Records - err error + desc string + opts *Opts + output *cpio.Archive + want Records + err error }{ { desc: "no conflicts, just records", @@ -474,18 +454,19 @@ func TestOptsWrite(t *testing.T) { "foo": cpio.Symlink("foo", "elsewhere"), }, }, - }, - ma: &MockArchiver{ - Records: make(Records), - BaseArchive: []cpio.Record{ + BaseArchive: &Archive{Archive: archive(t, cpio.Directory("etc", 0o777), cpio.Directory("etc/nginx", 0o777), - }, + )}, + }, + output: &cpio.Archive{ + Files: make(map[string]cpio.Record), }, want: Records{ - "foo": cpio.Symlink("foo", "elsewhere"), - "etc": cpio.Directory("etc", 0o777), - "etc/nginx": cpio.Directory("etc/nginx", 0o777), + "foo": cpio.Symlink("foo", "elsewhere"), + "etc": cpio.Directory("etc", 0o777), + "etc/nginx": cpio.Directory("etc/nginx", 0o777), + cpio.Trailer: cpio.TrailerRecord, }, }, { @@ -496,15 +477,16 @@ func TestOptsWrite(t *testing.T) { "etc": cpio.Symlink("etc", "whatever"), }, }, - }, - ma: &MockArchiver{ - Records: make(Records), - BaseArchive: []cpio.Record{ + BaseArchive: &Archive{Archive: archive(t, cpio.Directory("etc", 0o777), - }, + )}, + }, + output: &cpio.Archive{ + Files: make(map[string]cpio.Record), }, want: Records{ - "etc": cpio.Symlink("etc", "whatever"), + "etc": cpio.Symlink("etc", "whatever"), + cpio.Trailer: cpio.TrailerRecord, }, }, { @@ -515,14 +497,16 @@ func TestOptsWrite(t *testing.T) { "foo/bar/baz": cpio.Symlink("foo/bar/baz", "elsewhere"), }, }, + BaseArchive: nil, }, - ma: &MockArchiver{ - Records: make(Records), + output: &cpio.Archive{ + Files: make(map[string]cpio.Record), }, want: Records{ "foo": cpio.Directory("foo", 0o755), "foo/bar": cpio.Directory("foo/bar", 0o755), "foo/bar/baz": cpio.Symlink("foo/bar/baz", "elsewhere"), + cpio.Trailer: cpio.TrailerRecord, }, }, { @@ -534,14 +518,16 @@ func TestOptsWrite(t *testing.T) { "foo/bar/baz": cpio.Symlink("foo/bar/baz", "elsewhere"), }, }, + BaseArchive: nil, }, - ma: &MockArchiver{ - Records: make(Records), + output: &cpio.Archive{ + Files: make(map[string]cpio.Record), }, want: Records{ "foo": cpio.Directory("foo", 0o755), "foo/bar": cpio.Directory("foo/bar", 0o444), "foo/bar/baz": cpio.Symlink("foo/bar/baz", "elsewhere"), + cpio.Trailer: cpio.TrailerRecord, }, }, { @@ -553,20 +539,21 @@ func TestOptsWrite(t *testing.T) { "exists": cpio.Directory("exists", 0o777), }, }, - }, - ma: &MockArchiver{ - Records: make(Records), - BaseArchive: []cpio.Record{ + BaseArchive: &Archive{Archive: archive(t, cpio.Directory("etc", 0o755), cpio.Directory("foo", 0o444), cpio.Directory("exists", 0), - }, + )}, + }, + output: &cpio.Archive{ + Files: make(map[string]cpio.Record), }, want: Records{ - "etc": cpio.Directory("etc", 0o755), - "exists": cpio.Directory("exists", 0o777), - "foo": cpio.Directory("foo", 0o444), - "foo/bar": cpio.Symlink("foo/bar", "elsewhere"), + "etc": cpio.Directory("etc", 0o755), + "exists": cpio.Directory("exists", 0o777), + "foo": cpio.Directory("foo", 0o444), + "foo/bar": cpio.Symlink("foo/bar", "elsewhere"), + cpio.Trailer: cpio.TrailerRecord, }, }, { @@ -575,15 +562,16 @@ func TestOptsWrite(t *testing.T) { Files: &Files{ Records: map[string]cpio.Record{}, }, - }, - ma: &MockArchiver{ - Records: make(Records), - BaseArchive: []cpio.Record{ + BaseArchive: &Archive{Archive: archive(t, cpio.StaticFile("init", "boo", 0o555), - }, + )}, + }, + output: &cpio.Archive{ + Files: make(map[string]cpio.Record), }, want: Records{ - "init": cpio.StaticFile("init", "boo", 0o555), + "init": cpio.StaticFile("init", "boo", 0o555), + cpio.Trailer: cpio.TrailerRecord, }, }, { @@ -594,16 +582,17 @@ func TestOptsWrite(t *testing.T) { "init": cpio.StaticFile("init", "bar", 0o444), }, }, - }, - ma: &MockArchiver{ - Records: make(Records), - BaseArchive: []cpio.Record{ + BaseArchive: &Archive{Archive: archive(t, cpio.StaticFile("init", "boo", 0o555), - }, + )}, + }, + output: &cpio.Archive{ + Files: make(map[string]cpio.Record), }, want: Records{ - "init": cpio.StaticFile("init", "bar", 0o444), - "inito": cpio.StaticFile("inito", "boo", 0o555), + "init": cpio.StaticFile("init", "bar", 0o444), + "inito": cpio.StaticFile("inito", "boo", 0o555), + cpio.Trailer: cpio.TrailerRecord, }, }, { @@ -612,16 +601,17 @@ func TestOptsWrite(t *testing.T) { Files: &Files{ Records: map[string]cpio.Record{}, }, + BaseArchive: &Archive{Archive: archive(t, + cpio.StaticFile("init", "boo", 0o555), + )}, UseExistingInit: true, }, - ma: &MockArchiver{ - Records: make(Records), - BaseArchive: []cpio.Record{ - cpio.StaticFile("init", "boo", 0o555), - }, + output: &cpio.Archive{ + Files: make(map[string]cpio.Record), }, want: Records{ - "init": cpio.StaticFile("init", "boo", 0o555), + "init": cpio.StaticFile("init", "boo", 0o555), + cpio.Trailer: cpio.TrailerRecord, }, }, { @@ -632,32 +622,30 @@ func TestOptsWrite(t *testing.T) { "init": cpio.StaticFile("init", "huh", 0o111), }, }, + BaseArchive: &Archive{Archive: archive(t, + cpio.StaticFile("init", "boo", 0o555), + )}, UseExistingInit: true, }, - ma: &MockArchiver{ - Records: make(Records), - BaseArchive: []cpio.Record{ - cpio.StaticFile("init", "boo", 0o555), - }, + output: &cpio.Archive{ + Files: make(map[string]cpio.Record), }, want: Records{ - "init": cpio.StaticFile("init", "boo", 0o555), - "inito": cpio.StaticFile("inito", "huh", 0o111), + "init": cpio.StaticFile("init", "boo", 0o555), + "inito": cpio.StaticFile("inito", "huh", 0o111), + cpio.Trailer: cpio.TrailerRecord, }, }, } { t.Run(fmt.Sprintf("Test %02d (%s)", i, tt.desc), func(t *testing.T) { - tt.opts.BaseArchive = tt.ma - tt.opts.OutputFile = tt.ma + tt.opts.OutputFile = &Archive{tt.output} - if err := Write(tt.opts); err != tt.err { - t.Errorf("Write() = %v, want %v", err, tt.err) - } else if err == nil && !tt.ma.FinishCalled { - t.Errorf("Finish wasn't called on archive") + if err := Write(tt.opts); !errors.Is(err, tt.err) { + t.Errorf("Write = %v, want %v", err, tt.err) } - if !RecordsEqual(tt.ma.Records, tt.want, sameNameModeContent) { - t.Errorf("Write() = %v, want %v", tt.ma.Records, tt.want) + if !recordsEqual(tt.output.Files, tt.want, sameNameModeContent) { + t.Errorf("Write() = %v, want %v", tt.output.Files, tt.want) } }) } diff --git a/uroot/uroot.go b/uroot/uroot.go index 03dcbf5..1121a1d 100644 --- a/uroot/uroot.go +++ b/uroot/uroot.go @@ -184,11 +184,11 @@ type Opts struct { SkipLDD bool // OutputFile is the archive output file. - OutputFile initramfs.Writer + OutputFile initramfs.WriteOpener // BaseArchive is an existing initramfs to include in the resulting // initramfs. - BaseArchive initramfs.Reader + BaseArchive initramfs.ReadOpener // UseExistingInit determines whether the existing init from // BaseArchive should be used. diff --git a/uroot/uroot_test.go b/uroot/uroot_test.go index 1b222f5..793e1d6 100644 --- a/uroot/uroot_test.go +++ b/uroot/uroot_test.go @@ -15,17 +15,11 @@ import ( "github.com/u-root/gobusybox/src/pkg/golang" "github.com/u-root/mkuimage/cpio" "github.com/u-root/mkuimage/uroot/builder" + "github.com/u-root/mkuimage/uroot/initramfs" itest "github.com/u-root/mkuimage/uroot/initramfs/test" "github.com/u-root/uio/ulog/ulogtest" ) -type inMemArchive struct { - *cpio.Archive -} - -// Finish implements initramfs.Writer.Finish. -func (inMemArchive) Finish() error { return nil } - func TestCreateInitramfs(t *testing.T) { dir := t.TempDir() syscall.Umask(0) @@ -413,8 +407,8 @@ func TestCreateInitramfs(t *testing.T) { }, } { t.Run(fmt.Sprintf("Test %d [%s]", i, tt.name), func(t *testing.T) { - archive := inMemArchive{cpio.InMemArchive()} - tt.opts.OutputFile = archive + archive := cpio.InMemArchive() + tt.opts.OutputFile = &initramfs.Archive{archive} err := CreateInitramfs(l, tt.opts) for _, want := range tt.errs { if !errors.Is(err, want) { @@ -426,7 +420,7 @@ func TestCreateInitramfs(t *testing.T) { } for _, v := range tt.validators { - if err := v.Validate(archive.Archive); err != nil { + if err := v.Validate(archive); err != nil { t.Errorf("validator failed: %v / archive:\n%s", err, archive) } }