github.com/xyproto/u-root@v6.0.1-0.20200302025726-5528e0c77a3c+incompatible/cmds/boot/boot2/boot.go (about) 1 // Copyright 2017-2018 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 main 6 7 import ( 8 "errors" 9 "flag" 10 "fmt" 11 "log" 12 "strconv" 13 "strings" 14 15 "github.com/u-root/u-root/pkg/boot/diskboot" 16 "github.com/u-root/u-root/pkg/boot/kexec" 17 "github.com/u-root/u-root/pkg/cmdline" 18 "github.com/u-root/u-root/pkg/mount" 19 ) 20 21 var ( 22 v = flag.Bool("v", false, "Print debug messages") 23 verbose = func(string, ...interface{}) {} 24 dryrun = flag.Bool("dryrun", false, "Only print out kexec commands") 25 26 devGlob = flag.String("dev", "/sys/class/block/*", "Device glob") 27 sDeviceIndex = flag.String("d", "", "Device index") 28 sConfigIndex = flag.String("c", "", "Config index") 29 sEntryIndex = flag.String("n", "", "Entry index") 30 removeCmdlineItem = flag.String("remove", "console", "comma separated list of kernel params value to remove from parsed kernel configuration (default to console)") 31 reuseCmdlineItem = flag.String("reuse", "console", "comma separated list of kernel params value to reuse from current kernel (default to console)") 32 appendCmdline = flag.String("append", "", "Additional kernel params") 33 34 devices []*diskboot.Device 35 ) 36 37 func getDevice() (*diskboot.Device, error) { 38 devices = diskboot.FindDevices(*devGlob) 39 if len(devices) == 0 { 40 return nil, errors.New("No devices found") 41 } 42 43 verbose("Got devices: %#v", devices) 44 var err error 45 deviceIndex := 0 46 if len(devices) > 1 { 47 if *sDeviceIndex == "" { 48 for i, device := range devices { 49 log.Printf("Device #%v: %s", i, device) 50 } 51 return nil, errors.New("multiple devices found - must specify a device index") 52 } 53 if deviceIndex, err = strconv.Atoi(*sDeviceIndex); err != nil || 54 deviceIndex < 0 || deviceIndex >= len(devices) { 55 return nil, fmt.Errorf("invalid device index %q", *sDeviceIndex) 56 } 57 } 58 return devices[deviceIndex], nil 59 } 60 61 func getConfig(device *diskboot.Device) (*diskboot.Config, error) { 62 configs := device.Configs 63 if len(configs) == 0 { 64 return nil, errors.New("No config found") 65 } 66 67 verbose("Got configs: %#v", configs) 68 var err error 69 configIndex := 0 70 if len(configs) > 1 { 71 if *sConfigIndex == "" { 72 for i, config := range configs { 73 log.Printf("Config #%v: path: %v", i, config.ConfigPath) 74 } 75 return nil, errors.New("Multiple configs found - must specify a config index") 76 } 77 if configIndex, err = strconv.Atoi(*sConfigIndex); err != nil || 78 configIndex < 0 || configIndex >= len(configs) { 79 return nil, fmt.Errorf("invalid config index %q", *sConfigIndex) 80 } 81 } 82 return configs[configIndex], nil 83 } 84 85 func getEntry(config *diskboot.Config) (*diskboot.Entry, error) { 86 verbose("Got entries: %#v", config.Entries) 87 var err error 88 entryIndex := 0 89 if *sEntryIndex != "" { 90 if entryIndex, err = strconv.Atoi(*sEntryIndex); err != nil || 91 entryIndex < 0 || entryIndex >= len(config.Entries) { 92 return nil, fmt.Errorf("invalid entry index %q", *sEntryIndex) 93 } 94 } else if config.DefaultEntry >= 0 { 95 entryIndex = config.DefaultEntry 96 } else { 97 for i, entry := range config.Entries { 98 log.Printf("Entry #%v: %#v", i, entry) 99 } 100 return nil, errors.New("No entry specified") 101 } 102 return &config.Entries[entryIndex], nil 103 } 104 105 func bootEntry(config *diskboot.Config, entry *diskboot.Entry) error { 106 verbose("Booting entry: %v", entry) 107 filter := cmdline.NewUpdateFilter(*appendCmdline, strings.Split(*removeCmdlineItem, ","), strings.Split(*reuseCmdlineItem, ",")) 108 err := entry.KexecLoad(config.MountPath, filter, *dryrun) 109 if err != nil { 110 return fmt.Errorf("wrror doing kexec load: %v", err) 111 } 112 113 if *dryrun { 114 return nil 115 } 116 117 err = kexec.Reboot() 118 if err != nil { 119 return fmt.Errorf("error doing kexec reboot: %v", err) 120 } 121 return nil 122 } 123 124 func cleanDevices() { 125 for _, device := range devices { 126 if err := device.Unmount(mount.MNT_FORCE); err != nil { 127 log.Printf("Error unmounting device %s: %v", device, err) 128 } 129 } 130 } 131 132 func main() { 133 flag.Parse() 134 if *v { 135 verbose = log.Printf 136 } 137 defer cleanDevices() 138 139 device, err := getDevice() 140 if err != nil { 141 log.Panic(err) 142 } 143 config, err := getConfig(device) 144 if err != nil { 145 log.Panic(err) 146 } 147 entry, err := getEntry(config) 148 if err != nil { 149 log.Panic(err) 150 } 151 if err := bootEntry(config, entry); err != nil { 152 log.Panic(err) 153 } 154 }