Skip to content

Commit 8933a57

Browse files
committed
Basic EFI KCL editor
1 parent ada36c8 commit 8933a57

File tree

1 file changed

+139
-0
lines changed

1 file changed

+139
-0
lines changed

bin/zbm-efi-kcl

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
#!/bin/bash
2+
# vim: softtabstop=2 shiftwidth=2 expandtab
3+
4+
cleanup() {
5+
if [[ -f "${TEMP_EFI}" && -z "${PRESERVE_TEMP_EFI}" ]]; then
6+
rm "${TEMP_EFI}"
7+
fi
8+
[ -f "${TEMP_KCL}" ] && rm "${TEMP_KCL}"
9+
}
10+
11+
usage() {
12+
cat <<-EOF
13+
USAGE: $0 [-e <arg>] [-f <arg>] [-k <arg>] [-o <arg>]
14+
15+
-e <arg> ZFSBootMenu EFI file
16+
-f <arg> Replace kernel command line with contents of file
17+
-k <arg> Replace kernel command line with quoted arguments
18+
-o <arg> Output file; if undefined the input file will be replaced
19+
20+
If neither -f or -k are provided, the command line from the
21+
input EFI will be opened in \$EDITOR.
22+
EOF
23+
}
24+
25+
INPUT_EFI=
26+
OUTPUT_EFI=
27+
ARG_FILE=
28+
ARG_VAR=
29+
30+
while getopts "e:f:k:o:" opt; do
31+
case "${opt}" in
32+
e)
33+
INPUT_EFI="${OPTARG}"
34+
if [ ! -f "${INPUT_EFI}" ]; then
35+
echo "Unable to open ${INPUT_EFI}"
36+
exit 1
37+
fi
38+
# Set OUTPUT_EFI to the input by default
39+
[ -z "${OUTPUT_EFI}" ] && OUTPUT_EFI="${INPUT_EFI}"
40+
;;
41+
o)
42+
# Override the output file
43+
OUTPUT_EFI="${OPTARG}"
44+
;;
45+
f)
46+
ARG_FILE="${OPTARG}"
47+
ARG_VAR=
48+
if [ ! -f "${ARG_FILE}" ]; then
49+
echo "Unable to open ${ARG_FILE}"
50+
exit 1
51+
fi
52+
;;
53+
k)
54+
ARG_VAR="${OPTARG}"
55+
ARG_FILE=
56+
;;
57+
*)
58+
usage
59+
exit 1
60+
;;
61+
esac
62+
done
63+
64+
if [ -z "${INPUT_EFI}" ]; then
65+
usage
66+
exit 1
67+
fi
68+
69+
if ! command -v objcopy > /dev/null 2>&1 ; then
70+
echo "Missing required binary 'objcopy'"
71+
exit 1
72+
fi
73+
74+
trap cleanup EXIT INT TERM
75+
76+
TEMP_EFI="$(mktemp)"
77+
if ! objout="$( objcopy --remove-section .cmdline "${INPUT_EFI}" "${TEMP_EFI}" 2>&1 )"; then
78+
echo "Unable to remove .cmdline from '${INPUT_EFI}'"
79+
echo "${objout}"
80+
exit 1
81+
fi
82+
83+
TEMP_KCL="$(mktemp)"
84+
if [ -n "${ARG_VAR}" ]; then
85+
echo -n "${ARG_VAR}" > "${TEMP_KCL}"
86+
elif [ -n "${ARG_FILE}" ]; then
87+
cp "${ARG_FILE}" "${TEMP_KCL}" || exit 1
88+
else
89+
if ! objout="$( objcopy --dump-section .cmdline="${TEMP_KCL}" "${INPUT_EFI}" 2>&1 )"; then
90+
echo "Unable to extract cmdline from '${INPUT_EFI}'"
91+
echo "${objout}"
92+
exit 1
93+
fi
94+
95+
# Remove null terminators
96+
sed -i 's/\x0//g' "${TEMP_KCL}"
97+
98+
# Strip leading and trailing spaces
99+
sed -i 's/^[[:space:]]*//g;s/[[:space:]]*$//g' "${TEMP_KCL}"
100+
101+
if ! command -v "${EDITOR:=vi}" >/dev/null 2>&1 ; then
102+
echo "define \$EDITOR to edit"
103+
exit 1
104+
fi
105+
106+
if ! "${EDITOR}" "${TEMP_KCL}"; then
107+
echo "failed to edit KCL for ${INPUT_EFI}"
108+
exit 1
109+
fi
110+
fi
111+
112+
# Strip leading and trailing spaces
113+
sed -i 's/^[[:space:]]*//g;s/[[:space:]]*$//g' "${TEMP_KCL}"
114+
115+
# Remove existing null terminators
116+
sed -i 's/\x0//g' "${TEMP_KCL}"
117+
118+
# Collapse multiple lines into one
119+
sed -i -z 's/\n/ /g' "${TEMP_KCL}"
120+
121+
# Pad with a space; replicating Dracut behavior.
122+
# FIXME: Is this strictly needed?
123+
sed -i 's/^/ /' "${TEMP_KCL}"
124+
125+
# Add a null terminator for the efi stub; replicating Dracut behavior
126+
echo -ne "\x00" >> "${TEMP_KCL}"
127+
128+
if objout="$( objcopy --add-section .cmdline="${TEMP_KCL}" --change-section-vma .cmdline=0x30000 "${TEMP_EFI}" 2>&1 )"; then
129+
if ! cp "${TEMP_EFI}" "${OUTPUT_EFI}" ; then
130+
echo "Unable to copy ${TEMP_EFI} to ${OUTPUT}"
131+
echo "Preserving '${TEMP_EFI}'"
132+
PRESERVE_TEMP_EFI=1
133+
exit 1
134+
fi
135+
else
136+
echo "Unable to add commandline to ${TEMP_KCL}"
137+
echo "${objout}"
138+
exit 1
139+
fi

0 commit comments

Comments
 (0)