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 }