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  }