Skip to content

Commit

Permalink
Basic EFI KCL editor
Browse files Browse the repository at this point in the history
  • Loading branch information
zdykstra committed May 3, 2022
1 parent ada36c8 commit 8933a57
Showing 1 changed file with 139 additions and 0 deletions.
139 changes: 139 additions & 0 deletions bin/zbm-efi-kcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#!/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

0 comments on commit 8933a57

Please sign in to comment.