mkimage revision 1.87
11.31Sjmcneill#!/bin/sh
21.87Sjmmv# $NetBSD: mkimage,v 1.87 2024/12/29 09:46:44 jmmv Exp $
31.13Schristos#
41.45Schristos# Copyright (c) 2013, 2014 The NetBSD Foundation, Inc.
51.1Sagc# All rights reserved.
61.1Sagc#
71.17Schristos# This code is derived from software contributed to The NetBSD Foundation
81.17Schristos# by Christos Zoulas.
91.17Schristos#
101.1Sagc# Redistribution and use in source and binary forms, with or without
111.1Sagc# modification, are permitted provided that the following conditions
121.1Sagc# are met:
131.1Sagc# 1. Redistributions of source code must retain the above copyright
141.1Sagc#    notice, this list of conditions and the following disclaimer.
151.1Sagc# 2. Redistributions in binary form must reproduce the above copyright
161.1Sagc#    notice, this list of conditions and the following disclaimer in the
171.1Sagc#    documentation and/or other materials provided with the distribution.
181.17Schristos# 3. Neither the name of The NetBSD Foundation nor the names of its
191.17Schristos#    contributors may be used to endorse or promote products derived
201.17Schristos#    from this software without specific prior written permission.
211.17Schristos#
221.17Schristos# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
231.17Schristos# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
241.17Schristos# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
251.17Schristos# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
261.17Schristos# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
271.17Schristos# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
281.17Schristos# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
291.17Schristos# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
301.17Schristos# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
311.17Schristos# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
321.17Schristos# POSSIBILITY OF SUCH DAMAGE.
331.1Sagc#
341.1Sagc
351.58Shubertf#
361.58Shubertf# Makes a bootable image for the host architecture given.
371.58Shubertf# The host specific functions are pulled in from a /bin/sh script in the
381.58Shubertf# "conf" directory, and is expected to provide the following shell
391.58Shubertf# functions, which are called in the following order:
401.58Shubertf#
411.58Shubertf#  - make_fstab: Creates the host's /etc/fstab with / on ${rootdev}.
421.58Shubertf#    If -m is given, a number of directories are put on a tmpfs RAM disk
431.58Shubertf#  - customize: After unpacking the sets, this gets the system to
441.58Shubertf#    a working state, e. g. by setting up /etc/rc.conf and /dev
451.58Shubertf#  - populate: Add common goods like kernel and bootloader
461.58Shubertf#  - make_label: Prints disklabel to stdout
471.58Shubertf#
481.58Shubertf
491.33Sjmcneillset -e
501.33Sjmcneill
511.17SchristosDIR="$(cd "$(dirname "$0")" && pwd)"
521.17SchristosPROG="$(basename "$0")"
531.17Schristos
541.66SjmcneillMAKE=${TOOL_MAKE:-make}
551.21SchristosDISKLABEL=${TOOL_DISKLABEL:-disklabel}
561.24SchristosFDISK=${TOOL_FDISK:-fdisk}
571.73SjmcneillGPT=${TOOL_GPT:-gpt}
581.21SchristosMAKEFS=${TOOL_MAKEFS:-makefs}
591.25SjmcneillMTREE=${TOOL_MTREE:-mtree}
601.45SchristosINSTALLBOOT=${TOOL_INSTALLBOOT:-installboot}
611.59SchristosMKUBOOTIMAGE=${TOOL_MKUBOOTIMAGE:-mkubootimage}
621.44SastGZIP_CMD=${TOOL_GZIP:-gzip} # ${GZIP} is special to gzip(1)
631.21Schristos
641.87Sjmmvpostfix=false
651.87Sjmmv[ "${MKPOSTFIX:-yes}" = no ] || postfix=true
661.87Sjmmv
671.17Schristossrc="/usr/src"
681.84Sskrllsets="base comp etc games gpufw man manhtml misc modules rescue tests text"
691.83Sskrllxsets="xbase xcomp xetc xfont xserver"
701.17Schristosminfree="10%"
711.17Schristosbar="==="
721.17Schristos
731.67Skretmp="$(mktemp -d "${TMPDIR:-/tmp}/$PROG.XXXXXX")"
741.17Schristosmnt="${tmp}/mnt"
751.46Schristosmkdir -p "${mnt}/etc" "${mnt}/dev"
761.23Schristos
771.17Schristostrap "cleanup" 0 1 2 3 15
781.17Schristos
791.17Schristoscleanup() {
801.17Schristos	case "$tmp" in
811.68Skre	"${TMPDIR:-/tmp}/$PROG."*)	rm -fr "$tmp";;
821.17Schristos	esac
831.17Schristos}
841.1Sagc
851.69Skrefail() {
861.69Skre	IFS=' '
871.69Skre	echo >&2 "${PROG}: $*"
881.69Skre	exit 1
891.69Skre}
901.69Skre
911.17Schristosgetsize() {
921.17Schristos	set -- $(ls -l $1)
931.17Schristos	echo $5
941.1Sagc}
951.1Sagc
961.63Sjmcneillgetsectors() {
971.63Sjmcneill	case "$1" in
981.63Sjmcneill	*g)
991.63Sjmcneill		m=1073741824
1001.63Sjmcneill		v=${1%g}
1011.63Sjmcneill		;;
1021.63Sjmcneill	*m)
1031.63Sjmcneill		m=1048576
1041.63Sjmcneill		v=${1%m}
1051.63Sjmcneill		;;
1061.63Sjmcneill	*k)
1071.63Sjmcneill		m=1024
1081.63Sjmcneill		v=${1%k}
1091.63Sjmcneill		;;
1101.63Sjmcneill	*[0-9b])
1111.63Sjmcneill		m=1
1121.63Sjmcneill		v=${1%b}
1131.63Sjmcneill		;;
1141.63Sjmcneill	esac
1151.63Sjmcneill	echo $((m * v / 512))
1161.63Sjmcneill}
1171.63Sjmcneill
1181.85Schristosminwrites_fstab_entries() {
1191.85Schristos	$minwrites || return 0
1201.85Schristos	cat << EOF
1211.85Schristostmpfs		/var/log		tmpfs	rw,union,-s32M
1221.85Schristostmpfs		/var/run		tmpfs	rw,union,-s1M
1231.85Schristostmpfs		/var/mail		tmpfs	rw,union,-s10M
1241.87Sjmmvtmpfs		/var/chroot		tmpfs	rw,union,-s10M
1251.87SjmmvEOF
1261.87Sjmmv	if $postfix; then
1271.87Sjmmv	cat << EOF
1281.85Schristostmpfs		/var/spool/postfix	tmpfs	rw,union,-s20M
1291.85Schristostmpfs		/var/db/postfix		tmpfs	rw,union,-s1M
1301.85SchristosEOF
1311.87Sjmmv	fi
1321.85Schristos}
1331.85Schristos
1341.85Schristosmake_fstab_gpt() {
1351.85Schristos	local boot=$1
1361.85Schristos	local rootopts=
1371.85Schristos	if $minwrites; then
1381.85Schristos		rootopts=,log,nodevmtime
1391.85Schristos	fi
1401.85Schristos
1411.85Schristos	cat > ${mnt}/etc/fstab << EOF
1421.85Schristos# NetBSD /etc/fstab
1431.85Schristos# See /usr/share/examples/fstab/ for more examples.
1441.85SchristosNAME=${gpt_label_ffs:-netbsd-root}	/		ffs	rw,noatime${rootopts}	1 1
1451.85SchristosNAME=${gpt_label_boot:-$boot}		/boot		msdos	rw	1 1
1461.85Schristosptyfs		/dev/pts	ptyfs	rw
1471.85Schristosprocfs		/proc		procfs	rw
1481.85Schristostmpfs		/var/shm	tmpfs	rw,-m1777,-sram%25
1491.85SchristosEOF
1501.85Schristos	minwrites_fstab_entries >> ${mnt}/etc/fstab
1511.85Schristos}
1521.85Schristos
1531.85Schristos# From Richard Neswold's:
1541.85Schristos# http://rich-tbp.blogspot.com/2013/03/netbsd-on-rpi-minimizing-disk-writes.html
1551.85Schristos# Also for the postfix stuff below
1561.85Schristosmake_fstab_normal() {
1571.85Schristos	local rootopts=
1581.85Schristos	if $minwrites; then
1591.85Schristos		rootopts=,nodevmtime
1601.85Schristos	fi
1611.85Schristos	cat > ${mnt}/etc/fstab << EOF
1621.85Schristos# NetBSD /etc/fstab
1631.85Schristos# See /usr/share/examples/fstab/ for more examples.
1641.86SchristosROOT.a		/			ffs	rw,log,noatime${rootopts}	1 1
1651.85SchristosROOT.e		/boot			msdos	rw				1 1
1661.85Schristosptyfs		/dev/pts		ptyfs	rw
1671.85Schristosprocfs		/proc			procfs	rw
1681.85Schristostmpfs		/tmp			tmpfs	rw,-s32M
1691.85Schristostmpfs		/var/shm		tmpfs	rw,-m1777,-sram%25
1701.85SchristosEOF
1711.85Schristos	minwrites_fstab_entries >> ${mnt}/etc/fstab
1721.85Schristos}
1731.85Schristos
1741.85Schristosmake_fstab_default() {
1751.85Schristos	if $gpt; then
1761.85Schristos		make_fstab_gpt "$@"
1771.85Schristos	else
1781.85Schristos		make_fstab_normal
1791.85Schristos	fi
1801.85Schristos	echo "./etc/fstab type=file uname=root gname=wheel mode=0644" \
1811.85Schristos	    >> "$tmp/selected_sets"
1821.85Schristos
1831.85Schristos	# Missing mount points from fstab
1841.85Schristos	echo "./proc type=dir uname=root gname=wheel mode=0755" \
1851.85Schristos	    >> "$tmp/selected_sets"
1861.85Schristos}
1871.85Schristos
1881.12Schristosusage() {
1891.12Schristos	cat << EOF 1>&2
1901.60SmartinUsage: $PROG -h <host-arch> [-bdmx] [-B <byte-order>] [-K <kerneldir>] [-S <srcdir>] [-D <destdir>] [-c <custom-files-dir>] [-s <Mb size>] [<image>]
1911.39Schristos
1921.39Schristos-b	Boot only, no sets loaded
1931.47Schristos-r	root device kind (sd, wd, ld)
1941.39Schristos-d	Add the debug sets
1951.43Schristos-m	Optimize the OS installation to mimimize disk writes for SSDs
1961.57Shubertf-x	Load the X sets too, not just the base ones
1971.12SchristosEOF
1981.13Schristos	exit 1
1991.12Schristos}
2001.12Schristos
2011.32Sjmcneill# First pass for options to get the host and src directories
2021.60SmartinOPTS="B:D:K:S:bc:dh:mr:s:x"
2031.4Schristoswhile getopts "$OPTS" f
2041.4Schristosdo
2051.4Schristos	case $f in
2061.4Schristos	h)	h="$OPTARG";;
2071.32Sjmcneill	S)	src="$OPTARG";;
2081.4Schristos	*)	;;
2091.4Schristos	esac
2101.4Schristosdone
2111.4Schristos
2121.4Schristosif [ -z "$h" ]
2131.4Schristosthen
2141.4Schristos	usage
2151.4Schristosfi
2161.4Schristos
2171.5Schristosif [ ! -f "${DIR}/conf/${h}.conf" ]
2181.4Schristosthen
2191.5Schristos	echo $PROG: ${DIR}/conf/${h}.conf is not present 1>&2
2201.4Schristos	exit 1
2211.4Schristosfi
2221.4Schristos
2231.56Sjmcneillresize=false
2241.73Sjmcneillgpt=false
2251.74Sjmcneillgpt_hybrid=false
2261.56Sjmcneill
2271.5Schristos. "${DIR}/conf/${h}.conf"
2281.45Schristosrelease="/usr/obj/${MACHINE}/release"
2291.4Schristos
2301.17Schristosselected_sets="$sets"
2311.50Sskrlldsets_p=false
2321.50Sskrllxsets_p=false
2331.39Schristosminwrites=false
2341.47Schristosrootdev=ld
2351.60Smartinendian=
2361.17Schristos
2371.4SchristosOPTIND=1
2381.4Schristoswhile getopts "$OPTS" f
2391.4Schristosdo
2401.4Schristos	case $f in
2411.60Smartin	B)	endian="-B $OPTARG";;
2421.18Schristos	D)	release="$OPTARG";;
2431.18Schristos	K)	kernel="$OPTARG";;
2441.32Sjmcneill	S)	;;
2451.41Schristos	b)	bootonly=true;;
2461.50Sskrll	d)	dsets_p=true
2471.39Schristos		selected_sets="$selected_sets debug"
2481.50Sskrll		if $xsets_p; then
2491.39Schristos			selected_sets="$selected_sets xdebug"
2501.39Schristos		fi
2511.39Schristos		;;
2521.4Schristos	c)	custom="$OPTARG";;
2531.4Schristos	h)	;;
2541.39Schristos	m)	minwrites=true;;
2551.47Schristos	r)	rootdev="$OPTARG";;
2561.4Schristos	s)	size="$OPTARG";;
2571.50Sskrll	x)	xsets_p=true
2581.39Schristos		selected_sets="$selected_sets $xsets"
2591.50Sskrll		if $dsets_p; then
2601.39Schristos		    selected_sets="$selected_sets xdebug"
2611.39Schristos		fi
2621.39Schristos		;;
2631.6Schristos	*)	usage;;
2641.1Sagc	esac
2651.1Sagcdone
2661.81Smlelstvif [ -n "${MKREPRO_TIMESTAMP}" ]; then
2671.80Schristos	timestamp_opt="-T ${MKREPRO_TIMESTAMP}"
2681.80Schristos	volume_opt=",volume_id=$((${MKREPRO_TIMESTAMP} & 0xffff))"
2691.80Schristosfi
2701.1Sagc
2711.20Sjmcneillshift $(( $OPTIND - 1 ))
2721.4Schristosif [ -n "$1" ]; then
2731.1Sagc	# take the next argument as being the image name
2741.1Sagc	image="$1"
2751.1Sagc	shift
2761.1Sagcfi
2771.1Sagc
2781.22Schristoscase "$image" in
2791.22Schristos*.gz)	compress=true; image="${image%.gz}";;
2801.22Schristos*)	compress=false;;
2811.22Schristosesac
2821.22Schristos
2831.45Schristosif [ -z "${bootonly}" ]; then
2841.36Sgarbled	echo ${bar} configuring sets ${bar}
2851.51Sskrll	(cat "${release}/etc/mtree/NetBSD.dist"
2861.36Sgarbled	for i in $selected_sets; do
2871.36Sgarbled		s="${release}/etc/mtree/set.$i"
2881.36Sgarbled		if [ -f "$s" ]; then
2891.36Sgarbled			cat "$s"
2901.36Sgarbled		fi
2911.36Sgarbled	done) > "$tmp/selected_sets"
2921.36Sgarbledfi
2931.1Sagc
2941.4Schristosmake_fstab
2951.17Schristoscustomize
2961.17Schristospopulate
2971.1Sagc
2981.72Sjmcneillif [ ! "${MKDTB}" = "no" ]; then
2991.72Sjmcneill	#
3001.72Sjmcneill	# Part of the dtb set resides on the FAT partition (/boot/dtb/*), and
3011.72Sjmcneill	# the rest on FFS. Split it up here.
3021.72Sjmcneill	#
3031.72Sjmcneill	echo ${bar} Installing devicetree blobs ${bar}
3041.72Sjmcneill	mkdir -p "${mnt}/boot"
3051.72Sjmcneill	cp -r "${release}/boot/dtb" "${mnt}/boot/dtb"
3061.72Sjmcneill
3071.72Sjmcneill	mkdir -p "${mnt}/etc/mtree"
3081.72Sjmcneill	cp "${release}/etc/mtree/set.dtb" "${mnt}/etc/mtree/set.dtb"
3091.72Sjmcneill	echo "./etc/mtree/set.dtb type=file uname=root gname=wheel mode=0444" >> "$tmp/selected_sets"
3101.72Sjmcneill
3111.72Sjmcneill	mkdir -p "${mnt}/var/db/obsolete"
3121.72Sjmcneill	cp "${release}/var/db/obsolete/dtb" "${mnt}/var/db/obsolete/dtb"
3131.72Sjmcneill	echo "./var/db/obsolete/dtb type=file uname=root gname=wheel mode=0644" >>"$tmp/selected_sets"
3141.72Sjmcneillfi
3151.72Sjmcneill
3161.45Schristosif [ -n "${msdosid}" ]; then
3171.17Schristos	echo ${bar} Populating msdos filesystem ${bar}
3181.72Sjmcneill
3191.71Smartin	case $(( ${msdosid} )) in
3201.71Smartin	1)	fat_opt=",fat_type=12";;
3211.71Smartin	4|6|14)	fat_opt=",fat_type=16";;
3221.71Smartin	11|12)	fat_opt=",fat_type=32";;
3231.71Smartin	*)	fat_opt=;;
3241.71Smartin	esac
3251.71Smartin	${MAKEFS} -N ${release}/etc -t msdos \
3261.80Schristos	    -o "volume_label=NETBSD${fat_opt}${volume_opt}" ${timestamp_opt} \
3271.63Sjmcneill	    -O $((${init} / 2))m -s $((${boot} / 2))m \
3281.41Schristos	    ${image} ${mnt}/boot
3291.1Sagcfi
3301.1Sagc
3311.45Schristosif [ -z "${bootonly}" ]; then
3321.36Sgarbled	echo ${bar} Populating ffs filesystem ${bar}
3331.60Smartin	${MAKEFS} -rx ${endian} -N ${release}/etc -t ffs \
3341.80Schristos	    -O ${ffsoffset} ${timestamp_opt} \
3351.61Sjmcneill	    -o d=4096,f=8192,b=65536 -b $((${extra}))m \
3361.36Sgarbled	    -F "$tmp/selected_sets" ${image} "${release}" "${mnt}"
3371.36Sgarbledfi
3381.1Sagc
3391.23Schristosif [ "${size}" = 0 ]; then
3401.77Srin	size="$(getsize "${image}")"
3411.76Sriastrad	# Round up to a multiple of 4m and add 1m of slop.
3421.76Sriastrad	alignunit=$((4*1024*1024))
3431.77Srin	alignsize=$((alignunit*((size + alignunit - 1)/alignunit)))
3441.76Sriastrad	alignsize=$((alignsize + 1024*1024))
3451.77Srin	if [ "${size}" -lt "${alignsize}" ]; then
3461.77Srin		dd bs=1 count="$((alignsize - size))" if=/dev/zero \
3471.77Srin			>> "${image}" 2> /dev/null
3481.77Srin		size="${alignsize}"
3491.76Sriastrad	fi
3501.17Schristosfi
3511.1Sagc
3521.73Sjmcneillif $gpt; then
3531.74Sjmcneill	if $gpt_hybrid; then
3541.74Sjmcneill		gpt_flags="-H"
3551.74Sjmcneill	fi
3561.80Schristos	gpt_flags="${gpt_flags} ${timestamp_opt}"
3571.30Sjmcneill	initsecs=$((${init} * 1024))
3581.30Sjmcneill	bootsecs=$((${boot} * 1024))
3591.73Sjmcneill	ffsstart="$(getsectors ${ffsoffset})"
3601.73Sjmcneill
3611.73Sjmcneill	echo ${bar} Clearing existing partitions ${bar}
3621.74Sjmcneill	${GPT} ${gpt_flags} ${image} destroy || true
3631.73Sjmcneill
3641.73Sjmcneill	echo ${bar} Creating partitions ${bar}
3651.74Sjmcneill	${GPT} ${gpt_flags} ${image} create ${gpt_create_flags}
3661.75Sjmcneill	${GPT} ${gpt_flags} ${image} add -b ${initsecs} -s ${bootsecs} -l ${gpt_label_boot:-EFI} -t ${gpt_boot_type:-efi}
3671.74Sjmcneill	${GPT} ${gpt_flags} ${image} set -a required -i 1
3681.74Sjmcneill	${GPT} ${gpt_flags} ${image} add -a 4m -b ${ffsstart} -l ${gpt_label_ffs:-netbsd-root} -t ffs
3691.74Sjmcneill	${GPT} ${gpt_flags} ${image} show
3701.74Sjmcneill	if $gpt_hybrid; then
3711.74Sjmcneill		echo ${bar} Creating hybrid MBR ${bar}
3721.74Sjmcneill		${FDISK} -f -g -u -0 -a -s ${msdosid}/${initsecs}/${bootsecs} -F ${image}
3731.74Sjmcneill		${FDISK} -f -g -u -3 -s 238/1/$((${initsecs} - 1)) -F ${image}
3741.74Sjmcneill		${FDISK} -F ${image}
3751.74Sjmcneill	fi
3761.73Sjmcneillelse
3771.73Sjmcneill	if [ -n "${msdosid}" ]; then
3781.73Sjmcneill		echo ${bar} Running fdisk ${bar}
3791.73Sjmcneill		initsecs=$((${init} * 1024))
3801.73Sjmcneill		bootsecs=$((${boot} * 1024))
3811.73Sjmcneill		${FDISK} -f -i ${image}
3821.73Sjmcneill		${FDISK} -f -a -u -0 -s ${msdosid}/${initsecs}/${bootsecs} -F ${image}
3831.73Sjmcneill		if [ -z "${bootonly}" ]; then
3841.73Sjmcneill			ffsstart="$(getsectors ${ffsoffset})"
3851.73Sjmcneill			imagesize="$(getsize "${image}")"
3861.73Sjmcneill			imagesecs="$(getsectors ${imagesize})"
3871.73Sjmcneill			ffssize="$(expr ${imagesecs} - ${ffsstart})"
3881.73Sjmcneill			${FDISK} -f -u -1 -s 169/${ffsstart}/${ffssize} -F ${image}
3891.73Sjmcneill		fi
3901.73Sjmcneill
3911.73Sjmcneill		echo ${bar} Adding label ${bar}
3921.73Sjmcneill		make_label > ${tmp}/label
3931.79Sjmcneill		${DISKLABEL} -m -R -F ${image} ${tmp}/label
3941.73Sjmcneill	elif [ -n "${netbsdid}" ]; then
3951.73Sjmcneill		echo ${bar} Adding label ${bar}
3961.73Sjmcneill		make_label > ${tmp}/label
3971.79Sjmcneill		${DISKLABEL} -m -R -F ${image} ${tmp}/label
3981.73Sjmcneill
3991.73Sjmcneill		echo ${bar} Running fdisk ${bar}
4001.73Sjmcneill		${FDISK} -f -i ${image}
4011.73Sjmcneill		${FDISK} -f -a -u -0 -s 169/${init} ${image}
4021.73Sjmcneill		${INSTALLBOOT} -f -v ${image} ${release}/usr/mdec/bootxx_ffsv1
4031.63Sjmcneill	fi
4041.2Sagcfi
4051.22Schristos
4061.22Schristosif $compress; then
4071.22Schristos	echo ${bar} Compressing image ${bar}
4081.23Schristos	rm -f "${image}.gz"
4091.80Schristos	${GZIP_CMD} -n -9 ${image}
4101.22Schristos	image="${image}.gz"
4111.22Schristosfi
4121.22Schristos
4131.17Schristosecho ${bar} Image is ${image} ${bar}
414