mirror of
https://github.com/token2/snapd.git
synced 2026-03-13 11:15:47 -07:00
* tests: fix muinstaller tests for 24 * many: build drivers tree when current mount is not the target mount In some cases (when using the snapd install API or when installing from initramfs), the place where the kernel snap / components used for the installation are mounted is different to the final location in the installed system. This change considers this so the drivers tree is generated with symlinks pointing to the final expected location. * overlord: use model to check if we need to set-up drivers tree instead of using a device context, as for the installation using snapd API case we have a model but not a context. * tests/lib/tools/setup_nested_hybrid_system.sh: re-try kpartx -d * tests/muinstaller-real: check that drivers tree is created * tests/muinstaller-real: we need a bigger disk with latest kernel * tests/lib/tools/setup_nested_hybrid_system.sh: clean up after building muinstaller. On classic we have weird issues otherwise due to a desktop agent installing lxd. * tests/lib/prepare-restore.sh: purge lxd-installer lxd-installer was causing failures in the restore step for 24.04.
682 lines
25 KiB
Go
682 lines
25 KiB
Go
// -*- Mode: Go; indent-tabs-mode: t -*-
|
|
|
|
/*
|
|
* Copyright (C) 2024 Canonical Ltd
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 3 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
package kernel_test
|
|
|
|
import (
|
|
"errors"
|
|
"io/fs"
|
|
"os"
|
|
"path/filepath"
|
|
"syscall"
|
|
|
|
. "gopkg.in/check.v1"
|
|
|
|
"github.com/snapcore/snapd/dirs"
|
|
"github.com/snapcore/snapd/kernel"
|
|
"github.com/snapcore/snapd/logger"
|
|
"github.com/snapcore/snapd/osutil"
|
|
"github.com/snapcore/snapd/snap"
|
|
"github.com/snapcore/snapd/testutil"
|
|
)
|
|
|
|
type kernelDriversTestSuite struct {
|
|
testutil.BaseTest
|
|
}
|
|
|
|
var _ = Suite(&kernelDriversTestSuite{})
|
|
|
|
func (s *kernelDriversTestSuite) SetUpTest(c *C) {
|
|
s.BaseTest.SetUpTest(c)
|
|
|
|
dirs.SetRootDir(c.MkDir())
|
|
s.AddCleanup(func() { dirs.SetRootDir("") })
|
|
}
|
|
|
|
func (s *kernelDriversTestSuite) TestKernelVersionFromModulesDir(c *C) {
|
|
mountDir := filepath.Join(dirs.RunDir, "mnt/pc-kernel")
|
|
c.Assert(os.MkdirAll(mountDir, 0755), IsNil)
|
|
|
|
// No map file
|
|
ver, err := kernel.KernelVersionFromModulesDir(mountDir)
|
|
c.Check(err, ErrorMatches, `open .*/run/mnt/pc-kernel/modules: no such file or directory`)
|
|
c.Check(ver, Equals, "")
|
|
|
|
// Create directory so kernel version can be found
|
|
c.Assert(os.MkdirAll(filepath.Join(
|
|
mountDir, "modules", "5.15.0-78-generic"), 0755), IsNil)
|
|
ver, err = kernel.KernelVersionFromModulesDir(mountDir)
|
|
c.Check(err, IsNil)
|
|
c.Check(ver, Equals, "5.15.0-78-generic")
|
|
|
|
// Too many matches
|
|
c.Assert(os.MkdirAll(filepath.Join(
|
|
mountDir, "modules", "5.15.0-90-generic"), 0755), IsNil)
|
|
ver, err = kernel.KernelVersionFromModulesDir(mountDir)
|
|
c.Check(err, ErrorMatches, `more than one modules directory in ".*/run/mnt/pc-kernel/modules"`)
|
|
c.Check(ver, Equals, "")
|
|
}
|
|
|
|
func (s *kernelDriversTestSuite) TestKernelVersionFromModulesDirNoModDir(c *C) {
|
|
mountDir := filepath.Join(dirs.RunDir, "mnt/pc-kernel")
|
|
c.Assert(os.MkdirAll(mountDir, 0755), IsNil)
|
|
|
|
c.Assert(os.MkdirAll(filepath.Join(mountDir, "modules"), 0755), IsNil)
|
|
// Create file instead of directory
|
|
c.Assert(os.WriteFile(filepath.Join(
|
|
mountDir, "modules", "5.15.0-78-generic"), []byte{}, 0644), IsNil)
|
|
ver, err := kernel.KernelVersionFromModulesDir(mountDir)
|
|
c.Check(err, ErrorMatches, `no modules directory found in ".*/run/mnt/pc-kernel/modules"`)
|
|
c.Check(ver, Equals, "")
|
|
}
|
|
|
|
func (s *kernelDriversTestSuite) TestKernelVersionFromModulesDirBadVersion(c *C) {
|
|
mountDir := filepath.Join(dirs.RunDir, "mnt/pc-kernel")
|
|
c.Assert(os.MkdirAll(filepath.Join(
|
|
mountDir, "modules", "5.15.myway"), 0755), IsNil)
|
|
|
|
ver, err := kernel.KernelVersionFromModulesDir(mountDir)
|
|
c.Check(err, ErrorMatches, `no modules directory found in ".*/run/mnt/pc-kernel/modules"`)
|
|
c.Check(ver, Equals, "")
|
|
}
|
|
|
|
type createKernelSnapFilesOpts struct {
|
|
withFwUpdatesDir bool
|
|
}
|
|
|
|
func createKernelSnapFiles(c *C, kversion, kdir string, opts createKernelSnapFilesOpts) {
|
|
c.Assert(os.MkdirAll(kdir, 0755), IsNil)
|
|
|
|
// Create modinfo files
|
|
modDir := filepath.Join(kdir, "modules", kversion)
|
|
c.Assert(os.MkdirAll(modDir, 0755), IsNil)
|
|
modFile := []string{"modules.builtin.alias.bin", "modules.dep.bin", "modules.symbols"}
|
|
allFiles := append(modFile, "other.mod", "foo.bin")
|
|
for _, f := range allFiles {
|
|
c.Assert(os.WriteFile(filepath.Join(modDir, f), []byte{}, 0644), IsNil)
|
|
}
|
|
|
|
// Create firmware
|
|
fwDir := filepath.Join(kdir, "firmware")
|
|
c.Assert(os.MkdirAll(fwDir, 0755), IsNil)
|
|
// Regular files
|
|
for _, f := range []string{"blob1", "blob2"} {
|
|
c.Assert(os.WriteFile(filepath.Join(fwDir, f), []byte{}, 0644), IsNil)
|
|
}
|
|
if opts.withFwUpdatesDir {
|
|
c.Assert(os.MkdirAll(filepath.Join(fwDir, "updates"), 0755), IsNil)
|
|
}
|
|
// Directory, write file inside
|
|
fwSubDir := filepath.Join(fwDir, "subdir")
|
|
c.Assert(os.MkdirAll(fwSubDir, 0755), IsNil)
|
|
blob3 := filepath.Join(fwSubDir, "blob3")
|
|
c.Assert(os.WriteFile(blob3, []byte{}, 0644), IsNil)
|
|
// Symlink
|
|
os.Symlink("subdir/blob3", filepath.Join(fwDir, "ln_to_blob3"))
|
|
}
|
|
|
|
func (s *kernelDriversTestSuite) TestBuildKernelDriversTree(c *C) {
|
|
// Build twice to make sure the function is idempotent
|
|
testBuildKernelDriversTree(c, createKernelSnapFilesOpts{})
|
|
testBuildKernelDriversTree(c, createKernelSnapFilesOpts{})
|
|
|
|
// Now remove and check
|
|
treeRoot := filepath.Join(dirs.SnapdStateDir(dirs.GlobalRootDir), "kernel", "pc-kernel", "1")
|
|
kernel.RemoveKernelDriversTree(treeRoot)
|
|
c.Assert(osutil.FileExists(treeRoot), Equals, false)
|
|
}
|
|
|
|
func (s *kernelDriversTestSuite) TestBuildKernelDriversTreeWithUpdates(c *C) {
|
|
testBuildKernelDriversTree(c, createKernelSnapFilesOpts{withFwUpdatesDir: true})
|
|
|
|
// Now remove and check
|
|
treeRoot := filepath.Join(dirs.SnapdStateDir(dirs.GlobalRootDir), "kernel", "pc-kernel", "1")
|
|
kernel.RemoveKernelDriversTree(treeRoot)
|
|
c.Assert(osutil.FileExists(treeRoot), Equals, false)
|
|
}
|
|
|
|
type expectInode struct {
|
|
file string
|
|
fType fs.FileMode
|
|
linkTarget string
|
|
}
|
|
|
|
func doDirChecks(c *C, dir string, expected []expectInode) {
|
|
entries, err := os.ReadDir(dir)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(len(entries), Equals, len(expected))
|
|
for i, ent := range entries {
|
|
c.Check(ent.Name(), Equals, expected[i].file)
|
|
c.Check(ent.Type(), Equals, expected[i].fType)
|
|
if ent.Type() == fs.ModeSymlink {
|
|
dest, err := os.Readlink(filepath.Join(dir, ent.Name()))
|
|
c.Assert(err, IsNil)
|
|
c.Check(dest, Equals, expected[i].linkTarget)
|
|
}
|
|
}
|
|
}
|
|
|
|
func testBuildKernelDriversTree(c *C, opts createKernelSnapFilesOpts) {
|
|
mountDir := filepath.Join(dirs.SnapMountDir, "pc-kernel/1")
|
|
kversion := "5.15.0-78-generic"
|
|
createKernelSnapFiles(c, kversion, mountDir, opts)
|
|
|
|
// Now build the tree
|
|
destDir := kernel.DriversTreeDir(dirs.GlobalRootDir, "pc-kernel", snap.R(1))
|
|
c.Assert(kernel.EnsureKernelDriversTree(
|
|
kernel.MountPoints{
|
|
Current: mountDir,
|
|
Target: mountDir},
|
|
nil, destDir,
|
|
&kernel.KernelDriversTreeOptions{KernelInstall: true}), IsNil)
|
|
|
|
// Check content is as expected
|
|
modsRoot := filepath.Join(dirs.SnapdStateDir(dirs.GlobalRootDir), "kernel", "pc-kernel", "1", "lib", "modules", kversion)
|
|
modsMntDir := filepath.Join(mountDir, "modules", kversion)
|
|
expected := []expectInode{
|
|
{"kernel", fs.ModeSymlink, filepath.Join(modsMntDir, "kernel")},
|
|
{"modules.builtin.alias.bin", 0, ""},
|
|
{"modules.dep.bin", 0, ""},
|
|
{"modules.symbols", 0, ""},
|
|
{"updates", fs.ModeDir, ""},
|
|
{"vdso", fs.ModeSymlink, filepath.Join(modsMntDir, "vdso")},
|
|
}
|
|
doDirChecks(c, modsRoot, expected)
|
|
|
|
// Check firmware entries
|
|
fwRoot := filepath.Join(dirs.SnapdStateDir(dirs.GlobalRootDir), "kernel", "pc-kernel", "1", "lib", "firmware")
|
|
fwMntDir := filepath.Join(mountDir, "firmware")
|
|
expected = []expectInode{
|
|
{"blob1", fs.ModeSymlink, filepath.Join(fwMntDir, "blob1")},
|
|
{"blob2", fs.ModeSymlink, filepath.Join(fwMntDir, "blob2")},
|
|
{"ln_to_blob3", fs.ModeSymlink, "subdir/blob3"},
|
|
{"subdir", fs.ModeSymlink, filepath.Join(fwMntDir, "subdir")},
|
|
{"updates", fs.ModeDir, ""},
|
|
}
|
|
doDirChecks(c, fwRoot, expected)
|
|
|
|
// Check symlinks to files point to real files
|
|
for _, ln := range []string{
|
|
filepath.Join(fwRoot, "blob1"),
|
|
filepath.Join(fwRoot, "blob2"),
|
|
filepath.Join(fwRoot, "ln_to_blob3"),
|
|
filepath.Join(fwRoot, "subdir/blob3"),
|
|
} {
|
|
path, err := filepath.EvalSymlinks(ln)
|
|
c.Assert(err, IsNil)
|
|
exists, isReg, err := osutil.RegularFileExists(path)
|
|
c.Assert(err, IsNil)
|
|
c.Check(exists, Equals, true)
|
|
c.Check(isReg, Equals, true)
|
|
}
|
|
}
|
|
|
|
func (s *kernelDriversTestSuite) TestBuildKernelDriversNoModsOrFw(c *C) {
|
|
buf, restore := logger.MockLogger()
|
|
defer restore()
|
|
|
|
mountDir := filepath.Join(dirs.SnapMountDir, "pc-kernel/11")
|
|
c.Assert(os.MkdirAll(mountDir, 0755), IsNil)
|
|
|
|
// Build the tree should not fail
|
|
destDir := kernel.DriversTreeDir(dirs.GlobalRootDir, "pc-kernel", snap.R(1))
|
|
err := kernel.EnsureKernelDriversTree(
|
|
kernel.MountPoints{
|
|
Current: mountDir,
|
|
Target: mountDir}, nil, destDir,
|
|
&kernel.KernelDriversTreeOptions{KernelInstall: true})
|
|
c.Assert(err, IsNil)
|
|
|
|
// but log should warn about this
|
|
c.Assert(buf.String(), testutil.Contains, `no modules found in "`+mountDir+`"`)
|
|
c.Assert(buf.String(), testutil.Contains, `no firmware found in "`+mountDir+`/firmware"`)
|
|
}
|
|
|
|
func createKernelSnapFilesOnlyModules(c *C, kversion, kdir string) {
|
|
c.Assert(os.MkdirAll(kdir, 0755), IsNil)
|
|
|
|
// Create modinfo files
|
|
modDir := filepath.Join(kdir, "modules", kversion)
|
|
c.Assert(os.MkdirAll(modDir, 0755), IsNil)
|
|
c.Assert(os.WriteFile(filepath.Join(modDir, "modules.dep.bin"), []byte{}, 0644), IsNil)
|
|
}
|
|
|
|
func (s *kernelDriversTestSuite) TestBuildKernelDriversOnlyMods(c *C) {
|
|
buf, restore := logger.MockLogger()
|
|
defer restore()
|
|
|
|
mountDir := filepath.Join(dirs.RunDir, "mnt/pc-kernel")
|
|
kversion := "5.15.0-78-generic"
|
|
createKernelSnapFilesOnlyModules(c, kversion, mountDir)
|
|
|
|
// Build the tree should not fail
|
|
destDir := kernel.DriversTreeDir(dirs.GlobalRootDir, "pc-kernel", snap.R(1))
|
|
err := kernel.EnsureKernelDriversTree(
|
|
kernel.MountPoints{
|
|
Current: mountDir,
|
|
Target: mountDir}, nil, destDir,
|
|
&kernel.KernelDriversTreeOptions{KernelInstall: true})
|
|
c.Assert(err, IsNil)
|
|
|
|
// check created file
|
|
modPath := filepath.Join(dirs.SnapdStateDir(dirs.GlobalRootDir), "kernel", "pc-kernel", "1", "lib", "modules", kversion, "modules.dep.bin")
|
|
exists, isReg, err := osutil.RegularFileExists(modPath)
|
|
c.Assert(err, IsNil)
|
|
c.Check(exists, Equals, true)
|
|
c.Check(isReg, Equals, true)
|
|
|
|
// but log should warn about this
|
|
c.Assert(buf.String(), testutil.Contains, `no firmware found in "`+mountDir+`/firmware"`)
|
|
}
|
|
|
|
func (s *kernelDriversTestSuite) TestBuildKernelDriversOnlyModsWithTargetDir(c *C) {
|
|
buf, restore := logger.MockLogger()
|
|
defer restore()
|
|
|
|
mountDir := filepath.Join(dirs.RunDir, "mnt/tmp-mount")
|
|
kTargetDir := filepath.Join(dirs.RunDir, "mnt/pc-kernel")
|
|
kversion := "5.15.0-78-generic"
|
|
createKernelSnapFilesOnlyModules(c, kversion, mountDir)
|
|
|
|
// Build the tree should not fail
|
|
destDir := kernel.DriversTreeDir(dirs.GlobalRootDir, "pc-kernel", snap.R(1))
|
|
err := kernel.EnsureKernelDriversTree(
|
|
kernel.MountPoints{
|
|
Current: mountDir,
|
|
Target: kTargetDir}, nil, destDir,
|
|
&kernel.KernelDriversTreeOptions{KernelInstall: true})
|
|
c.Assert(err, IsNil)
|
|
|
|
// check created file
|
|
modPath := filepath.Join(dirs.SnapdStateDir(dirs.GlobalRootDir), "kernel", "pc-kernel", "1", "lib", "modules", kversion)
|
|
modDepBinPath := filepath.Join(modPath, "modules.dep.bin")
|
|
exists, isReg, err := osutil.RegularFileExists(modDepBinPath)
|
|
c.Assert(err, IsNil)
|
|
c.Check(exists, Equals, true)
|
|
c.Check(isReg, Equals, true)
|
|
// Check symlinks points to final target
|
|
modsPath := filepath.Join(modPath, "kernel")
|
|
modsTarget, err := os.Readlink(modsPath)
|
|
c.Assert(err, IsNil)
|
|
c.Check(modsTarget, Equals, filepath.Join(kTargetDir, "modules", kversion, "kernel"))
|
|
|
|
// but log should warn about this
|
|
c.Assert(buf.String(), testutil.Contains, `no firmware found in "`+mountDir+`/firmware"`)
|
|
}
|
|
|
|
func createKernelSnapFilesOnlyFw(c *C, kdir string) {
|
|
c.Assert(os.MkdirAll(kdir, 0755), IsNil)
|
|
|
|
// Create firmware files
|
|
fwDir := filepath.Join(kdir, "firmware")
|
|
c.Assert(os.MkdirAll(fwDir, 0755), IsNil)
|
|
c.Assert(os.WriteFile(filepath.Join(fwDir, "wifi_fw.bin"), []byte{}, 0644), IsNil)
|
|
}
|
|
|
|
func (s *kernelDriversTestSuite) TestBuildKernelDriversOnlyFw(c *C) {
|
|
buf, restore := logger.MockLogger()
|
|
defer restore()
|
|
|
|
mountDir := filepath.Join(dirs.RunDir, "mnt/pc-kernel")
|
|
createKernelSnapFilesOnlyFw(c, mountDir)
|
|
|
|
// Build the tree should not fail
|
|
destDir := kernel.DriversTreeDir(dirs.GlobalRootDir, "pc-kernel", snap.R(1))
|
|
err := kernel.EnsureKernelDriversTree(
|
|
kernel.MountPoints{
|
|
Current: mountDir,
|
|
Target: mountDir}, nil, destDir,
|
|
&kernel.KernelDriversTreeOptions{KernelInstall: true})
|
|
c.Assert(err, IsNil)
|
|
|
|
// check link
|
|
fwPath := filepath.Join(dirs.SnapdStateDir(dirs.GlobalRootDir), "kernel", "pc-kernel", "1", "lib", "firmware", "wifi_fw.bin")
|
|
c.Assert(osutil.IsSymlink(fwPath), Equals, true)
|
|
|
|
// but log should warn about this
|
|
c.Assert(buf.String(), testutil.Contains, `no modules found in "`+mountDir+`"`)
|
|
}
|
|
|
|
func (s *kernelDriversTestSuite) TestBuildKernelDriversOnlyFwWithTargetDir(c *C) {
|
|
buf, restore := logger.MockLogger()
|
|
defer restore()
|
|
|
|
mountDir := filepath.Join(dirs.RunDir, "mnt/tmp-mount")
|
|
kTargetDir := filepath.Join(dirs.RunDir, "mnt/pc-kernel")
|
|
createKernelSnapFilesOnlyFw(c, mountDir)
|
|
|
|
// Build the tree should not fail
|
|
destDir := kernel.DriversTreeDir(dirs.GlobalRootDir, "pc-kernel", snap.R(1))
|
|
err := kernel.EnsureKernelDriversTree(
|
|
kernel.MountPoints{
|
|
Current: mountDir,
|
|
Target: kTargetDir}, nil, destDir,
|
|
&kernel.KernelDriversTreeOptions{KernelInstall: true})
|
|
c.Assert(err, IsNil)
|
|
|
|
// check link
|
|
fwPath := filepath.Join(dirs.SnapdStateDir(dirs.GlobalRootDir), "kernel", "pc-kernel", "1", "lib", "firmware", "wifi_fw.bin")
|
|
fwPathTarget, err := os.Readlink(fwPath)
|
|
c.Assert(err, IsNil)
|
|
c.Check(fwPathTarget, Equals, filepath.Join(kTargetDir, "firmware", "wifi_fw.bin"))
|
|
|
|
// but log should warn about this
|
|
c.Assert(buf.String(), testutil.Contains, `no modules found in "`+mountDir+`"`)
|
|
}
|
|
|
|
func (s *kernelDriversTestSuite) TestBuildKernelDriversAbsFwSymlink(c *C) {
|
|
mountDir := filepath.Join(dirs.RunDir, "mnt/pc-kernel")
|
|
|
|
// Create firmware files
|
|
fwDir := filepath.Join(mountDir, "firmware")
|
|
c.Assert(os.MkdirAll(fwDir, 0755), IsNil)
|
|
// Symlink
|
|
os.Symlink("/absdir/blob3", filepath.Join(fwDir, "ln_to_abs"))
|
|
|
|
// Fails on the absolute path in the link
|
|
destDir := kernel.DriversTreeDir(dirs.GlobalRootDir, "pc-kernel", snap.R(1))
|
|
err := kernel.EnsureKernelDriversTree(
|
|
kernel.MountPoints{
|
|
Current: mountDir,
|
|
Target: mountDir}, nil, destDir,
|
|
&kernel.KernelDriversTreeOptions{KernelInstall: true})
|
|
c.Assert(err, ErrorMatches, `symlink \".*lib/firmware/ln_to_abs\" points to absolute path \"/absdir/blob3\"`)
|
|
|
|
// Make sure the tree has been deleted
|
|
treeRoot := filepath.Join(dirs.SnapdStateDir(dirs.GlobalRootDir), "kernel", "pc-kernel", "1")
|
|
c.Assert(osutil.FileExists(treeRoot), Equals, false)
|
|
}
|
|
|
|
func (s *kernelDriversTestSuite) TestBuildKernelDriversTreeCleanup(c *C) {
|
|
mountDir := filepath.Join(dirs.RunDir, "mnt/pc-kernel")
|
|
kversion := "5.15.0-78-generic"
|
|
createKernelSnapFiles(c, kversion, mountDir, createKernelSnapFilesOpts{})
|
|
|
|
restore := kernel.MockOsSymlink(func(string, string) error {
|
|
return errors.New("mocked symlink error")
|
|
})
|
|
defer restore()
|
|
|
|
// Now build the tree
|
|
destDir := kernel.DriversTreeDir(dirs.GlobalRootDir, "pc-kernel", snap.R(1))
|
|
err := kernel.EnsureKernelDriversTree(
|
|
kernel.MountPoints{
|
|
Current: mountDir,
|
|
Target: mountDir}, nil, destDir,
|
|
&kernel.KernelDriversTreeOptions{KernelInstall: true})
|
|
c.Assert(err, ErrorMatches, "mocked symlink error")
|
|
|
|
// Make sure the tree has been deleted
|
|
treeRoot := filepath.Join(dirs.SnapdStateDir(dirs.GlobalRootDir), "kernel", "pc-kernel", "1")
|
|
c.Assert(osutil.FileExists(treeRoot), Equals, false)
|
|
}
|
|
|
|
func (s *kernelDriversTestSuite) TestBuildKernelDriversBadFileType(c *C) {
|
|
mountDir := filepath.Join(dirs.RunDir, "mnt/pc-kernel")
|
|
kversion := "5.15.0-78-generic"
|
|
createKernelSnapFiles(c, kversion, mountDir, createKernelSnapFilesOpts{})
|
|
|
|
// Additional file of not expected type in "firmware"
|
|
fwDir := filepath.Join(mountDir, "firmware")
|
|
c.Assert(syscall.Mkfifo(filepath.Join(fwDir, "fifo"), 0666), IsNil)
|
|
|
|
// Now build the tree
|
|
destDir := kernel.DriversTreeDir(dirs.GlobalRootDir, "pc-kernel", snap.R(1))
|
|
err := kernel.EnsureKernelDriversTree(
|
|
kernel.MountPoints{
|
|
Current: mountDir,
|
|
Target: mountDir}, nil, destDir,
|
|
&kernel.KernelDriversTreeOptions{KernelInstall: true})
|
|
c.Assert(err, ErrorMatches, `"fifo" has unexpected file type: p---------`)
|
|
|
|
// Make sure the tree has been deleted
|
|
treeRoot := filepath.Join(dirs.SnapdStateDir(dirs.GlobalRootDir), "kernel", "pc-kernel", "1")
|
|
c.Assert(osutil.FileExists(treeRoot), Equals, false)
|
|
}
|
|
|
|
func createKernelModulesCompFiles(c *C, kversion, compdir, filePrefix string) {
|
|
c.Assert(os.MkdirAll(compdir, 0755), IsNil)
|
|
|
|
// Create some kernel module file
|
|
modDir := filepath.Join(compdir, "modules", kversion, "kernel/foo")
|
|
c.Assert(os.MkdirAll(modDir, 0755), IsNil)
|
|
c.Assert(os.WriteFile(filepath.Join(modDir, filePrefix+".ko.zst"), []byte{}, 0644), IsNil)
|
|
|
|
// and some fw
|
|
fwDir := filepath.Join(compdir, "firmware")
|
|
c.Assert(os.MkdirAll(fwDir, 0755), IsNil)
|
|
c.Assert(os.WriteFile(filepath.Join(fwDir, filePrefix+".bin"), []byte{}, 0644), IsNil)
|
|
}
|
|
|
|
func (s *kernelDriversTestSuite) TestBuildKernelDriversTreeWithKernelAndComps(c *C) {
|
|
// Build twice to make sure the function is idempotent
|
|
opts := &kernel.KernelDriversTreeOptions{KernelInstall: true}
|
|
testBuildKernelDriversTreeWithComps(c, opts)
|
|
testBuildKernelDriversTreeWithComps(c, opts)
|
|
|
|
// Now remove and check
|
|
treeRoot := filepath.Join(dirs.SnapdStateDir(dirs.GlobalRootDir), "kernel", "pc-kernel", "1")
|
|
kernel.RemoveKernelDriversTree(treeRoot)
|
|
c.Assert(osutil.FileExists(treeRoot), Equals, false)
|
|
}
|
|
|
|
func (s *kernelDriversTestSuite) TestBuildKernelDriversTreeCompsNoKernelInstall(c *C) {
|
|
// Kernel needs to have been installed first
|
|
testBuildKernelDriversTree(c, createKernelSnapFilesOpts{})
|
|
// Build twice to make sure the function is idempotent
|
|
opts := &kernel.KernelDriversTreeOptions{KernelInstall: false}
|
|
testBuildKernelDriversTreeWithComps(c, opts)
|
|
testBuildKernelDriversTreeWithComps(c, opts)
|
|
|
|
// Now remove and check
|
|
treeRoot := filepath.Join(dirs.SnapdStateDir(dirs.GlobalRootDir), "kernel", "pc-kernel", "1")
|
|
kernel.RemoveKernelDriversTree(treeRoot)
|
|
c.Assert(osutil.FileExists(treeRoot), Equals, false)
|
|
|
|
// No _tmp folder should be around
|
|
treeRoot = filepath.Join(dirs.SnapdStateDir(dirs.GlobalRootDir), "kernel", "pc-kernel", "1_tmp")
|
|
c.Assert(osutil.FileExists(treeRoot), Equals, false)
|
|
}
|
|
|
|
func (s *kernelDriversTestSuite) TestBuildKernelDriversTreeCompsNoKernel(c *C) {
|
|
mockCmd := testutil.MockCommand(c, "depmod", "")
|
|
defer mockCmd.Restore()
|
|
|
|
mountDir := filepath.Join(dirs.RunDir, "mnt/pc-kernel")
|
|
kversion := "5.15.0-78-generic"
|
|
createKernelSnapFiles(c, kversion, mountDir, createKernelSnapFilesOpts{})
|
|
|
|
compMntDir1 := filepath.Join(dirs.RunDir, "mnt/kernel-snaps/comp1")
|
|
compMntDir2 := filepath.Join(dirs.RunDir, "mnt/kernel-snaps/comp2")
|
|
createKernelModulesCompFiles(c, kversion, compMntDir1, "comp1")
|
|
createKernelModulesCompFiles(c, kversion, compMntDir2, "comp2")
|
|
kmodsConts := []snap.ContainerPlaceInfo{
|
|
snap.MinimalComponentContainerPlaceInfo("comp1", snap.R(11), "pc-kernel"),
|
|
snap.MinimalComponentContainerPlaceInfo("comp2", snap.R(22), "pc-kernel"),
|
|
}
|
|
compsMntPts := []kernel.ModulesCompMountPoints{
|
|
{"comp1", kernel.MountPoints{kmodsConts[0].MountDir(), kmodsConts[0].MountDir()}},
|
|
{"comp2", kernel.MountPoints{kmodsConts[1].MountDir(), kmodsConts[1].MountDir()}},
|
|
}
|
|
|
|
// Now build the tree, will fail as no kernel was installed previously
|
|
destDir := kernel.DriversTreeDir(dirs.GlobalRootDir, "pc-kernel", snap.R(1))
|
|
err := kernel.EnsureKernelDriversTree(
|
|
kernel.MountPoints{
|
|
Current: mountDir,
|
|
Target: mountDir},
|
|
compsMntPts, destDir, &kernel.KernelDriversTreeOptions{KernelInstall: false})
|
|
c.Assert(err, ErrorMatches, `while swapping .*: no such file or directory`)
|
|
}
|
|
|
|
func testBuildKernelDriversTreeWithComps(c *C, opts *kernel.KernelDriversTreeOptions) {
|
|
mockCmd := testutil.MockCommand(c, "depmod", "")
|
|
defer mockCmd.Restore()
|
|
|
|
mountDir := filepath.Join(dirs.SnapMountDir, "pc-kernel/1")
|
|
kversion := "5.15.0-78-generic"
|
|
createKernelSnapFiles(c, kversion, mountDir, createKernelSnapFilesOpts{})
|
|
|
|
compMntDir1 := filepath.Join(dirs.SnapMountDir, "pc-kernel/components/mnt/comp1/11")
|
|
compMntDir2 := filepath.Join(dirs.SnapMountDir, "pc-kernel/components/mnt/comp2/22")
|
|
createKernelModulesCompFiles(c, kversion, compMntDir1, "comp1")
|
|
createKernelModulesCompFiles(c, kversion, compMntDir2, "comp2")
|
|
kmodsConts := []snap.ContainerPlaceInfo{
|
|
snap.MinimalComponentContainerPlaceInfo("comp1", snap.R(11), "pc-kernel"),
|
|
snap.MinimalComponentContainerPlaceInfo("comp2", snap.R(22), "pc-kernel"),
|
|
}
|
|
compsMntPts := []kernel.ModulesCompMountPoints{
|
|
{"comp1", kernel.MountPoints{kmodsConts[0].MountDir(), kmodsConts[0].MountDir()}},
|
|
{"comp2", kernel.MountPoints{kmodsConts[1].MountDir(), kmodsConts[1].MountDir()}},
|
|
}
|
|
|
|
workSubdir := "1_tmp"
|
|
if opts.KernelInstall {
|
|
workSubdir = "1"
|
|
}
|
|
treeRoot := filepath.Join(dirs.SnapdStateDir(dirs.GlobalRootDir), "kernel", "pc-kernel", workSubdir)
|
|
// Find out if the directory already exists, as in that case
|
|
// there are no calls to depmod
|
|
exists, isDir, err := osutil.DirExists(treeRoot)
|
|
c.Assert(err, IsNil)
|
|
|
|
// Now build the tree
|
|
destDir := kernel.DriversTreeDir(dirs.GlobalRootDir, "pc-kernel", snap.R(1))
|
|
c.Assert(kernel.EnsureKernelDriversTree(
|
|
kernel.MountPoints{
|
|
Current: mountDir,
|
|
Target: mountDir},
|
|
compsMntPts, destDir, opts), IsNil)
|
|
|
|
if exists {
|
|
c.Assert(isDir, Equals, true)
|
|
c.Assert(mockCmd.Calls(), IsNil)
|
|
} else {
|
|
c.Assert(mockCmd.Calls(), DeepEquals, [][]string{
|
|
{"depmod", "-b", treeRoot, kversion},
|
|
})
|
|
}
|
|
|
|
// Check modules root dir is as expected
|
|
modsRoot := filepath.Join(dirs.SnapdStateDir(dirs.GlobalRootDir), "kernel", "pc-kernel", "1", "lib", "modules", kversion)
|
|
modsMntDir := filepath.Join(mountDir, "modules", kversion)
|
|
expected := []expectInode{
|
|
{"kernel", fs.ModeSymlink, filepath.Join(modsMntDir, "kernel")},
|
|
{"modules.builtin.alias.bin", 0, ""},
|
|
{"modules.dep.bin", 0, ""},
|
|
{"modules.symbols", 0, ""},
|
|
{"updates", fs.ModeDir, ""},
|
|
{"vdso", fs.ModeSymlink, filepath.Join(modsMntDir, "vdso")},
|
|
}
|
|
doDirChecks(c, modsRoot, expected)
|
|
|
|
// Check links for modules shipped in components
|
|
updatesDir := filepath.Join(modsRoot, "updates")
|
|
expected = []expectInode{
|
|
{"comp1", fs.ModeSymlink, filepath.Join(compMntDir1, "modules", kversion)},
|
|
{"comp2", fs.ModeSymlink, filepath.Join(compMntDir2, "modules", kversion)},
|
|
}
|
|
doDirChecks(c, updatesDir, expected)
|
|
|
|
// Check firmware entries from snap
|
|
fwRoot := filepath.Join(dirs.SnapdStateDir(dirs.GlobalRootDir), "kernel", "pc-kernel", "1", "lib", "firmware")
|
|
fwMntDir := filepath.Join(mountDir, "firmware")
|
|
expected = []expectInode{
|
|
{"blob1", fs.ModeSymlink, filepath.Join(fwMntDir, "blob1")},
|
|
{"blob2", fs.ModeSymlink, filepath.Join(fwMntDir, "blob2")},
|
|
{"ln_to_blob3", fs.ModeSymlink, "subdir/blob3"},
|
|
{"subdir", fs.ModeSymlink, filepath.Join(fwMntDir, "subdir")},
|
|
{"updates", fs.ModeDir, ""},
|
|
}
|
|
doDirChecks(c, fwRoot, expected)
|
|
|
|
// Check firmware entries from components
|
|
fwUpdates := filepath.Join(fwRoot, "updates")
|
|
expected = []expectInode{
|
|
{"comp1.bin", fs.ModeSymlink, filepath.Join(compMntDir1, "firmware/comp1.bin")},
|
|
{"comp2.bin", fs.ModeSymlink, filepath.Join(compMntDir2, "firmware/comp2.bin")},
|
|
}
|
|
doDirChecks(c, fwUpdates, expected)
|
|
|
|
// Check symlinks to files point to real files
|
|
for _, ln := range []string{
|
|
filepath.Join(updatesDir, "comp1/kernel/foo/comp1.ko.zst"),
|
|
filepath.Join(updatesDir, "comp2/kernel/foo/comp2.ko.zst"),
|
|
filepath.Join(fwRoot, "blob1"),
|
|
filepath.Join(fwRoot, "blob2"),
|
|
filepath.Join(fwRoot, "ln_to_blob3"),
|
|
filepath.Join(fwRoot, "subdir/blob3"),
|
|
filepath.Join(fwUpdates, "comp1.bin"),
|
|
filepath.Join(fwUpdates, "comp2.bin"),
|
|
} {
|
|
path, err := filepath.EvalSymlinks(ln)
|
|
c.Assert(err, IsNil)
|
|
exists, isReg, err := osutil.RegularFileExists(path)
|
|
c.Assert(err, IsNil)
|
|
c.Check(exists, Equals, true)
|
|
c.Check(isReg, Equals, true)
|
|
}
|
|
|
|
if !opts.KernelInstall {
|
|
// Check that there is no tmp folder left behind
|
|
tmpDir := filepath.Join(dirs.SnapdStateDir(dirs.GlobalRootDir), "kernel", "pc-kernel", "1_tmp")
|
|
exists, _, _ = osutil.RegularFileExists(tmpDir)
|
|
c.Check(exists, Equals, false)
|
|
}
|
|
}
|
|
|
|
func (s *kernelDriversTestSuite) TestBuildKernelDriversTreeCompsWithTargetDir(c *C) {
|
|
mockCmd := testutil.MockCommand(c, "depmod", "")
|
|
defer mockCmd.Restore()
|
|
|
|
// Kernel needs to have been installed first
|
|
testBuildKernelDriversTree(c, createKernelSnapFilesOpts{})
|
|
|
|
mountDir := filepath.Join(dirs.RunDir, "mnt/pc-kernel")
|
|
kversion := "5.15.0-78-generic"
|
|
createKernelSnapFiles(c, kversion, mountDir, createKernelSnapFilesOpts{})
|
|
|
|
compMntDir1 := filepath.Join(dirs.RunDir, "mnt/kernel-snaps/comp1")
|
|
createKernelModulesCompFiles(c, kversion, compMntDir1, "comp1")
|
|
kmodCont := snap.MinimalComponentContainerPlaceInfo("comp1", snap.R(11), "pc-kernel")
|
|
// Current mount is different to the one in the final system
|
|
compsMntPts := []kernel.ModulesCompMountPoints{
|
|
{"comp1", kernel.MountPoints{
|
|
Current: compMntDir1,
|
|
Target: kmodCont.MountDir()}},
|
|
}
|
|
|
|
// Now build the tree, will fail as no kernel was installed previously
|
|
destDir := kernel.DriversTreeDir(dirs.GlobalRootDir, "pc-kernel", snap.R(1))
|
|
err := kernel.EnsureKernelDriversTree(
|
|
kernel.MountPoints{
|
|
Current: mountDir,
|
|
Target: mountDir},
|
|
compsMntPts, destDir, &kernel.KernelDriversTreeOptions{KernelInstall: false})
|
|
c.Assert(err, IsNil)
|
|
|
|
// Check firmware entries from components
|
|
fwRoot := filepath.Join(dirs.SnapdStateDir(dirs.GlobalRootDir), "kernel", "pc-kernel", "1", "lib", "firmware")
|
|
fwUpdates := filepath.Join(fwRoot, "updates")
|
|
expected := []expectInode{
|
|
{"comp1.bin", fs.ModeSymlink, filepath.Join(kmodCont.MountDir(), "firmware/comp1.bin")},
|
|
}
|
|
doDirChecks(c, fwUpdates, expected)
|
|
}
|