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 }