github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/bootloader/lk_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2019 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package bootloader_test
    21  
    22  import (
    23  	"io/ioutil"
    24  	"os"
    25  	"path/filepath"
    26  	"sort"
    27  
    28  	. "gopkg.in/check.v1"
    29  
    30  	"github.com/snapcore/snapd/boot"
    31  	"github.com/snapcore/snapd/bootloader"
    32  	"github.com/snapcore/snapd/bootloader/lkenv"
    33  	"github.com/snapcore/snapd/osutil"
    34  	"github.com/snapcore/snapd/snap"
    35  	"github.com/snapcore/snapd/snap/snapfile"
    36  	"github.com/snapcore/snapd/snap/snaptest"
    37  )
    38  
    39  type lkTestSuite struct {
    40  	baseBootenvTestSuite
    41  }
    42  
    43  var _ = Suite(&lkTestSuite{})
    44  
    45  func (s *lkTestSuite) TestNewLk(c *C) {
    46  	bootloader.MockLkFiles(c, s.rootdir, nil)
    47  	l := bootloader.NewLk(s.rootdir, nil)
    48  	c.Assert(l, NotNil)
    49  	c.Check(bootloader.LkRuntimeMode(l), Equals, true)
    50  	c.Check(l.ConfigFile(), Equals, filepath.Join(s.rootdir, "/dev/disk/by-partlabel", "snapbootsel"))
    51  }
    52  
    53  func (s *lkTestSuite) TestNewLkImageBuildingTime(c *C) {
    54  	opts := &bootloader.Options{
    55  		PrepareImageTime: true,
    56  	}
    57  	bootloader.MockLkFiles(c, s.rootdir, opts)
    58  	l := bootloader.NewLk(s.rootdir, opts)
    59  	c.Assert(l, NotNil)
    60  	c.Check(bootloader.LkRuntimeMode(l), Equals, false)
    61  	c.Check(l.ConfigFile(), Equals, filepath.Join(s.rootdir, "/boot/lk", "snapbootsel.bin"))
    62  }
    63  
    64  func (s *lkTestSuite) TestSetGetBootVar(c *C) {
    65  	bootloader.MockLkFiles(c, s.rootdir, nil)
    66  	l := bootloader.NewLk(s.rootdir, nil)
    67  	bootVars := map[string]string{"snap_mode": boot.TryStatus}
    68  	l.SetBootVars(bootVars)
    69  
    70  	v, err := l.GetBootVars("snap_mode")
    71  	c.Assert(err, IsNil)
    72  	c.Check(v, HasLen, 1)
    73  	c.Check(v["snap_mode"], Equals, boot.TryStatus)
    74  }
    75  
    76  func (s *lkTestSuite) TestExtractKernelAssetsUnpacksBootimgImageBuilding(c *C) {
    77  	opts := &bootloader.Options{
    78  		PrepareImageTime: true,
    79  	}
    80  	bootloader.MockLkFiles(c, s.rootdir, opts)
    81  	l := bootloader.NewLk(s.rootdir, opts)
    82  
    83  	c.Assert(l, NotNil)
    84  
    85  	files := [][]string{
    86  		{"kernel.img", "I'm a kernel"},
    87  		{"initrd.img", "...and I'm an initrd"},
    88  		{"boot.img", "...and I'm an boot image"},
    89  		{"dtbs/foo.dtb", "g'day, I'm foo.dtb"},
    90  		{"dtbs/bar.dtb", "hello, I'm bar.dtb"},
    91  		// must be last
    92  		{"meta/kernel.yaml", "version: 4.2"},
    93  	}
    94  	si := &snap.SideInfo{
    95  		RealName: "ubuntu-kernel",
    96  		Revision: snap.R(42),
    97  	}
    98  	fn := snaptest.MakeTestSnapWithFiles(c, packageKernel, files)
    99  	snapf, err := snapfile.Open(fn)
   100  	c.Assert(err, IsNil)
   101  
   102  	info, err := snap.ReadInfoFromSnapFile(snapf, si)
   103  	c.Assert(err, IsNil)
   104  
   105  	err = l.ExtractKernelAssets(info, snapf)
   106  	c.Assert(err, IsNil)
   107  
   108  	// just boot.img and snapbootsel.bin are there, no kernel.img
   109  	infos, err := ioutil.ReadDir(filepath.Join(s.rootdir, "boot", "lk", ""))
   110  	c.Assert(err, IsNil)
   111  	var fnames []string
   112  	for _, info := range infos {
   113  		fnames = append(fnames, info.Name())
   114  	}
   115  	sort.Strings(fnames)
   116  	c.Assert(fnames, HasLen, 2)
   117  	c.Assert(fnames, DeepEquals, []string{"boot.img", "snapbootsel.bin"})
   118  }
   119  
   120  func (s *lkTestSuite) TestExtractKernelAssetsUnpacksCustomBootimgImageBuilding(c *C) {
   121  	opts := &bootloader.Options{
   122  		PrepareImageTime: true,
   123  	}
   124  	bootloader.MockLkFiles(c, s.rootdir, opts)
   125  	l := bootloader.NewLk(s.rootdir, opts)
   126  
   127  	c.Assert(l, NotNil)
   128  
   129  	// first configure custom boot image file name
   130  	env := lkenv.NewEnv(l.ConfigFile())
   131  	env.Load()
   132  	env.ConfigureBootimgName("boot-2.img")
   133  	err := env.Save()
   134  	c.Assert(err, IsNil)
   135  
   136  	files := [][]string{
   137  		{"kernel.img", "I'm a kernel"},
   138  		{"initrd.img", "...and I'm an initrd"},
   139  		{"boot-2.img", "...and I'm an boot image"},
   140  		{"dtbs/foo.dtb", "g'day, I'm foo.dtb"},
   141  		{"dtbs/bar.dtb", "hello, I'm bar.dtb"},
   142  		// must be last
   143  		{"meta/kernel.yaml", "version: 4.2"},
   144  	}
   145  	si := &snap.SideInfo{
   146  		RealName: "ubuntu-kernel",
   147  		Revision: snap.R(42),
   148  	}
   149  	fn := snaptest.MakeTestSnapWithFiles(c, packageKernel, files)
   150  	snapf, err := snapfile.Open(fn)
   151  	c.Assert(err, IsNil)
   152  
   153  	info, err := snap.ReadInfoFromSnapFile(snapf, si)
   154  	c.Assert(err, IsNil)
   155  
   156  	err = l.ExtractKernelAssets(info, snapf)
   157  	c.Assert(err, IsNil)
   158  
   159  	// boot-2.img is there
   160  	bootimg := filepath.Join(s.rootdir, "boot", "lk", "boot-2.img")
   161  	c.Assert(osutil.FileExists(bootimg), Equals, true)
   162  }
   163  
   164  func (s *lkTestSuite) TestExtractKernelAssetsUnpacksAndRemoveInRuntimeMode(c *C) {
   165  	bootloader.MockLkFiles(c, s.rootdir, nil)
   166  	lk := bootloader.NewLk(s.rootdir, nil)
   167  	c.Assert(lk, NotNil)
   168  
   169  	// create mock bootsel, boot_a, boot_b partitions
   170  	for _, partName := range []string{"snapbootsel", "boot_a", "boot_b"} {
   171  		mockPart := filepath.Join(s.rootdir, "/dev/disk/by-partlabel/", partName)
   172  		err := os.MkdirAll(filepath.Dir(mockPart), 0755)
   173  		c.Assert(err, IsNil)
   174  		err = ioutil.WriteFile(mockPart, nil, 0600)
   175  		c.Assert(err, IsNil)
   176  	}
   177  	// ensure we have a valid boot env
   178  	bootselPartition := filepath.Join(s.rootdir, "/dev/disk/by-partlabel/snapbootsel")
   179  	lkenv := lkenv.NewEnv(bootselPartition)
   180  	lkenv.ConfigureBootPartitions("boot_a", "boot_b")
   181  	err := lkenv.Save()
   182  	c.Assert(err, IsNil)
   183  
   184  	// mock a kernel snap that has a boot.img
   185  	files := [][]string{
   186  		{"boot.img", "I'm the default boot image name"},
   187  	}
   188  	si := &snap.SideInfo{
   189  		RealName: "ubuntu-kernel",
   190  		Revision: snap.R(42),
   191  	}
   192  	fn := snaptest.MakeTestSnapWithFiles(c, packageKernel, files)
   193  	snapf, err := snapfile.Open(fn)
   194  	c.Assert(err, IsNil)
   195  
   196  	info, err := snap.ReadInfoFromSnapFile(snapf, si)
   197  	c.Assert(err, IsNil)
   198  
   199  	// now extract
   200  	err = lk.ExtractKernelAssets(info, snapf)
   201  	c.Assert(err, IsNil)
   202  
   203  	// and validate it went to the "boot_a" partition
   204  	bootA := filepath.Join(s.rootdir, "/dev/disk/by-partlabel/boot_a")
   205  	content, err := ioutil.ReadFile(bootA)
   206  	c.Assert(err, IsNil)
   207  	c.Assert(string(content), Equals, "I'm the default boot image name")
   208  
   209  	// also validate that bootB is empty
   210  	bootB := filepath.Join(s.rootdir, "/dev/disk/by-partlabel/boot_b")
   211  	content, err = ioutil.ReadFile(bootB)
   212  	c.Assert(err, IsNil)
   213  	c.Assert(content, HasLen, 0)
   214  
   215  	// test that boot partition got set
   216  	err = lkenv.Load()
   217  	c.Assert(err, IsNil)
   218  	bootPart, err := lkenv.GetBootPartition("ubuntu-kernel_42.snap")
   219  	c.Assert(err, IsNil)
   220  	c.Assert(bootPart, Equals, "boot_a")
   221  
   222  	// now remove the kernel
   223  	err = lk.RemoveKernelAssets(info)
   224  	c.Assert(err, IsNil)
   225  	// and ensure its no longer available in the boot partitions
   226  	err = lkenv.Load()
   227  	c.Assert(err, IsNil)
   228  	bootPart, err = lkenv.GetBootPartition("ubuntu-kernel_42.snap")
   229  	c.Assert(err, ErrorMatches, "cannot find kernel .* in boot image partitions")
   230  	c.Assert(bootPart, Equals, "")
   231  }