%PDF- %PDF-
| Direktori : /proc/thread-self/root/backups/router/usr/local/sbin/ |
| Current File : //proc/thread-self/root/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