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 49set -e 50 51DIR="$(cd "$(dirname "$0")" && pwd)" 52PROG="$(basename "$0")" 53 54MAKE=${TOOL_MAKE:-make} 55DISKLABEL=${TOOL_DISKLABEL:-disklabel} 56FDISK=${TOOL_FDISK:-fdisk} 57GPT=${TOOL_GPT:-gpt} 58MAKEFS=${TOOL_MAKEFS:-makefs} 59MTREE=${TOOL_MTREE:-mtree} 60INSTALLBOOT=${TOOL_INSTALLBOOT:-installboot} 61MKUBOOTIMAGE=${TOOL_MKUBOOTIMAGE:-mkubootimage} 62GZIP_CMD=${TOOL_GZIP:-gzip} # ${GZIP} is special to gzip(1) 63 64postfix=false 65[ "${MKPOSTFIX:-yes}" = no ] || postfix=true 66 67src="/usr/src" 68sets="base comp etc games gpufw man manhtml misc modules rescue tests text" 69xsets="xbase xcomp xetc xfont xserver" 70minfree="10%" 71bar="===" 72 73tmp="$(mktemp -d "${TMPDIR:-/tmp}/$PROG.XXXXXX")" 74mnt="${tmp}/mnt" 75mkdir -p "${mnt}/etc" "${mnt}/dev" 76 77trap "cleanup" 0 1 2 3 15 78 79cleanup() { 80 case "$tmp" in 81 "${TMPDIR:-/tmp}/$PROG."*) rm -fr "$tmp";; 82 esac 83} 84 85fail() { 86 IFS=' ' 87 echo >&2 "${PROG}: $*" 88 exit 1 89} 90 91getsize() { 92 set -- $(ls -l $1) 93 echo $5 94} 95 96getsectors() { 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 118minwrites_fstab_entries() { 119 $minwrites || return 0 120 cat << EOF 121tmpfs /var/log tmpfs rw,union,-s32M 122tmpfs /var/run tmpfs rw,union,-s1M 123tmpfs /var/mail tmpfs rw,union,-s10M 124tmpfs /var/chroot tmpfs rw,union,-s10M 125EOF 126 if $postfix; then 127 cat << EOF 128tmpfs /var/spool/postfix tmpfs rw,union,-s20M 129tmpfs /var/db/postfix tmpfs rw,union,-s1M 130EOF 131 fi 132} 133 134make_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. 144NAME=${gpt_label_ffs:-netbsd-root} / ffs rw,noatime${rootopts} 1 1 145NAME=${gpt_label_boot:-$boot} /boot msdos rw 1 1 146ptyfs /dev/pts ptyfs rw 147procfs /proc procfs rw 148tmpfs /var/shm tmpfs rw,-m1777,-sram%25 149EOF 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 156make_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. 164ROOT.a / ffs rw,log,noatime${rootopts} 1 1 165ROOT.e /boot msdos rw 1 1 166ptyfs /dev/pts ptyfs rw 167procfs /proc procfs rw 168tmpfs /tmp tmpfs rw,-s32M 169tmpfs /var/shm tmpfs rw,-m1777,-sram%25 170EOF 171 minwrites_fstab_entries >> ${mnt}/etc/fstab 172} 173 174make_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 188usage() { 189 cat << EOF 1>&2 190Usage: $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 197EOF 198 exit 1 199} 200 201# First pass for options to get the host and src directories 202OPTS="B:D:K:S:bc:dh:mr:s:x" 203while getopts "$OPTS" f 204do 205 case $f in 206 h) h="$OPTARG";; 207 S) src="$OPTARG";; 208 *) ;; 209 esac 210done 211 212if [ -z "$h" ] 213then 214 usage 215fi 216 217if [ ! -f "${DIR}/conf/${h}.conf" ] 218then 219 echo $PROG: ${DIR}/conf/${h}.conf is not present 1>&2 220 exit 1 221fi 222 223resize=false 224gpt=false 225gpt_hybrid=false 226 227. "${DIR}/conf/${h}.conf" 228release="/usr/obj/${MACHINE}/release" 229 230selected_sets="$sets" 231dsets_p=false 232xsets_p=false 233minwrites=false 234rootdev=ld 235endian= 236 237OPTIND=1 238while getopts "$OPTS" f 239do 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 265done 266if [ -n "${MKREPRO_TIMESTAMP}" ]; then 267 timestamp_opt="-T ${MKREPRO_TIMESTAMP}" 268 volume_opt=",volume_id=$((${MKREPRO_TIMESTAMP} & 0xffff))" 269fi 270 271shift $(( $OPTIND - 1 )) 272if [ -n "$1" ]; then 273 # take the next argument as being the image name 274 image="$1" 275 shift 276fi 277 278case "$image" in 279*.gz) compress=true; image="${image%.gz}";; 280*) compress=false;; 281esac 282 283if [ -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" 292fi 293 294make_fstab 295customize 296populate 297 298if [ ! "${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" 314fi 315 316if [ -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 329fi 330 331if [ -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}" 337fi 338 339if [ "${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 350fi 351 352if $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 376else 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 404fi 405 406if $compress; then 407 echo ${bar} Compressing image ${bar} 408 rm -f "${image}.gz" 409 ${GZIP_CMD} -n -9 ${image} 410 image="${image}.gz" 411fi 412 413echo ${bar} Image is ${image} ${bar} 414