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