mkimage revision 1.8
1#! /bin/sh
2
3# $NetBSD: mkimage,v 1.8 2013/01/14 12:12:19 jmcneill Exp $
4
5# Copyright (c) 2012 Alistair Crooks <agc@NetBSD.org>
6# All rights reserved.
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions
10# are met:
11# 1. Redistributions of source code must retain the above copyright
12#    notice, this list of conditions and the following disclaimer.
13# 2. Redistributions in binary form must reproduce the above copyright
14#    notice, this list of conditions and the following disclaimer in the
15#    documentation and/or other materials provided with the distribution.
16#
17# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27#
28
29# find next available vnd, from kre
30next_avail ()
31{
32	local dev="$1"
33	local N=$(( ${#dev} + 1 ))
34	local unit units
35
36	units=$(
37		sysctl -n hw.disknames		|
38			tr ' ' '\012'		|
39			grep '^'"${dev}"'[0-9]'	|
40			sort -n -k 1.$N			)
41
42	test -z "${units}" && {
43		test -e "/dev/${dev}0a" || {
44			echo >&2 "No ${dev}s available!"
45			return 1
46		}
47		echo "${dev}0"
48		return
49	}
50
51	N=0
52	for unit in ${units}
53	do
54		if [ "${unit}" = "${dev}${N}" ]
55		then
56			N=$(( N + 1 ))
57		else
58			echo "${dev}${N}"
59			return
60		fi
61	done
62
63	test -e /dev/"${dev}${N}a" || {
64		echo >&2 "All ${dev}s in use"
65		return 1
66	}
67
68	echo "${dev}${N}"
69}
70
71# find the size of the gzipped files in a .tgz archive
72sizeone() {
73	if [ ! -f "$1" ]
74	then
75		echo "$PROG: Missing set $1" 1>&2
76		echo 0
77		return;
78	fi
79        case "$1" in 
80        *.tgz|*.tar.gz)
81                tar tvzf "$1" | awk '{ tot += $5 } END { print tot }'
82                ;;
83        *.tbz|*.tar.bz2)
84                tar tvjf "$1" | awk '{ tot += $5 } END { print tot }' 
85                ;;
86        *)
87                echo 0
88                ;; 
89        esac
90}
91
92usage() {
93	cat << EOF 1>&2
94Usage: $PROG [-S <setsdir>] [-c <custom-files-dir>] [-h <host-arch>] [-s <size>]
95EOF
96exit 1
97}
98
99finish() {
100    cleanup
101    ${sudo} umount ${mnt}
102    ${sudo} vnconfig -u ${vnddev}
103}
104
105DIR="$(dirname "$0")"
106PROG="$(basename "$0")"
107bar="==="
108sudo=
109mnt="${TMPDIR:-/tmp}/image.$$"
110src="/usr/src"
111obj="/usr/obj"
112
113# First pass for options to get the host
114OPTS="S:c:h:s:x"
115while getopts "$OPTS" f
116do
117	case $f in
118	h)	h="$OPTARG";;
119	*)	;;
120	esac
121done
122
123if [ -z "$h" ]
124then
125	usage
126fi
127
128if [ ! -f "${DIR}/conf/${h}.conf" ]
129then
130	echo $PROG: ${DIR}/conf/${h}.conf is not present 1>&2
131	exit 1
132fi
133
134. "${DIR}/conf/${h}.conf"
135
136OPTIND=1
137while getopts "$OPTS" f
138do
139	case $f in
140	S)	setsdir="$OPTARG";;
141	c)	custom="$OPTARG";;
142	h)	;;
143	s)	size="$OPTARG";;
144	x)	set -x;;
145	*)	usage;;
146	esac
147done
148
149trap finish 0 1 2 3 15
150
151shift $(( "$OPTIND" - 1 ))
152if [ -n "$1" ]; then
153	# take the next argument as being the image name
154	image="$1"
155	shift
156fi
157
158total=0
159for s in ${sets}; do
160	one="$(sizeone ${setsdir}/${s}.tgz)"
161	total=$(( ${total} +  ${one} ))
162done
163# calculate size of custom files
164custsize=0
165if [ -d "${custom}" ]; then
166	custsize=$(ls -lR "${custom}" | awk 'NF == 9 { tot += $5 } END { print tot }')
167fi
168total=$(( ( ( ${total} + ${custsize} ) / 1000000 ) + ${overhead} ))
169if [ $size -eq 0 ]; then
170        # auto-size the pkgs fs
171        size=${total}
172else
173        # check that we've been given enough space
174        if [ ${total} -gt ${size} ]; then
175                echo "$PROG: Given size is ${size} MB, but we need ${total} MB" >&2
176                exit 1
177        fi
178fi
179
180echo "${bar} making a new ${size} MB image in ${image} ${bar}"
181dd if=/dev/zero of=${image} bs=1m count=${size} conv=sparse
182
183vnddev=$(next_avail vnd)
184echo "${bar} mounting image via vnd ${vnddev} ${bar}"
185${sudo} vnconfig ${vnddev} ${image}
186${sudo} mkdir -p ${mnt}
187make_filesystems
188
189${sudo} mkdir -p ${mnt}/etc ${mnt}/dev
190
191echo "${bar} installing sets ${bar}"
192(cd ${mnt} &&
193	for s in ${sets}; do
194		if [ -f "${s}" ]; then
195			echo ${s}
196			${sudo} tar xpzf ${setsdir}/${s}.tgz
197		fi
198	done
199)
200
201echo "${bar} performing customisations ${bar}"
202
203make_fstab
204
205${sudo} cat > ${mnt}/etc/rc.conf << EOF
206#
207# see rc.conf(5) for more information.
208#
209# Use program=YES to enable program, NO to disable it. program_flags are
210# passed to the program on the command line.
211#
212
213# Load the defaults in from /etc/defaults/rc.conf (if it's readable).
214# These can be overridden below.
215#
216if [ -r /etc/defaults/rc.conf ]; then
217        . /etc/defaults/rc.conf
218fi
219
220# If this is not set to YES, the system will drop into single-user mode.
221#
222rc_configured=YES
223
224hostname=${h}
225
226EOF
227
228customize
229
230for d in ${specialdirs}; do
231	${sudo} mkdir -p ${mnt}/${d}
232done
233
234if [ \( -n "${custom}" \) -a \( -d "${custom}" \) ]; then
235	echo "${bar} user customisations from files in ${custom} ${bar}"
236	(cd ${custom} && ${sudo} pax -rwpe . ${mnt})
237fi
238
239exit 0
240