4 _root="$(dirname "${0}")"
5 . "${_root}/lib/env.sh"
10 targets="prepwork admin overlay packages patch prepboot preptmp prepetc imgboot imgconf imgetc imgall custom"
13 [ "${*}" ] && printf "${*}\n\n"
14 echo "********************************************************************************"
15 echo "Usage: $(basename "${0}") <-a arch> <-c conf> <-b basedir> <-t stagedir>"
16 echo ' <-i pkgsdir> <-p patchdir> <-r rootdir> <-l logfile> [-h] <targets>'
17 echo " -a arch Arch for image target (default: current arch: $(uname -m))"
18 echo ' -c conf Conf name for image target (default: GENERIC)'
19 echo ' -b basedir Basedir for automagic defaults'
20 echo ' -t stagedir Staging directory name (${target}/tree)'
21 echo ' -r rootdir Directory holding the virgin source tree (${target}/world/root)'
22 echo ' -o overlaydir Directory holding an overlay tree (${target}/config/overlay)'
23 echo ' -i pkgsdir Directory holding packages to install (${target}/pkg)'
24 echo ' -p patchdir Directory holding patches to apply (${target}/config/patch)'
25 echo ' -d confdir Conf md_size files and old cpios (${target}/config/conf)'
26 echo ' -l logfile File to hold stderr spam (${stage}/gentree.log'
27 echo ' -h Hello! >^-^<'
29 echo 'Available targets:'
30 for target in ${targets}
37 while getopts "a:c:b:t:r:o:i:p:w:l:h" opt
40 a) arch="${OPTARG}" ;;
41 c) conf="${OPTARG}" ;;
42 b) base="${OPTARG}" ;;
43 t) tree="${OPTARG}" ;;
44 r) root="${OPTARG}" ;;
45 o) ovly="${OPTARG}" ;;
46 i) pkgs="${OPTARG}" ;;
47 p) ptch="${OPTARG}" ;;
48 d) cnfd="${OPTARG}" ;;
49 l) logf="${OPTARG}" ;;
51 [?]) pebkac "Unrecognized option ${opt}" ;;
54 shift $(( $OPTIND - 1 ))
56 sequence="${*:-${targets}}"
58 base="${base:-$(dirname "${0}")/..}" #"
59 base="$(realpath "${base}")"
61 arch="${arch:-$(uname -m)}"
62 conf="${conf:-GENERIC}"
64 target="${base}/targets/${arch}/${conf}"
66 tree="${tree:-${target}/tree}"
67 root="${root:-${target}/world/root}"
68 ovly="${ovly:-${target}/config/overlay}"
69 pkgs="${pkgs:-${target}/pkg}"
70 ptch="${ptch:-${target}/config/patch}"
71 cnfd="${cnfd:-${target}/config/conf}"
72 logf="${logf:-${tree}/gentree.log}"
74 stage="${stage:-${base}/tree}"
75 pkgs="${pkgs:-${base}/pkg}"
76 patch="${patch:-${base}/patch}"
77 overlay="${overlay:-${base}/overlay}"
78 root="${root:-${base}/root}"
79 logfile="${logfile:-${stage}/gentree.log}"
82 tree="$(realpath "${tree}")"
92 # Make sure the provided file(s) have only one link!
95 if [ -f "${1}" -a "$(stat -f '%l' "${1}")" -gt 1 ]
97 cp -p "${1}" "${1}.tmp" && mv "${1}.tmp" "${1}" || err "breaklink failed"
105 log Prepare workspace
106 if [ -d "${tree}" -a \( -d "${sroot}" -o -d "${sboot}" -o -d "${sconf}" \) ]
108 yn n " ${a_yellow}*${a_normal} Workspace already exists. Delete? [y/N]" || err Aborting
109 chk rm -Rf "${sroot}" "${sboot}" "${sconf}"
111 chk mkdir -p "${sroot}"
112 # Eliminate schg, because it interferes with hardlinks
113 chk chflags -R noschg "${root}/lib"
114 chk chflags -R noschg "${root}/libexec"
115 chk chflags -R noschg "${root}/sbin"
116 chk chflags -R noschg "${root}/usr"
117 ( cd "${root}" && find . | cpio -p --link "${sroot}" ) || chk
121 log Create an emergency user admin/admin
122 # delink passwd to ensure it doesn't get patched in-place
123 chk onelink "${sroot}/etc/passwd" "${sroot}/etc/master.passwd"
124 echo '$1$2rXOWsK/$eiBHA6K7xL96DZbcY24YR0' | chk chroot "${sroot}" /usr/sbin/pw useradd admin -u 999 -g wheel -G operator -c Administrator -d /usr/home/admin -m -s /bin/csh -H 0
128 [ -d "${ovly}" ] || return
129 log Apply overlay from "${ovly##${base}/}"
130 ( cd "${ovly}" && find . | cpio -p "${sroot}" ) || chk
134 [ -d "${pkgs}" ] || return
135 count="$(ls -1 "${pkgs}" | wc -l)"
136 [ "${count}" -gt 0 ] || return
137 log Install ${count} packages from "${pkgs##${base}/}"
138 chk mkdir -p "${sroot}/pkg"
139 ( cd "${pkgs}" && find . | cpio -p --link "${sroot}/pkg" ) || chk
140 chk chroot "${sroot}" /bin/sh -c 'cd /pkg; exec pkg_add -F *'
141 chk rm -Rf "${sroot}/pkg"
145 [ -d "${ptch}" ] || return
146 log Apply patches from "${ptch##${base}/}"
147 for file in "${ptch}"/*
149 note "... $(basename "${file}")"
150 ( cd "${sroot}" && patch < "${file}" ) || chk
152 sed -e '/^+++ /!d; s/^+++ //; s/[ ]*[0-9: .+-]*$//' "${file}" | while read orig
154 rm -f "${sroot}/${orig}.orig"
161 chk mv "${sroot}/boot/boot" "${sroot}/boot/boot.blk"
162 chk ln -sf . "${sroot}/boot/boot"
167 ( cd "${sroot}/tmp" && find . | cpio -p --link ../var/tmp ) || chk
168 chk rm -Rf "${sroot}/tmp"
169 chk ln -sf var/tmp "${sroot}/tmp"
174 chk mkdir -p "${sroot}/etc/local"
175 chk mkdir -p "${sroot}/usr/local/etc" # Silence warnings
176 ( cd "${sroot}/usr/local/etc" && find . | cpio -p --link ../../../etc/local ) || chk
177 chk rm -Rf "${sroot}/usr/local/etc"
178 chk ln -sf ../../etc/local "${sroot}/usr/local/etc"
182 log Create boot imgsrc
183 chk mv "${sroot}/boot" "${tree}"
184 chk mkdir -p "${sroot}/boot"
185 chk rm -f "${sboot}/kernel"/*.symbols
186 # Gzipped kernel is okay
187 chk onelink "${sboot}/kernel/kernel"
188 chk gzip -9 "${sboot}/kernel/kernel"
189 # Compress all files in /boot/kernel
190 # Loader cannot handle gzipped modules. Decompress the required modules
191 # kldload cannot handle gzipped modules either
192 #find "${sboot}/kernel" -type f | xargs gzip -9f || chk
193 #cat "${sboot}/loader.conf" | grep '_load=' | sed -e 's/^\(.*\)_load=.*$/\1/' | while read mod
195 # [ -f "${sboot}/kernel/${mod}.ko.gz" ] && gunzip "${sboot}/kernel/${mod}.ko.gz" || chk
198 # Instead: put all modules in the root image, except those needed to boot the kernel
199 chk mkdir -p "${sroot}/boot/boot"
200 chk mkdir -p "${sroot}/boot/kernel"
201 chk ln -sf "../etc/zfs" "${sroot}/boot/zfs"
203 # Link all modules into the root fs
204 ( cd "${sboot}/kernel" && find . -name '*.ko' -o -name 'linker.hints' | cpio -p --link "${sroot}/boot/kernel" ) || chk
206 # Remove all modules from the root fs that are preloaded by the loader
207 cat "${sboot}/loader.conf" | grep '_load=' | sed -e 's#^\(.*\)_load=.*$#'"${sroot}/boot/kernel/"'\1.ko#' | xargs rm -f
209 # Remove all modules from the boot fs that are present in the root fs
210 ( cd "${sroot}/boot/kernel" && ls -1 ) | sed -e 's#^#'"${sboot}/kernel/"'#' | xargs rm -f
212 # Link the preloaded modules from the boot fs to the root fs, to provide a homogenous view
213 ( cd "${sboot}/kernel" && ls -1 ) | while read mod
215 ln -sf "../boot/kernel/${mod}" "${sroot}/boot/kernel/${mod}"
221 chk mkdir -p "${sroot}/conf"
222 echo "ufs:/dev/ufs/conf" > "${sroot}/conf/diskless_remount" || chk
223 chk mkdir -p "${sconf}/backup"
224 chk mkdir -p "${sconf}/base"
225 chk mkdir -p "${sconf}/default"
227 # Create packdirs for each
228 for pack in "${cnfd}"/*.md_size
230 pack="$(basename "${pack%%.md_size}")"
231 chk mkdir -p "${sconf}/base/${pack}"
232 chk mkdir -p "${sconf}/default/${pack}"
233 ( cat "${cnfd}/${pack}.md_size" > "${sconf}/base/${pack}/md_size" ) || chk
235 chk chown -R :operator "${sconf}"
236 ( find "${sconf}" -print0 | xargs -0 chmod o-rwx ) || chk
240 # etc requires special handling to ensure everything is properly arranged.
241 log Create etc confpack
242 chk touch "${sroot}/etc/diskless"
243 # Touch /COPYRIGHT to provide an immutable time anchor for saveconfig
244 chk touch "${sroot}/COPYRIGHT"
245 chk sleep 1 # Make sure anchor is at least one second older than everything in custom
246 chk mkdir -p "${tree}/pack"
247 chk mv "${sroot}/etc" "${tree}/pack"
248 chk mkdir -p "${sroot}/etc"
249 chk cp -p "${tree}/pack/etc/rc" "${tree}/pack/etc/rc.subr" "${tree}/pack/etc/rc.initdiskless" "${tree}/pack/etc/login.conf.db" "${tree}/pack/etc/diskless" "${sroot}/etc"
251 # Make sure etc confpack exists; default if necessary
252 chk mkdir -p "${sconf}/base/etc"
253 chk mkdir -p "${sconf}/default/etc"
254 [ -e "${sconf}/base/etc/md_size" ] || echo "10240" > "${sconf}/base/etc/md_size"
256 ( cd "${tree}/pack" && find etc | cpio -o ) | gzip -9 > "${sconf}/base/etc.cpio.gz" || chk
257 chk rm -Rf "${tree}/pack/etc"
261 log Create remaining confpacks
262 chk mkdir -p "${tree}/pack"
263 for pack in "${cnfd}"/*.md_size
265 pack="$(basename "${pack%%.md_size}")"
266 # Ignore etc, as it was processed in do_imgetc
267 [ "${pack}" = "etc" ] && continue
269 chk mv "${sroot}/${pack}" "${tree}/pack"
270 chk mkdir -p "${sroot}/${pack}"
271 ( cd "${tree}/pack" && find "${pack}" | cpio -o ) | gzip -9 > "${sconf}/base/${pack}.cpio.gz" || chk
272 chk rm -Rf "${tree}/pack/${pack}"
277 log Patch in custom config
278 ( cd "${cnfd}" && find . -name '*.md_size' -o -print | cpio -p --link "${sconf}/default" ) || chk
279 # Make sure files in default are newer than the tagfile, so they will be caught by saveconfig
280 find "${sconf}/default" -type f -print0 | xargs -0 touch
281 # If there are scavenged cpio.gz confpacks, touch their contents as well.
282 chk mkdir -p "${tree}/pack"
283 if ls -1 "${sconf}/default" | grep -q '.cpio.gz'
285 chk rm -Rf "${tree}/pack"/*
286 for file in "${sconf}/default"/*.cpio.gz
288 pack="$(basename "${file%%.cpio.gz}")"
289 zcat "${file}" | ( cd "${tree}/pack"; cpio -id ) || chk
290 find "${tree}/pack" -type f -print0 | xargs -0 touch
291 ( cd "${tree}/pack"; find . | cpio -o ) | gzip -9 > "${file}"
292 chk rm -Rf "${tree}/pack"/*
297 for step in ${sequence}
299 echo "${targets}" | grep -q "${step}" || err Unrecognized target "${step}"