Home | History | Annotate | Line # | Download | only in embedded
mkimage revision 1.87
      1 #!/bin/sh
      2 # $NetBSD: mkimage,v 1.87 2024/12/29 09:46:44 jmmv Exp $
      3 #
      4 # Copyright (c) 2013, 2014 The NetBSD Foundation, Inc.
      5 # All rights reserved.
      6 #
      7 # This code is derived from software contributed to The NetBSD Foundation
      8 # by Christos Zoulas.
      9 #
     10 # Redistribution and use in source and binary forms, with or without
     11 # modification, are permitted provided that the following conditions
     12 # are met:
     13 # 1. Redistributions of source code must retain the above copyright
     14 #    notice, this list of conditions and the following disclaimer.
     15 # 2. Redistributions in binary form must reproduce the above copyright
     16 #    notice, this list of conditions and the following disclaimer in the
     17 #    documentation and/or other materials provided with the distribution.
     18 # 3. Neither the name of The NetBSD Foundation nor the names of its
     19 #    contributors may be used to endorse or promote products derived
     20 #    from this software without specific prior written permission.
     21 #
     22 # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     23 # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     24 # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     25 # PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     26 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     27 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     28 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     29 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     30 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     31 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     32 # POSSIBILITY OF SUCH DAMAGE.
     33 #
     34 
     35 #
     36 # Makes a bootable image for the host architecture given.
     37 # The host specific functions are pulled in from a /bin/sh script in the
     38 # "conf" directory, and is expected to provide the following shell
     39 # functions, which are called in the following order:
     40 #
     41 #  - make_fstab: Creates the host's /etc/fstab with / on ${rootdev}.
     42 #    If -m is given, a number of directories are put on a tmpfs RAM disk
     43 #  - customize: After unpacking the sets, this gets the system to
     44 #    a working state, e. g. by setting up /etc/rc.conf and /dev
     45 #  - populate: Add common goods like kernel and bootloader
     46 #  - make_label: Prints disklabel to stdout
     47 #
     48 
     49 set -e
     50 
     51 DIR="$(cd "$(dirname "$0")" && pwd)"
     52 PROG="$(basename "$0")"
     53 
     54 MAKE=${TOOL_MAKE:-make}
     55 DISKLABEL=${TOOL_DISKLABEL:-disklabel}
     56 FDISK=${TOOL_FDISK:-fdisk}
     57 GPT=${TOOL_GPT:-gpt}
     58 MAKEFS=${TOOL_MAKEFS:-makefs}
     59 MTREE=${TOOL_MTREE:-mtree}
     60 INSTALLBOOT=${TOOL_INSTALLBOOT:-installboot}
     61 MKUBOOTIMAGE=${TOOL_MKUBOOTIMAGE:-mkubootimage}
     62 GZIP_CMD=${TOOL_GZIP:-gzip} # ${GZIP} is special to gzip(1)
     63 
     64 postfix=false
     65 [ "${MKPOSTFIX:-yes}" = no ] || postfix=true
     66 
     67 src="/usr/src"
     68 sets="base comp etc games gpufw man manhtml misc modules rescue tests text"
     69 xsets="xbase xcomp xetc xfont xserver"
     70 minfree="10%"
     71 bar="==="
     72 
     73 tmp="$(mktemp -d "${TMPDIR:-/tmp}/$PROG.XXXXXX")"
     74 mnt="${tmp}/mnt"
     75 mkdir -p "${mnt}/etc" "${mnt}/dev"
     76 
     77 trap "cleanup" 0 1 2 3 15
     78 
     79 cleanup() {
     80 	case "$tmp" in
     81 	"${TMPDIR:-/tmp}/$PROG."*)	rm -fr "$tmp";;
     82 	esac
     83 }
     84 
     85 fail() {
     86 	IFS=' '
     87 	echo >&2 "${PROG}: $*"
     88 	exit 1
     89 }
     90 
     91 getsize() {
     92 	set -- $(ls -l $1)
     93 	echo $5
     94 }
     95 
     96 getsectors() {
     97 	case "$1" in
     98 	*g)
     99 		m=1073741824
    100 		v=${1%g}
    101 		;;
    102 	*m)
    103 		m=1048576
    104 		v=${1%m}
    105 		;;
    106 	*k)
    107 		m=1024
    108 		v=${1%k}
    109 		;;
    110 	*[0-9b])
    111 		m=1
    112 		v=${1%b}
    113 		;;
    114 	esac
    115 	echo $((m * v / 512))
    116 }
    117 
    118 minwrites_fstab_entries() {
    119 	$minwrites || return 0
    120 	cat << EOF
    121 tmpfs		/var/log		tmpfs	rw,union,-s32M
    122 tmpfs		/var/run		tmpfs	rw,union,-s1M
    123 tmpfs		/var/mail		tmpfs	rw,union,-s10M
    124 tmpfs		/var/chroot		tmpfs	rw,union,-s10M
    125 EOF
    126 	if $postfix; then
    127 	cat << EOF
    128 tmpfs		/var/spool/postfix	tmpfs	rw,union,-s20M
    129 tmpfs		/var/db/postfix		tmpfs	rw,union,-s1M
    130 EOF
    131 	fi
    132 }
    133 
    134 make_fstab_gpt() {
    135 	local boot=$1
    136 	local rootopts=
    137 	if $minwrites; then
    138 		rootopts=,log,nodevmtime
    139 	fi
    140 
    141 	cat > ${mnt}/etc/fstab << EOF
    142 # NetBSD /etc/fstab
    143 # See /usr/share/examples/fstab/ for more examples.
    144 NAME=${gpt_label_ffs:-netbsd-root}	/		ffs	rw,noatime${rootopts}	1 1
    145 NAME=${gpt_label_boot:-$boot}		/boot		msdos	rw	1 1
    146 ptyfs		/dev/pts	ptyfs	rw
    147 procfs		/proc		procfs	rw
    148 tmpfs		/var/shm	tmpfs	rw,-m1777,-sram%25
    149 EOF
    150 	minwrites_fstab_entries >> ${mnt}/etc/fstab
    151 }
    152 
    153 # From Richard Neswold's:
    154 # http://rich-tbp.blogspot.com/2013/03/netbsd-on-rpi-minimizing-disk-writes.html
    155 # Also for the postfix stuff below
    156 make_fstab_normal() {
    157 	local rootopts=
    158 	if $minwrites; then
    159 		rootopts=,nodevmtime
    160 	fi
    161 	cat > ${mnt}/etc/fstab << EOF
    162 # NetBSD /etc/fstab
    163 # See /usr/share/examples/fstab/ for more examples.
    164 ROOT.a		/			ffs	rw,log,noatime${rootopts}	1 1
    165 ROOT.e		/boot			msdos	rw				1 1
    166 ptyfs		/dev/pts		ptyfs	rw
    167 procfs		/proc			procfs	rw
    168 tmpfs		/tmp			tmpfs	rw,-s32M
    169 tmpfs		/var/shm		tmpfs	rw,-m1777,-sram%25
    170 EOF
    171 	minwrites_fstab_entries >> ${mnt}/etc/fstab
    172 }
    173 
    174 make_fstab_default() {
    175 	if $gpt; then
    176 		make_fstab_gpt "$@"
    177 	else
    178 		make_fstab_normal
    179 	fi
    180 	echo "./etc/fstab type=file uname=root gname=wheel mode=0644" \
    181 	    >> "$tmp/selected_sets"
    182 
    183 	# Missing mount points from fstab
    184 	echo "./proc type=dir uname=root gname=wheel mode=0755" \
    185 	    >> "$tmp/selected_sets"
    186 }
    187 
    188 usage() {
    189 	cat << EOF 1>&2
    190 Usage: $PROG -h <host-arch> [-bdmx] [-B <byte-order>] [-K <kerneldir>] [-S <srcdir>] [-D <destdir>] [-c <custom-files-dir>] [-s <Mb size>] [<image>]
    191 
    192 -b	Boot only, no sets loaded
    193 -r	root device kind (sd, wd, ld)
    194 -d	Add the debug sets
    195 -m	Optimize the OS installation to mimimize disk writes for SSDs
    196 -x	Load the X sets too, not just the base ones
    197 EOF
    198 	exit 1
    199 }
    200 
    201 # First pass for options to get the host and src directories
    202 OPTS="B:D:K:S:bc:dh:mr:s:x"
    203 while getopts "$OPTS" f
    204 do
    205 	case $f in
    206 	h)	h="$OPTARG";;
    207 	S)	src="$OPTARG";;
    208 	*)	;;
    209 	esac
    210 done
    211 
    212 if [ -z "$h" ]
    213 then
    214 	usage
    215 fi
    216 
    217 if [ ! -f "${DIR}/conf/${h}.conf" ]
    218 then
    219 	echo $PROG: ${DIR}/conf/${h}.conf is not present 1>&2
    220 	exit 1
    221 fi
    222 
    223 resize=false
    224 gpt=false
    225 gpt_hybrid=false
    226 
    227 . "${DIR}/conf/${h}.conf"
    228 release="/usr/obj/${MACHINE}/release"
    229 
    230 selected_sets="$sets"
    231 dsets_p=false
    232 xsets_p=false
    233 minwrites=false
    234 rootdev=ld
    235 endian=
    236 
    237 OPTIND=1
    238 while getopts "$OPTS" f
    239 do
    240 	case $f in
    241 	B)	endian="-B $OPTARG";;
    242 	D)	release="$OPTARG";;
    243 	K)	kernel="$OPTARG";;
    244 	S)	;;
    245 	b)	bootonly=true;;
    246 	d)	dsets_p=true
    247 		selected_sets="$selected_sets debug"
    248 		if $xsets_p; then
    249 			selected_sets="$selected_sets xdebug"
    250 		fi
    251 		;;
    252 	c)	custom="$OPTARG";;
    253 	h)	;;
    254 	m)	minwrites=true;;
    255 	r)	rootdev="$OPTARG";;
    256 	s)	size="$OPTARG";;
    257 	x)	xsets_p=true
    258 		selected_sets="$selected_sets $xsets"
    259 		if $dsets_p; then
    260 		    selected_sets="$selected_sets xdebug"
    261 		fi
    262 		;;
    263 	*)	usage;;
    264 	esac
    265 done
    266 if [ -n "${MKREPRO_TIMESTAMP}" ]; then
    267 	timestamp_opt="-T ${MKREPRO_TIMESTAMP}"
    268 	volume_opt=",volume_id=$((${MKREPRO_TIMESTAMP} & 0xffff))"
    269 fi
    270 
    271 shift $(( $OPTIND - 1 ))
    272 if [ -n "$1" ]; then
    273 	# take the next argument as being the image name
    274 	image="$1"
    275 	shift
    276 fi
    277 
    278 case "$image" in
    279 *.gz)	compress=true; image="${image%.gz}";;
    280 *)	compress=false;;
    281 esac
    282 
    283 if [ -z "${bootonly}" ]; then
    284 	echo ${bar} configuring sets ${bar}
    285 	(cat "${release}/etc/mtree/NetBSD.dist"
    286 	for i in $selected_sets; do
    287 		s="${release}/etc/mtree/set.$i"
    288 		if [ -f "$s" ]; then
    289 			cat "$s"
    290 		fi
    291 	done) > "$tmp/selected_sets"
    292 fi
    293 
    294 make_fstab
    295 customize
    296 populate
    297 
    298 if [ ! "${MKDTB}" = "no" ]; then
    299 	#
    300 	# Part of the dtb set resides on the FAT partition (/boot/dtb/*), and
    301 	# the rest on FFS. Split it up here.
    302 	#
    303 	echo ${bar} Installing devicetree blobs ${bar}
    304 	mkdir -p "${mnt}/boot"
    305 	cp -r "${release}/boot/dtb" "${mnt}/boot/dtb"
    306 
    307 	mkdir -p "${mnt}/etc/mtree"
    308 	cp "${release}/etc/mtree/set.dtb" "${mnt}/etc/mtree/set.dtb"
    309 	echo "./etc/mtree/set.dtb type=file uname=root gname=wheel mode=0444" >> "$tmp/selected_sets"
    310 
    311 	mkdir -p "${mnt}/var/db/obsolete"
    312 	cp "${release}/var/db/obsolete/dtb" "${mnt}/var/db/obsolete/dtb"
    313 	echo "./var/db/obsolete/dtb type=file uname=root gname=wheel mode=0644" >>"$tmp/selected_sets"
    314 fi
    315 
    316 if [ -n "${msdosid}" ]; then
    317 	echo ${bar} Populating msdos filesystem ${bar}
    318 
    319 	case $(( ${msdosid} )) in
    320 	1)	fat_opt=",fat_type=12";;
    321 	4|6|14)	fat_opt=",fat_type=16";;
    322 	11|12)	fat_opt=",fat_type=32";;
    323 	*)	fat_opt=;;
    324 	esac
    325 	${MAKEFS} -N ${release}/etc -t msdos \
    326 	    -o "volume_label=NETBSD${fat_opt}${volume_opt}" ${timestamp_opt} \
    327 	    -O $((${init} / 2))m -s $((${boot} / 2))m \
    328 	    ${image} ${mnt}/boot
    329 fi
    330 
    331 if [ -z "${bootonly}" ]; then
    332 	echo ${bar} Populating ffs filesystem ${bar}
    333 	${MAKEFS} -rx ${endian} -N ${release}/etc -t ffs \
    334 	    -O ${ffsoffset} ${timestamp_opt} \
    335 	    -o d=4096,f=8192,b=65536 -b $((${extra}))m \
    336 	    -F "$tmp/selected_sets" ${image} "${release}" "${mnt}"
    337 fi
    338 
    339 if [ "${size}" = 0 ]; then
    340 	size="$(getsize "${image}")"
    341 	# Round up to a multiple of 4m and add 1m of slop.
    342 	alignunit=$((4*1024*1024))
    343 	alignsize=$((alignunit*((size + alignunit - 1)/alignunit)))
    344 	alignsize=$((alignsize + 1024*1024))
    345 	if [ "${size}" -lt "${alignsize}" ]; then
    346 		dd bs=1 count="$((alignsize - size))" if=/dev/zero \
    347 			>> "${image}" 2> /dev/null
    348 		size="${alignsize}"
    349 	fi
    350 fi
    351 
    352 if $gpt; then
    353 	if $gpt_hybrid; then
    354 		gpt_flags="-H"
    355 	fi
    356 	gpt_flags="${gpt_flags} ${timestamp_opt}"
    357 	initsecs=$((${init} * 1024))
    358 	bootsecs=$((${boot} * 1024))
    359 	ffsstart="$(getsectors ${ffsoffset})"
    360 
    361 	echo ${bar} Clearing existing partitions ${bar}
    362 	${GPT} ${gpt_flags} ${image} destroy || true
    363 
    364 	echo ${bar} Creating partitions ${bar}
    365 	${GPT} ${gpt_flags} ${image} create ${gpt_create_flags}
    366 	${GPT} ${gpt_flags} ${image} add -b ${initsecs} -s ${bootsecs} -l ${gpt_label_boot:-EFI} -t ${gpt_boot_type:-efi}
    367 	${GPT} ${gpt_flags} ${image} set -a required -i 1
    368 	${GPT} ${gpt_flags} ${image} add -a 4m -b ${ffsstart} -l ${gpt_label_ffs:-netbsd-root} -t ffs
    369 	${GPT} ${gpt_flags} ${image} show
    370 	if $gpt_hybrid; then
    371 		echo ${bar} Creating hybrid MBR ${bar}
    372 		${FDISK} -f -g -u -0 -a -s ${msdosid}/${initsecs}/${bootsecs} -F ${image}
    373 		${FDISK} -f -g -u -3 -s 238/1/$((${initsecs} - 1)) -F ${image}
    374 		${FDISK} -F ${image}
    375 	fi
    376 else
    377 	if [ -n "${msdosid}" ]; then
    378 		echo ${bar} Running fdisk ${bar}
    379 		initsecs=$((${init} * 1024))
    380 		bootsecs=$((${boot} * 1024))
    381 		${FDISK} -f -i ${image}
    382 		${FDISK} -f -a -u -0 -s ${msdosid}/${initsecs}/${bootsecs} -F ${image}
    383 		if [ -z "${bootonly}" ]; then
    384 			ffsstart="$(getsectors ${ffsoffset})"
    385 			imagesize="$(getsize "${image}")"
    386 			imagesecs="$(getsectors ${imagesize})"
    387 			ffssize="$(expr ${imagesecs} - ${ffsstart})"
    388 			${FDISK} -f -u -1 -s 169/${ffsstart}/${ffssize} -F ${image}
    389 		fi
    390 
    391 		echo ${bar} Adding label ${bar}
    392 		make_label > ${tmp}/label
    393 		${DISKLABEL} -m -R -F ${image} ${tmp}/label
    394 	elif [ -n "${netbsdid}" ]; then
    395 		echo ${bar} Adding label ${bar}
    396 		make_label > ${tmp}/label
    397 		${DISKLABEL} -m -R -F ${image} ${tmp}/label
    398 
    399 		echo ${bar} Running fdisk ${bar}
    400 		${FDISK} -f -i ${image}
    401 		${FDISK} -f -a -u -0 -s 169/${init} ${image}
    402 		${INSTALLBOOT} -f -v ${image} ${release}/usr/mdec/bootxx_ffsv1
    403 	fi
    404 fi
    405 
    406 if $compress; then
    407 	echo ${bar} Compressing image ${bar}
    408 	rm -f "${image}.gz"
    409 	${GZIP_CMD} -n -9 ${image}
    410 	image="${image}.gz"
    411 fi
    412 
    413 echo ${bar} Image is ${image} ${bar}
    414