github.com/Lephar/snapd@v0.0.0-20210825215435-c7fba9cef4d2/bootloader/uboot_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2014-2015 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  	"os"
    24  	"path/filepath"
    25  	"time"
    26  
    27  	. "gopkg.in/check.v1"
    28  
    29  	"github.com/snapcore/snapd/bootloader"
    30  	"github.com/snapcore/snapd/bootloader/ubootenv"
    31  	"github.com/snapcore/snapd/osutil"
    32  	"github.com/snapcore/snapd/snap"
    33  	"github.com/snapcore/snapd/snap/snapfile"
    34  	"github.com/snapcore/snapd/snap/snaptest"
    35  	"github.com/snapcore/snapd/testutil"
    36  )
    37  
    38  type ubootTestSuite struct {
    39  	baseBootenvTestSuite
    40  }
    41  
    42  var _ = Suite(&ubootTestSuite{})
    43  
    44  func (s *ubootTestSuite) TestNewUboot(c *C) {
    45  	// no files means bl is not present, but we can still create the bl object
    46  	u := bootloader.NewUboot(s.rootdir, nil)
    47  	c.Assert(u, NotNil)
    48  	c.Assert(u.Name(), Equals, "uboot")
    49  
    50  	present, err := u.Present()
    51  	c.Assert(err, IsNil)
    52  	c.Assert(present, Equals, false)
    53  
    54  	// now with files present, the bl is present
    55  	bootloader.MockUbootFiles(c, s.rootdir, nil)
    56  	present, err = u.Present()
    57  	c.Assert(err, IsNil)
    58  	c.Assert(present, Equals, true)
    59  }
    60  
    61  func (s *ubootTestSuite) TestUbootGetEnvVar(c *C) {
    62  	bootloader.MockUbootFiles(c, s.rootdir, nil)
    63  	u := bootloader.NewUboot(s.rootdir, nil)
    64  	c.Assert(u, NotNil)
    65  	err := u.SetBootVars(map[string]string{
    66  		"snap_mode": "",
    67  		"snap_core": "4",
    68  	})
    69  	c.Assert(err, IsNil)
    70  
    71  	m, err := u.GetBootVars("snap_mode", "snap_core")
    72  	c.Assert(err, IsNil)
    73  	c.Assert(m, DeepEquals, map[string]string{
    74  		"snap_mode": "",
    75  		"snap_core": "4",
    76  	})
    77  }
    78  
    79  func (s *ubootTestSuite) TestGetBootloaderWithUboot(c *C) {
    80  	bootloader.MockUbootFiles(c, s.rootdir, nil)
    81  
    82  	bootloader, err := bootloader.Find(s.rootdir, nil)
    83  	c.Assert(err, IsNil)
    84  	c.Assert(bootloader.Name(), Equals, "uboot")
    85  }
    86  
    87  func (s *ubootTestSuite) TestUbootSetEnvNoUselessWrites(c *C) {
    88  	bootloader.MockUbootFiles(c, s.rootdir, nil)
    89  	u := bootloader.NewUboot(s.rootdir, nil)
    90  	c.Assert(u, NotNil)
    91  
    92  	envFile := bootloader.UbootConfigFile(u)
    93  	env, err := ubootenv.Create(envFile, 4096)
    94  	c.Assert(err, IsNil)
    95  	env.Set("snap_ab", "b")
    96  	env.Set("snap_mode", "")
    97  	err = env.Save()
    98  	c.Assert(err, IsNil)
    99  
   100  	st, err := os.Stat(envFile)
   101  	c.Assert(err, IsNil)
   102  	time.Sleep(100 * time.Millisecond)
   103  
   104  	// note that we set to the same var as above
   105  	err = u.SetBootVars(map[string]string{"snap_ab": "b"})
   106  	c.Assert(err, IsNil)
   107  
   108  	env, err = ubootenv.Open(envFile)
   109  	c.Assert(err, IsNil)
   110  	c.Assert(env.String(), Equals, "snap_ab=b\n")
   111  
   112  	st2, err := os.Stat(envFile)
   113  	c.Assert(err, IsNil)
   114  	c.Assert(st.ModTime(), Equals, st2.ModTime())
   115  }
   116  
   117  func (s *ubootTestSuite) TestUbootSetBootVarFwEnv(c *C) {
   118  	bootloader.MockUbootFiles(c, s.rootdir, nil)
   119  	u := bootloader.NewUboot(s.rootdir, nil)
   120  
   121  	err := u.SetBootVars(map[string]string{"key": "value"})
   122  	c.Assert(err, IsNil)
   123  
   124  	content, err := u.GetBootVars("key")
   125  	c.Assert(err, IsNil)
   126  	c.Assert(content, DeepEquals, map[string]string{"key": "value"})
   127  }
   128  
   129  func (s *ubootTestSuite) TestUbootGetBootVarFwEnv(c *C) {
   130  	bootloader.MockUbootFiles(c, s.rootdir, nil)
   131  	u := bootloader.NewUboot(s.rootdir, nil)
   132  
   133  	err := u.SetBootVars(map[string]string{"key2": "value2"})
   134  	c.Assert(err, IsNil)
   135  
   136  	content, err := u.GetBootVars("key2")
   137  	c.Assert(err, IsNil)
   138  	c.Assert(content, DeepEquals, map[string]string{"key2": "value2"})
   139  }
   140  
   141  func (s *ubootTestSuite) TestExtractKernelAssetsAndRemove(c *C) {
   142  	bootloader.MockUbootFiles(c, s.rootdir, nil)
   143  	u := bootloader.NewUboot(s.rootdir, nil)
   144  
   145  	files := [][]string{
   146  		{"kernel.img", "I'm a kernel"},
   147  		{"initrd.img", "...and I'm an initrd"},
   148  		{"dtbs/foo.dtb", "g'day, I'm foo.dtb"},
   149  		{"dtbs/bar.dtb", "hello, I'm bar.dtb"},
   150  		// must be last
   151  		{"meta/kernel.yaml", "version: 4.2"},
   152  	}
   153  	si := &snap.SideInfo{
   154  		RealName: "ubuntu-kernel",
   155  		Revision: snap.R(42),
   156  	}
   157  	fn := snaptest.MakeTestSnapWithFiles(c, packageKernel, files)
   158  	snapf, err := snapfile.Open(fn)
   159  	c.Assert(err, IsNil)
   160  
   161  	info, err := snap.ReadInfoFromSnapFile(snapf, si)
   162  	c.Assert(err, IsNil)
   163  
   164  	err = u.ExtractKernelAssets(info, snapf)
   165  	c.Assert(err, IsNil)
   166  
   167  	// this is where the kernel/initrd is unpacked
   168  	kernelAssetsDir := filepath.Join(s.rootdir, "boot", "uboot", "ubuntu-kernel_42.snap")
   169  
   170  	for _, def := range files {
   171  		if def[0] == "meta/kernel.yaml" {
   172  			break
   173  		}
   174  
   175  		fullFn := filepath.Join(kernelAssetsDir, def[0])
   176  		c.Check(fullFn, testutil.FileEquals, def[1])
   177  	}
   178  
   179  	// remove
   180  	err = u.RemoveKernelAssets(info)
   181  	c.Assert(err, IsNil)
   182  
   183  	c.Check(osutil.FileExists(kernelAssetsDir), Equals, false)
   184  }
   185  
   186  func (s *ubootTestSuite) TestExtractRecoveryKernelAssets(c *C) {
   187  	bootloader.MockUbootFiles(c, s.rootdir, nil)
   188  	u := bootloader.NewUboot(s.rootdir, nil)
   189  
   190  	files := [][]string{
   191  		{"kernel.img", "I'm a kernel"},
   192  		{"initrd.img", "...and I'm an initrd"},
   193  		{"dtbs/foo.dtb", "foo dtb"},
   194  		{"dtbs/bar.dto", "bar dtbo"},
   195  		// must be last
   196  		{"meta/kernel.yaml", "version: 4.2"},
   197  	}
   198  	si := &snap.SideInfo{
   199  		RealName: "ubuntu-kernel",
   200  		Revision: snap.R(42),
   201  	}
   202  	fn := snaptest.MakeTestSnapWithFiles(c, packageKernel, files)
   203  	snapf, err := snapfile.Open(fn)
   204  	c.Assert(err, IsNil)
   205  
   206  	info, err := snap.ReadInfoFromSnapFile(snapf, si)
   207  	c.Assert(err, IsNil)
   208  
   209  	// try with empty recovery dir first to check the errors
   210  	err = u.ExtractRecoveryKernelAssets("", info, snapf)
   211  	c.Assert(err, ErrorMatches, "internal error: recoverySystemDir unset")
   212  
   213  	// now the expected behavior
   214  	err = u.ExtractRecoveryKernelAssets("recovery-dir", info, snapf)
   215  	c.Assert(err, IsNil)
   216  
   217  	// this is where the kernel/initrd is unpacked
   218  	kernelAssetsDir := filepath.Join(s.rootdir, "recovery-dir", "kernel")
   219  
   220  	for _, def := range files {
   221  		if def[0] == "meta/kernel.yaml" {
   222  			break
   223  		}
   224  
   225  		fullFn := filepath.Join(kernelAssetsDir, def[0])
   226  		c.Check(fullFn, testutil.FileEquals, def[1])
   227  	}
   228  }
   229  
   230  func (s *ubootTestSuite) TestUbootUC20OptsPlacement(c *C) {
   231  	tt := []struct {
   232  		blOpts  *bootloader.Options
   233  		expEnv  string
   234  		comment string
   235  	}{
   236  		{
   237  			nil,
   238  			"/boot/uboot/uboot.env",
   239  			"traditional uboot.env",
   240  		},
   241  		{
   242  			&bootloader.Options{Role: bootloader.RoleRunMode, NoSlashBoot: true},
   243  			"/uboot/ubuntu/boot.sel",
   244  			"uc20 install mode boot.sel",
   245  		},
   246  		{
   247  			&bootloader.Options{Role: bootloader.RoleRunMode},
   248  			"/boot/uboot/boot.sel",
   249  			"uc20 run mode boot.sel",
   250  		},
   251  		{
   252  			&bootloader.Options{Role: bootloader.RoleRecovery},
   253  			"/uboot/ubuntu/boot.sel",
   254  			"uc20 recovery boot.sel",
   255  		},
   256  	}
   257  
   258  	for _, t := range tt {
   259  		dir := c.MkDir()
   260  		bootloader.MockUbootFiles(c, dir, t.blOpts)
   261  		u := bootloader.NewUboot(dir, t.blOpts)
   262  		c.Assert(u, NotNil, Commentf(t.comment))
   263  		c.Assert(bootloader.UbootConfigFile(u), Equals, filepath.Join(dir, t.expEnv), Commentf(t.comment))
   264  
   265  		// if we set boot vars on the uboot, we can open the config file and
   266  		// get the same variables
   267  		c.Assert(u.SetBootVars(map[string]string{"hello": "there"}), IsNil)
   268  		env, err := ubootenv.Open(filepath.Join(dir, t.expEnv))
   269  		c.Assert(err, IsNil)
   270  		c.Assert(env.Get("hello"), Equals, "there")
   271  	}
   272  }