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