-
Notifications
You must be signed in to change notification settings - Fork 66
/
zbm-builder.sh
executable file
·275 lines (223 loc) · 6.57 KB
/
zbm-builder.sh
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
#!/bin/bash
# vim: softtabstop=2 shiftwidth=2 expandtab
sanitise_path() {
local rpath
if rpath="$(readlink -f "${1}")" && [ -d "${rpath}" ]; then
echo "${rpath}"
return 0
fi
return 1
}
boolean_enabled() {
local val="${1:-}"
case "${val,,}" in
yes|y|on|1) return 0 ;;
*) return 1 ;;
esac
}
usage() {
cat << EOF
Build ZFSBootMenu images in an OCI container using podman or docker.
Usage: $0 [options]
OPTIONS:
-h Display this help text
-b <path>
Use an alternate build directory
(Default: current directory)
-c <config>
Specify the path to a configuration file that will be sourced
(Default: \${BUILD_DIRECTORY}/zbm-builder.conf, if it exists)
-d Force use of docker instead of podman
-M <argument>
Provide a comma-separated list of options to use for volume
mounts of the build directory and (if specified) ZFSBootMenu
source tree within the build container. For example, specify
zbm-builder -M z
to label the volumes for use with SELinux.
NOTE: An 'ro' option is always added to the volume mounted from
the ZFSBootMenu source tree.
-O <argument>
Provide an option to 'podman run' or 'docker run'; if the
argument accepts one or more options, use a form with no spaces
or make sure each option gets its own '-O', e.g.:
zbm-builder -O -v -O /boot/efi/EFI/zfsbootmenu:/output
zbm-builder -O --volume -O /boot/efi/EFI/zfsbootmenu:/output
zbm-builder -O --volume=/boot/efi/EFI/zfsbootmenu:/output
May be specified multiple times.
-i <image>
Build within the named container image
(Default: ghcr.io/zbm-dev/zbm-builder:latest)
-l <path>
Build from ZFSBootMenu source tree at <path>, mounted read-only
(Default: fetch upstream source tree inside container)
-L <path>
Build from ZFSBootMenu source tree at <path>, with a temporary
read-write overlay atop the tree
(Default: fetch upstream source tree inside container)
-R Remove any existing hostid in the build directory
-H Do not include host /etc/hostid in image
(If ./hostid exists, this switch will be ignored)
-- <arguments>
Additional arguments to the zbm-builder container
For more information, see documentation at
https://github.com/zbm-dev/zfsbootmenu/blob/master/README.md
https://github.com/zbm-dev/zfsbootmenu/blob/master/docs/BUILD.md
EOF
}
SKIP_HOSTID=
REMOVE_HOST_FILES=
MOUNT_FLAGS=
# By default, use the latest upstream build container image
BUILD_IMG="ghcr.io/zbm-dev/zbm-builder:latest"
# By default, build from the current directory
BUILD_DIRECTORY="${PWD}"
# By default, there is no local repo and it is not overlaid
BUILD_REPO=
BUILD_OVERLAY=
# Arguments to the build script
BUILD_ARGS=()
# Arguments for the container runtime
RUNTIME_ARGS=()
# Optional configuration file
CONFIG=
if command -v podman >/dev/null 2>&1; then
PODMAN="podman"
else
PODMAN="docker"
fi
CMDOPTS="b:dhi:l:L:c:M:O:HR"
# First pass to get build directory and configuration file
while getopts "${CMDOPTS}" opt; do
case "${opt}" in
b)
BUILD_DIRECTORY="${OPTARG}"
;;
c)
CONFIG="${OPTARG}"
;;
h)
usage
exit 0
;;
esac
done
# Make sure the build directory is identifiable
if ! BUILD_DIRECTORY="$( sanitise_path "${BUILD_DIRECTORY}" )"; then
echo "ERROR: build directory does not exist"
exit 1
fi
# If a configuration wasn't specified, use a default it one exists
if [ -z "${CONFIG}" ] && [ -r "${BUILD_DIRECTORY}/zbm-builder.conf" ]; then
CONFIG="${BUILD_DIRECTORY}/zbm-builder.conf"
fi
# Read the optional configuration
if [ -n "${CONFIG}" ]; then
if [ -r "${CONFIG}" ]; then
# shellcheck disable=SC1090
source "${CONFIG}"
else
echo "ERROR: non-existent configuration specified"
exit 1
fi
fi
OPTIND=1
while getopts "${CMDOPTS}" opt; do
case "${opt}" in
# These have already been parsed in first pass
b|c|h)
;;
d)
PODMAN=docker
;;
i)
BUILD_IMG="${OPTARG}"
;;
l)
BUILD_REPO="${OPTARG}"
BUILD_OVERLAY=""
;;
L)
BUILD_REPO="${OPTARG}"
BUILD_OVERLAY="yes"
;;
M)
MOUNT_FLAGS="${OPTARG}"
;;
O)
RUNTIME_ARGS+=( "${OPTARG}" )
;;
H)
SKIP_HOSTID="yes"
;;
R)
REMOVE_HOST_FILES="yes"
;;
*)
usage
exit 1
;;
esac
done
# Drop all processed arguments
shift $((OPTIND-1))
if ! command -v "${PODMAN}" >/dev/null 2>&1; then
echo "ERROR: this script requires podman or docker"
exit 1
fi
# Always mount a build directory at /build
RUNTIME_ARGS+=( "-v" "${BUILD_DIRECTORY}:/build${MOUNT_FLAGS:+:${MOUNT_FLAGS}}" )
# Only mount a local repo at /zbm if specified
if [ -n "${BUILD_REPO}" ]; then
if ! BUILD_REPO="$( sanitise_path "${BUILD_REPO}" )"; then
echo "ERROR: local repository does not exist"
exit 1
fi
mntopt=""
case "${BUILD_OVERLAY,,}" in
yes) mntopt="O" ;;
*) mntopt="ro" ;;
esac
RUNTIME_ARGS+=( "-v" "${BUILD_REPO}:/zbm:${mntopt}${MOUNT_FLAGS:+,${MOUNT_FLAGS}}" )
unset mntopt
fi
# Remove existing hostid
if boolean_enabled "${REMOVE_HOST_FILES}" && [ -e "${BUILD_DIRECTORY}/hostid" ]; then
if ! rm "${BUILD_DIRECTORY}/hostid"; then
echo "ERROR: failed to remove hostid from build directory"
exit 1
fi
echo "Removed hostid by user request"
fi
# If no local hostid is available, copy the system hostid if desired
if ! [ -r "${BUILD_DIRECTORY}"/hostid ]; then
if ! boolean_enabled "${SKIP_HOSTID}" && [ -r /etc/hostid ]; then
if ! cp /etc/hostid "${BUILD_DIRECTORY}"/hostid; then
echo "ERROR: unable to copy /etc/hostid"
echo "Copy a hostid file to ./hostid or use -H to disable"
exit 1
fi
fi
fi
# If no config is specified, use in-tree default but force EFI and components
if ! [ -r "${BUILD_DIRECTORY}"/config.yaml ]; then
BUILD_ARGS=(
"-e" ".EFI.Enabled=true"
"-e" ".Components.Enabled=true"
"${BUILD_ARGS[@]}"
)
fi
# Try to include ZBM hooks in the images by default
if [ -d "${BUILD_DIRECTORY}/hooks" ]; then
# Write a dracut configuration snippet
mkdir -p "${BUILD_DIRECTORY}/dracut.conf.d"
echo "zfsbootmenu_hook_root=/build/hooks" \
> "${BUILD_DIRECTORY}/dracut.conf.d/user_hooks.conf"
# Write a mkinitcpio configuration snippet
mkdir -p "${BUILD_DIRECTORY}/mkinitcpio.conf.d"
echo "zfsbootmenu_hook_root=/build/hooks" \
> "${BUILD_DIRECTORY}/mkinitcpio.conf.d/user_hooks.conf"
fi
# Make `/build` the working directory so relative paths in configs make sense
exec "${PODMAN}" run \
--rm -w "/build" "${RUNTIME_ARGS[@]}" \
"${BUILD_IMG}" "${BUILD_ARGS[@]}" "$@"