-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(initramfs): change into fs.FS
This commit changes the `initramfs` package completely by refactoring it into a `fs.FS`. The `initramfs.FS` is tested with `fstest.TestFS` for proper implementation of `fs.FS` and `fs.File`. It changes the `Writer` into a `FileWriter` working with any `fs.File`. The virtrun's packages use is refactored to reflect those changes. Readability of the initramfs construction is improved. With this, the components are much more decoupled, which should allow for improved testability.
- Loading branch information
Showing
42 changed files
with
1,376 additions
and
1,567 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// SPDX-FileCopyrightText: 2024 Tobias Böhm <code@aibor.de> | ||
// | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
package elf | ||
|
||
import "errors" | ||
|
||
var ( | ||
// ErrNoInterpreter is returned if no interpreter is found in an ELF file. | ||
ErrNoInterpreter = errors.New("no interpreter in ELF file") | ||
|
||
// ErrNotELFFile is returned if the file does not have an ELF magic number. | ||
ErrNotELFFile = errors.New("is not an ELF file") | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,4 +6,4 @@ | |
|
||
//go:generate go generate -v ./testdata/cmd | ||
|
||
package initramfs_test | ||
package elf_test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,7 @@ | |
// | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
package initramfs | ||
package elf | ||
|
||
import ( | ||
"bytes" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
// SPDX-FileCopyrightText: 2024 Tobias Böhm <code@aibor.de> | ||
// | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
package elf | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"iter" | ||
"path/filepath" | ||
) | ||
|
||
// LibCollection is a deduplicated collection of dynamically linked libraries | ||
// and paths they are found at. | ||
type LibCollection struct { | ||
libs map[string]int | ||
searchPaths map[string]int | ||
} | ||
|
||
func (c *LibCollection) Libs() iter.Seq[string] { | ||
return func(yield func(string) bool) { | ||
for name := range c.libs { | ||
if !yield(name) { | ||
return | ||
} | ||
} | ||
} | ||
} | ||
|
||
func (c *LibCollection) SearchPaths() iter.Seq[string] { | ||
return func(yield func(string) bool) { | ||
for name := range c.searchPaths { | ||
if !yield(name) { | ||
return | ||
} | ||
} | ||
} | ||
} | ||
|
||
// CollectLibsFor recursively resolves the dynamically linked shared objects of | ||
// all given ELF files. | ||
// | ||
// The dynamic linker consumed LD_LIBRARY_PATH from the environment. | ||
func CollectLibsFor(files ...string) (LibCollection, error) { | ||
collection := LibCollection{ | ||
libs: make(map[string]int), | ||
searchPaths: make(map[string]int), | ||
} | ||
|
||
for _, name := range files { | ||
err := collectLibsFor(collection.libs, name) | ||
if err != nil { | ||
return collection, fmt.Errorf("[%s]: %w", name, err) | ||
} | ||
} | ||
|
||
for name := range collection.libs { | ||
dir, _ := filepath.Split(name) | ||
|
||
err := collectSearchPathsFor(collection.searchPaths, dir) | ||
if err != nil { | ||
return collection, fmt.Errorf("[%s]: %w", name, err) | ||
} | ||
} | ||
|
||
return collection, nil | ||
} | ||
|
||
func collectLibsFor(libs map[string]int, name string) error { | ||
// For each regular file, try to get linked shared objects. | ||
// Ignore if it is not an ELF file or if it is statically linked (has no | ||
// interpreter). Collect the absolute paths of the found shared objects | ||
// deduplicated in a set. | ||
paths, err := Ldd(name) | ||
if err != nil { | ||
if errors.Is(err, ErrNotELFFile) || | ||
errors.Is(err, ErrNoInterpreter) { | ||
return nil | ||
} | ||
|
||
return err | ||
} | ||
|
||
for _, p := range paths { | ||
absPath, err := filepath.Abs(p) | ||
if err != nil { | ||
return fmt.Errorf("absolute path: %w", err) | ||
} | ||
|
||
libs[absPath]++ | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func collectSearchPathsFor(paths map[string]int, dir string) error { | ||
dir = filepath.Clean(dir) | ||
if dir == "" { | ||
return nil | ||
} | ||
|
||
paths[dir]++ | ||
|
||
// Try if the directory has symbolic links and resolve them, so we | ||
// get the real path that the dynamic linker needs. | ||
canonicalDir, err := filepath.EvalSymlinks(dir) | ||
if err != nil { | ||
return fmt.Errorf("resolve symlinks: %w", err) | ||
} | ||
|
||
if canonicalDir != dir { | ||
paths[canonicalDir]++ | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// SPDX-FileCopyrightText: 2024 Tobias Böhm <code@aibor.de> | ||
// | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
package elf_test | ||
|
||
import ( | ||
"slices" | ||
"testing" | ||
|
||
"github.com/aibor/virtrun/internal/elf" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestLibCollection_CollectLibsFor(t *testing.T) { | ||
collection, err := elf.CollectLibsFor("testdata/bin/main") | ||
require.NoError(t, err) | ||
|
||
expectedLibs := []string{ | ||
"testdata/lib/libfunc2.so", | ||
"testdata/lib/libfunc3.so", | ||
"testdata/lib/libfunc1.so", | ||
} | ||
|
||
expectedLinks := []string{ | ||
"testdata/lib", | ||
} | ||
|
||
for _, name := range expectedLibs { | ||
expected := elf.MustAbsPath(t, name) | ||
actual := slices.Collect(collection.Libs()) | ||
assert.Contains(t, actual, expected, name) | ||
} | ||
|
||
for _, name := range expectedLinks { | ||
expected := elf.MustAbsPath(t, name) | ||
actual := slices.Collect(collection.SearchPaths()) | ||
assert.Contains(t, actual, expected, name) | ||
} | ||
} |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// SPDX-FileCopyrightText: 2024 Tobias Böhm <code@aibor.de> | ||
// | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
package elf | ||
|
||
import ( | ||
"path/filepath" | ||
"slices" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func AssertContainsPaths(tb testing.TB, actual, expected []string) bool { | ||
tb.Helper() | ||
|
||
expectedAbs := make(map[string]string, len(expected)) | ||
|
||
for _, path := range expected { | ||
abs, err := filepath.Abs(path) | ||
require.NoErrorf(tb, err, "must absolute path %s", path) | ||
|
||
expectedAbs[abs] = path | ||
} | ||
|
||
for _, path := range actual { | ||
abs, err := filepath.Abs(path) | ||
require.NoErrorf(tb, err, "must absolute path %s", path) | ||
|
||
relPath, exists := expectedAbs[abs] | ||
if !exists { | ||
continue | ||
} | ||
|
||
idx := slices.Index(expected, relPath) | ||
if idx >= 0 { | ||
expected = slices.Delete(expected, idx, idx+1) | ||
} | ||
} | ||
|
||
return assert.Empty(tb, expected) | ||
} | ||
|
||
func MustAbsPath(tb testing.TB, path string) string { | ||
tb.Helper() | ||
|
||
abs, err := filepath.Abs(path) | ||
require.NoError(tb, err) | ||
|
||
return abs | ||
} |
Oops, something went wrong.