/ lib / util.zsh
util.zsh
  1  #-
  2  # Copyright (c) 2023-2025 The HardenedBSD Project
  3  #
  4  # Redistribution and use in source and binary forms, with or without
  5  # modification, are permitted provided that the following conditions
  6  # are met:
  7  # 1. Redistributions of source code must retain the above copyright
  8  #    notice, this list of conditions and the following disclaimer.
  9  # 2. Redistributions in binary form must reproduce the above copyright
 10  #    notice, this list of conditions and the following disclaimer in the
 11  #    documentation and/or other materials provided with the distribution.
 12  #
 13  # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 14  # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15  # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 16  # ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 17  # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 18  # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 19  # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 20  # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 21  # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 22  # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 23  # SUCH DAMAGE.
 24  #
 25  # Author: Shawn Webb <shawn.webb@hardenedbsd.org>
 26  
 27  function check_sanity() {
 28  	if [ -z "${LOCKFILE}" ]; then
 29  		echo "[-] LOCKFILE required" >&2
 30  		return 1
 31  	fi
 32  
 33  	if [ -f "${LOCKFILE}" ]; then
 34  		echo "[-] Build locked. Remove ${LOCKFILE}." >&2
 35  		return 1
 36  	fi
 37  
 38  	if [ $(id -u) -gt 0 ]; then
 39  		echo "[-] Must be run as root" >&2
 40  		return 1
 41  	fi
 42  
 43  	if [ -z "${SRCDIR}" ]; then
 44  		echo "[-] SRCDIR required" >&2
 45  		return 1
 46  	fi
 47  
 48  	if [ ! -d ${SRCDIR} ]; then
 49  		echo "[] ${SRCDIR} not a directory" >&2
 50  		return 1
 51  	fi
 52  
 53  	if [ -z "${BRANCH}" ]; then
 54  		echo "[-] BRANCH required" >&2
 55  		return 1
 56  	fi
 57  
 58  	if [ ! -x ${GIT} ]; then
 59  		echo "[-] ${GIT} not found" >&2
 60  		return 1
 61  	fi
 62  
 63  	if [ ${SIGNED} -gt 0 ]; then
 64  		if [ -z "${SSH_KEY}" ]; then
 65  			echo "[-] Signed build request, but SSH_KEY not specified" >&2
 66  			return 1
 67  		fi
 68  
 69  	       	if [ ! -f "${SSH_KEY}" ]; then
 70  			echo "[-] SSH key \"${SSH_KEY}\" not found" >&2
 71  			return 1
 72  		fi
 73  
 74  		if [ ! -x "${SSH_KEYGEN}" ]; then
 75  			echo "[-] ${SSH_KEYGEN} not found" >&2
 76  			return 1
 77  		fi
 78  	fi
 79  
 80  	if [ ${QUARTERLY} -eq 1 ]; then
 81  		if [ -z "${QUARTERLY_BRANCH_NAME}" ]; then
 82  			echo "[-] QUARTERLY_BRANCH_NAME must be set" >&2
 83  			return 1
 84  		fi
 85  	fi
 86  
 87  	if [ ${PUBLISH_INSTALLERS} -gt 0 ]; then
 88  		if [ -z "${INSTALLER_PUBDIR}" ]; then
 89  			echo "[-] Installer publishing requested, but INSTALLER_PUBDIR not specified" >&2
 90  			return 1
 91  		fi
 92  
 93  		if [ ! -d "${INSTALLER_PUBDIR}" ]; then
 94  			echo "[-] INSTALLER_PUBDIR \"${INSTALLER_PUBDIR}\" not found" >&2
 95  			return 1
 96  		fi
 97  	fi
 98  
 99  	if [ ${PUBLISH_UPDATE} -gt 0 ]; then
100  		if [ -z "${UPDATE_PUBDIR}" ]; then
101  			echo "[-] Update publishing requested, but UPDATE_PUBDIR not specified" >&2
102  			return 1
103  		fi
104  
105  		if [ ! -d "${UPDATE_PUBDIR}" ]; then
106  			echo "[-] UPDATE_PUBDIR \"${UPDATE_PUBDIR}\" not found" >&2
107  			return 1
108  		fi
109  	fi
110  
111  	return 0
112  }
113  
114  function lock_build() {
115  	touch ${LOCKFILE}
116  	return ${?}
117  }
118  
119  function unlock_build() {
120  	rm -f ${LOCKFILE}
121  	return ${?}
122  }
123  
124  function prep_build() {
125  	if [ ! -z "${OBJDIR_TMPFS}" ]; then
126  		if [ ${BUILD_INSTALLERS} -gt 0 ] && [ ${PUBLISH_INSTALLERS} -gt 0 ]; then
127  			umount -f ${OBJDIR_TMPFS} || true
128  			mkdir -p ${OBJDIR_TMPFS}
129  			mount -t tmpfs tmpfs ${OBJDIR_TMPFS}
130  		fi
131  	fi
132  }
133  
134  function get_quarterly_branch_name() {
135  	echo "${QUARTERLY_BRANCH_NAME}-$(date +%Y)q$(( ($(date +%-m)-1)/3+1 ))"
136  }
137  
138  function cleanup() {
139  	local shouldexit
140  	local res
141  
142  	if [ ! -z "${OBJDIR_TMPFS}" ]; then
143  		if [ ${BUILD_INSTALLERS} -gt 0 ] && [ ${PUBLISH_INSTALLERS} -gt 0 ]; then
144  			umount ${OBJDIR_TMPFS}
145  			rm -rf ${OBJDIR_TMPFS}
146  		fi
147  	fi
148  
149  	if [ ! -z "${UPDATE_OUTPUTDIR}" ] && [ -d ${UPDATE_OUTPUTDIR} ]; then
150  		find ${UPDATE_OUTPUTDIR} -type f | xargs rm -f
151  	fi
152  
153  	unlock_build
154  	res=${?}
155  	if [ ${res} -gt 0 ]; then
156  		return ${res}
157  	fi
158  
159  	shouldexit="${1}"
160  	if [ ! -z "${shouldexit}" ]; then
161  		exit ${shouldexit}
162  	fi
163  
164  	return 0
165  }
166  
167  function get_objdir() {
168  	if [ ! -z "${OBJDIR_TMPFS}" ]; then
169  		echo ${OBJDIR_TMPFS}
170  		return 0
171  	fi
172  
173  	make -C ${SRCDIR} -V .OBJDIR buildworld
174  	return ${?}
175  }
176  
177  function get_pkgbase_repodir() {
178  	local res
179  
180  	dir=$(make -C ${SRCDIR} -V OBJROOT packages)
181  	res=${?}
182  	if [ ${res} -gt 0 ]; then
183  		return ${?}
184  	fi
185  
186  	echo "${dir}/repo"
187  
188  	return ${?}
189  }
190  
191  function get_latest_build_id() {
192  	local publishdir
193  	local vernum
194  
195  	publishdir="${1}"
196  	if [ -z "${publishdir}" ]; then
197  		echo "[-] ${0}: specify publish directory" >&2
198  		return 0
199  	fi
200  
201  	if [ -f ${publishdir}/index.txt ]; then
202  		vernum=$(cat ${publishdir}/index.txt)
203  		echo ${vernum}
204  		return ${vernum}
205  	fi
206  
207  	echo 1
208  	return 0
209  }
210  
211  function get_next_build_id() {
212  	local vernum
213  
214  	vernum=$(get_latest_build_id "${1}")
215  	if [ ${vernum} -eq 0 ]; then
216  		echo 0
217  		return 0
218  	fi
219  
220  	vernum=$((${vernum} + 1))
221  	echo ${vernum}
222  	return 0
223  }
224  
225  function cache_build_id() {
226  	local fulldir
227  	local pubdir
228  	local vernum
229  	local res
230  
231  	pubdir="${1}"
232  	vernum=${2}
233  	fulldir="${3}"
234  
235  	if [ -z "${pubdir}" ] || [ -z "${vernum}" ]; then
236  		return 1
237  	fi
238  
239  	echo -n ${vernum} > ${pubdir}/index.txt
240  	chmod 755 ${pubdir}/index.txt
241  
242  	if [ ! -z "${fulldir}" ]; then
243  		ln -sf ${fulldir} ${pubdir}/LATEST
244  		res=${?}
245  		if [ ${res} -gt 0 ]; then
246  			return ${res}
247  		fi
248  	fi
249  
250  	return 0
251  }
252  
253  function sign_file() {
254  	local f
255  
256  	f="${1}"
257  
258  	if [ -z "${f}" ] || [ ! -f ${f} ]; then
259  		return 1
260  	fi
261  
262  	yes | ${SSH_KEYGEN} -Y sign -f ${SSH_KEY} -n file ${f}
263  	return ${?}
264  }
265  
266  function sign_directory() {
267  	local pubdir
268  	local res
269  	local f
270  
271  	pubdir="${1}"
272  	if [ -z "${pubdir}" ]; then
273  		echo "[-] ${0}: Specify publish directory" >&2
274  		return 1
275  	fi
276  
277  	(
278  		cd ${pubir}
279  		for f in $(find ${pubdir} -maxdepth 1 -type f -a ! -name \*.sig); do
280  			sign_file ${f}
281  			res=${?}
282  			if [ ${res} -gt 0 ]; then
283  				exit ${res}
284  			fi
285  		done
286  	)
287  
288  	return 0
289  }