github.com/Lephar/snapd@v0.0.0-20210825215435-c7fba9cef4d2/bootloader/export_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2017 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 21 22 import ( 23 "io/ioutil" 24 "os" 25 "path/filepath" 26 27 . "gopkg.in/check.v1" 28 29 "github.com/snapcore/snapd/bootloader/lkenv" 30 "github.com/snapcore/snapd/bootloader/ubootenv" 31 "github.com/snapcore/snapd/osutil" 32 "github.com/snapcore/snapd/osutil/disks" 33 ) 34 35 // creates a new Androidboot bootloader object 36 func NewAndroidBoot(rootdir string) Bootloader { 37 return newAndroidBoot(rootdir, nil) 38 } 39 40 func MockAndroidBootFile(c *C, rootdir string, mode os.FileMode) { 41 f := &androidboot{rootdir: rootdir} 42 err := os.MkdirAll(f.dir(), 0755) 43 c.Assert(err, IsNil) 44 err = ioutil.WriteFile(f.configFile(), nil, mode) 45 c.Assert(err, IsNil) 46 } 47 48 func NewUboot(rootdir string, blOpts *Options) ExtractedRecoveryKernelImageBootloader { 49 return newUboot(rootdir, blOpts).(ExtractedRecoveryKernelImageBootloader) 50 } 51 52 func MockUbootFiles(c *C, rootdir string, blOpts *Options) { 53 u := &uboot{rootdir: rootdir} 54 u.setDefaults() 55 u.processBlOpts(blOpts) 56 err := os.MkdirAll(u.dir(), 0755) 57 c.Assert(err, IsNil) 58 59 // ensure that we have a valid uboot.env too 60 env, err := ubootenv.Create(u.envFile(), 4096) 61 c.Assert(err, IsNil) 62 err = env.Save() 63 c.Assert(err, IsNil) 64 } 65 66 func NewGrub(rootdir string, opts *Options) RecoveryAwareBootloader { 67 return newGrub(rootdir, opts).(RecoveryAwareBootloader) 68 } 69 70 func MockGrubFiles(c *C, rootdir string) { 71 err := os.MkdirAll(filepath.Join(rootdir, "/boot/grub"), 0755) 72 c.Assert(err, IsNil) 73 err = ioutil.WriteFile(filepath.Join(rootdir, "/boot/grub/grub.cfg"), nil, 0644) 74 c.Assert(err, IsNil) 75 } 76 77 func NewLk(rootdir string, opts *Options) ExtractedRecoveryKernelImageBootloader { 78 if opts == nil { 79 opts = &Options{ 80 Role: RoleSole, 81 } 82 } 83 return newLk(rootdir, opts).(ExtractedRecoveryKernelImageBootloader) 84 } 85 86 // LkConfigFile returns the primary lk bootloader environment file. 87 func LkConfigFile(b Bootloader) (string, error) { 88 lk := b.(*lk) 89 return lk.envBackstore(primaryStorage) 90 } 91 92 func UbootConfigFile(b Bootloader) string { 93 u := b.(*uboot) 94 return u.envFile() 95 } 96 97 func MockLkFiles(c *C, rootdir string, opts *Options) (restore func()) { 98 var cleanups []func() 99 if opts == nil { 100 // default to v1, uc16/uc18 version for test simplicity 101 opts = &Options{ 102 Role: RoleSole, 103 } 104 } 105 106 l := &lk{rootdir: rootdir} 107 l.processOpts(opts) 108 109 var version lkenv.Version 110 switch opts.Role { 111 case RoleSole: 112 version = lkenv.V1 113 case RoleRunMode: 114 version = lkenv.V2Run 115 case RoleRecovery: 116 version = lkenv.V2Recovery 117 } 118 119 // setup some role specific things 120 if opts.Role == RoleRunMode || opts.Role == RoleRecovery { 121 // then we need to setup some additional files - namely the kernel 122 // command line and a mock disk for that 123 lkBootDisk := &disks.MockDiskMapping{ 124 // mock the partition labels, since these structures won't have 125 // filesystems, but they will have partition labels 126 PartitionLabelToPartUUID: map[string]string{ 127 "snapbootsel": "snapbootsel-partuuid", 128 "snapbootselbak": "snapbootselbak-partuuid", 129 "snaprecoverysel": "snaprecoverysel-partuuid", 130 "snaprecoveryselbak": "snaprecoveryselbak-partuuid", 131 // for run mode kernel snaps 132 "boot_a": "boot-a-partuuid", 133 "boot_b": "boot-b-partuuid", 134 // for recovery system kernel snaps 135 "boot_ra": "boot-ra-partuuid", 136 "boot_rb": "boot-rb-partuuid", 137 }, 138 DiskHasPartitions: true, 139 DevNum: "lk-boot-disk-dev-num", 140 } 141 142 m := map[string]*disks.MockDiskMapping{ 143 "lk-boot-disk": lkBootDisk, 144 } 145 146 // mock the disk 147 r := disks.MockDeviceNameDisksToPartitionMapping(m) 148 cleanups = append(cleanups, r) 149 150 // now mock the kernel command line 151 cmdLine := filepath.Join(c.MkDir(), "cmdline") 152 ioutil.WriteFile(cmdLine, []byte("snapd_lk_boot_disk=lk-boot-disk"), 0644) 153 r = osutil.MockProcCmdline(cmdLine) 154 cleanups = append(cleanups, r) 155 } 156 157 // next create empty env file 158 buf := make([]byte, 4096) 159 f, err := l.envBackstore(primaryStorage) 160 c.Assert(err, IsNil) 161 162 c.Assert(os.MkdirAll(filepath.Dir(f), 0755), IsNil) 163 err = ioutil.WriteFile(f, buf, 0660) 164 c.Assert(err, IsNil) 165 166 // now write env in it with correct crc 167 env := lkenv.NewEnv(f, "", version) 168 if version == lkenv.V2Recovery { 169 env.InitializeBootPartitions("boot_ra", "boot_rb") 170 } else { 171 env.InitializeBootPartitions("boot_a", "boot_b") 172 } 173 174 err = env.Save() 175 c.Assert(err, IsNil) 176 177 // also make the empty files for the boot_a and boot_b partitions 178 if opts.Role == RoleRunMode || opts.Role == RoleRecovery { 179 // for uc20 roles we need to mock the files in /dev/disk/by-partuuid 180 // and we also need to mock the snapbootselbak file (the snapbootsel 181 // was created above when we created envFile()) 182 for _, label := range []string{"boot_a", "boot_b", "boot_ra", "boot_rb", "snapbootselbak"} { 183 disk, err := disks.DiskFromDeviceName("lk-boot-disk") 184 c.Assert(err, IsNil) 185 partUUID, err := disk.FindMatchingPartitionUUIDWithPartLabel(label) 186 c.Assert(err, IsNil) 187 bootFile := filepath.Join(rootdir, "/dev/disk/by-partuuid", partUUID) 188 c.Assert(os.MkdirAll(filepath.Dir(bootFile), 0755), IsNil) 189 c.Assert(ioutil.WriteFile(bootFile, nil, 0755), IsNil) 190 } 191 } else { 192 // for non-uc20 roles just mock the files in /dev/disk/by-partlabel 193 for _, partName := range []string{"boot_a", "boot_b"} { 194 mockPart := filepath.Join(rootdir, "/dev/disk/by-partlabel/", partName) 195 err := os.MkdirAll(filepath.Dir(mockPart), 0755) 196 c.Assert(err, IsNil) 197 err = ioutil.WriteFile(mockPart, nil, 0600) 198 c.Assert(err, IsNil) 199 } 200 } 201 return func() { 202 for _, r := range cleanups { 203 r() 204 } 205 } 206 } 207 208 func LkRuntimeMode(b Bootloader) bool { 209 lk := b.(*lk) 210 return !lk.prepareImageTime 211 } 212 213 func MockAddBootloaderToFind(blConstructor func(string, *Options) Bootloader) (restore func()) { 214 oldLen := len(bootloaders) 215 bootloaders = append(bootloaders, blConstructor) 216 return func() { 217 bootloaders = bootloaders[:oldLen] 218 } 219 } 220 221 var ( 222 EditionFromDiskConfigAsset = editionFromDiskConfigAsset 223 EditionFromConfigAsset = editionFromConfigAsset 224 ConfigAssetFrom = configAssetFrom 225 StaticCommandLineForGrubAssetEdition = staticCommandLineForGrubAssetEdition 226 )