mkimage revision 1.5
1#! /bin/sh
2
3# $NetBSD: mkimage,v 1.5 2013/01/13 20:58:38 christos 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
105trap finish 0 1 2 3 15
106DIR="$(dirname "$0")"
107PROG="$(basename "$0")"
108bar="==="
109sudo=
110mnt="/tmp/image.$$"
111src="/usr/src"
112obj="/usr/obj"
113
114# First pass for options to get the host
115OPTS="S:c:h:s:x"
116while getopts "$OPTS" f
117do
118	case $f in
119	h)	h="$OPTARG";;
120	*)	;;
121	esac
122done
123
124if [ -z "$h" ]
125then
126	usage
127fi
128
129if [ ! -f "${DIR}/conf/${h}.conf" ]
130then
131	echo $PROG: ${DIR}/conf/${h}.conf is not present 1>&2
132	exit 1
133fi
134
135. "${DIR}/conf/${h}.conf"
136
137OPTIND=1
138while getopts "$OPTS" f
139do
140	case $f in
141	S)	setsdir="$OPTARG";;
142	c)	custom="$OPTARG";;
143	h)	;;
144	s)	size="$OPTARG";;
145	x)	set -x;;
146	*)	;;
147	esac
148done
149
150shift $(( "$OPTIND" - 1 ))
151if [ -n "$1" ]; then
152	# take the next argument as being the image name
153	image="$1"
154	shift
155fi
156
157total=0
158for s in ${sets}; do
159	one="$(sizeone ${setsdir}/${s}.tgz)"
160	total=$(( ${total} +  ${one} ))
161done
162# calculate size of custom files
163custsize=0
164if [ -d "${custom}" ]; then
165	custsize=$(ls -lR "${custom}" | awk 'NF == 9 { tot += $5 } END { print tot }')
166fi
167total=$(( ( ( ${total} + ${custsize} ) / 1000000 ) + ${overhead} ))
168if [ $size -eq 0 ]; then
169        # auto-size the pkgs fs
170        size=${total}
171else
172        # check that we've been given enough space
173        if [ ${total} -gt ${size} ]; then
174                echo "$PROG: Given size is ${size} MB, but we need ${total} MB" >&2
175                exit 1
176        fi
177fi
178
179echo "${bar} making a new ${size} MB image in ${image} ${bar}"
180dd if=/dev/zero of=${image} bs=1m count=${size} conv=sparse
181
182vnddev=$(next_avail vnd)
183echo "${bar} mounting image via vnd ${vnddev} ${bar}"
184${sudo} vnconfig ${vnddev} ${image}
185${sudo} mkdir -p ${mnt}
186make_filesystems
187
188${sudo} mkdir -p ${mnt}/etc ${mnt}/dev
189
190echo "${bar} installing sets ${bar}"
191(cd ${mnt} &&
192	for s in ${sets}; do
193		if [ -f "${s}" ]; then
194			echo ${s}
195			${sudo} tar xpzf ${setsdir}/${s}.tgz
196		fi
197	done
198)
199
200echo "${bar} performing customisations ${bar}"
201
202make_fstab
203
204${sudo} cat > ${mnt}/etc/rc.conf << EOF
205#
206# see rc.conf(5) for more information.
207#
208# Use program=YES to enable program, NO to disable it. program_flags are
209# passed to the program on the command line.
210#
211
212# Load the defaults in from /etc/defaults/rc.conf (if it's readable).
213# These can be overridden below.
214#
215if [ -r /etc/defaults/rc.conf ]; then
216        . /etc/defaults/rc.conf
217fi
218
219# If this is not set to YES, the system will drop into single-user mode.
220#
221rc_configured=YES
222
223hostname=${h}
224
225EOF
226
227customize
228
229for d in ${specialdirs}; do
230	${sudo} mkdir -p ${mnt}/${d}
231done
232
233if [ \( -n "${custom}" \) -a \( -d "${custom}" \) ]; then
234	echo "${bar} user customisations from files in ${custom} ${bar}"
235	(cd ${custom} && ${sudo} pax -rwpe . ${mnt})
236fi
237
238exit 0
239