github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/tools/vpdbootmanager/add.go (about) 1 // Copyright 2017-2019 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 "encoding/json" 9 "errors" 10 "flag" 11 "fmt" 12 "net" 13 "os" 14 15 "github.com/u-root/u-root/pkg/boot/systembooter" 16 "github.com/u-root/u-root/pkg/vpd" 17 ) 18 19 var dryRun = false 20 21 func add(entrytype string, args []string) error { 22 var entry systembooter.Booter 23 var err error 24 switch entrytype { 25 case "netboot": 26 if len(args) < 2 { 27 return fmt.Errorf("You need to pass method and MAC address") 28 } 29 entry, err = parseNetbootFlags(args[0], args[1], args[2:]) 30 if err != nil { 31 return err 32 } 33 case "localboot": 34 if len(args) < 1 { 35 return fmt.Errorf("You need to provide method") 36 } 37 entry, err = parseLocalbootFlags(args[0], args[1:]) 38 if err != nil { 39 return err 40 } 41 default: 42 return fmt.Errorf("Unknown entry type") 43 } 44 if dryRun { 45 b, err := json.Marshal(entry) 46 if err != nil { 47 return err 48 } 49 fmt.Fprintln(os.Stderr, "Using -dryrun, will not write any variable. Content of boot entry:") 50 fmt.Println(string(b)) 51 return nil 52 } 53 return addBootEntry(entry) 54 } 55 56 func parseLocalbootFlags(method string, args []string) (*systembooter.LocalBooter, error) { 57 cfg := &systembooter.LocalBooter{ 58 Type: "localboot", 59 Method: method, 60 } 61 flg := flag.NewFlagSet("localboot", flag.ExitOnError) 62 flg.StringVar(&cfg.KernelArgs, "kernel-args", "", "additional kernel args") 63 flg.StringVar(&cfg.Initramfs, "ramfs", "", "path of ramfs to be used for kexec'ing into the target kernel.") 64 flg.StringVar(&vpd.VpdDir, "vpd-dir", vpd.VpdDir, "VPD dir to use") 65 flg.BoolVar(&dryRun, "dryrun", false, "only print values that would be set") 66 67 switch method { 68 case "grub": 69 flg.Parse(args) 70 case "path": 71 if len(args) < 2 { 72 return nil, fmt.Errorf("You need to pass DeviceGUID and Kernel path") 73 } 74 cfg.DeviceGUID = args[0] 75 cfg.Kernel = args[1] 76 flg.Parse(args[2:]) 77 default: 78 return nil, fmt.Errorf("Method needs to be grub or path") 79 } 80 return cfg, nil 81 } 82 83 func parseNetbootFlags(method, mac string, args []string) (*systembooter.NetBooter, error) { 84 if method != "dhcpv4" && method != "dhcpv6" { 85 return nil, fmt.Errorf("Method needs to be either dhcpv4 or dhcpv6") 86 } 87 88 _, err := net.ParseMAC(mac) 89 if err != nil { 90 return nil, err 91 } 92 93 cfg := &systembooter.NetBooter{ 94 Type: "netboot", 95 Method: method, 96 MAC: mac, 97 } 98 99 flg := flag.NewFlagSet("netboot", flag.ExitOnError) 100 overrideURL := flg.String("override-url", "", "an optional URL used to override the boot file URL used") 101 retries := flg.Int("retries", -1, "the number of times a DHCP request should be retried if failed.") 102 flg.BoolVar(&dryRun, "dryrun", false, "only print values that would be set") 103 flg.StringVar(&vpd.VpdDir, "vpd-dir", vpd.VpdDir, "VPD dir to use") 104 flg.Parse(args) 105 106 if *overrideURL != "" { 107 cfg.OverrideURL = overrideURL 108 } 109 110 if *retries != -1 { 111 cfg.Retries = retries 112 } 113 114 return cfg, nil 115 } 116 117 func addBootEntry(cfg systembooter.Booter) error { 118 data, err := json.Marshal(cfg) 119 if err != nil { 120 return err 121 } 122 for i := 1; i < vpd.MaxBootEntry; i++ { 123 key := fmt.Sprintf("Boot%04d", i) 124 if _, err := vpd.Get(key, false); err != nil { 125 if os.IsNotExist(err) { 126 if err := vpd.Set(key, data, false); err != nil { 127 return err 128 } 129 return nil 130 } 131 return err 132 } 133 } 134 return errors.New("Maximum number of boot entries already set") 135 }