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