github.com/david-imola/snapd@v0.0.0-20210611180407-2de8ddeece6d/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 }