-
Notifications
You must be signed in to change notification settings - Fork 2
/
main.go
154 lines (129 loc) · 3.36 KB
/
main.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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package main
import (
"flag"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/florianl/bluebox/initramfs"
)
var (
output string
arch string
version bool
)
var (
execs []string
readOnlys []string
args [][]string
env map[string]string
)
var (
executableUsage = "Embed statically linked executable into the archive and execute it once " +
"with the resulting init.\nArgument can be specified multiple times.\n\nFormat:\n" +
"foo:bar\t\t\tWhen foo is executed bar will be the given argument.\n" +
"date:+%%s\t\tWhen executed it will print the date as Unix timestamp.\n" +
"bazinga:\"-bingo -73\"\tAdd the executable bazinga with the arguments '-bingo' and '-73'."
readOnlyUsage = "Just embed the given file into the archive. The file will not be executed " +
"by the resulting init.\nArgument can be specified multiple times."
envVarUsage = "Set environment variable.\n\nFormat:\nfoo=bar\n" +
"Argument can be specified multiple times."
)
func init() {
flag.StringVar(&output, "o", "initramfs.cpio", "Define the name of the output file.")
flag.StringVar(&arch, "a", "", "Target architecture of the resulting archive. All values "+
"that are accepted by GOARCH are possible.\nBy default the host architecture is used.")
flag.Func("e", executableUsage, embedExec)
flag.Func("r", readOnlyUsage, embedFile)
flag.Func("v", envVarUsage, embedEnvVar)
flag.BoolVar(&version, "version", false, "Print revision of this bluebox executable and return.")
env = make(map[string]string)
}
func usage() {
cmd := filepath.Base(os.Args[0])
fmt.Printf("%s creates a bootable initramfs, that will embed the given statically "+
"linked executables.\n\n", cmd)
flag.PrintDefaults()
}
// fail print the error to stderr and calls exit.
func fail(err error) {
fmt.Fprintf(os.Stderr, "%s\n", err)
os.Exit(1)
}
func main() {
flag.Usage = usage
flag.Parse()
if version {
showVersion()
return
}
bluebox := initramfs.New()
for i := range execs {
if err := bluebox.Execute(execs[i], args[i]...); err != nil {
fail(err)
}
}
for _, file := range readOnlys {
if err := bluebox.Embed(file); err != nil {
fail(err)
}
}
if arch != "" {
if err := bluebox.Setarch(arch); err != nil {
fail(err)
}
}
if len(env) != 0 {
for k, v := range env {
bluebox.Setenv(k, v)
}
}
archive, err := os.OpenFile(output, os.O_CREATE|os.O_RDWR, 0o644)
if err != nil {
fail(err)
}
defer archive.Close()
if err := bluebox.Generate(archive); err != nil {
fail(err)
}
}
// Examples:
// foo:bar
// foo:"-v -bar"
// foo
func embedExec(arg string) error {
if len(arg) == 0 {
return nil
}
split := strings.SplitN(arg, ":", 2)
cmd := split[0]
if cmd == "init" || cmd == "bluebox-init" || cmd == "bluebox" {
return fmt.Errorf("embedded executable should not be named '%s'", cmd)
}
execs = append(execs, cmd)
if len(split) == 1 {
args = append(args, []string{})
return nil
}
options := strings.TrimPrefix(split[1], "\"")
options = strings.TrimSuffix(options, "\"")
arguments := strings.Split(options, " ")
args = append(args, arguments)
return nil
}
func embedFile(file string) error {
readOnlys = append(readOnlys, file)
return nil
}
func embedEnvVar(arg string) error {
if len(arg) == 0 {
return nil
}
split := strings.SplitN(arg, "=", 2)
if len(split) == 1 {
env[split[0]] = "TRUE"
} else {
env[split[0]] = split[1]
}
return nil
}