#!/bin/sh # $NetBSD: mkimage,v 1.78.2.1 2024/02/03 11:47:08 martin Exp $ # # Copyright (c) 2013, 2014 The NetBSD Foundation, Inc. # All rights reserved. # # This code is derived from software contributed to The NetBSD Foundation # by Christos Zoulas. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. Neither the name of The NetBSD Foundation nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # # Makes a bootable image for the host architecture given. # The host specific functions are pulled in from a /bin/sh script in the # "conf" directory, and is expected to provide the following shell # functions, which are called in the following order: # # - make_fstab: Creates the host's /etc/fstab with / on ${rootdev}. # If -m is given, a number of directories are put on a tmpfs RAM disk # - customize: After unpacking the sets, this gets the system to # a working state, e. g. by setting up /etc/rc.conf and /dev # - populate: Add common goods like kernel and bootloader # - make_label: Prints disklabel to stdout # set -e DIR="$(cd "$(dirname "$0")" && pwd)" PROG="$(basename "$0")" MAKE=${TOOL_MAKE:-make} DISKLABEL=${TOOL_DISKLABEL:-disklabel} FDISK=${TOOL_FDISK:-fdisk} GPT=${TOOL_GPT:-gpt} MAKEFS=${TOOL_MAKEFS:-makefs} MTREE=${TOOL_MTREE:-mtree} INSTALLBOOT=${TOOL_INSTALLBOOT:-installboot} MKUBOOTIMAGE=${TOOL_MKUBOOTIMAGE:-mkubootimage} GZIP_CMD=${TOOL_GZIP:-gzip} # ${GZIP} is special to gzip(1) src="/usr/src" sets="base comp etc games gpufw man misc modules rescue tests text" xsets="xbase xcomp xetc xfont xserver" minfree="10%" bar="===" tmp="$(mktemp -d "${TMPDIR:-/tmp}/$PROG.XXXXXX")" mnt="${tmp}/mnt" mkdir -p "${mnt}/etc" "${mnt}/dev" trap "cleanup" 0 1 2 3 15 cleanup() { case "$tmp" in "${TMPDIR:-/tmp}/$PROG."*) rm -fr "$tmp";; esac } fail() { IFS=' ' echo >&2 "${PROG}: $*" exit 1 } getsize() { set -- $(ls -l $1) echo $5 } getsectors() { case "$1" in *g) m=1073741824 v=${1%g} ;; *m) m=1048576 v=${1%m} ;; *k) m=1024 v=${1%k} ;; *[0-9b]) m=1 v=${1%b} ;; esac echo $((m * v / 512)) } usage() { cat << EOF 1>&2 Usage: $PROG -h [-bdmx] [-B ] [-K ] [-S ] [-D ] [-c ] [-s ] [] -b Boot only, no sets loaded -r root device kind (sd, wd, ld) -d Add the debug sets -m Optimize the OS installation to mimimize disk writes for SSDs -x Load the X sets too, not just the base ones EOF exit 1 } # First pass for options to get the host and src directories OPTS="B:D:K:S:bc:dh:mr:s:x" while getopts "$OPTS" f do case $f in h) h="$OPTARG";; S) src="$OPTARG";; *) ;; esac done if [ -z "$h" ] then usage fi if [ ! -f "${DIR}/conf/${h}.conf" ] then echo $PROG: ${DIR}/conf/${h}.conf is not present 1>&2 exit 1 fi resize=false gpt=false gpt_hybrid=false . "${DIR}/conf/${h}.conf" release="/usr/obj/${MACHINE}/release" selected_sets="$sets" dsets_p=false xsets_p=false minwrites=false rootdev=ld endian= OPTIND=1 while getopts "$OPTS" f do case $f in B) endian="-B $OPTARG";; D) release="$OPTARG";; K) kernel="$OPTARG";; S) ;; b) bootonly=true;; d) dsets_p=true selected_sets="$selected_sets debug" if $xsets_p; then selected_sets="$selected_sets xdebug" fi ;; c) custom="$OPTARG";; h) ;; m) minwrites=true;; r) rootdev="$OPTARG";; s) size="$OPTARG";; x) xsets_p=true selected_sets="$selected_sets $xsets" if $dsets_p; then selected_sets="$selected_sets xdebug" fi ;; *) usage;; esac done shift $(( $OPTIND - 1 )) if [ -n "$1" ]; then # take the next argument as being the image name image="$1" shift fi case "$image" in *.gz) compress=true; image="${image%.gz}";; *) compress=false;; esac if [ -z "${bootonly}" ]; then echo ${bar} configuring sets ${bar} (cat "${release}/etc/mtree/NetBSD.dist" for i in $selected_sets; do s="${release}/etc/mtree/set.$i" if [ -f "$s" ]; then cat "$s" fi done) > "$tmp/selected_sets" fi make_fstab customize populate if [ ! "${MKDTB}" = "no" ]; then # # Part of the dtb set resides on the FAT partition (/boot/dtb/*), and # the rest on FFS. Split it up here. # echo ${bar} Installing devicetree blobs ${bar} mkdir -p "${mnt}/boot" cp -r "${release}/boot/dtb" "${mnt}/boot/dtb" mkdir -p "${mnt}/etc/mtree" cp "${release}/etc/mtree/set.dtb" "${mnt}/etc/mtree/set.dtb" echo "./etc/mtree/set.dtb type=file uname=root gname=wheel mode=0444" >> "$tmp/selected_sets" mkdir -p "${mnt}/var/db/obsolete" cp "${release}/var/db/obsolete/dtb" "${mnt}/var/db/obsolete/dtb" echo "./var/db/obsolete/dtb type=file uname=root gname=wheel mode=0644" >>"$tmp/selected_sets" fi if [ -n "${msdosid}" ]; then echo ${bar} Populating msdos filesystem ${bar} case $(( ${msdosid} )) in 1) fat_opt=",fat_type=12";; 4|6|14) fat_opt=",fat_type=16";; 11|12) fat_opt=",fat_type=32";; *) fat_opt=;; esac ${MAKEFS} -N ${release}/etc -t msdos \ -o "volume_label=NETBSD${fat_opt}" \ -O $((${init} / 2))m -s $((${boot} / 2))m \ ${image} ${mnt}/boot fi if [ -z "${bootonly}" ]; then echo ${bar} Populating ffs filesystem ${bar} ${MAKEFS} -rx ${endian} -N ${release}/etc -t ffs \ -O ${ffsoffset} \ -o d=4096,f=8192,b=65536 -b $((${extra}))m \ -F "$tmp/selected_sets" ${image} "${release}" "${mnt}" fi if [ "${size}" = 0 ]; then size="$(getsize "${image}")" # Round up to a multiple of 4m and add 1m of slop. alignunit=$((4*1024*1024)) alignsize=$((alignunit*((size + alignunit - 1)/alignunit))) alignsize=$((alignsize + 1024*1024)) if [ "${size}" -lt "${alignsize}" ]; then dd bs=1 count="$((alignsize - size))" if=/dev/zero \ >> "${image}" 2> /dev/null size="${alignsize}" fi fi if $gpt; then if $gpt_hybrid; then gpt_flags="-H" fi initsecs=$((${init} * 1024)) bootsecs=$((${boot} * 1024)) ffsstart="$(getsectors ${ffsoffset})" echo ${bar} Clearing existing partitions ${bar} ${GPT} ${gpt_flags} ${image} destroy || true echo ${bar} Creating partitions ${bar} ${GPT} ${gpt_flags} ${image} create ${gpt_create_flags} ${GPT} ${gpt_flags} ${image} add -b ${initsecs} -s ${bootsecs} -l ${gpt_label_boot:-EFI} -t ${gpt_boot_type:-efi} ${GPT} ${gpt_flags} ${image} set -a required -i 1 ${GPT} ${gpt_flags} ${image} add -a 4m -b ${ffsstart} -l ${gpt_label_ffs:-netbsd-root} -t ffs ${GPT} ${gpt_flags} ${image} show if $gpt_hybrid; then echo ${bar} Creating hybrid MBR ${bar} ${FDISK} -f -g -u -0 -a -s ${msdosid}/${initsecs}/${bootsecs} -F ${image} ${FDISK} -f -g -u -3 -s 238/1/$((${initsecs} - 1)) -F ${image} ${FDISK} -F ${image} fi else if [ -n "${msdosid}" ]; then echo ${bar} Running fdisk ${bar} initsecs=$((${init} * 1024)) bootsecs=$((${boot} * 1024)) ${FDISK} -f -i ${image} ${FDISK} -f -a -u -0 -s ${msdosid}/${initsecs}/${bootsecs} -F ${image} if [ -z "${bootonly}" ]; then ffsstart="$(getsectors ${ffsoffset})" imagesize="$(getsize "${image}")" imagesecs="$(getsectors ${imagesize})" ffssize="$(expr ${imagesecs} - ${ffsstart})" ${FDISK} -f -u -1 -s 169/${ffsstart}/${ffssize} -F ${image} fi echo ${bar} Adding label ${bar} make_label > ${tmp}/label ${DISKLABEL} -m -R -F ${image} ${tmp}/label elif [ -n "${netbsdid}" ]; then echo ${bar} Adding label ${bar} make_label > ${tmp}/label ${DISKLABEL} -m -R -F ${image} ${tmp}/label echo ${bar} Running fdisk ${bar} ${FDISK} -f -i ${image} ${FDISK} -f -a -u -0 -s 169/${init} ${image} ${INSTALLBOOT} -f -v ${image} ${release}/usr/mdec/bootxx_ffsv1 fi fi if $compress; then echo ${bar} Compressing image ${bar} rm -f "${image}.gz" ${GZIP_CMD} -9 ${image} image="${image}.gz" fi echo ${bar} Image is ${image} ${bar}