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 "Usage: $(basename "${0}") <-b basedir> <-t stagedir> <-i pkgsdir> <-p patchdir>"
15 echo " <-r rootdir> <-l logfile> [-h] <targets>"
16 echo ' -b basedir Basedir for automagic defaults'
17 echo ' -t stagedir Staging directory name (Default: ${base}/stage)'
18 echo ' -i pkgsdir Directory holding packages to install (Default: ${base}/pkg)'
19 echo ' -p patchdir Directory holding patches to apply (Default: ${base}/patch)'
20 echo ' -o overlaydir Directory holding an overlay tree (Default: ${base}/overlay)'
21 echo ' -r rootdir Directory holding the virgin source tree (Default: ${base}/root)'
22 echo ' -l logfile File to hold stderr spam (Default: ${stage}/gentree.log'
23 echo ' -h Hello! >^-^<'
25 echo 'Available targets:'
26 for target in ${targets}
33 while getopts "b:t:i:p:o:r:l:h" opt
36 b) base="${OPTARG}" ;;
37 t) stage="${OPTARG}" ;;
38 i) pkgs="${OPTARG}" ;;
39 p) patch="${OPTARG}" ;;
40 o) overlay="${OPTARG}" ;;
41 r) root="${OPTARG}" ;;
42 l) logfile="${OPTARG}" ;;
44 [?]) pebkac "Unrecognized option ${opt}" ;;
47 shift $(( $OPTIND - 1 ))
49 sequence="${*:-${targets}}"
51 base="${base:-/usr/home/cyberleo/world}"
52 base="$(realpath "${base}")"
53 stage="${stage:-${base}/tree}"
54 pkgs="${pkgs:-${base}/pkg}"
55 patch="${patch:-${base}/patch}"
56 overlay="${overlay:-${base}/overlay}"
57 root="${root:-${base}/root}"
58 logfile="${logfile:-${stage}/gentree.log}"
61 stage="$(realpath "${stage}")"
71 # Make sure the provided file(s) have only one link!
74 if [ -f "${1}" -a "$(stat -f '%l' "${1}")" -gt 1 ]
76 cp -p "${1}" "${1}.tmp" && mv "${1}.tmp" "${1}" || err "breaklink failed"
85 if [ -d "${stage}" -a \( -d "${sroot}" -o -d "${sboot}" -o -d "${sconf}" \) ]
87 yn n " ${a_yellow}*${a_normal} Workspace already exists. Delete? [y/N]" || err Aborting
88 chk rm -Rf "${sroot}" "${sboot}" "${sconf}"
90 chk mkdir -p "${sroot}"
91 # Eliminate schg, because it interferes with hardlinks
92 chk chflags -R noschg "${root}/lib"
93 chk chflags -R noschg "${root}/libexec"
94 chk chflags -R noschg "${root}/sbin"
95 chk chflags -R noschg "${root}/usr"
96 ( cd "${root}" && find . | cpio -p --link "${sroot}" ) || chk
100 log Create an emergency user admin/admin
101 # delink passwd to ensure it doesn't get patched in-place
102 chk onelink "${sroot}/etc/passwd" "${sroot}/etc/master.passwd"
103 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
107 log Apply overlay from "${overlay##${base}/}"
108 [ -d "${overlay}" ] || return
109 ( cd "${overlay}" && find . | cpio -p "${sroot}" ) || chk
113 if [ -d "${pkgs}" -a "$(ls -1 "${pkgs}" | wc -l)" -gt 0 ]
115 count="$(ls -1 "${pkgs}" | wc -l)"
116 log Install ${count} packages from "${pkgs##${base}/}"
117 chk mkdir -p "${sroot}/pkg"
118 ( cd "${pkgs}" && find . | cpio -p --link "${sroot}/pkg" ) || chk
119 chk chroot "${sroot}" /bin/sh -c 'cd /pkg; exec pkg_add -F *'
120 chk rm -Rf "${sroot}/pkg"
125 log Apply patches from "${patch##${base}/}"
126 for file in "${patch}"/*
128 note "... $(basename "${file}")"
129 ( cd "${sroot}" && patch < "${file}" ) || chk
131 sed -e '/^+++ /!d; s/^+++ //; s/[ ]*[0-9: .+-]*$//' "${file}" | while read target
133 rm -f "${sroot}/${target}.orig"
140 chk mv "${sroot}/boot/boot" "${sroot}/boot/boot.blk"
141 chk ln -sf . "${sroot}/boot/boot"
146 ( cd "${sroot}/tmp" && find . | cpio -p --link ../var/tmp ) || chk
147 chk rm -Rf "${sroot}/tmp"
148 chk ln -sf var/tmp "${sroot}/tmp"
153 chk mkdir -p "${sroot}/etc/local"
154 chk mkdir -p "${sroot}/usr/local/etc" # Silence warnings
155 ( cd "${sroot}/usr/local/etc" && find . | cpio -p --link ../../../etc/local ) || chk
156 chk rm -Rf "${sroot}/usr/local/etc"
157 chk ln -sf ../../etc/local "${sroot}/usr/local/etc"
161 log Create boot imgsrc
162 chk mv "${sroot}/boot" "${stage}"
163 chk mkdir -p "${sroot}/boot"
164 chk rm -f "${sboot}/kernel"/*.symbols
165 # Gzipped kernel is okay
166 chk onelink "${sboot}/kernel/kernel"
167 chk gzip -9 "${sboot}/kernel/kernel"
168 # Compress all files in /boot/kernel
169 # Loader cannot handle gzipped modules. Decompress the required modules
170 # kldload cannot handle gzipped modules either
171 #find "${sboot}/kernel" -type f | xargs gzip -9f || chk
172 #cat "${sboot}/loader.conf" | grep '_load=' | sed -e 's/^\(.*\)_load=.*$/\1/' | while read mod
174 # [ -f "${sboot}/kernel/${mod}.ko.gz" ] && gunzip "${sboot}/kernel/${mod}.ko.gz" || chk
177 # Instead: put all modules in the root image, except those needed to boot the kernel
178 chk mkdir -p "${sroot}/boot/boot"
179 chk mkdir -p "${sroot}/boot/kernel"
180 chk ln -sf "../etc/zfs" "${sroot}/boot/zfs"
182 # Link all modules into the root fs
183 ( cd "${sboot}/kernel" && find . -name '*.ko' -o -name 'linker.hints' | cpio -p --link "${sroot}/boot/kernel" ) || chk
185 # Remove all modules from the root fs that are preloaded by the loader
186 cat "${sboot}/loader.conf" | grep '_load=' | sed -e 's#^\(.*\)_load=.*$#'"${sroot}/boot/kernel/"'\1.ko#' | xargs rm -f
188 # Remove all modules from the boot fs that are present in the root fs
189 ( cd "${sroot}/boot/kernel" && ls -1 ) | sed -e 's#^#'"${sboot}/kernel/"'#' | xargs rm -f
191 # Link the preloaded modules from the boot fs to the root fs, to provide a homogenous view
192 ( cd "${sboot}/kernel" && ls -1 ) | while read mod
194 ln -sf "../boot/kernel/${mod}" "${sroot}/boot/kernel/${mod}"
200 chk mkdir -p "${sroot}/conf"
201 echo "ufs:/dev/ufs/conf" > "${sroot}/conf/diskless_remount" || chk
202 chk mkdir -p "${sconf}/backup"
203 chk mkdir -p "${sconf}/base"
204 chk mkdir -p "${sconf}/default"
206 # Create packdirs for each
207 for pack in "${base}/conf"/*.md_size
209 pack="$(basename "${pack%%.md_size}")"
210 chk mkdir -p "${sconf}/base/${pack}"
211 chk mkdir -p "${sconf}/default/${pack}"
212 ( cat "${base}/conf/${pack}.md_size" > "${sconf}/base/${pack}/md_size" ) || chk
214 chk chown -R :operator "${sconf}"
215 ( find "${sconf}" -print0 | xargs -0 chmod o-rwx ) || chk
219 # etc requires special handling to ensure everything is properly arranged.
220 log Create etc confpack
221 chk touch "${sroot}/etc/diskless"
222 # Touch /COPYRIGHT to provide an immutable time anchor for saveconfig
223 chk touch "${sroot}/COPYRIGHT"
224 chk sleep 1 # Make sure diskless is at least one second older than everything in custom
225 chk mkdir -p "${stage}/pack"
226 chk mv "${sroot}/etc" "${stage}/pack"
227 chk mkdir -p "${sroot}/etc"
228 chk cp -p "${stage}/pack/etc/rc" "${stage}/pack/etc/rc.subr" "${stage}/pack/etc/rc.initdiskless" "${stage}/pack/etc/login.conf.db" "${stage}/pack/etc/diskless" "${sroot}/etc"
230 # Make sure etc confpack exists; default if necessary
231 chk mkdir -p "${sconf}/base/etc"
232 chk mkdir -p "${sconf}/default/etc"
233 [ -e "${sconf}/base/etc/md_size" ] || echo "10240" > "${sconf}/base/etc/md_size"
235 ( cd "${stage}/pack" && find etc | cpio -o ) | gzip -9 > "${sconf}/base/etc.cpio.gz" || chk
236 chk rm -Rf "${stage}/pack/etc"
240 log Create remaining confpacks
241 chk mkdir -p "${stage}/pack"
242 for pack in "${base}/conf"/*.md_size
244 pack="$(basename "${pack%%.md_size}")"
245 # Ignore etc, as it was processed in do_imgetc
246 [ "${pack}" = "etc" ] && continue
248 chk mv "${sroot}/${pack}" "${stage}/pack"
249 chk mkdir -p "${sroot}/${pack}"
250 ( cd "${stage}/pack" && find "${pack}" | cpio -o ) | gzip -9 > "${sconf}/base/${pack}.cpio.gz" || chk
251 chk rm -Rf "${stage}/pack/${pack}"
256 log Patch in custom config
257 ( cd "${base}/conf" && find . | egrep -v '^\./.*\.md_size$' | cpio -p --link "${sconf}/default" ) || chk
258 # Make sure files in default are newer than the tagfile, so they will be caught by saveconfig
259 find "${sconf}/default" -type f -print0 | xargs -0 touch
260 # If there are scavenged cpio.gz confpacks, touch their contents as well.
261 chk mkdir -p "${stage}/pack"
262 chk rm -Rf "${stage}/pack"/*
263 for file in "${sconf}/default"/*.cpio.gz
265 pack="$(basename "${file%%.cpio.gz}")"
266 zcat "${file}" | ( cd "${stage}/pack"; cpio -id ) || chk
267 find "${stage}/pack" -type f -print0 | xargs -0 touch
268 ( cd "${stage}/pack"; find . | cpio -o ) | gzip -9 > "${file}"
269 chk rm -Rf "${stage}/pack"/*
273 for step in ${sequence}
275 echo "${targets}" | grep -q "${step}" || err Unrecognized target "${step}"