Skip to content

Commit

Permalink
Add arbitrary symlinks to archive
Browse files Browse the repository at this point in the history
Signed-off-by: Chris Koch <[email protected]>
  • Loading branch information
hugelgupf committed Feb 14, 2024
1 parent d46c521 commit 38aea63
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 0 deletions.
30 changes: 30 additions & 0 deletions uimage/uimage.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,11 @@ type Opts struct {
// - "/home/foo" is equivalent to "/home/foo:home/foo".
ExtraFiles []string

// Symlinks to create in the archive. File path in archive -> target
//
// Target can be the name of a command. If not, it will be created as given.
Symlinks map[string]string

// If true, do not use ldd to pick up dependencies from local machine for
// ExtraFiles. Useful if you have all deps revision controlled and wish to
// ensure builds are repeatable, and/or if the local machine's binaries use
Expand Down Expand Up @@ -293,6 +298,22 @@ func WithEnv(gopts ...golang.Opt) Modifier {
}
}

// WithSymlink adds a symlink to the archive.
//
// Target can be the name of a command. If not, it will be created as given.
func WithSymlink(file string, target string) Modifier {
return func(o *Opts) error {
if o.Symlinks == nil {
o.Symlinks = make(map[string]string)
}
if other, ok := o.Symlinks[file]; ok {
return fmt.Errorf("%w: cannot add symlink for %q as %q, already points to %q", os.ErrExist, file, target, other)
}
o.Symlinks[file] = target
return nil
}
}

// WithFiles adds files to the archive.
//
// Shared library dependencies will automatically also be added to the archive
Expand Down Expand Up @@ -563,6 +584,15 @@ func CreateInitramfs(l *llog.Logger, opts Opts) error {
if err := opts.addSymlinkTo(l, archive, opts.DefaultShell, "bin/defaultsh"); err != nil {
return fmt.Errorf("%w: %w", err, errDefaultshSymlink)
}
for p, target := range opts.Symlinks {
p = path.Clean(p)
if len(p) >= 1 && p[0] == '/' {
p = p[1:]
}
if err := opts.addSymlinkTo(l, archive, target, p); err != nil {
return fmt.Errorf("%w: could not add additional symlink", err)
}
}

// Finally, write the archive.
if err := initramfs.Write(archive); err != nil {
Expand Down
100 changes: 100 additions & 0 deletions uimage/uimage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,52 @@ func TestCreateInitramfs(t *testing.T) {
},
errs: []error{initramfs.ErrNoPath},
},
{
name: "symlinks",
opts: Opts{
Env: golang.Default(golang.DisableCGO()),
TempDir: dir,
InitCmd: "init",
DefaultShell: "ls",
Symlinks: map[string]string{
"ubin/foo": "ls",
"ubin/fooa": "/bin/systemd",
},
Commands: BusyboxCmds(
"github.com/u-root/u-root/cmds/core/init",
"github.com/u-root/u-root/cmds/core/ls",
),
},
validators: []itest.ArchiveValidator{
itest.HasFile{Path: "bbin/bb"},
itest.HasRecord{R: cpio.Symlink("bbin/init", "bb")},
itest.HasRecord{R: cpio.Symlink("bbin/ls", "bb")},
itest.HasRecord{R: cpio.Symlink("bin/defaultsh", "../bbin/ls")},
itest.HasRecord{R: cpio.Symlink("bin/sh", "../bbin/ls")},
itest.HasRecord{R: cpio.Symlink("ubin/foo", "../bbin/ls")},
itest.HasRecord{R: cpio.Symlink("ubin/fooa", "../bin/systemd")},
},
},
{
name: "dup symlinks",
opts: Opts{
Env: golang.Default(golang.DisableCGO()),
TempDir: dir,
InitCmd: "init",
DefaultShell: "ls",
Symlinks: map[string]string{
"/bbin/ls": "init",
},
Commands: BusyboxCmds(
"github.com/u-root/u-root/cmds/core/init",
"github.com/u-root/u-root/cmds/core/ls",
),
},
errs: []error{os.ErrExist},
validators: []itest.ArchiveValidator{
itest.IsEmpty{},
},
},
} {
t.Run(fmt.Sprintf("Test %d [%s]", i, tt.name), func(t *testing.T) {
archive := cpio.InMemArchive()
Expand Down Expand Up @@ -892,6 +938,60 @@ func TestCreateInitramfsWithAPI(t *testing.T) {
itest.HasContent{Path: "etc/foo", Content: "bar"},
},
},
{
name: "symlinks",
opts: []Modifier{
WithTempDir(dir),
WithEnv(golang.DisableCGO()),
WithInit("init"),
WithShell("ls"),
WithBusyboxCommands(
"github.com/u-root/u-root/cmds/core/init",
"github.com/u-root/u-root/cmds/core/ls",
),
WithSymlink("ubin/foo", "ls"),
WithSymlink("ubin/fooa", "/bin/systemd"),
},
validators: []itest.ArchiveValidator{
itest.HasFile{Path: "bbin/bb"},
itest.HasRecord{R: cpio.Symlink("bbin/init", "bb")},
itest.HasRecord{R: cpio.Symlink("bbin/ls", "bb")},
itest.HasRecord{R: cpio.Symlink("bin/defaultsh", "../bbin/ls")},
itest.HasRecord{R: cpio.Symlink("bin/sh", "../bbin/ls")},
itest.HasRecord{R: cpio.Symlink("ubin/foo", "../bbin/ls")},
itest.HasRecord{R: cpio.Symlink("ubin/fooa", "../bin/systemd")},
},
},
{
name: "dup symlinks",
opts: []Modifier{
WithTempDir(dir),
WithEnv(golang.DisableCGO()),
WithInit("init"),
WithShell("ls"),
WithBusyboxCommands(
"github.com/u-root/u-root/cmds/core/init",
"github.com/u-root/u-root/cmds/core/ls",
),
WithSymlink("/bbin/ls", "init"),
},
errs: []error{os.ErrExist},
validators: []itest.ArchiveValidator{
itest.IsEmpty{},
},
},
{
name: "dup with symlinks",
opts: []Modifier{
WithTempDir(dir),
WithSymlink("ubin/ls", "/bin/foo"),
WithSymlink("ubin/ls", "../bbin/ls"),
},
errs: []error{os.ErrExist},
validators: []itest.ArchiveValidator{
itest.IsEmpty{},
},
},
} {
t.Run(fmt.Sprintf("Test %d [%s]", i, tt.name), func(t *testing.T) {
archive := cpio.InMemArchive()
Expand Down

0 comments on commit 38aea63

Please sign in to comment.