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  )