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