route: ensure RTM_IFINFO is sent first when bring interface down/up
[dragonfly.git] / initrd / mkinitrd.sh
CommitLineData
e79a303f
AL
1#!/bin/sh
2#
3# Copyright (c) 2010, 2018
4# The DragonFly Project. All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9#
10# 1. Redistributions of source code must retain the above copyright
11# notice, this list of conditions and the following disclaimer.
12# 2. Redistributions in binary form must reproduce the above copyright
13# notice, this list of conditions and the following disclaimer in
14# the documentation and/or other materials provided with the
15# distribution.
16# 3. Neither the name of The DragonFly Project nor the names of its
17# contributors may be used to endorse or promote products derived
18# from this software without specific, prior written permission.
19#
20# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25# INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
26# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31# SUCH DAMAGE.
32#
33
34#
35# Description
36#
37# This tool packs the (statically linked) rescue tools (at /rescue by
38# default) and contents specified by "-c <content_dirs>", such as the
39# necessary etc files, into an UFS-formatted VN image. This image is
40# installed at /boot/kernel/initrd.img.gz and used as the initial ramdisk
41# to help mount the real root filesystem when it is encrypted or on LVM.
42#
43
44
45#
46# Default configurations
47#
48
cf7cecf5 49# Directory hierarchy on the initrd
e79a303f
AL
50#
51# * 'new_root' will always be created
52# * 'sbin' will be symlinked to 'bin'
53# * 'tmp' will be symlinked to 'var/tmp'
54#
55INITRD_DIRS="bin dev etc mnt var"
56
57# Directory of the statically linked rescue tools which will be copied
58# onto the initrd.
59RESCUE_DIR="/rescue"
60
61# Specify the location that the initrd will be installed to, i.e.,
62# <BOOT_DIR>/kernel/initrd.img.gz
63BOOT_DIR="/boot"
64
65# Maximum size (number of MB) allowed for the initrd image
66INITRD_SIZE_MAX="15" # MB
67
bc897c50 68# When run from the buildworld/installworld environment do not require that
9b724c0d
MD
69# things like uniq, kldload, mount, newfs, etc be in the cross-tools.
70# These must run natively for the current system version.
71#
72PATH=${PATH}:/sbin:/usr/sbin:/bin:/usr/bin
e79a303f
AL
73
74#
75# Helper functions
76#
77
78log() {
79 echo "$@" >&2
80}
81
82error() {
83 local rc=$1
84 shift
85 log "$@"
86 exit ${rc}
87}
88
89check_dirs() {
90 for _dir; do
91 [ -d "${_dir}" ] ||
92 error 1 "Directory '${_dir}' does not exist"
93 done
94 return 0
95}
96
97# Calculate the total size of the given directory, taking care of the
98# hard links.
99#
100# NOTE: Do not use 'du' since it gives the disk usage of the files,
101# which varies between different filesystems.
102#
103calc_size() {
104 find "$1" -ls | \
105 awk '{ print $7,$1 }' | \
106 sort -n -k 2 | \
107 uniq -f 1 | \
108 awk '{ sum+=$1 } END { print sum }' # byte
109}
110
111
112#
113# Functions
114#
115
116calc_initrd_size() {
117 log "Calculating required initrd size ..."
118 isize=0
119 for _dir; do
120 csize=$(calc_size ${_dir})
121 log "* ${_dir}: ${csize} bytes"
122 isize=$((${isize} + ${csize}))
123 done
124 # Round initrd size up by MB
125 isize_mb=$(echo ${isize} | awk '
126 function ceil(x) {
127 y = int(x);
128 return (x>y ? y+1 : y);
129 }
130 {
131 mb = $1/1024/1024;
132 print ceil(mb);
133 }')
bc897c50
AL
134 # Reserve another 1 MB for advanced user to add custom files to the
135 # initrd without creating it from scratch.
e79a303f
AL
136 echo $((${isize_mb} + 1))
137}
138
139create_vn() {
bc897c50
AL
140 kldstat -qm vn || kldload -n vn ||
141 error 1 "Failed to load vn kernel module"
142
e79a303f
AL
143 VN_DEV=$(vnconfig -c -S ${INITRD_SIZE}m -Z -T vn ${INITRD_FILE}) &&
144 echo "Configured ${VN_DEV}" ||
145 error 1 "Failed to configure VN device"
146
147 newfs -i 131072 -m 0 /dev/${VN_DEV}s0 &&
148 echo "Formatted initrd image with UFS" ||
149 error 1 "Failed to format the initrd image"
150 mount_ufs /dev/${VN_DEV}s0 ${BUILD_DIR} &&
151 echo "Mounted initrd image on ${BUILD_DIR}" ||
152 error 1 "Failed to mount initrd image on ${BUILD_DIR}"
153}
154
155destroy_vn() {
156 umount /dev/${VN_DEV}s0 &&
157 echo "Unmounted initrd image" ||
158 error 1 "Failed to umount initrd image"
159 vnconfig -u ${VN_DEV} &&
160 echo "Unconfigured ${VN_DEV}" ||
161 error 1 "Failed to unconfigure ${VN_DEV}"
162}
163
164make_hier() {
f170ef59
AL
165 mkdir -p ${BUILD_DIR}/new_root ||
166 error 1 "Failed to mkdir ${BUILD_DIR}/new_root"
e79a303f
AL
167 # Symlink 'sbin' to 'bin'
168 ln -sf bin ${BUILD_DIR}/sbin
169 # Symlink 'tmp' to 'var/tmp', as '/var' will be mounted with
170 # tmpfs, saving a second tmpfs been mounted on '/tmp'.
171 ln -sf var/tmp ${BUILD_DIR}/tmp
172 for _dir in ${INITRD_DIRS}; do
173 [ ! -d "${BUILD_DIR}/${_dir}" ] &&
174 mkdir -p ${BUILD_DIR}/${_dir}
175 done
176 echo "Created directory structure"
177}
178
179copy_rescue() {
180 cpdup -o -u ${RESCUE_DIR}/ ${BUILD_DIR}/bin/ &&
181 echo "Copied ${RESCUE_DIR} to ${BUILD_DIR}/bin" ||
182 error 1 "Failed to copy ${RESCUE_DIR} to ${BUILD_DIR}/bin"
183}
184
185copy_content() {
186 for _dir in ${CONTENT_DIRS}; do
187 cpdup -o -u ${_dir}/ ${BUILD_DIR}/ &&
188 echo "Copied ${_dir} to ${BUILD_DIR}" ||
189 error 1 "Failed to copy ${dir} to ${BUILD_DIR}"
190 done
191}
192
193print_info() {
194 lt ${BUILD_DIR}
195 df -h ${BUILD_DIR}
196}
197
198# Check the validity of the created initrd image before moving over.
199# This prevents creating an empty and broken initrd image by running
200# this tool but without ${CONTENT_DIRS} prepared.
201#
202# NOTE: Need more improvements.
203#
204check_initrd()
205{
f170ef59
AL
206 [ -x "${BUILD_DIR}/sbin/oinit" ] &&
207 [ -x "${BUILD_DIR}/bin/sh" ] &&
208 [ -x "${BUILD_DIR}/etc/rc" ] || {
e79a303f 209 destroy_vn
f170ef59 210 error 1 "Ivalid initrd image!"
e79a303f
AL
211 }
212}
213
214usage() {
215 error 2 \
216 "usage: ${0##*/} [-b boot_dir] [-r rescue_dir]" \
217 "[-s size] [-S max_size] -c <content_dirs>"
218}
219
220
221#
222# Main
223#
224
225while getopts :b:c:hr:s:S: opt; do
226 case ${opt} in
227 b)
228 BOOT_DIR="${OPTARG}"
229 ;;
230 c)
231 CONTENT_DIRS="${OPTARG}"
232 ;;
233 h)
234 usage
235 ;;
236 r)
237 RESCUE_DIR="${OPTARG}"
238 ;;
239 s)
240 INITRD_SIZE="${OPTARG}"
241 ;;
242 S)
243 INITRD_SIZE_MAX="${OPTARG}"
244 ;;
245 \?)
246 log "Invalid option -${OPTARG}"
247 usage
248 ;;
249 :)
250 log "Option -${OPTARG} requires an argument"
251 usage
252 ;;
253 esac
254done
255
256shift $((OPTIND - 1))
257[ $# -ne 0 ] && usage
258[ -z "${BOOT_DIR}" -o -z "${RESCUE_DIR}" -o -z "${CONTENT_DIRS}" ] && usage
259check_dirs ${BOOT_DIR} ${RESCUE_DIR} ${CONTENT_DIRS}
260
261VN_DEV=""
262INITRD_SIZE=${INITRD_SIZE%[mM]} # MB
263INITRD_SIZE_MAX=${INITRD_SIZE_MAX%[mM]} # MB
264
265BUILD_DIR=$(mktemp -d -t initrd) || error $? "Cannot create build directory"
266echo "Initrd build directory: ${BUILD_DIR}"
267INITRD_FILE="${BUILD_DIR}.img"
268INITRD_DEST="${BOOT_DIR}/kernel/initrd.img.gz"
269
270CSIZE=$(calc_initrd_size ${RESCUE_DIR} ${CONTENT_DIRS})
271echo "Required initrd image size: ${CSIZE} MB"
272if [ -n "${INITRD_SIZE}" -a "${INITRD_SIZE}" != "0" ]; then
273 if [ ${CSIZE} -gt ${INITRD_SIZE} ]; then
274 error 1 "Given initrd size (${INITRD_SIZE} MB) too small"
275 fi
276else
277 INITRD_SIZE=${CSIZE}
278fi
279echo "Initrd size: ${INITRD_SIZE} MB"
280
281if [ -n "${INITRD_SIZE_MAX}" -a "${INITRD_SIZE_MAX}" != "0" ] && \
282 [ ${INITRD_SIZE} -gt ${INITRD_SIZE_MAX} ]; then
283 error 1 "Exceeded the maximum size (${INITRD_SIZE_MAX} MB)"
284fi
285
286create_vn
287make_hier
288copy_rescue
289copy_content
290print_info
291destroy_vn
292rm -rf ${BUILD_DIR}
293
294echo -n "Compressing ${INITRD_FILE} ..."
295gzip -9 ${INITRD_FILE}
296echo " OK"
297
298if [ -f "${INITRD_DEST}" ]; then
299 echo -n "Backing up ${INITRD_DEST} ..."
300 mv ${INITRD_DEST} ${INITRD_DEST}.old
301 echo " OK (${INITRD_DEST}.old)"
302fi
303
bc897c50 304echo -n "Installing ${INITRD_FILE}.gz to ${INITRD_DEST} ..."
f170ef59 305install -o root -g wheel -m 444 ${INITRD_FILE}.gz ${INITRD_DEST}
e79a303f 306echo " OK"
57179abe 307rm -f ${INITRD_FILE}.gz