mirror of
https://github.com/ipxe/ipxe
synced 2026-05-04 03:03:43 +03:00
[build] Create util/gensrvimg for building network boot server images
In the spirit of util/genfsimg, create a script util/gensrvimg that can be used to install compiled iPXE binaries to a directory tree suitable for copying to a TFTP or HTTP server. The script detects the CPU architecture for each input file and installs it into the appropriate subdirectory. Top-level symlinks are created for each filename, with earlier files taking precedence. Signed binaries are detected and automatically placed into a Secure Boot specific subdirectory, thereby allowing the reduced-feature Secure Boot binaries to coexist with full-feature binaries in a single installation directory tree. An iPXE shim may be specified and will be automatically installed alongside the signed binaries, with the relevant symlink created for each signed binary. Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
@@ -360,7 +360,7 @@ jobs:
|
||||
shimx64.efi
|
||||
|
||||
combine:
|
||||
name: BIOS + UEFI
|
||||
name: Combine
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- bios
|
||||
@@ -370,7 +370,10 @@ jobs:
|
||||
container:
|
||||
image: ghcr.io/ipxe/ipxe-builder-utils
|
||||
env:
|
||||
binaries: >-
|
||||
efishims: >-
|
||||
-e shim/shimaa64.efi
|
||||
-e shim/shimx64.efi
|
||||
fsbinaries: >-
|
||||
bin-x86_64-pcbios/${DRIVERS}.lkrn
|
||||
bin-arm32-efi/${DRIVERS}.efi
|
||||
bin-arm64-efi/${DRIVERS}.efi
|
||||
@@ -379,6 +382,38 @@ jobs:
|
||||
bin-riscv32-efi/${DRIVERS}.efi
|
||||
bin-riscv64-efi/${DRIVERS}.efi
|
||||
bin-x86_64-efi/${DRIVERS}.efi
|
||||
srvbinaries: >-
|
||||
bin/ipxe.pxe
|
||||
bin/ipxe-legacy.pxe
|
||||
bin/undionly.kpxe
|
||||
bin-arm32-efi/ipxe.efi
|
||||
bin-arm32-efi/ipxe-legacy.efi
|
||||
bin-arm32-efi/snponly.efi
|
||||
bin-arm64-efi/ipxe.efi
|
||||
bin-arm64-efi/ipxe-legacy.efi
|
||||
bin-arm64-efi/snponly.efi
|
||||
bin-arm64-efi-sb/ipxe.efi
|
||||
bin-arm64-efi-sb/snponly.efi
|
||||
bin-i386-efi/ipxe.efi
|
||||
bin-i386-efi/ipxe-legacy.efi
|
||||
bin-i386-efi/snponly.efi
|
||||
bin-loong64-efi/ipxe.efi
|
||||
bin-loong64-efi/ipxe-legacy.efi
|
||||
bin-loong64-efi/snponly.efi
|
||||
bin-riscv32-efi/ipxe.efi
|
||||
bin-riscv32-efi/ipxe-legacy.efi
|
||||
bin-riscv32-efi/snponly.efi
|
||||
bin-riscv64-efi/ipxe.efi
|
||||
bin-riscv64-efi/ipxe-legacy.efi
|
||||
bin-riscv64-efi/snponly.efi
|
||||
bin-x86_64-efi/ipxe.efi
|
||||
bin-x86_64-efi/ipxe-legacy.efi
|
||||
bin-x86_64-efi/snponly.efi
|
||||
bin-x86_64-efi-sb/ipxe.efi
|
||||
bin-x86_64-efi-sb/snponly.efi
|
||||
bin-x86_64-pcbios/ipxe.pxe
|
||||
bin-x86_64-pcbios/ipxe-legacy.pxe
|
||||
bin-x86_64-pcbios/undionly.kpxe
|
||||
steps:
|
||||
|
||||
- name: Check out code
|
||||
@@ -387,9 +422,9 @@ jobs:
|
||||
- name: Download
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
pattern: "{bin-x86_64-pcbios,bin-*-efi,bin-*-efi-sb,shim}"
|
||||
pattern: "{bin,bin-x86_64-pcbios,bin-*-efi,bin-*-efi-sb,shim}"
|
||||
|
||||
- name: Combine
|
||||
- name: ISO + USB
|
||||
run: |
|
||||
# Provide an editable placeholder autoexec.ipxe for the USB image
|
||||
cat > autoexec.ipxe <<'EOF'
|
||||
@@ -400,11 +435,16 @@ jobs:
|
||||
&& shell || autoboot
|
||||
EOF
|
||||
for DRIVERS in ipxe ipxe-legacy ; do
|
||||
./src/util/genfsimg -o ${DRIVERS}.iso ${{ env.binaries }}
|
||||
./src/util/genfsimg -o ${DRIVERS}.iso ${{ env.fsbinaries }}
|
||||
./src/util/genfsimg -o ${DRIVERS}.usb -s autoexec.ipxe \
|
||||
${{ env.binaries }}
|
||||
${{ env.fsbinaries }}
|
||||
done
|
||||
|
||||
- name: Server
|
||||
run: |
|
||||
./src/util/gensrvimg -o ipxeboot.tar.gz ${{ env.efishims }} \
|
||||
${{ env.srvbinaries }}
|
||||
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
@@ -415,6 +455,7 @@ jobs:
|
||||
ipxe.usb
|
||||
ipxe-legacy.iso
|
||||
ipxe-legacy.usb
|
||||
ipxeboot.tar.gz
|
||||
|
||||
netboot:
|
||||
name: Netboot
|
||||
|
||||
@@ -49,6 +49,8 @@ get_word() {
|
||||
#
|
||||
efi_boot_name() {
|
||||
local FILENAME
|
||||
local MZSIG
|
||||
local PEOFF
|
||||
local PESIG
|
||||
local ARCH
|
||||
|
||||
|
||||
Executable
+325
@@ -0,0 +1,325 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Generate a network bootable directory image
|
||||
|
||||
set -e
|
||||
set -u
|
||||
|
||||
# Print usage message
|
||||
#
|
||||
help() {
|
||||
echo "usage: ${0} [OPTIONS] foo.[k]pxe|foo.efi [bar.[k]pxe|bar.efi,...]"
|
||||
echo
|
||||
echo "where OPTIONS are:"
|
||||
echo " -h show this help"
|
||||
echo " -a ARCH select default CPU architecture [x86_64]"
|
||||
echo " -d DIR install images to directory"
|
||||
echo " -e SHIM specify an EFI shim helper"
|
||||
echo " -o FILE save image archive to file"
|
||||
}
|
||||
|
||||
# Get hex byte from binary file
|
||||
#
|
||||
get_byte() {
|
||||
local FILENAME
|
||||
local OFFSET
|
||||
|
||||
FILENAME="${1}"
|
||||
OFFSET="${2}"
|
||||
|
||||
od -j "${OFFSET}" -N 1 -A n -t x1 -- "${FILENAME}" | tr -d " "
|
||||
}
|
||||
|
||||
# Get hex word from binary file
|
||||
#
|
||||
get_word() {
|
||||
local FILENAME
|
||||
local OFFSET
|
||||
local LSB
|
||||
local MSB
|
||||
|
||||
FILENAME="${1}"
|
||||
OFFSET="${2}"
|
||||
|
||||
LSB=$(get_byte "${FILENAME}" $(( ${OFFSET} + 0 )) )
|
||||
MSB=$(get_byte "${FILENAME}" $(( ${OFFSET} + 1 )) )
|
||||
echo "${MSB}${LSB}"
|
||||
}
|
||||
|
||||
# Get hex dword from binary file
|
||||
#
|
||||
get_dword() {
|
||||
local FILENAME
|
||||
local OFFSET
|
||||
local LSW
|
||||
local MSW
|
||||
|
||||
FILENAME="${1}"
|
||||
OFFSET="${2}"
|
||||
|
||||
LSW=$(get_word "${FILENAME}" $(( ${OFFSET} + 0 )) )
|
||||
MSW=$(get_word "${FILENAME}" $(( ${OFFSET} + 2 )) )
|
||||
echo "${MSW}${LSW}"
|
||||
}
|
||||
|
||||
# Get appropriate subdirectory name for CPU architecture from EFI binary
|
||||
#
|
||||
efi_subdir_name() {
|
||||
local FILENAME
|
||||
local MZSIG
|
||||
local PEOFF
|
||||
local PESIG
|
||||
local ARCH
|
||||
local OPTSIG
|
||||
local SECSIZE
|
||||
local SBSUFFIX
|
||||
|
||||
FILENAME="${1}"
|
||||
|
||||
MZSIG=$(get_word "${FILENAME}" 0)
|
||||
if [ "${MZSIG}" != "5a4d" ] ; then
|
||||
echo "${FILENAME}: invalid MZ header" >&2
|
||||
exit 1
|
||||
fi
|
||||
PEOFF=$(get_byte "${FILENAME}" 0x3c)
|
||||
PESIG=$(get_word "${FILENAME}" 0x${PEOFF})
|
||||
if [ "${PESIG}" != "4550" ] ; then
|
||||
echo "${FILENAME}: invalid PE header" >&2
|
||||
exit 1
|
||||
fi
|
||||
ARCH=$(get_word "${FILENAME}" $(( 0x${PEOFF} + 4 )) )
|
||||
OPTSIG=$(get_word "${FILENAME}" $(( 0x${PEOFF} + 24 )) )
|
||||
case "${OPTSIG}" in
|
||||
"010b" )
|
||||
SECSIZE=$(get_dword "${FILENAME}" $(( 0x${PEOFF} + 156 )) )
|
||||
;;
|
||||
"020b" )
|
||||
SECSIZE=$(get_dword "${FILENAME}" $(( 0x${PEOFF} + 172 )) )
|
||||
;;
|
||||
* )
|
||||
echo "${FILENAME}: unrecognised optional header ${OPTSIG}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
if [ "${SECSIZE}" != "00000000" ] ; then
|
||||
SBSUFFIX="-sb"
|
||||
else
|
||||
SBSUFFIX=""
|
||||
fi
|
||||
case "${ARCH}" in
|
||||
"014c" )
|
||||
echo "i386${SBSUFFIX}"
|
||||
;;
|
||||
"8664" )
|
||||
echo "x86_64${SBSUFFIX}"
|
||||
;;
|
||||
"01c2" )
|
||||
echo "arm32${SBSUFFIX}"
|
||||
;;
|
||||
"6264" )
|
||||
echo "loong64${SBSUFFIX}"
|
||||
;;
|
||||
"aa64" )
|
||||
echo "arm64${SBSUFFIX}"
|
||||
;;
|
||||
"5064" )
|
||||
echo "riscv64${SBSUFFIX}"
|
||||
;;
|
||||
"5032" )
|
||||
echo "riscv32${SBSUFFIX}"
|
||||
;;
|
||||
* )
|
||||
echo "${FILENAME}: unrecognised EFI architecture ${ARCH}" >&2
|
||||
exit 1
|
||||
esac
|
||||
}
|
||||
|
||||
# Get appropriate subdirectory name for CPU architecture from iPXE NBP
|
||||
#
|
||||
nbp_subdir_name() {
|
||||
local FILENAME
|
||||
local LJMP
|
||||
local SEGMENT
|
||||
local MAGIC
|
||||
local ARCH
|
||||
|
||||
FILENAME="${1}"
|
||||
|
||||
LJMP=$(get_byte "${FILENAME}" 0)
|
||||
if [ "${LJMP}" != "ea" ] ; then
|
||||
echo "${FILENAME}: invalid LJMP instruction" >&2
|
||||
exit 1
|
||||
fi
|
||||
SEGMENT=$(get_word "${FILENAME}" 3)
|
||||
if [ "${SEGMENT}" != "07c0" ] ; then
|
||||
echo "${FILENAME}: invalid LJMP segment" >&2
|
||||
exit 1
|
||||
fi
|
||||
MAGIC=$(get_word "${FILENAME}" 6)
|
||||
if [ "${MAGIC}" != "18ae" ] ; then
|
||||
echo "${FILENAME}: invalid iPXE magic" >&2
|
||||
exit 1
|
||||
fi
|
||||
ARCH=$(get_byte "${FILENAME}" 5)
|
||||
case "${ARCH}" in
|
||||
"32" )
|
||||
echo "i386"
|
||||
;;
|
||||
"64" )
|
||||
echo "x86_64"
|
||||
;;
|
||||
* )
|
||||
echo "${FILENAME}: unrecognised NBP architecture ${ARCH}" >&2
|
||||
exit 1
|
||||
esac
|
||||
}
|
||||
|
||||
# Get appropriate subdirectory name for CPU architecture
|
||||
#
|
||||
subdir_name() {
|
||||
local FILENAME
|
||||
local BYTE
|
||||
|
||||
FILENAME="${1}"
|
||||
|
||||
BYTE=$(get_byte "${FILENAME}" 0)
|
||||
case "${BYTE}" in
|
||||
"4d" )
|
||||
efi_subdir_name "${FILENAME}"
|
||||
;;
|
||||
"ea" )
|
||||
nbp_subdir_name "${FILENAME}"
|
||||
;;
|
||||
* )
|
||||
echo "${FILENAME}: unrecognised format" >&2
|
||||
exit 1
|
||||
esac
|
||||
}
|
||||
|
||||
# Parse command-line options
|
||||
#
|
||||
DEFARCH=x86_64
|
||||
OUTDIR=
|
||||
OUTFILE=
|
||||
SHIMAA64=
|
||||
SHIMX64=
|
||||
while getopts "ha:d:e:o:" OPTION ; do
|
||||
case "${OPTION}" in
|
||||
h)
|
||||
help
|
||||
exit 0
|
||||
;;
|
||||
a)
|
||||
DEFARCH="${OPTARG}"
|
||||
;;
|
||||
d)
|
||||
OUTDIR="${OPTARG}"
|
||||
;;
|
||||
e)
|
||||
SHIM="${OPTARG}"
|
||||
SHIMARCH=$(subdir_name "${SHIM}")
|
||||
case "${SHIMARCH}" in
|
||||
arm64* )
|
||||
SHIMAA64="${SHIM}"
|
||||
;;
|
||||
x86_64* )
|
||||
SHIMX64="${SHIM}"
|
||||
;;
|
||||
* )
|
||||
echo "${SHIM}: unsupported shim architecture" >&2
|
||||
exit 1
|
||||
esac
|
||||
;;
|
||||
o)
|
||||
OUTFILE="${OPTARG}"
|
||||
;;
|
||||
*)
|
||||
help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
if [ -z "${OUTDIR}" -a -z "${OUTFILE}" ] ; then
|
||||
echo "${0}: no output directory or file given" >&2
|
||||
help
|
||||
exit 1
|
||||
fi
|
||||
shift $(( OPTIND - 1 ))
|
||||
if [ $# -eq 0 ] ; then
|
||||
echo "${0}: no input files given" >&2
|
||||
help
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create temporary working directory, if applicable
|
||||
#
|
||||
WORKDIR=
|
||||
if [ -z "${OUTDIR}" ] ; then
|
||||
WORKDIR=$(mktemp -d "${OUTFILE}.XXXXXX")
|
||||
OUTDIR="${WORKDIR}/ipxeboot"
|
||||
fi
|
||||
mkdir -p "${OUTDIR}"
|
||||
|
||||
# Copy files to output directory
|
||||
#
|
||||
for FILENAME ; do
|
||||
SUBDIR=$(subdir_name "${FILENAME}")
|
||||
ARCH="${SUBDIR%-sb}"
|
||||
DESTDIR="${OUTDIR}/${SUBDIR}"
|
||||
BASENAME=$(basename "${FILENAME}")
|
||||
SHIMLINK="${BASENAME%.efi}-shim.efi"
|
||||
mkdir -p "${DESTDIR}"
|
||||
install -m 644 "${FILENAME}" "${DESTDIR}/${BASENAME}"
|
||||
case "${SUBDIR}" in
|
||||
arm64-sb )
|
||||
if [ -n "${SHIMAA64}" ] ; then
|
||||
install -m 644 "${SHIMAA64}" "${DESTDIR}/shimaa64.efi"
|
||||
ln -sfn "shimaa64.efi" "${DESTDIR}/${SHIMLINK}"
|
||||
fi
|
||||
;;
|
||||
x86_64-sb )
|
||||
if [ -n "${SHIMX64}" ] ; then
|
||||
install -m 644 "${SHIMX64}" "${DESTDIR}/shimx64.efi"
|
||||
ln -sfn "shimx64.efi" "${DESTDIR}/${SHIMLINK}"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
if [ "${ARCH}" = "${DEFARCH}" ] ; then
|
||||
if [ "${ARCH}" = "${SUBDIR}" ] ; then
|
||||
ln -sfn "${SUBDIR}/${BASENAME}" "${OUTDIR}/${BASENAME}"
|
||||
else
|
||||
ln -sfn "${SUBDIR}" "${OUTDIR}/sb"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Create output archive file, if applicable
|
||||
#
|
||||
if [ -n "${OUTFILE}" ] ; then
|
||||
TOPDIR=$(dirname "${OUTDIR}")
|
||||
BASENAME=$(basename "${OUTDIR}")
|
||||
case "${OUTFILE}" in
|
||||
*.tar )
|
||||
tar cf "${OUTFILE}" -C "${TOPDIR}" "${BASENAME}"
|
||||
;;
|
||||
*.tar.gz | *.tgz )
|
||||
tar czf "${OUTFILE}" -C "${TOPDIR}" "${BASENAME}"
|
||||
;;
|
||||
*.tar.bz2 )
|
||||
tar cjf "${OUTFILE}" -C "${TOPDIR}" "${BASENAME}"
|
||||
;;
|
||||
*.tar.xz )
|
||||
tar cJf "${OUTFILE}" -C "${TOPDIR}" "${BASENAME}"
|
||||
;;
|
||||
* )
|
||||
echo "${OUTFILE}: unrecognised archive format" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Clean up temporary working directory
|
||||
#
|
||||
if [ -n "${WORKDIR}" ] ; then
|
||||
rm -rf "${WORKDIR}"
|
||||
fi
|
||||
Reference in New Issue
Block a user