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 }