github.com/hugelgupf/u-root@v0.0.0-20191023214958-4807c632154c/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/cmdline"
    16  	"github.com/u-root/u-root/pkg/diskboot"
    17  	"github.com/u-root/u-root/pkg/kexec"
    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: path: %v type: %v",
    50  					i, device.DevPath, device.Fstype)
    51  			}
    52  			return nil, errors.New("Multiple devices found - must specify a device index")
    53  		}
    54  		if deviceIndex, err = strconv.Atoi(*sDeviceIndex); err != nil ||
    55  			deviceIndex < 0 || deviceIndex >= len(devices) {
    56  			return nil, fmt.Errorf("invalid device index %q", *sDeviceIndex)
    57  		}
    58  	}
    59  	return devices[deviceIndex], nil
    60  }
    61  
    62  func getConfig(device *diskboot.Device) (*diskboot.Config, error) {
    63  	configs := device.Configs
    64  	if len(configs) == 0 {
    65  		return nil, errors.New("No config found")
    66  	}
    67  
    68  	verbose("Got configs: %#v", configs)
    69  	var err error
    70  	configIndex := 0
    71  	if len(configs) > 1 {
    72  		if *sConfigIndex == "" {
    73  			for i, config := range configs {
    74  				log.Printf("Config #%v: path: %v", i, config.ConfigPath)
    75  			}
    76  			return nil, errors.New("Multiple configs found - must specify a config index")
    77  		}
    78  		if configIndex, err = strconv.Atoi(*sConfigIndex); err != nil ||
    79  			configIndex < 0 || configIndex >= len(configs) {
    80  			return nil, fmt.Errorf("invalid config index %q", *sConfigIndex)
    81  		}
    82  	}
    83  	return configs[configIndex], nil
    84  }
    85  
    86  func getEntry(config *diskboot.Config) (*diskboot.Entry, error) {
    87  	verbose("Got entries: %#v", config.Entries)
    88  	var err error
    89  	entryIndex := 0
    90  	if *sEntryIndex != "" {
    91  		if entryIndex, err = strconv.Atoi(*sEntryIndex); err != nil ||
    92  			entryIndex < 0 || entryIndex >= len(config.Entries) {
    93  			return nil, fmt.Errorf("invalid entry index %q", *sEntryIndex)
    94  		}
    95  	} else if config.DefaultEntry >= 0 {
    96  		entryIndex = config.DefaultEntry
    97  	} else {
    98  		for i, entry := range config.Entries {
    99  			log.Printf("Entry #%v: %#v", i, entry)
   100  		}
   101  		return nil, errors.New("No entry specified")
   102  	}
   103  	return &config.Entries[entryIndex], nil
   104  }
   105  
   106  func bootEntry(config *diskboot.Config, entry *diskboot.Entry) error {
   107  	verbose("Booting entry: %v", entry)
   108  	filter := cmdline.NewUpdateFilter(*appendCmdline, strings.Split(*removeCmdlineItem, ","), strings.Split(*reuseCmdlineItem, ","))
   109  	err := entry.KexecLoad(config.MountPath, filter, *dryrun)
   110  	if err != nil {
   111  		return fmt.Errorf("wrror doing kexec load: %v", err)
   112  	}
   113  
   114  	if *dryrun {
   115  		return nil
   116  	}
   117  
   118  	err = kexec.Reboot()
   119  	if err != nil {
   120  		return fmt.Errorf("error doing kexec reboot: %v", err)
   121  	}
   122  	return nil
   123  }
   124  
   125  func cleanDevices() {
   126  	for _, device := range devices {
   127  		if err := mount.Unmount(device.MountPath, true, false); err != nil {
   128  			log.Printf("Error unmounting device %v: %v", device.DevPath, err)
   129  		}
   130  	}
   131  }
   132  
   133  func main() {
   134  	flag.Parse()
   135  	if *v {
   136  		verbose = log.Printf
   137  	}
   138  	defer cleanDevices()
   139  
   140  	device, err := getDevice()
   141  	if err != nil {
   142  		log.Panic(err)
   143  	}
   144  	config, err := getConfig(device)
   145  	if err != nil {
   146  		log.Panic(err)
   147  	}
   148  	entry, err := getEntry(config)
   149  	if err != nil {
   150  		log.Panic(err)
   151  	}
   152  	if err := bootEntry(config, entry); err != nil {
   153  		log.Panic(err)
   154  	}
   155  }