script/gentree: clean up custom config applicator to ignore missing cpios
[CDN/Mosi.git] / script / makeworld
1 #!/bin/sh
2
3 # Load shlib and modules
4 _root="$(dirname "${0}")"; . "${_root}/lib/env.sh"
5 want log
6
7 pebkac() {
8   [ "${*}" ] && printf "%s\n\n" "${*}"
9   echo "Usage: $(basename "${0}") -m <makeopts> -a <arch> -c <conf> <target, ...>"
10   echo "  -m <makeopts>   Provide additional flags to make"
11   echo "  -a <arch>       World architecture (i386, amd64)"
12   echo "  -c <conf>       World configuration (in worlds/<arch>/<conf>)"
13   echo "  -s <srctree>    Override source tree selection"
14   echo "  -h              Help!"
15   echo "  -v              Verbose (show build log in real time)"
16   echo ""
17   echo "If, for some reason, you wish to spread out builds across multiple"
18   echo "invocations, these might come in handy:"
19   echo "  -p              Prepare chroot environment"
20   echo "  -d              Don't prepare or clean up chroot during run"
21   echo "  -q              Clean up chroot environment"
22   echo ""
23   echo "Available make targets:"
24   for make_tgt in ${make_tgts}
25   do
26     echo "  ${make_tgt}"
27   done
28   exit 1
29 }
30
31 # Prepare chroot for build
32 prepare() {
33   [ "${CHROOT_DIRTY}" -a ! "${CHROOT_PREPARE}" ] && return 0
34   # Verify environment sanity
35   [ -d "${build}" ] && omg "${build}: directory exists; purging" && cleanup
36   mount | grep -q "${build}" && wtf "Stuff is mounted under ${build}; cannot continue"
37   ls -1 "${seed}"/base.?? >/dev/null 2>&1 || wtf "Populate seed directory ${seed} first"
38   [ -f "${SRCS}/sys/conf/newvers.sh" ] || wtf "Need sources in ${SRCS} to build"
39
40   # Cleanup trap here, so that an abort during prepare can clean up properly
41   trap "cleanup" exit hup int term kill
42
43   meh "Preparing build chroot"
44   [ -d "${build}" ] && wtf "${build}: directory exists"
45   mkdir -p "${build}" || wtf
46   cat "${seed}"/base.?? | tar xCf "${build}" - || wtf
47   mkdir -p "${build}/usr/obj" || wtf
48
49   meh "Mounting chroot filesystems"
50   mkdir -p "${world}/log"
51   mkdir -p "${world}/obj"
52   mkdir -p "${world}/root"
53   mount -t devfs devfs "${build}/dev" || wtf
54   # Mount /usr/src as a union, so that changes to it will not affect the underlying tree
55   # unionfs suffers from deadlocks; don't use it
56   mount -t nullfs -r "${SRCS}" "${build}/usr/src" || wtf
57   mount -t nullfs "${world}/obj" "${build}/usr/obj" || wtf
58   mount -t nullfs "${world}/root" "${build}/mnt" || wtf
59
60   if [ -d "${world}/config" ]
61   then
62     meh "Installing build-time configuration"
63     [ -f "${world}/config/${CONF}" ] && cp "${world}/config/${CONF}" "${SRCS}/sys/${ARCH}/conf/"
64     [ -f "${world}/config/make.conf" ] && cp "${world}/config/make.conf" "${build}/etc/"
65     [ -f "${world}/config/src.conf" ] && cp "${world}/config/src.conf" "${build}/etc/"
66   fi
67   return 0
68 }
69
70 # Cleanup chroot
71 cleanup() {
72   [ "${BUILD_VERBOSE}" ] || exec 1>&3
73   [ "${CHROOT_DIRTY}" -a ! "${CHROOT_CLEAN}" ] && return 0
74   meh "Cleaning up"
75   umount -f "${build}/mnt"
76   umount -f "${build}/usr/obj"
77   umount -f "${build}/usr/src"
78   umount -f "${build}/dev"
79   mount | grep -q "${build}/" && wtf "Stuff is still mounted under ${build}; not removing"
80   chflags -R noschg "${build}"
81   rm -Rf "${build}"
82   trap "" exit hup int term kill
83   return 0
84 }
85
86 # Root directory of makeworld
87 ROOT="$(realpath "$(dirname "${0}")/..")"
88
89 # Location of worlds
90 WORLDS="${ROOT}/worlds"
91
92 # Compute make -j<cpus*2>
93 make_cpus="$(sysctl -n hw.ncpu)"
94 make_jobs="$(( ${make_cpus} * 2 ))"
95 make_tgts="buildworld buildkernel distrib-dirs installworld installkernel distribution"
96
97 # Defaults
98 ARCH="$(uname -m)"
99 CONF="GENERIC"
100 MAKEOPTS="-j${make_jobs}"
101 SRCS=""
102 CHROOT_PREPARE=""
103 CHROOT_DIRTY=""
104 CHROOT_CLEAN=""
105 BUILD_VERBOSE=""
106
107 while getopts "m:a:c:hpdq" opt
108 do
109   case "${opt}" in
110     m) MAKEOPTS="${MAKEOPTS} ${OPTARG}" ;;
111     a) ARCH="${OPTARG}" ;;
112     c) CONF="${OPTARG}" ;;
113     s) SRCS="${OPTARG}" ;;
114     p) CHROOT_PREPARE="TRUE" ;;
115     d) CHROOT_DIRTY="TRUE" ;;
116     q) CHROOT_CLEAN="TRUE" ;;
117     v) BUILD_VERBOSE="TRUE" ;;
118     h) pebkac ;;
119     [?]) pebkac "Unrecognized option ${opt}" ;;
120   esac
121 done
122 shift $(( $OPTIND - 1 ))
123
124 # Should be root after this point
125 want root
126
127 # Build make target sequence
128 sequence="${*:-${make_tgts}}"
129
130 # Target world directory
131 world="${WORLDS}/${ARCH}/${CONF}"
132 # Source chroot seed directory
133 seed="${ROOT}/seed/base/$(uname -m)"
134 # Root directory for chroot
135 build="${world}/chroot"
136
137 if [ -z "${SRCS}" ]
138 then
139   # Locate a usable source tree
140   # Pick world/src over /usr/src if it exists at all, even if it is not usable, to provide warning of bad configs
141   SRCS="${world}/src"
142   [ -L "${SRCS}" -o -d "${SRCS}" ] || SRCS=/usr/src
143 fi
144 SRCS="$(realpath "${SRCS}")"
145
146 # Environment for chroot build
147 env="
148 USER=root
149 HOME=/root
150 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
151 SHELL=/bin/sh
152 "
153
154 date="$(date +%Y%m%d)"
155
156 # Check if target config exists
157 [ -d "${world}" ] || wtf "${ARCH}/${CONF} doesn't exist"
158
159 if [ "${CHROOT_PREPARE}" ]
160 then
161   prepare
162   trap "" exit
163   meh "Chroot prepared"
164   exit
165 fi
166
167 if [ "${CHROOT_CLEAN}" ]
168 then
169   cleanup
170   meh "Chroot cleaned"
171   exit
172 fi
173
174 meh "Making world for ${ARCH}/${CONF}"
175
176 prepare
177
178 meh "Seed: ${seed}"
179 meh "Srctree: ${SRCS}"
180 meh "Config: ${ARCH}/${CONF}"
181 meh "Builddir: ${build}"
182 meh "make ${MAKEOPTS}"
183 meh "DESTDIR=${world}/root"
184
185 for step in ${sequence}
186 do
187   build_log="${world}/log/${date}-${step}.log"
188   meh "==> Step: ${step} -> ${build_log}"
189   [ "${BUILD_VERBOSE}" ] || exec 3>&1 > /dev/null
190   script "${build_log}" env -i ${env} chroot "${build}" sh -c \
191     "cd /usr/src; time make ${MAKEOPTS} ${step} TARGET=${ARCH} KERNCONF=${CONF} DESTDIR=/mnt" || wtf "chroot-cmd ${step}"
192   [ "${BUILD_VERBOSE}" ] || exec 1>&3
193 done
194
195 # Copy the config files into the target, to keep a record of the build options
196 [ -f "${world}/config/${CONF}" ] && cp "${world}/config/${CONF}" "${build}/boot/kernel/"
197 [ -f "${world}/config/make.conf" ] && cp "${world}/config/make.conf" "${build}/etc/"
198 [ -f "${world}/config/src.conf" ] && cp "${world}/config/src.conf" "${build}/etc/"