140 lines
3.2 KiB
Bash
Executable File
140 lines
3.2 KiB
Bash
Executable File
#!/bin/bash
|
|
# vim: softtabstop=2 shiftwidth=2 expandtab
|
|
|
|
cleanup() {
|
|
if [[ -f "${TEMP_EFI}" && -z "${PRESERVE_TEMP_EFI}" ]]; then
|
|
rm "${TEMP_EFI}"
|
|
fi
|
|
[ -f "${TEMP_KCL}" ] && rm "${TEMP_KCL}"
|
|
}
|
|
|
|
usage() {
|
|
cat <<-EOF
|
|
USAGE: $0 [-e <arg>] [-f <arg>] [-k <arg>] [-o <arg>]
|
|
|
|
-e <arg> ZFSBootMenu EFI file
|
|
-f <arg> Replace kernel command line with contents of file
|
|
-k <arg> Replace kernel command line with quoted arguments
|
|
-o <arg> Output file; if undefined the input file will be replaced
|
|
|
|
If neither -f or -k are provided, the command line from the
|
|
input EFI will be opened in \$EDITOR.
|
|
EOF
|
|
}
|
|
|
|
INPUT_EFI=
|
|
OUTPUT_EFI=
|
|
ARG_FILE=
|
|
ARG_VAR=
|
|
|
|
while getopts "e:f:k:o:" opt; do
|
|
case "${opt}" in
|
|
e)
|
|
INPUT_EFI="${OPTARG}"
|
|
if [ ! -f "${INPUT_EFI}" ]; then
|
|
echo "Unable to open ${INPUT_EFI}"
|
|
exit 1
|
|
fi
|
|
# Set OUTPUT_EFI to the input by default
|
|
[ -z "${OUTPUT_EFI}" ] && OUTPUT_EFI="${INPUT_EFI}"
|
|
;;
|
|
o)
|
|
# Override the output file
|
|
OUTPUT_EFI="${OPTARG}"
|
|
;;
|
|
f)
|
|
ARG_FILE="${OPTARG}"
|
|
ARG_VAR=
|
|
if [ ! -f "${ARG_FILE}" ]; then
|
|
echo "Unable to open ${ARG_FILE}"
|
|
exit 1
|
|
fi
|
|
;;
|
|
k)
|
|
ARG_VAR="${OPTARG}"
|
|
ARG_FILE=
|
|
;;
|
|
*)
|
|
usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [ -z "${INPUT_EFI}" ]; then
|
|
usage
|
|
exit 1
|
|
fi
|
|
|
|
if ! command -v objcopy > /dev/null 2>&1 ; then
|
|
echo "Missing required binary 'objcopy'"
|
|
exit 1
|
|
fi
|
|
|
|
trap cleanup EXIT INT TERM
|
|
|
|
TEMP_EFI="$(mktemp)"
|
|
if ! objout="$( objcopy --remove-section .cmdline "${INPUT_EFI}" "${TEMP_EFI}" 2>&1 )"; then
|
|
echo "Unable to remove .cmdline from '${INPUT_EFI}'"
|
|
echo "${objout}"
|
|
exit 1
|
|
fi
|
|
|
|
TEMP_KCL="$(mktemp)"
|
|
if [ -n "${ARG_VAR}" ]; then
|
|
echo -n "${ARG_VAR}" > "${TEMP_KCL}"
|
|
elif [ -n "${ARG_FILE}" ]; then
|
|
cp "${ARG_FILE}" "${TEMP_KCL}" || exit 1
|
|
else
|
|
if ! objout="$( objcopy --dump-section .cmdline="${TEMP_KCL}" "${INPUT_EFI}" 2>&1 )"; then
|
|
echo "Unable to extract cmdline from '${INPUT_EFI}'"
|
|
echo "${objout}"
|
|
exit 1
|
|
fi
|
|
|
|
# Remove null terminators
|
|
sed -i 's/\x0//g' "${TEMP_KCL}"
|
|
|
|
# Strip leading and trailing spaces
|
|
sed -i 's/^[[:space:]]*//g;s/[[:space:]]*$//g' "${TEMP_KCL}"
|
|
|
|
if ! command -v "${EDITOR:=vi}" >/dev/null 2>&1 ; then
|
|
echo "define \$EDITOR to edit"
|
|
exit 1
|
|
fi
|
|
|
|
if ! "${EDITOR}" "${TEMP_KCL}"; then
|
|
echo "failed to edit KCL for ${INPUT_EFI}"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Strip leading and trailing spaces
|
|
sed -i 's/^[[:space:]]*//g;s/[[:space:]]*$//g' "${TEMP_KCL}"
|
|
|
|
# Remove existing null terminators
|
|
sed -i 's/\x0//g' "${TEMP_KCL}"
|
|
|
|
# Collapse multiple lines into one
|
|
sed -i -z 's/\n/ /g' "${TEMP_KCL}"
|
|
|
|
# Pad with a space; replicating Dracut behavior.
|
|
# FIXME: Is this strictly needed?
|
|
sed -i 's/^/ /' "${TEMP_KCL}"
|
|
|
|
# Add a null terminator for the efi stub; replicating Dracut behavior
|
|
echo -ne "\x00" >> "${TEMP_KCL}"
|
|
|
|
if objout="$( objcopy --add-section .cmdline="${TEMP_KCL}" --change-section-vma .cmdline=0x30000 "${TEMP_EFI}" 2>&1 )"; then
|
|
if ! cp "${TEMP_EFI}" "${OUTPUT_EFI}" ; then
|
|
echo "Unable to copy ${TEMP_EFI} to ${OUTPUT}"
|
|
echo "Preserving '${TEMP_EFI}'"
|
|
PRESERVE_TEMP_EFI=1
|
|
exit 1
|
|
fi
|
|
else
|
|
echo "Unable to add commandline to ${TEMP_KCL}"
|
|
echo "${objout}"
|
|
exit 1
|
|
fi
|