github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/boot/localboot/localboot.go (about)

     1  // Copyright 2020 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package localboot contains helper functions for booting off local disks.
     6  package localboot
     7  
     8  import (
     9  	"context"
    10  	"sort"
    11  
    12  	"github.com/mvdan/u-root-coreutils/pkg/boot"
    13  	"github.com/mvdan/u-root-coreutils/pkg/boot/bls"
    14  	"github.com/mvdan/u-root-coreutils/pkg/boot/esxi"
    15  	"github.com/mvdan/u-root-coreutils/pkg/boot/grub"
    16  	"github.com/mvdan/u-root-coreutils/pkg/boot/syslinux"
    17  	"github.com/mvdan/u-root-coreutils/pkg/mount"
    18  	"github.com/mvdan/u-root-coreutils/pkg/mount/block"
    19  	"github.com/mvdan/u-root-coreutils/pkg/ulog"
    20  )
    21  
    22  // Sort the image in descending order by rank
    23  type byRank []boot.OSImage
    24  
    25  func (a byRank) Less(i, j int) bool { return a[i].Rank() > a[j].Rank() }
    26  func (a byRank) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
    27  func (a byRank) Len() int           { return len(a) }
    28  
    29  // parse treats device as a block device with a file system.
    30  func parse(l ulog.Logger, device *block.BlockDev, devices block.BlockDevices, mountDir string, mountPool *mount.Pool) []boot.OSImage {
    31  	imgs, err := bls.ScanBLSEntries(l, mountDir, nil)
    32  	if err != nil {
    33  		l.Printf("No systemd-boot BootLoaderSpec configs found on %s, trying another format...: %v", device, err)
    34  	}
    35  
    36  	// Grub parser may want to load files (kernel, initramfs, modules, ...)
    37  	// from another partition, thus it is given devices and mountPool in
    38  	// order to reuse mounts and mount more file systems.
    39  	grubImgs, err := grub.ParseLocalConfig(context.Background(), mountDir, devices, mountPool)
    40  	if err != nil {
    41  		l.Printf("No GRUB configs found on %s, trying another format...: %v", device, err)
    42  	}
    43  	imgs = append(imgs, grubImgs...)
    44  
    45  	syslinuxImgs, err := syslinux.ParseLocalConfig(context.Background(), mountDir)
    46  	if err != nil {
    47  		l.Printf("No syslinux configs found on %s: %v", device, err)
    48  	}
    49  	imgs = append(imgs, syslinuxImgs...)
    50  
    51  	return imgs
    52  }
    53  
    54  // parseUnmounted treats device as unmounted, with or without partitions.
    55  func parseUnmounted(l ulog.Logger, device *block.BlockDev, mountPool *mount.Pool) []boot.OSImage {
    56  	// This will try to mount device partition 5 and 6.
    57  	imgs, mps, err := esxi.LoadDisk(device.DevicePath())
    58  	if mps != nil {
    59  		mountPool.Add(mps...)
    60  	}
    61  	if err != nil {
    62  		l.Printf("No ESXi disk configs found on %s: %v", device, err)
    63  	}
    64  
    65  	// This tries to mount the device itself, in case it's an installer CD.
    66  	img, mp, err := esxi.LoadCDROM(device.DevicePath())
    67  	if mp != nil {
    68  		mountPool.Add(mp)
    69  	}
    70  	if err != nil {
    71  		l.Printf("No ESXi CDROM configs found on %s: %v", device, err)
    72  	}
    73  	if img != nil {
    74  		imgs = append(imgs, img)
    75  	}
    76  	// Convert from *MultibootImage to OSImage.
    77  	var images []boot.OSImage
    78  	for _, i := range imgs {
    79  		images = append(images, i)
    80  	}
    81  	return images
    82  }
    83  
    84  // Localboot tries to boot from any local filesystem by parsing grub configuration
    85  func Localboot(l ulog.Logger, blockDevs block.BlockDevices, mp *mount.Pool) ([]boot.OSImage, error) {
    86  	var images []boot.OSImage
    87  	for _, device := range blockDevs {
    88  		imgs := parseUnmounted(l, device, mp)
    89  		if len(imgs) > 0 {
    90  			images = append(images, imgs...)
    91  		} else {
    92  			m, err := mp.Mount(device, mount.ReadOnly)
    93  			if err != nil {
    94  				continue
    95  			}
    96  			imgs = parse(l, device, blockDevs, m.Path, mp)
    97  			images = append(images, imgs...)
    98  		}
    99  	}
   100  
   101  	sort.Sort(byRank(images))
   102  	return images, nil
   103  }