%PDF- %PDF-
Direktori : /backups/router/usr/local/sbin/ |
Current File : //backups/router/usr/local/sbin/opnsense-update |
#!/bin/sh # Copyright (c) 2015-2025 Franco Fichtner <franco@opnsense.org> # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. set -e if [ "$(id -u)" != "0" ]; then echo "Must be root." >&2 exit 1 fi CONFIGFILE="/usr/local/etc/opnsense-update.conf" SIG_KEY="^[[:space:]]*signature_type:[[:space:]]*" URL_KEY="^[[:space:]]*url:[[:space:]]*" VERSIONDIR="/usr/local/opnsense/version" WORKPREFIX="/var/cache/opnsense-update" REPOSDIR="/usr/local/etc/pkg/repos" DEBUGDIR="/usr/lib/debug" KERNELDIR="/boot/kernel" TEE="/usr/bin/tee -a" PRODUCT="OPNsense" PKG="pkg-static" RELEASE="25.1.1" PENDINGDIR="${WORKPREFIX}/.sets.pending" PIPEFILE="${WORKPREFIX}/.upgrade.pipe" LOGFILE="${WORKPREFIX}/.upgrade.log" ORIGIN="${REPOSDIR}/${PRODUCT}.conf" WORKDIR="${WORKPREFIX}/${$}" IDENT=$(sysctl -n kern.ident) ARCH=$(uname -p) PENDING_BASE="${WORKPREFIX}/.base.pending" PENDING_KERNEL="${WORKPREFIX}/.kernel.pending" PENDING_PKGS="${WORKPREFIX}/.pkgs.pending" INSECURE_PKGS="${WORKPREFIX}/.pkgs.insecure" INSTALLED_BASE= if [ -f ${VERSIONDIR}/base ]; then INSTALLED_BASE=$(cat ${VERSIONDIR}/base) fi LOCKED_BASE= if [ -f ${VERSIONDIR}/base.lock ]; then LOCKED_BASE=1 fi INSTALLED_PKGS= if [ -f ${VERSIONDIR}/pkgs ]; then INSTALLED_PKGS=$(cat ${VERSIONDIR}/pkgs) fi LOCKED_PKGS= if [ -f ${VERSIONDIR}/pkgs.lock ]; then LOCKED_PKGS=1 fi INSTALLED_KERNEL= if [ -f ${VERSIONDIR}/kernel ]; then INSTALLED_KERNEL=$(cat ${VERSIONDIR}/kernel) fi LOCKED_KERNEL= if [ -f ${VERSIONDIR}/kernel.lock ]; then LOCKED_KERNEL=1 fi read_config() { # try to not evaluate syntax errors local LINE=$(grep ^"${1}"='"[^"]*"$' ${CONFIGFILE} 2> /dev/null || true) if [ -n "${LINE}" ]; then eval export CFG_${LINE} else eval export CFG_"${1}"= fi } kernel_version() { # It's faster to ask uname as long as the base # system is consistent that should work instead # of doing the magic of `freebsd-version -k'. uname -r } base_version() { # The utility has the version embedded, so # we execute it to check which one it is. FREEBSD_VERSION="${1}/bin/freebsd-version" if [ -f "${FREEBSD_VERSION}" ]; then ${FREEBSD_VERSION} fi } mirror_abi() { local DIR="\2" local OPT=${1} if [ -n "${DO_SNAPSHOT}" ]; then DIR="snapshots" fi ABI=$(opnsense-verify -a) if [ "${OPT}" = "pin" ]; then # main archtecture to guarantee aux set fetch success ABI="${ABI%:*}:amd64" fi if [ -n "${DO_ABI}" ]; then ABIPARTS=${DO_ABI#"-a "} ABI=${ABIPARTS%%/*} SUB=${ABIPARTS#*/} if [ -z "${SUB%%*/*}" ]; then echo "Mirror has too many subdirectories." >&2 exit 1 fi if [ "${ABI}" != "${SUB}" ]; then DIR=${SUB} fi fi # The first part after ABI is our suffix and # we need all of it to find the correct sets. MIRROR=$(sed -n 's/'"${URL_KEY}"'\"\(.*\/${ABI}\/\)\([^\/]*\)\/.*/\1'"${DIR}"'/p' ${ORIGIN}) if [ -z "${MIRROR}" ]; then echo "Mirror read failed." >&2 exit 1 fi if [ "${OPT}" != "raw" ]; then eval MIRROR="${MIRROR}" fi echo "${MIRROR}" } mirror_sub() { # make sure it actually looks like a key before returning URL=$(mirror_abi raw | sed -n 's/.*\/\([^\/]*\)\/${ABI}\/.*/\1/p' | egrep -i '[a-z0-9]{8}(-[a-z0-9]{4}){3}-[a-z0-9]{12}' || true) if [ -n "${URL}" ]; then echo ${URL} fi } empty_cache() { if [ -d ${WORKPREFIX} ]; then # completely empty cache as per request find ${WORKPREFIX} -d 1 -print0 | xargs -0 rm -r fi } flush_temporary() { # remove our stale pyc files not handled by pkg find /usr/local/opnsense -type f -name "*.pyc" -delete for DIR in /boot /usr/libexec/bsdinstall /usr/local; do # remove spurious files from pkg find ${DIR} ! \( -type d \) -a \ \( -name "*.pkgsave" -o -name ".pkgtemp.*" \) -delete # processs spurious directories from pkg # (may not be empty so -delete does not work) find ${DIR} -type d -name ".pkgtemp.*" -print0 | \ xargs -0 -n1 rm -r done } backup_origin() { # keep a backup of the currently used repos and core package name mkdir -p ${WORKDIR} for CONF in $(find ${WORKDIR} -name '*.conf'); do rm -rf ${CONF} done for CONF in $(find ${REPOSDIR} -name '*.conf'); do cp ${CONF} ${WORKDIR} done } recover_origin() { echo "!!!!!!!!! ATTENTION !!!!!!!!!" echo "! Lost upstream repository. !" echo "! Attempting to recover it. !" echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" sleep 3 # for dramatic effect mkdir -p ${REPOSDIR} for CONF in $(find ${REPOSDIR} -name '*.conf'); do rm -rf ${CONF} done for CONF in $(find ${WORKDIR} -name '*.conf'); do cp ${CONF} ${REPOSDIR} done # recover lost package(s) ${PKG} install -yr ${PRODUCT} ${1} } clean_base() { echo -n "Cleaning obsolete files..." if [ ! -f ${VERSIONDIR}/base.obsolete ]; then exit_msg " failed, no base.obsolete found" fi while read FILE; do rm -f ${FILE} done < ${VERSIONDIR}/base.obsolete echo " done" } DO_ABI= DO_BASE= DO_CHECK= DO_CLEAN= DO_DEFAULTS= DO_DEVICE= DO_EMPTY= DO_FLUSH= DO_FORCE= DO_INSECURE= DO_KERNEL= DO_LOCAL= DO_LOCK= DO_LOGFILE= DO_MIRROR= DO_MIRRORABI= DO_MIRRORDIR= DO_MIRRORURL= DO_ORIGIN= DO_PKGS= DO_RELEASE= DO_SIZE= DO_SKIP= DO_SNAPSHOT= DO_TEST= DO_TESTS= DO_TYPE= DO_UNLOCK= DO_UPGRADE= DO_VERBOSE= DO_VERSION= if [ "${IDENT}" != "${IDENT#*-}" ]; then DO_DEVICE="-D ${IDENT#*-}" fi while getopts A:a:BbCcD:deFfGiKkLl:Mm:n:OPpQRr:SsTt:UuVvxXz OPT; do case ${OPT} in A) DO_MIRRORABI="-A ${OPTARG}" ;; a) DO_ABI="-a ${OPTARG}" ;; B) DO_FORCE="-f" DO_BASE="-B" DO_KERNEL= DO_PKGS= ;; b) DO_BASE="-b" ;; C) DO_CLEAN="-C" ;; c) DO_CHECK="-c" ;; D) DO_DEVICE="-D ${OPTARG}" ;; d) DO_DEFAULTS="-d" ;; e) DO_EMPTY="-e" ;; F) DO_FLUSH="-F" ;; f) DO_FORCE="-f" ;; G) DO_LOGFILE="-G" ;; i) DO_INSECURE="-i" ;; K) DO_FORCE="-f" DO_BASE= DO_KERNEL="-K" DO_PKGS= ;; k) DO_KERNEL="-k" ;; L) DO_LOCK="-L" ;; l) DO_LOCAL="-l ${OPTARG}" ;; M) DO_MIRROR="-M" ;; m) DO_MIRRORURL="-m ${OPTARG}" ;; n) DO_MIRRORDIR="-n ${OPTARG}" ;; O) DO_ORIGIN="-O" ;; P) DO_FORCE="-f" DO_PKGS="-P" DO_KERNEL= DO_BASE= ;; p) DO_PKGS="-p" ;; Q) DO_TESTS="-Q" ;; R) DO_RELEASE="-R" ;; r) DO_RELEASE="-r ${OPTARG}" ;; s) DO_SKIP="-s" ;; S) DO_SIZE="-S" ;; T) DO_TEST="-T" ;; t) DO_TYPE="-t ${OPTARG}" ;; U) DO_UNLOCK="-U" ;; u) DO_UPGRADE="-u" # assume -R but yield to explicit -R/-r if [ -z "${DO_RELEASE}" ]; then DO_RELEASE="-R" fi ;; V) DO_VERBOSE="-V" ;; v) DO_VERSION="-v" ;; X) DO_MIRROR="-X" ;; x) DO_MIRROR="-x" ;; z) DO_SNAPSHOT="-z" ;; *) echo "Usage: man ${0##*/}" >&2 exit 1 ;; esac done shift $((OPTIND - 1)) if [ -n "${*}" ]; then echo "Usage: man ${0##*/}" >&2 exit 1 fi if [ -n "${DO_VERBOSE}" ]; then set -x fi if [ "${DO_EMPTY}" ]; then empty_cache fi if [ "${DO_FLUSH}" ]; then flush_temporary fi if [ "${DO_RELEASE}" = "-R" ]; then read_config UPGRADE_RELEASE if [ -n "${CFG_UPGRADE_RELEASE}" ]; then RELEASE=${CFG_UPGRADE_RELEASE} read_config UPGRADE_HINT if [ -n "${CFG_UPGRADE_HINT}" ]; then DO_ABI="-a ${CFG_UPGRADE_HINT}" fi else RELEASE=unknown fi elif [ -n "${DO_RELEASE}" ]; then RELEASE=${DO_RELEASE#"-r "} fi if [ -n "${DO_VERSION}" ]; then if [ -n "${DO_BASE}" ]; then echo ${INSTALLED_BASE} elif [ -n "${DO_KERNEL}" ]; then echo ${INSTALLED_KERNEL} elif [ -n "${DO_PKGS}" ]; then echo ${INSTALLED_PKGS} elif [ "${DO_RELEASE}" != "-R" -o -n "${CFG_UPGRADE_RELEASE}" ]; then echo ${RELEASE} fi exit 0 fi if [ -n "${DO_DEFAULTS}" ]; then # restore default before potential replace cp ${ORIGIN}.sample ${ORIGIN} fi if [ ! -f ${ORIGIN} ]; then echo "Missing ${ORIGIN}" >&2 exit 1 fi if [ -n "${DO_MIRRORURL}" ]; then # replace the package repo location sed -i '' '/'"${URL_KEY}"'/s|".*${ABI}|"'"${DO_MIRRORURL#"-m "}"'/${ABI}|' ${ORIGIN} fi if [ -n "${DO_MIRRORABI}" ]; then # replace the package repo ABI MIRRORABI=${DO_MIRRORABI#"-A "} if [ -z "${MIRRORABI%%*/*}" ]; then echo "Mirror ABI cannot be a subdirectory" >&2 exit 1 fi sed -i '' '/'"${URL_KEY}"'/s|\(${ABI}/\)\([^/]*\)\(/.*\)|\1'"${MIRRORABI}"'\3|' ${ORIGIN} fi if [ -n "${DO_MIRRORDIR}" ]; then # replace the package repo name MIRRORDIR=${DO_MIRRORDIR#"-n "} if [ -n "${MIRRORDIR%%*/*}" ]; then # only replace subdirectory sed -i '' '/'"${URL_KEY}"'/s|\(${ABI}/[^/]*/\)\(.*\)|\1'"${MIRRORDIR}"'\",|' ${ORIGIN} else # replace full path sed -i '' '/'"${URL_KEY}"'/s|${ABI}.*|${ABI}/'"${MIRRORDIR}"'\",|' ${ORIGIN} fi fi if [ "${DO_MIRROR}" = "-M" ]; then # only print mirror URL mirror_abi exit 0 elif [ "${DO_MIRROR}" = "-x" ]; then # only print mirror subscription key mirror_sub exit 0 elif [ "${DO_MIRROR}" = "-X" ]; then # print bogons/changelog fetch URL # appropriate for the configuration # requiring pre and postprocessing if [ -z "$(mirror_sub)" ]; then ORIGIN=${ORIGIN}.sample if [ ! -f ${ORIGIN} ]; then echo "Missing ${ORIGIN}" >&2 exit 1 fi fi URL=$(mirror_abi pin) echo ${URL%/*}/$(opnsense-version -x) exit 0 elif [ -n "${DO_ORIGIN}" ]; then # only print repository configuration cat ${ORIGIN} exit 0 elif [ -n "${DO_LOGFILE}" ]; then # only print upgrade log if [ -f ${LOGFILE} ]; then cat ${LOGFILE} fi exit 0 elif [ -n "${DO_SKIP}" ]; then # only invoke mirror replacements exit 0 fi if ! grep -q "${SIG_KEY}\"fingerprints\"" ${ORIGIN}; then # enable insecure mode if repo is unsigned DO_INSECURE="-i" [ -z "${DO_CHECK}" ] && echo "WARNING: ${ORIGIN} does not use fingerprints, disabling signature checks." >&2 fi if [ -n "${DO_TEST}" ]; then if [ -n "${DO_BASE}" -a -n "${LOCKED_BASE}" ]; then exit 1 elif [ -n "${DO_KERNEL}" -a -n "${LOCKED_KERNEL}" ]; then exit 1 elif [ -n "${DO_PKGS}" -a -n "${LOCKED_PKGS}" ]; then exit 1 fi exit 0 fi if [ -z "${DO_TYPE}${DO_KERNEL}${DO_BASE}${DO_PKGS}" ]; then if [ -n "${DO_UPGRADE}" -o -n "${DO_CHECK}" ]; then DO_KERNEL="-k" DO_BASE="-b" DO_PKGS="-p" fi fi if [ -n "${DO_LOCK}" ]; then mkdir -p ${VERSIONDIR} if [ -n "${DO_KERNEL}" ]; then touch ${VERSIONDIR}/kernel.lock fi if [ -n "${DO_BASE}" ]; then touch ${VERSIONDIR}/base.lock fi if [ -n "${DO_PKGS}" ]; then touch ${VERSIONDIR}/pkgs.lock fi exit 0 elif [ -n "${DO_UNLOCK}" ]; then if [ -n "${DO_KERNEL}" ]; then rm -f ${VERSIONDIR}/kernel.lock fi if [ -n "${DO_BASE}" ]; then rm -f ${VERSIONDIR}/base.lock fi if [ -n "${DO_PKGS}" ]; then rm -f ${VERSIONDIR}/pkgs.lock fi exit 0 fi # DO_CHECK is not included, must be forced because we need both modes if [ -z "${DO_FORCE}${DO_SIZE}" ]; then # disable kernel if locked if [ -n "${DO_KERNEL}" -a -n "${LOCKED_KERNEL}" -a \ -z "${DO_UPGRADE}" ]; then [ -z "${DO_CHECK}" ] && echo "Kernel locked at ${INSTALLED_KERNEL}, skipping." DO_KERNEL= fi # disable base if locked if [ -n "${DO_BASE}" -a -n "${LOCKED_BASE}" -a \ -z "${DO_UPGRADE}" ]; then [ -z "${DO_CHECK}" ] && echo "Base locked at ${INSTALLED_BASE}, skipping." DO_BASE= fi # disable packages if locked if [ -n "${DO_PKGS}" -a -n "${LOCKED_PKGS}" -a \ -z "${DO_UPGRADE}" ]; then [ -z "${DO_CHECK}" ] && echo "Packages locked at ${INSTALLED_PKGS}, skipping." DO_PKGS= DO_TYPE= fi fi if [ -n "${DO_CHECK}" ]; then if [ "${DO_RELEASE}" = "-R" -a "${RELEASE}" = "unknown" ]; then # always error if we selected unknown release exit 1 fi # -B / -K are setting -f so lead with their checks here if [ "${DO_BASE}" = "-B" ]; then if [ -f "${PENDING_BASE}" ]; then exit 0 fi elif [ "${DO_KERNEL}" = "-K" ]; then if [ -f "${PENDING_KERNEL}" ]; then exit 0 fi elif [ -n "${DO_FORCE}" ]; then exit 0 fi # non-upgrade compare operations can be done now when not forced if [ -n "${DO_TYPE}" ]; then if [ "$(opnsense-version -n)" != "${DO_TYPE#"-t "}" ]; then exit 0 fi fi if [ -n "${DO_KERNEL}" ]; then if [ "${RELEASE}" != "${INSTALLED_KERNEL}" ]; then exit 0 fi fi if [ -n "${DO_BASE}" ]; then if [ "${RELEASE}" != "${INSTALLED_BASE}" ]; then exit 0 fi fi if [ -n "${DO_PKGS}" -a -n "${DO_UPGRADE}" ]; then if [ "${RELEASE}" != "${INSTALLED_PKGS}" ]; then exit 0 fi fi exit 1 fi if [ "${DO_KERNEL}" = "-K" ]; then if [ ! -f "${PENDING_KERNEL}" ]; then # must error out to prevent reboot exit 1 fi RELEASE=$(cat "${PENDING_KERNEL}") WORKDIR=${PENDINGDIR} rm -f "${PENDING_KERNEL}" elif [ "${DO_BASE}" = "-B" ]; then if [ ! -f "${PENDING_BASE}" ]; then # must error out to prevent reboot exit 1 fi RELEASE=$(cat "${PENDING_BASE}") WORKDIR=${PENDINGDIR} rm -f "${PENDING_BASE}" elif [ "${DO_PKGS}" = "-P" ]; then if [ ! -f "${PENDING_PKGS}" ]; then # must error out to prevent reboot exit 1 fi RELEASE=$(cat "${PENDING_PKGS}") WORKDIR=${PENDINGDIR} if [ -f "${INSECURE_PKGS}" ]; then DO_INSECURE="-i" fi rm -f "${PENDING_PKGS}" "${INSECURE_PKGS}" elif [ -n "${DO_LOCAL}" ]; then WORKDIR=${DO_LOCAL#"-l "} fi if [ "${DO_PKGS}" = "-p" -a -z "${DO_UPGRADE}${DO_SIZE}" ]; then CORE=$(opnsense-version -n) # clean up deferred sets that could be there rm -rf ${PENDINGDIR}/packages-* backup_origin if ${PKG} update ${DO_FORCE} && ${PKG} upgrade -y ${DO_FORCE}; then if [ ! -f ${ORIGIN} ]; then recover_origin ${CORE} elif ! diff -q ${WORKDIR}/${PRODUCT}.conf ${ORIGIN} > /dev/null; then # rerun sync before there are any complaints ${PKG} update ${DO_FORCE} fi ${PKG} autoremove -y ${PKG} check -yda ${PKG} clean -ya else # cannot continue after failed upgrade exit 1 fi if [ -n "${DO_BASE}${DO_KERNEL}${DO_TYPE}" ]; then # script may have changed, relaunch... opnsense-update ${DO_BASE} ${DO_KERNEL} ${DO_LOCAL} \ ${DO_FORCE} ${DO_RELEASE} ${DO_TYPE} ${DO_DEFAULTS} \ ${DO_MIRRORABI} ${DO_MIRRORDIR} ${DO_MIRRORURL} \ ${DO_ABI} ${DO_VERBOSE} ${DO_CLEAN} fi # stop here to prevent the second pass exit 0 fi if [ -n "${DO_TYPE}" ]; then OLD=$(opnsense-version -n) NEW=${DO_TYPE#"-t "} if [ "${OLD}" != "${NEW}" -o -n "${DO_FORCE}" ]; then # cache packages in case something goes wrong ${PKG} fetch -yr ${PRODUCT} ${OLD} ${NEW} # strip vital flag from installed package type ${PKG} set -yv 0 ${OLD} backup_origin # attempt to install the new package type and... if ! ${PKG} install -yr ${PRODUCT} ${DO_FORCE} ${NEW}; then NEW=${OLD} fi # recover from fatal attempt if [ ! -f ${ORIGIN} ]; then recover_origin ${NEW} fi # unconditionally set vital flag for safety ${PKG} set -yv 1 ${NEW} # set exit code based on transition status [ "${OLD}" != "${NEW}" -o -n "${DO_FORCE}" ] fi fi DEVICE= if [ -n "${DO_DEVICE}" ]; then DEVICE="${DO_DEVICE#-D }" if [ -n "${DEVICE}" ]; then DEVICE="-${DEVICE}" fi fi KERNELSET=kernel-${RELEASE}-${ARCH}${DEVICE}.txz PACKAGESSET=packages-${RELEASE}-${ARCH}.tar TESTSSET=tests-${RELEASE}-${ARCH}.txz BASESET=base-${RELEASE}-${ARCH}.txz MIRROR="$(mirror_abi)/sets" if [ -n "${DO_SIZE}" ]; then if [ -n "${DO_BASE}" ]; then BASE_SIZE=$(fetch -s ${MIRROR}/${BASESET} 2> /dev/null) echo ${BASE_SIZE} elif [ -n "${DO_KERNEL}" ]; then KERNEL_SIZE=$(fetch -s ${MIRROR}/${KERNELSET} 2> /dev/null) echo ${KERNEL_SIZE} elif [ -n "${DO_PKGS}" ]; then PKGS_SIZE=$(fetch -s ${MIRROR}/${PACKAGESSET} 2> /dev/null) echo ${PKGS_SIZE} fi exit 0 fi if [ -z "${DO_FORCE}" ]; then # disable kernel update if up-to-date if [ "${RELEASE}" = "${INSTALLED_KERNEL}" -a -n "${DO_KERNEL}" ]; then DO_KERNEL= fi # disable base update if up-to-date if [ "${RELEASE}" = "${INSTALLED_BASE}" -a -n "${DO_BASE}" ]; then DO_BASE= fi # disable packages upgrade if up-to-date if [ "${RELEASE}" = "${INSTALLED_PKGS}" -a -n "${DO_PKGS}" ]; then [ -n "${DO_UPGRADE}" ] && DO_PKGS= fi # nothing to do if [ -z "${DO_KERNEL}${DO_BASE}${DO_PKGS}${DO_TESTS}${DO_CLEAN}${DO_EMPTY}" ]; then echo "Nothing to do." exit 0 fi fi exit_msg() { if [ -n "${1}" ]; then echo "${1}" fi exit 1 } fetch_set() { STAGE1="opnsense-fetch -T 30 -q -o ${WORKDIR}/${1}.sig ${MIRROR}/${1}.sig" STAGE2="opnsense-fetch -T 30 -q -o ${WORKDIR}/${1} ${MIRROR}/${1}" STAGE3="opnsense-verify -q ${WORKDIR}/${1}" if [ -n "${DO_LOCAL}" ]; then # already fetched, just test STAGE1="test -f ${WORKDIR}/${1}.sig" STAGE2="test -f ${WORKDIR}/${1}" fi if [ -n "${DO_INSECURE}" ]; then # no signature, no cry STAGE1=":" STAGE3=":" fi echo -n "Fetching ${1}: ." if ! mkdir -p ${WORKDIR}; then exit_msg " failed, mkdir error ${?}" fi if ! ${STAGE1}; then exit_msg " failed, no signature found" fi if ! ${STAGE2}; then exit_msg " failed, no update found" fi if [ -n "${DO_VERBOSE}" ]; then if ! ${STAGE3}; then # message did print already exit_msg fi else if ! ${STAGE3} 2> /dev/null; then exit_msg " failed, signature invalid" fi fi echo " done" } install_tests() { echo -n "Installing ${TESTSSET}..." # clear the previous state as it is contained here rm -rf /usr/tests if ! tar -C / -xpf ${WORKDIR}/${TESTSSET} --exclude="^.abi_hint"; then exit_msg " failed, tar error ${?}" fi echo " done" } install_kernel() { echo -n "Installing ${KERNELSET}..." for DIR in ${KERNELDIR} ${DEBUGDIR}${KERNELDIR}; do if [ -d ${DIR}.old ]; then if ! rm -r ${DIR}.old; then exit_msg " failed, rm error ${?}" fi fi if [ -d ${DIR} ]; then if ! mv ${DIR} ${DIR}.old; then exit_msg " failed, mv error ${?}" fi fi done if ! tar -C / -xpf ${WORKDIR}/${KERNELSET} --exclude="^.abi_hint"; then exit_msg " failed, tar error ${?}" fi if [ -z "${DO_UPGRADE}" ]; then if ! kldxref ${KERNELDIR}; then exit_msg " failed, kldxref error ${?}" fi fi echo " done" } install_base() { NOSCHGDIRS="/bin /sbin /lib /libexec /usr/bin /usr/sbin /usr/lib /var/empty" echo -n "Installing ${BASESET}..." if ! mkdir -p ${NOSCHGDIRS}; then exit_msg " failed, mkdir error ${?}" fi if ! chflags -R noschg ${NOSCHGDIRS}; then exit_msg " failed, chflags error ${?}" fi if ! tar -C / -xpf ${WORKDIR}/${BASESET} \ --exclude="^.abi_hint" \ --exclude="^.cshrc" \ --exclude="^.profile" \ --exclude="^boot/efi" \ --exclude="^etc/group" \ --exclude="^etc/master.passwd" \ --exclude="^etc/motd" \ --exclude="^etc/passwd" \ --exclude="^etc/pwd.db" \ --exclude="^etc/rc" \ --exclude="^etc/rc.shutdown" \ --exclude="^etc/shells" \ --exclude="^etc/spwd.db" \ --exclude="^etc/ttys" \ --exclude="^proc" \ --exclude="^root/.cshrc" \ --exclude="^root/.profile"; then exit_msg " failed, tar error ${?}" fi if ! kldxref ${KERNELDIR}; then exit_msg " failed, kldxref error ${?}" fi echo " done" } register_pkgs() { # We can't recover from this replacement, but # since the manual says we require a reboot # after `-P', it is to be considered a feature. sed -i '' '/'"${URL_KEY}"'/s/".*/"file:\/\/\/var\/cache\/opnsense-update\/.sets.pending\/packages-'"${RELEASE}"'\",/' ${ORIGIN} if [ -n "${DO_INSECURE}" ]; then # Insecure meant we didn't have any sets signatures, # and now the packages are internally signed again, # so we need to disable its native verification, too. sed -i '' '/'"${SIG_KEY}"'/s/\"fingerprints\"/\"none\"/' ${ORIGIN} fi } install_pkgs() { echo "Installing ${PACKAGESSET}..." # register local packages repository register_pkgs # prepare log file and pipe mkdir -p ${WORKPREFIX} : > ${LOGFILE} rm -f ${PIPEFILE} mkfifo ${PIPEFILE} # unlock all to avoid dependency stalls ${TEE} ${LOGFILE} < ${PIPEFILE} & ${PKG} unlock -ay > ${PIPEFILE} 2>&1 # run full upgrade from the local repository ${TEE} ${LOGFILE} < ${PIPEFILE} & if (${PKG} update -f -r ${PRODUCT} && \ ${PKG} upgrade -fy -r ${PRODUCT}) > ${PIPEFILE} 2>&1; then # re-register local packages repository # since the successful upgrade reset it register_pkgs ${TEE} ${LOGFILE} < ${PIPEFILE} & ${PKG} autoremove -qy > ${PIPEFILE} 2>&1 ${TEE} ${LOGFILE} < ${PIPEFILE} & ${PKG} check -yda > ${PIPEFILE} 2>&1 ${TEE} ${LOGFILE} < ${PIPEFILE} & ${PKG} clean -qya > ${PIPEFILE} 2>&1 # file is a pseudo-marker we feed from this script only echo "${RELEASE}" > ${VERSIONDIR}/pkgs fi } if [ "${DO_PKGS}" = "-p" ]; then if [ "${DO_RELEASE}" = "-R" -a "${RELEASE}" = "unknown" ]; then echo "No known packages set to fetch was specified." exit 1 fi if [ -z "${DO_FORCE}" -o -n "${DO_UPGRADE}" ]; then rm -f ${VERSIONDIR}/pkgs.lock fi fetch_set ${PACKAGESSET} fi if [ "${DO_BASE}" = "-b" ]; then if [ -z "${DO_FORCE}" -o -n "${DO_UPGRADE}" ]; then rm -f ${VERSIONDIR}/base.lock fi fetch_set ${BASESET} fi if [ "${DO_KERNEL}" = "-k" ]; then if [ -z "${DO_FORCE}" -o -n "${DO_UPGRADE}" ]; then rm -f ${VERSIONDIR}/kernel.lock fi fetch_set ${KERNELSET} fi if [ -n "${DO_TESTS}" ]; then # since tests are not vital they do not have a lock or version check fetch_set ${TESTSSET} install_tests fi if [ -n "${DO_KERNEL}" -a -z "${DO_UPGRADE}" ] || \ [ -n "${DO_BASE}" -a -z "${DO_UPGRADE}" ] || \ [ "${DO_PKGS}" = "-P" -a -z "${DO_UPGRADE}" ]; then echo "!!!!!!!!!!!! ATTENTION !!!!!!!!!!!!!!!" echo "! A critical upgrade is in progress. !" echo "! Please do not turn off the system. !" echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" fi if [ "${DO_PKGS}" = "-p" -a -n "${DO_UPGRADE}" ]; then echo -n "Extracting ${PACKAGESSET}..." # clean up from a potential previous run rm -rf ${PENDINGDIR}/packages-* mkdir -p ${PENDINGDIR}/packages-${RELEASE} ${PKG} update -q 2> /dev/null && ${PKG} clean -qya # extract packages to avoid unpacking after reboot tar -C${PENDINGDIR}/packages-${RELEASE} -xpf \ ${WORKDIR}/${PACKAGESSET} # add action marker for next run echo ${RELEASE} > "${PENDING_PKGS}" if [ -n "${DO_INSECURE}" ]; then touch "${INSECURE_PKGS}" fi echo " done" fi if [ "${DO_BASE}" = "-b" -a -n "${DO_UPGRADE}" ]; then echo -n "Extracting ${BASESET}..." # clean up from a potential previous run rm -rf ${PENDINGDIR}/base-* mkdir -p ${PENDINGDIR} # push pending base update to deferred mv ${WORKDIR}/${BASESET} ${PENDINGDIR} # add action marker for next run echo ${RELEASE} > "${PENDING_BASE}" echo " done" fi if [ "${DO_KERNEL}" = "-k" -a -n "${DO_UPGRADE}" ]; then echo -n "Extracting ${KERNELSET}..." # clean up from a potential previous run rm -rf ${PENDINGDIR}/kernel-* mkdir -p ${PENDINGDIR} # push pending base update to deferred mv ${WORKDIR}/${KERNELSET} ${PENDINGDIR} # add action marker for next run echo ${RELEASE} > "${PENDING_KERNEL}" echo " done" fi if [ -n "${DO_KERNEL}" -a -z "${DO_UPGRADE}" ]; then install_kernel # clean up deferred sets that could be there rm -rf ${PENDINGDIR}/kernel-* fi if [ -n "${DO_BASE}" -a -z "${DO_UPGRADE}" ]; then if [ "${DO_BASE}" = "-B" ]; then mkdir -p ${WORKDIR}/base-freebsd-version tar -C${WORKDIR}/base-freebsd-version -xpf \ ${WORKDIR}/${BASESET} ./bin/freebsd-version BASE_VER=$(base_version ${WORKDIR}/base-freebsd-version) KERNEL_VER=$(kernel_version) BASE_VER=${BASE_VER%%-*} KERNEL_VER=${KERNEL_VER%%-*} if [ "${BASE_VER}" != "${KERNEL_VER}" ]; then echo "Version number mismatch, aborting." echo " Kernel: ${KERNEL_VER}" echo " Base: ${BASE_VER}" # Clean all the pending updates, so that # packages are not upgraded as well. empty_cache exit 1 fi fi install_base # clean up deferred sets that could be there rm -rf ${PENDINGDIR}/base-* fi if [ "${DO_BASE}" = "-b" -a -z "${DO_UPGRADE}" ] || [ -n "${DO_CLEAN}" ]; then # only remove obsolete files on minor # updates or when being asked directly clean_base fi if [ "${DO_PKGS}" = "-P" -a -z "${DO_UPGRADE}" ]; then install_pkgs # clean up deferred sets that could be there rm -rf ${PENDINGDIR}/packages-* fi if [ -z "${DO_LOCAL}" ]; then if [ -d ${WORKPREFIX} ]; then # remove temporary update directories but keep upgrades and logs find ${WORKPREFIX} \! -name ".*" -d 1 -print0 | xargs -0 rm -r fi fi if [ "${DO_KERNEL}" = "-k" -o "${DO_BASE}" = "-b" -o -n "${DO_UPGRADE}" ]; then echo "Please reboot." fi