github.com/rminnich/u-root@v7.0.0+incompatible/pkg/bb/bbmain/register.go (about) 1 // Copyright 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 bbmain is the package imported by all rewritten busybox 6 // command-packages to register themselves. 7 package bbmain 8 9 import ( 10 "errors" 11 "fmt" 12 "os" 13 "path/filepath" 14 ) 15 16 // ErrNotRegistered is returned by Run if the given command is not registered. 17 var ErrNotRegistered = errors.New("command not registered") 18 19 // Noop is a noop function. 20 var Noop = func() {} 21 22 // ListCmds lists bb commands and verifies symlinks. 23 // It is by convention called when the bb command is invoked directly. 24 // For every command, there should be a symlink in /bbin, 25 // and for every symlink, there should be a command. 26 // Occasionally, we have bugs that result in one of these 27 // being false. Just running bb is an easy way to tell if something 28 // in your image is messed up. 29 func ListCmds() { 30 type known struct { 31 name string 32 bb string 33 } 34 names := map[string]*known{} 35 g, err := filepath.Glob("/bbin/*") 36 if err != nil { 37 fmt.Printf("bb: unable to enumerate /bbin") 38 } 39 40 // First step is to assemble a list of all possible 41 // names, both from /bbin/* and our built in commands. 42 for _, l := range g { 43 if l == "/bbin/bb" { 44 continue 45 } 46 b := filepath.Base(l) 47 names[b] = &known{name: l} 48 } 49 for n := range bbCmds { 50 if n == "bb" { 51 continue 52 } 53 if c, ok := names[n]; ok { 54 c.bb = n 55 continue 56 } 57 names[n] = &known{bb: n} 58 } 59 // Now walk the array of structs. 60 // We don't sort as we don't want the 61 // footprint of bringing in the package. 62 // If you want it sorted, bb | sort 63 var hadError bool 64 for c, k := range names { 65 if len(k.name) == 0 || len(k.bb) == 0 { 66 hadError = true 67 fmt.Printf("%s:\t", c) 68 if k.name == "" { 69 fmt.Printf("NO SYMLINK\t") 70 } else { 71 fmt.Printf("%q\t", k.name) 72 } 73 if k.bb == "" { 74 fmt.Printf("NO COMMAND\n") 75 } else { 76 fmt.Printf("%s\n", k.bb) 77 } 78 } 79 } 80 if hadError { 81 fmt.Println("There is at least one problem. Known causes:") 82 fmt.Println("At least two initrds -- one compiled in to the kernel, a second supplied by the bootloader.") 83 fmt.Println("The initrd cpio was changed after creation or merged with another one.") 84 fmt.Println("When the initrd was created, files were inserted into /bbin by mistake.") 85 fmt.Println("Post boot, files were added to /bbin.") 86 } 87 } 88 89 type bbCmd struct { 90 init, main func() 91 } 92 93 var bbCmds = map[string]bbCmd{} 94 95 var defaultCmd *bbCmd 96 97 // Register registers an init and main function for name. 98 func Register(name string, init, main func()) { 99 if _, ok := bbCmds[name]; ok { 100 panic(fmt.Sprintf("cannot register two commands with name %q", name)) 101 } 102 bbCmds[name] = bbCmd{ 103 init: init, 104 main: main, 105 } 106 } 107 108 // RegisterDefault registers a default init and main function. 109 func RegisterDefault(init, main func()) { 110 defaultCmd = &bbCmd{ 111 init: init, 112 main: main, 113 } 114 } 115 116 // Run runs the command with the given name. 117 // 118 // If the command's main exits without calling os.Exit, Run will exit with exit 119 // code 0. 120 func Run(name string) error { 121 var cmd *bbCmd 122 if c, ok := bbCmds[name]; ok { 123 cmd = &c 124 } else if defaultCmd != nil { 125 cmd = defaultCmd 126 } else { 127 return ErrNotRegistered 128 } 129 cmd.init() 130 cmd.main() 131 os.Exit(0) 132 // Unreachable. 133 return nil 134 }