Changeset View
Standalone View
usr.sbin/freebsd-update/freebsd-update.sh
Show First 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | -f conffile -- Read configuration options from conffile | ||||
(default: /etc/freebsd-update.conf) | (default: /etc/freebsd-update.conf) | ||||
-F -- Force a fetch operation to proceed | -F -- Force a fetch operation to proceed | ||||
-k KEY -- Trust an RSA key with SHA256 hash of KEY | -k KEY -- Trust an RSA key with SHA256 hash of KEY | ||||
-r release -- Target for upgrade (e.g., 11.1-RELEASE) | -r release -- Target for upgrade (e.g., 11.1-RELEASE) | ||||
-s server -- Server from which to fetch updates | -s server -- Server from which to fetch updates | ||||
(default: update.FreeBSD.org) | (default: update.FreeBSD.org) | ||||
-t address -- Mail output of cron command, if any, to address | -t address -- Mail output of cron command, if any, to address | ||||
(default: root) | (default: root) | ||||
-q -- Hide any status related messages | |||||
--not-running-from-cron | --not-running-from-cron | ||||
-- Run without a tty, for use by automated tools | -- Run without a tty, for use by automated tools | ||||
--currently-running release | --currently-running release | ||||
-- Update as if currently running this release | -- Update as if currently running this release | ||||
Commands: | Commands: | ||||
fetch -- Fetch updates from server | fetch -- Fetch updates from server | ||||
cron -- Sleep rand(3600) seconds, fetch updates, and send an | cron -- Sleep rand(3600) seconds, fetch updates, and send an | ||||
email if updates were found | email if updates were found | ||||
▲ Show 20 Lines • Show All 254 Lines • ▼ Show 20 Lines | config_VerboseLevel () { | ||||
if [ -z ${VERBOSELEVEL} ]; then | if [ -z ${VERBOSELEVEL} ]; then | ||||
case $1 in | case $1 in | ||||
[Dd][Ee][Bb][Uu][Gg]) | [Dd][Ee][Bb][Uu][Gg]) | ||||
VERBOSELEVEL=debug | VERBOSELEVEL=debug | ||||
;; | ;; | ||||
[Nn][Oo][Ss][Tt][Aa][Tt][Ss]) | [Nn][Oo][Ss][Tt][Aa][Tt][Ss]) | ||||
VERBOSELEVEL=nostats | VERBOSELEVEL=nostats | ||||
;; | ;; | ||||
[Nn][Oo][Nn][Ee]) | |||||
VERBOSELEVEL=none | |||||
;; | |||||
[Ss][Tt][Aa][Tt][Ss]) | [Ss][Tt][Aa][Tt][Ss]) | ||||
VERBOSELEVEL=stats | VERBOSELEVEL=stats | ||||
;; | ;; | ||||
*) | *) | ||||
return 1 | return 1 | ||||
;; | ;; | ||||
esac | esac | ||||
else | else | ||||
▲ Show 20 Lines • Show All 146 Lines • ▼ Show 20 Lines | -t) | ||||
if [ $# -eq 1 ]; then usage; fi; shift | if [ $# -eq 1 ]; then usage; fi; shift | ||||
config_MailTo $1 || usage | config_MailTo $1 || usage | ||||
;; | ;; | ||||
-v) | -v) | ||||
if [ $# -eq 1 ]; then usage; fi; shift | if [ $# -eq 1 ]; then usage; fi; shift | ||||
config_VerboseLevel $1 || usage | config_VerboseLevel $1 || usage | ||||
;; | ;; | ||||
# Aliases for "-v debug" and "-v nostats" | # Aliases for "-v none", "-v debug" and "-v nostats" | ||||
-q) | |||||
config_VerboseLevel none || usage | |||||
;; | |||||
--debug) | --debug) | ||||
config_VerboseLevel debug || usage | config_VerboseLevel debug || usage | ||||
;; | ;; | ||||
--no-stats) | --no-stats) | ||||
config_VerboseLevel nostats || usage | config_VerboseLevel nostats || usage | ||||
;; | ;; | ||||
# Commands | # Commands | ||||
Show All 10 Lines | parse_cmdline () { | ||||
done | done | ||||
# Make sure we have at least one command | # Make sure we have at least one command | ||||
if [ -z "${COMMANDS}" ]; then | if [ -z "${COMMANDS}" ]; then | ||||
usage | usage | ||||
fi | fi | ||||
} | } | ||||
print_error () { | |||||
if [ $# -eq 0 ]; then | |||||
while read LINE; do | |||||
echo "${LINE}" >&2 | |||||
done | |||||
else | |||||
echo $@ >&2 | |||||
fi | |||||
} | |||||
# Parse the configuration file | # Parse the configuration file | ||||
parse_conffile () { | parse_conffile () { | ||||
# If a configuration file was specified on the command line, check | # If a configuration file was specified on the command line, check | ||||
# that it exists and is readable. | # that it exists and is readable. | ||||
if [ ! -z "${CONFFILE}" ] && [ ! -r "${CONFFILE}" ]; then | if [ ! -z "${CONFFILE}" ] && [ ! -r "${CONFFILE}" ]; then | ||||
echo -n "File does not exist " | print_error -n "File does not exist " | ||||
echo -n "or is not readable: " | print_error -n "or is not readable: " | ||||
echo ${CONFFILE} | print_error ${CONFFILE} | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
# If a configuration file was not specified on the command line, | # If a configuration file was not specified on the command line, | ||||
# use the default configuration file path. If that default does | # use the default configuration file path. If that default does | ||||
# not exist, give up looking for any configuration. | # not exist, give up looking for any configuration. | ||||
if [ -z "${CONFFILE}" ]; then | if [ -z "${CONFFILE}" ]; then | ||||
CONFFILE="/etc/freebsd-update.conf" | CONFFILE="/etc/freebsd-update.conf" | ||||
Show All 9 Lines | parse_conffile () { | ||||
# Read the configuration file. Anything after the first '#' is | # Read the configuration file. Anything after the first '#' is | ||||
# ignored, and any blank lines are ignored. | # ignored, and any blank lines are ignored. | ||||
L=0 | L=0 | ||||
while read LINE; do | while read LINE; do | ||||
L=$(($L + 1)) | L=$(($L + 1)) | ||||
LINEX=`echo "${LINE}" | cut -f 1 -d '#'` | LINEX=`echo "${LINE}" | cut -f 1 -d '#'` | ||||
if ! configline ${LINEX}; then | if ! configline ${LINEX}; then | ||||
echo "Error processing configuration file, line $L:" | print_error "Error processing configuration file, line $L:" | ||||
echo "==> ${LINE}" | print_error "==> ${LINE}" | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
done < ${CONFFILE} | done < ${CONFFILE} | ||||
# Merge the settings read from the configuration file with those | # Merge the settings read from the configuration file with those | ||||
# provided at the command line. | # provided at the command line. | ||||
mergeconfig | mergeconfig | ||||
} | } | ||||
Show All 20 Lines | default_params () { | ||||
# Merge these defaults into the earlier-configured settings | # Merge these defaults into the earlier-configured settings | ||||
mergeconfig | mergeconfig | ||||
} | } | ||||
# Set utility output filtering options, based on ${VERBOSELEVEL} | # Set utility output filtering options, based on ${VERBOSELEVEL} | ||||
fetch_setup_verboselevel () { | fetch_setup_verboselevel () { | ||||
case ${VERBOSELEVEL} in | case ${VERBOSELEVEL} in | ||||
debug) | debug) | ||||
INFOREDIR="/dev/stdout" | |||||
QUIETREDIR="/dev/stderr" | QUIETREDIR="/dev/stderr" | ||||
QUIETFLAG=" " | QUIETFLAG="" | ||||
STATSREDIR="/dev/stderr" | STATSREDIR="/dev/stderr" | ||||
DDSTATS=".." | DDSTATS=".." | ||||
XARGST="-t" | XARGST="-t" | ||||
NDEBUG=" " | NDEBUG=" " | ||||
;; | ;; | ||||
nostats) | nostats) | ||||
QUIETREDIR="" | INFOREDIR="/dev/stdout" | ||||
QUIETREDIR="/dev/stdout" | |||||
QUIETFLAG="" | QUIETFLAG="" | ||||
STATSREDIR="/dev/null" | STATSREDIR="/dev/null" | ||||
DDSTATS=".." | DDSTATS=".." | ||||
XARGST="" | XARGST="" | ||||
NDEBUG="" | NDEBUG="" | ||||
;; | ;; | ||||
none) | |||||
INFOREDIR="/dev/null" | |||||
QUIETREDIR="/dev/null" | |||||
QUIETFLAG="-q" | |||||
STATSREDIR="/dev/null" | |||||
DDSTATS=".." | |||||
XARGST="" | |||||
NDEBUG="" | |||||
;; | |||||
stats) | stats) | ||||
INFOREDIR="/dev/stdout" | |||||
QUIETREDIR="/dev/null" | QUIETREDIR="/dev/null" | ||||
QUIETFLAG="-q" | QUIETFLAG="-q" | ||||
STATSREDIR="/dev/stdout" | STATSREDIR="/dev/stdout" | ||||
DDSTATS="" | DDSTATS="" | ||||
XARGST="" | XARGST="" | ||||
NDEBUG="-n" | NDEBUG="-n" | ||||
;; | ;; | ||||
esac | esac | ||||
Show All 11 Lines | fetchupgrade_check_params () { | ||||
_SERVERNAME_z=\ | _SERVERNAME_z=\ | ||||
"SERVERNAME must be given via command line or configuration file." | "SERVERNAME must be given via command line or configuration file." | ||||
_KEYPRINT_z="Key must be given via -k option or configuration file." | _KEYPRINT_z="Key must be given via -k option or configuration file." | ||||
_KEYPRINT_bad="Invalid key fingerprint: " | _KEYPRINT_bad="Invalid key fingerprint: " | ||||
_WORKDIR_bad="Directory does not exist or is not writable: " | _WORKDIR_bad="Directory does not exist or is not writable: " | ||||
_WORKDIR_bad2="Directory is not on a persistent filesystem: " | _WORKDIR_bad2="Directory is not on a persistent filesystem: " | ||||
if [ -z "${SERVERNAME}" ]; then | if [ -z "${SERVERNAME}" ]; then | ||||
echo -n "`basename $0`: " | print_error -n "`basename $0`: " | ||||
echo "${_SERVERNAME_z}" | print_error "${_SERVERNAME_z}" | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
if [ -z "${KEYPRINT}" ]; then | if [ -z "${KEYPRINT}" ]; then | ||||
echo -n "`basename $0`: " | print_error -n "`basename $0`: " | ||||
echo "${_KEYPRINT_z}" | print_error "${_KEYPRINT_z}" | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
if ! echo "${KEYPRINT}" | grep -qE "^[0-9a-f]{64}$"; then | if ! echo "${KEYPRINT}" | grep -qE "^[0-9a-f]{64}$"; then | ||||
echo -n "`basename $0`: " | print_error -n "`basename $0`: " | ||||
echo -n "${_KEYPRINT_bad}" | print_error -n "${_KEYPRINT_bad}" | ||||
echo ${KEYPRINT} | print_error ${KEYPRINT} | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then | if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then | ||||
echo -n "`basename $0`: " | print_error -n "`basename $0`: " | ||||
echo -n "${_WORKDIR_bad}" | print_error -n "${_WORKDIR_bad}" | ||||
echo ${WORKDIR} | print_error ${WORKDIR} | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
case `df -T ${WORKDIR}` in */dev/md[0-9]* | *tmpfs*) | case `df -T ${WORKDIR}` in */dev/md[0-9]* | *tmpfs*) | ||||
echo -n "`basename $0`: " | print_error -n "`basename $0`: " | ||||
echo -n "${_WORKDIR_bad2}" | print_error -n "${_WORKDIR_bad2}" | ||||
echo ${WORKDIR} | print_error ${WORKDIR} | ||||
exit 1 | exit 1 | ||||
;; | ;; | ||||
esac | esac | ||||
chmod 700 ${WORKDIR} | chmod 700 ${WORKDIR} | ||||
cd ${WORKDIR} || exit 1 | cd ${WORKDIR} || exit 1 | ||||
# Generate release number. The s/SECURITY/RELEASE/ bit exists | # Generate release number. The s/SECURITY/RELEASE/ bit exists | ||||
# to provide an upgrade path for FreeBSD Update 1.x users, since | # to provide an upgrade path for FreeBSD Update 1.x users, since | ||||
Show All 17 Lines | if ! echo "${RELNUM}" | grep -qE -- "-RELEASE$"; then | ||||
echo "System version: ${RELNUM}" | echo "System version: ${RELNUM}" | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
# Figure out what directory contains the running kernel | # Figure out what directory contains the running kernel | ||||
BOOTFILE=`sysctl -n kern.bootfile` | BOOTFILE=`sysctl -n kern.bootfile` | ||||
KERNELDIR=${BOOTFILE%/kernel} | KERNELDIR=${BOOTFILE%/kernel} | ||||
if ! [ -d ${KERNELDIR} ]; then | if ! [ -d ${KERNELDIR} ]; then | ||||
echo "Cannot identify running kernel" | print_error "Cannot identify running kernel" | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
# Figure out what kernel configuration is running. We start with | # Figure out what kernel configuration is running. We start with | ||||
# the output of `uname -i`, and then make the following adjustments: | # the output of `uname -i`, and then make the following adjustments: | ||||
# 1. Replace "SMP-GENERIC" with "SMP". Why the SMP kernel config | # 1. Replace "SMP-GENERIC" with "SMP". Why the SMP kernel config | ||||
# file says "ident SMP-GENERIC", I don't know... | # file says "ident SMP-GENERIC", I don't know... | ||||
# 2. If the kernel claims to be GENERIC _and_ ${ARCH} is "amd64" | # 2. If the kernel claims to be GENERIC _and_ ${ARCH} is "amd64" | ||||
Show All 22 Lines | "SERVERNAME must be given via command line or configuration file." | ||||
BDHASH=`echo ${BASEDIR} | sha256 -q` | BDHASH=`echo ${BASEDIR} | sha256 -q` | ||||
} | } | ||||
# Perform sanity checks etc. before fetching updates. | # Perform sanity checks etc. before fetching updates. | ||||
fetch_check_params () { | fetch_check_params () { | ||||
fetchupgrade_check_params | fetchupgrade_check_params | ||||
if ! [ -z "${TARGETRELEASE}" ]; then | if ! [ -z "${TARGETRELEASE}" ]; then | ||||
echo -n "`basename $0`: " | print_error -n "`basename $0`: " | ||||
echo -n "-r option is meaningless with 'fetch' command. " | print_error -n "-r option is meaningless with 'fetch' command. " | ||||
echo "(Did you mean 'upgrade' instead?)" | print_error "(Did you mean 'upgrade' instead?)" | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
# Check that we have updates ready to install | # Check that we have updates ready to install | ||||
if [ -f ${BDHASH}-install/kerneldone -a $FORCEFETCH -eq 0 ]; then | if [ -f ${BDHASH}-install/kerneldone -a $FORCEFETCH -eq 0 ]; then | ||||
echo "You have a partially completed upgrade pending" | print_error "You have a partially completed upgrade pending" | ||||
echo "Run '$0 install' first." | print_error "Run '$0 install' first." | ||||
echo "Run '$0 fetch -F' to proceed anyway." | print_error "Run '$0 fetch -F' to proceed anyway." | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
} | } | ||||
# Perform sanity checks etc. before fetching upgrades. | # Perform sanity checks etc. before fetching upgrades. | ||||
upgrade_check_params () { | upgrade_check_params () { | ||||
fetchupgrade_check_params | fetchupgrade_check_params | ||||
# Unless set otherwise, we're upgrading to the same kernel config. | # Unless set otherwise, we're upgrading to the same kernel config. | ||||
NKERNCONF=${KERNCONF} | NKERNCONF=${KERNCONF} | ||||
# We need TARGETRELEASE set | # We need TARGETRELEASE set | ||||
_TARGETRELEASE_z="Release target must be specified via -r option." | _TARGETRELEASE_z="Release target must be specified via -r option." | ||||
if [ -z "${TARGETRELEASE}" ]; then | if [ -z "${TARGETRELEASE}" ]; then | ||||
echo -n "`basename $0`: " | print_error -n "`basename $0`: " | ||||
echo "${_TARGETRELEASE_z}" | print_error "${_TARGETRELEASE_z}" | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
# The target release should be != the current release. | # The target release should be != the current release. | ||||
if [ "${TARGETRELEASE}" = "${RELNUM}" ]; then | if [ "${TARGETRELEASE}" = "${RELNUM}" ]; then | ||||
echo -n "`basename $0`: " | print_error -n "`basename $0`: " | ||||
echo "Cannot upgrade from ${RELNUM} to itself" | print_error "Cannot upgrade from ${RELNUM} to itself" | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
# Turning off AllowAdd or AllowDelete is a bad idea for upgrades. | # Turning off AllowAdd or AllowDelete is a bad idea for upgrades. | ||||
if [ "${ALLOWADD}" = "no" ]; then | if [ "${ALLOWADD}" = "no" ]; then | ||||
echo -n "`basename $0`: " | print_error -n "`basename $0`: " | ||||
echo -n "WARNING: \"AllowAdd no\" is a bad idea " | print_error -n "WARNING: \"AllowAdd no\" is a bad idea " | ||||
echo "when upgrading between releases." | print_error "when upgrading between releases." | ||||
echo | print_error | ||||
fi | fi | ||||
if [ "${ALLOWDELETE}" = "no" ]; then | if [ "${ALLOWDELETE}" = "no" ]; then | ||||
echo -n "`basename $0`: " | print_error -n "`basename $0`: " | ||||
echo -n "WARNING: \"AllowDelete no\" is a bad idea " | print_error -n "WARNING: \"AllowDelete no\" is a bad idea " | ||||
echo "when upgrading between releases." | print_error "when upgrading between releases." | ||||
echo | print_error | ||||
fi | fi | ||||
# Set EDITOR to /usr/bin/vi if it isn't already set | # Set EDITOR to /usr/bin/vi if it isn't already set | ||||
: ${EDITOR:='/usr/bin/vi'} | : ${EDITOR:='/usr/bin/vi'} | ||||
} | } | ||||
# Perform sanity checks and set some final parameters in | # Perform sanity checks and set some final parameters in | ||||
# preparation for installing updates. | # preparation for installing updates. | ||||
install_check_params () { | install_check_params () { | ||||
# Check that we are root. All sorts of things won't work otherwise. | # Check that we are root. All sorts of things won't work otherwise. | ||||
if [ `id -u` != 0 ]; then | if [ `id -u` != 0 ]; then | ||||
echo "You must be root to run this." | print_error "You must be root to run this." | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
# Check that securelevel <= 0. Otherwise we can't update schg files. | # Check that securelevel <= 0. Otherwise we can't update schg files. | ||||
if [ `sysctl -n kern.securelevel` -gt 0 ]; then | if [ `sysctl -n kern.securelevel` -gt 0 ]; then | ||||
echo "Updates cannot be installed when the system securelevel" | print_error "Updates cannot be installed when the system securelevel" | ||||
echo "is greater than zero." | print_error "is greater than zero." | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
# Check that we have a working directory | # Check that we have a working directory | ||||
_WORKDIR_bad="Directory does not exist or is not writable: " | _WORKDIR_bad="Directory does not exist or is not writable: " | ||||
if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then | if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then | ||||
echo -n "`basename $0`: " | print_error -n "`basename $0`: " | ||||
echo -n "${_WORKDIR_bad}" | print_error -n "${_WORKDIR_bad}" | ||||
echo ${WORKDIR} | print_error ${WORKDIR} | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
cd ${WORKDIR} || exit 1 | cd ${WORKDIR} || exit 1 | ||||
# Construct a unique name from ${BASEDIR} | # Construct a unique name from ${BASEDIR} | ||||
BDHASH=`echo ${BASEDIR} | sha256 -q` | BDHASH=`echo ${BASEDIR} | sha256 -q` | ||||
# Check that we have updates ready to install | # Check that we have updates ready to install | ||||
if ! [ -L ${BDHASH}-install ]; then | if ! [ -L ${BDHASH}-install ]; then | ||||
echo "No updates are available to install." | echo "No updates are available to install." | ||||
if [ $ISFETCHED -eq 0 ]; then | if [ $ISFETCHED -eq 0 ]; then | ||||
echo "Run '$0 fetch' first." | echo "Run '$0 fetch' first." | ||||
fi | fi | ||||
exit 0 | exit 0 | ||||
fi | fi | ||||
if ! [ -f ${BDHASH}-install/INDEX-OLD ] || | if ! [ -f ${BDHASH}-install/INDEX-OLD ] || | ||||
! [ -f ${BDHASH}-install/INDEX-NEW ]; then | ! [ -f ${BDHASH}-install/INDEX-NEW ]; then | ||||
echo "Update manifest is corrupt -- this should never happen." | print_error "Update manifest is corrupt -- this should never happen." | ||||
echo "Re-run '$0 fetch'." | print_error "Re-run '$0 fetch'." | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
# Figure out what directory contains the running kernel | # Figure out what directory contains the running kernel | ||||
BOOTFILE=`sysctl -n kern.bootfile` | BOOTFILE=`sysctl -n kern.bootfile` | ||||
KERNELDIR=${BOOTFILE%/kernel} | KERNELDIR=${BOOTFILE%/kernel} | ||||
if ! [ -d ${KERNELDIR} ]; then | if ! [ -d ${KERNELDIR} ]; then | ||||
echo "Cannot identify running kernel" | print_error "Cannot identify running kernel" | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
} | } | ||||
# Perform sanity checks and set some final parameters in | # Perform sanity checks and set some final parameters in | ||||
# preparation for UNinstalling updates. | # preparation for UNinstalling updates. | ||||
rollback_check_params () { | rollback_check_params () { | ||||
# Check that we are root. All sorts of things won't work otherwise. | # Check that we are root. All sorts of things won't work otherwise. | ||||
if [ `id -u` != 0 ]; then | if [ `id -u` != 0 ]; then | ||||
echo "You must be root to run this." | print_error "You must be root to run this." | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
# Check that we have a working directory | # Check that we have a working directory | ||||
_WORKDIR_bad="Directory does not exist or is not writable: " | _WORKDIR_bad="Directory does not exist or is not writable: " | ||||
if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then | if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then | ||||
echo -n "`basename $0`: " | print_error -n "`basename $0`: " | ||||
echo -n "${_WORKDIR_bad}" | print_error -n "${_WORKDIR_bad}" | ||||
echo ${WORKDIR} | print_error ${WORKDIR} | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
cd ${WORKDIR} || exit 1 | cd ${WORKDIR} || exit 1 | ||||
# Construct a unique name from ${BASEDIR} | # Construct a unique name from ${BASEDIR} | ||||
BDHASH=`echo ${BASEDIR} | sha256 -q` | BDHASH=`echo ${BASEDIR} | sha256 -q` | ||||
# Check that we have updates ready to rollback | # Check that we have updates ready to rollback | ||||
if ! [ -L ${BDHASH}-rollback ]; then | if ! [ -L ${BDHASH}-rollback ]; then | ||||
echo "No rollback directory found." | print_error "No rollback directory found." | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
if ! [ -f ${BDHASH}-rollback/INDEX-OLD ] || | if ! [ -f ${BDHASH}-rollback/INDEX-OLD ] || | ||||
! [ -f ${BDHASH}-rollback/INDEX-NEW ]; then | ! [ -f ${BDHASH}-rollback/INDEX-NEW ]; then | ||||
echo "Update manifest is corrupt -- this should never happen." | print_error "Update manifest is corrupt -- this should never happen." | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
} | } | ||||
# Perform sanity checks and set some final parameters | # Perform sanity checks and set some final parameters | ||||
# in preparation for comparing the system against the | # in preparation for comparing the system against the | ||||
# published index. Figure out which index we should | # published index. Figure out which index we should | ||||
# compare against: If the user is running *-p[0-9]+, | # compare against: If the user is running *-p[0-9]+, | ||||
# strip off the last part; if the user is running | # strip off the last part; if the user is running | ||||
# -SECURITY, call it -RELEASE. Chdir into the working | # -SECURITY, call it -RELEASE. Chdir into the working | ||||
# directory. | # directory. | ||||
IDS_check_params () { | IDS_check_params () { | ||||
export HTTP_USER_AGENT="freebsd-update (${COMMAND}, `uname -r`)" | export HTTP_USER_AGENT="freebsd-update (${COMMAND}, `uname -r`)" | ||||
_SERVERNAME_z=\ | _SERVERNAME_z=\ | ||||
"SERVERNAME must be given via command line or configuration file." | "SERVERNAME must be given via command line or configuration file." | ||||
_KEYPRINT_z="Key must be given via -k option or configuration file." | _KEYPRINT_z="Key must be given via -k option or configuration file." | ||||
_KEYPRINT_bad="Invalid key fingerprint: " | _KEYPRINT_bad="Invalid key fingerprint: " | ||||
_WORKDIR_bad="Directory does not exist or is not writable: " | _WORKDIR_bad="Directory does not exist or is not writable: " | ||||
if [ -z "${SERVERNAME}" ]; then | if [ -z "${SERVERNAME}" ]; then | ||||
echo -n "`basename $0`: " | print_error -n "`basename $0`: " | ||||
echo "${_SERVERNAME_z}" | print_error "${_SERVERNAME_z}" | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
if [ -z "${KEYPRINT}" ]; then | if [ -z "${KEYPRINT}" ]; then | ||||
echo -n "`basename $0`: " | print_error -n "`basename $0`: " | ||||
echo "${_KEYPRINT_z}" | print_error "${_KEYPRINT_z}" | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
if ! echo "${KEYPRINT}" | grep -qE "^[0-9a-f]{64}$"; then | if ! echo "${KEYPRINT}" | grep -qE "^[0-9a-f]{64}$"; then | ||||
echo -n "`basename $0`: " | print_error -n "`basename $0`: " | ||||
echo -n "${_KEYPRINT_bad}" | print_error -n "${_KEYPRINT_bad}" | ||||
echo ${KEYPRINT} | print_error ${KEYPRINT} | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then | if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then | ||||
echo -n "`basename $0`: " | print_error -n "`basename $0`: " | ||||
echo -n "${_WORKDIR_bad}" | print_error -n "${_WORKDIR_bad}" | ||||
echo ${WORKDIR} | print_error ${WORKDIR} | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
cd ${WORKDIR} || exit 1 | cd ${WORKDIR} || exit 1 | ||||
# Generate release number. The s/SECURITY/RELEASE/ bit exists | # Generate release number. The s/SECURITY/RELEASE/ bit exists | ||||
# to provide an upgrade path for FreeBSD Update 1.x users, since | # to provide an upgrade path for FreeBSD Update 1.x users, since | ||||
# the kernels provided by FreeBSD Update 1.x are always labelled | # the kernels provided by FreeBSD Update 1.x are always labelled | ||||
# as X.Y-SECURITY. | # as X.Y-SECURITY. | ||||
RELNUM=`uname -r | | RELNUM=`uname -r | | ||||
sed -E 's,-p[0-9]+,,' | | sed -E 's,-p[0-9]+,,' | | ||||
sed -E 's,-SECURITY,-RELEASE,'` | sed -E 's,-SECURITY,-RELEASE,'` | ||||
ARCH=`uname -m` | ARCH=`uname -m` | ||||
FETCHDIR=${RELNUM}/${ARCH} | FETCHDIR=${RELNUM}/${ARCH} | ||||
PATCHDIR=${RELNUM}/${ARCH}/bp | PATCHDIR=${RELNUM}/${ARCH}/bp | ||||
# Figure out what directory contains the running kernel | # Figure out what directory contains the running kernel | ||||
BOOTFILE=`sysctl -n kern.bootfile` | BOOTFILE=`sysctl -n kern.bootfile` | ||||
KERNELDIR=${BOOTFILE%/kernel} | KERNELDIR=${BOOTFILE%/kernel} | ||||
if ! [ -d ${KERNELDIR} ]; then | if ! [ -d ${KERNELDIR} ]; then | ||||
echo "Cannot identify running kernel" | print_error "Cannot identify running kernel" | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
# Figure out what kernel configuration is running. We start with | # Figure out what kernel configuration is running. We start with | ||||
# the output of `uname -i`, and then make the following adjustments: | # the output of `uname -i`, and then make the following adjustments: | ||||
# 1. Replace "SMP-GENERIC" with "SMP". Why the SMP kernel config | # 1. Replace "SMP-GENERIC" with "SMP". Why the SMP kernel config | ||||
# file says "ident SMP-GENERIC", I don't know... | # file says "ident SMP-GENERIC", I don't know... | ||||
# 2. If the kernel claims to be GENERIC _and_ ${ARCH} is "amd64" | # 2. If the kernel claims to be GENERIC _and_ ${ARCH} is "amd64" | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | # "$name server selection ..."; we allow either format. | ||||
host -t srv "${MLIST}" | | host -t srv "${MLIST}" | | ||||
sed -nE "s/${MLIST} (has SRV record|server selection) //Ip" | | sed -nE "s/${MLIST} (has SRV record|server selection) //Ip" | | ||||
cut -f 1,2,4 -d ' ' | | cut -f 1,2,4 -d ' ' | | ||||
sed -e 's/\.$//' | | sed -e 's/\.$//' | | ||||
sort > serverlist_full | sort > serverlist_full | ||||
# If no records, give up -- we'll just use the server name we were given. | # If no records, give up -- we'll just use the server name we were given. | ||||
if [ `wc -l < serverlist_full` -eq 0 ]; then | if [ `wc -l < serverlist_full` -eq 0 ]; then | ||||
echo "none found." | print_error "found no ${SERVERNAME} mirrors." | ||||
return 1 | return 1 | ||||
fi | fi | ||||
# Report how many mirrors we found. | # Report how many mirrors we found. | ||||
echo `wc -l < serverlist_full` "mirrors found." | echo `wc -l < serverlist_full` "mirrors found." | ||||
# Generate a random seed for use in picking mirrors. If HTTP_PROXY | # Generate a random seed for use in picking mirrors. If HTTP_PROXY | ||||
# is set, this will be used to generate the seed; otherwise, the seed | # is set, this will be used to generate the seed; otherwise, the seed | ||||
Show All 10 Lines | |||||
# Pick a mirror. Returns 1 if we have run out of mirrors to try. | # Pick a mirror. Returns 1 if we have run out of mirrors to try. | ||||
fetch_pick_server () { | fetch_pick_server () { | ||||
# Generate a list of not-yet-tried mirrors | # Generate a list of not-yet-tried mirrors | ||||
sort serverlist_tried | | sort serverlist_tried | | ||||
comm -23 serverlist_full - > serverlist | comm -23 serverlist_full - > serverlist | ||||
# Have we run out of mirrors? | # Have we run out of mirrors? | ||||
if [ `wc -l < serverlist` -eq 0 ]; then | if [ `wc -l < serverlist` -eq 0 ]; then | ||||
echo "No mirrors remaining, giving up." | print_error "No mirrors remaining, giving up." | ||||
return 1 | return 1 | ||||
fi | fi | ||||
# Find the highest priority level (lowest numeric value). | # Find the highest priority level (lowest numeric value). | ||||
SRV_PRIORITY=`cut -f 1 -d ' ' serverlist | sort -n | head -1` | SRV_PRIORITY=`cut -f 1 -d ' ' serverlist | sort -n | head -1` | ||||
# Add up the weights of the response lines at that priority level. | # Add up the weights of the response lines at that priority level. | ||||
SRV_WSUM=0; | SRV_WSUM=0; | ||||
▲ Show 20 Lines • Show All 88 Lines • ▼ Show 20 Lines | |||||
# Check that we have a public key with an appropriate hash, or | # Check that we have a public key with an appropriate hash, or | ||||
# fetch the key if it doesn't exist. Returns 1 if the key has | # fetch the key if it doesn't exist. Returns 1 if the key has | ||||
# not yet been fetched. | # not yet been fetched. | ||||
fetch_key () { | fetch_key () { | ||||
if [ -r pub.ssl ] && [ `${SHA256} -q pub.ssl` = ${KEYPRINT} ]; then | if [ -r pub.ssl ] && [ `${SHA256} -q pub.ssl` = ${KEYPRINT} ]; then | ||||
return 0 | return 0 | ||||
fi | fi | ||||
echo -n "Fetching public key from ${SERVERNAME}... " | echo -n "Fetching public key from ${SERVERNAME}... " | ||||
delphij: In quiet mode, shouldn't this be omitted (also the "done." in line 1164)? | |||||
rm -f pub.ssl | rm -f pub.ssl | ||||
fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/pub.ssl \ | fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/pub.ssl \ | ||||
2>${QUIETREDIR} || true | 2>${QUIETREDIR} >${INFOREDIR} || true | ||||
if ! [ -r pub.ssl ]; then | if ! [ -r pub.ssl ]; then | ||||
echo "failed." | print_error "failed to fetch public key from ${SERVERNAME}." | ||||
Not Done Inline ActionsI'd strongly recommend not using INFOREDIR as a flag, especially using negative logic. This would hurt readability and make the code hard to follow. delphij: I'd strongly recommend not using INFOREDIR as a flag, especially using negative logic. This… | |||||
Not Done Inline ActionsThe alternative is longer error messages as shown or adding an additional flag ... which is better? aryeeteygerald_rogers.com: The alternative is longer error messages as shown or adding an additional flag ... which is… | |||||
return 1 | return 1 | ||||
fi | fi | ||||
if ! [ `${SHA256} -q pub.ssl` = ${KEYPRINT} ]; then | if ! [ `${SHA256} -q pub.ssl` = ${KEYPRINT} ]; then | ||||
echo "key has incorrect hash." | print_error "public key from ${SERVERNAME} has incorrect hash." | ||||
Done Inline ActionsSimilar. delphij: Similar. | |||||
rm -f pub.ssl | rm -f pub.ssl | ||||
return 1 | return 1 | ||||
fi | fi | ||||
echo "done." | echo "done." | ||||
Done Inline ActionsSee comment above. delphij: See comment above. | |||||
} | } | ||||
# Fetch metadata signature, aka "tag". | # Fetch metadata signature, aka "tag". | ||||
fetch_tag () { | fetch_tag () { | ||||
echo -n "Fetching metadata signature " | echo -n "Fetching metadata signature " | ||||
echo ${NDEBUG} "for ${RELNUM} from ${SERVERNAME}... " | echo ${NDEBUG} "for ${RELNUM} from ${SERVERNAME}... " | ||||
rm -f latest.ssl | rm -f latest.ssl | ||||
fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/latest.ssl \ | fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/latest.ssl \ | ||||
Show All 11 Lines | if ! [ `wc -l < tag.new` = 1 ] || | ||||
! grep -qE \ | ! grep -qE \ | ||||
"^freebsd-update\|${ARCH}\|${RELNUM}\|[0-9]+\|[0-9a-f]{64}\|[0-9]{10}" \ | "^freebsd-update\|${ARCH}\|${RELNUM}\|[0-9]+\|[0-9a-f]{64}\|[0-9]{10}" \ | ||||
tag.new; then | tag.new; then | ||||
echo "invalid signature." | echo "invalid signature." | ||||
return 1 | return 1 | ||||
fi | fi | ||||
echo "done." | echo "done." | ||||
RELPATCHNUM=`cut -f 4 -d '|' < tag.new` | RELPATCHNUM=`cut -f 4 -d '|' < tag.new` | ||||
TINDEXHASH=`cut -f 5 -d '|' < tag.new` | TINDEXHASH=`cut -f 5 -d '|' < tag.new` | ||||
EOLTIME=`cut -f 6 -d '|' < tag.new` | EOLTIME=`cut -f 6 -d '|' < tag.new` | ||||
} | } | ||||
# Sanity-check the patch number in a tag, to make sure that we're not | # Sanity-check the patch number in a tag, to make sure that we're not | ||||
# going to "update" backwards and to prevent replay attacks. | # going to "update" backwards and to prevent replay attacks. | ||||
fetch_tagsanity () { | fetch_tagsanity () { | ||||
# Check that we're not going to move from -pX to -pY with Y < X. | # Check that we're not going to move from -pX to -pY with Y < X. | ||||
RELPX=`uname -r | sed -E 's,.*-,,'` | RELPX=`uname -r | sed -E 's,.*-,,'` | ||||
if echo ${RELPX} | grep -qE '^p[0-9]+$'; then | if echo ${RELPX} | grep -qE '^p[0-9]+$'; then | ||||
RELPX=`echo ${RELPX} | cut -c 2-` | RELPX=`echo ${RELPX} | cut -c 2-` | ||||
else | else | ||||
RELPX=0 | RELPX=0 | ||||
fi | fi | ||||
if [ "${RELPATCHNUM}" -lt "${RELPX}" ]; then | if [ "${RELPATCHNUM}" -lt "${RELPX}" ]; then | ||||
echo | print_error | ||||
echo -n "Files on mirror (${RELNUM}-p${RELPATCHNUM})" | print_error -n "Files on mirror (${RELNUM}-p${RELPATCHNUM})" | ||||
echo " appear older than what" | print_error " appear older than what" | ||||
echo "we are currently running (`uname -r`)!" | print_error "we are currently running (`uname -r`)!" | ||||
echo "Cowardly refusing to proceed any further." | print_error "Cowardly refusing to proceed any further." | ||||
return 1 | return 1 | ||||
fi | fi | ||||
# If "tag" exists and corresponds to ${RELNUM}, make sure that | # If "tag" exists and corresponds to ${RELNUM}, make sure that | ||||
# it contains a patch number <= RELPATCHNUM, in order to protect | # it contains a patch number <= RELPATCHNUM, in order to protect | ||||
# against rollback (replay) attacks. | # against rollback (replay) attacks. | ||||
if [ -f tag ] && | if [ -f tag ] && | ||||
grep -qE \ | grep -qE \ | ||||
"^freebsd-update\|${ARCH}\|${RELNUM}\|[0-9]+\|[0-9a-f]{64}\|[0-9]{10}" \ | "^freebsd-update\|${ARCH}\|${RELNUM}\|[0-9]+\|[0-9a-f]{64}\|[0-9]{10}" \ | ||||
tag; then | tag; then | ||||
LASTRELPATCHNUM=`cut -f 4 -d '|' < tag` | LASTRELPATCHNUM=`cut -f 4 -d '|' < tag` | ||||
if [ "${RELPATCHNUM}" -lt "${LASTRELPATCHNUM}" ]; then | if [ "${RELPATCHNUM}" -lt "${LASTRELPATCHNUM}" ]; then | ||||
echo | print_error | ||||
echo -n "Files on mirror (${RELNUM}-p${RELPATCHNUM})" | print_error -n "Files on mirror (${RELNUM}-p${RELPATCHNUM})" | ||||
echo " are older than the" | print_error " are older than the" | ||||
echo -n "most recently seen updates" | print_error -n "most recently seen updates" | ||||
echo " (${RELNUM}-p${LASTRELPATCHNUM})." | print_error " (${RELNUM}-p${LASTRELPATCHNUM})." | ||||
echo "Cowardly refusing to proceed any further." | print_error "Cowardly refusing to proceed any further." | ||||
return 1 | return 1 | ||||
fi | fi | ||||
fi | fi | ||||
} | } | ||||
# Fetch metadata index file | # Fetch metadata index file | ||||
fetch_metadata_index () { | fetch_metadata_index () { | ||||
echo ${NDEBUG} "Fetching metadata index... " | echo ${NDEBUG} "Fetching metadata index... " | ||||
rm -f ${TINDEXHASH} | rm -f ${TINDEXHASH} | ||||
fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/t/${TINDEXHASH} | fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/t/${TINDEXHASH} | ||||
2>${QUIETREDIR} | 2>${QUIETREDIR} | ||||
if ! [ -f ${TINDEXHASH} ]; then | if ! [ -f ${TINDEXHASH} ]; then | ||||
echo "failed." | echo "failed." | ||||
return 1 | return 1 | ||||
fi | fi | ||||
if [ `${SHA256} -q ${TINDEXHASH}` != ${TINDEXHASH} ]; then | if [ `${SHA256} -q ${TINDEXHASH}` != ${TINDEXHASH} ]; then | ||||
echo "update metadata index corrupt." | echo "update metadata index corrupt." | ||||
return 1 | return 1 | ||||
fi | fi | ||||
echo "done." | echo "done." | ||||
} | } | ||||
# Print an error message about signed metadata being bogus. | # Print an error message about signed metadata being bogus. | ||||
fetch_metadata_bogus () { | fetch_metadata_bogus () { | ||||
echo | print_error | ||||
echo "The update metadata$1 is correctly signed, but" | print_error "The update metadata$1 is correctly signed, but" | ||||
echo "failed an integrity check." | print_error "failed an integrity check." | ||||
echo "Cowardly refusing to proceed any further." | print_error "Cowardly refusing to proceed any further." | ||||
return 1 | return 1 | ||||
} | } | ||||
# Construct tINDEX.new by merging the lines named in $1 from ${TINDEXHASH} | # Construct tINDEX.new by merging the lines named in $1 from ${TINDEXHASH} | ||||
# with the lines not named in $@ from tINDEX.present (if that file exists). | # with the lines not named in $@ from tINDEX.present (if that file exists). | ||||
fetch_metadata_index_merge () { | fetch_metadata_index_merge () { | ||||
for METAFILE in $@; do | for METAFILE in $@; do | ||||
if [ `grep -E "^${METAFILE}\|" ${TINDEXHASH} | wc -l` \ | if [ `grep -E "^${METAFILE}\|" ${TINDEXHASH} | wc -l` \ | ||||
▲ Show 20 Lines • Show All 146 Lines • ▼ Show 20 Lines | if [ -s filelist ]; then | ||||
echo -n "Fetching `wc -l < filelist | tr -d ' '` " | echo -n "Fetching `wc -l < filelist | tr -d ' '` " | ||||
echo ${NDEBUG} "metadata files... " | echo ${NDEBUG} "metadata files... " | ||||
lam -s "${FETCHDIR}/m/" - -s ".gz" < filelist | | lam -s "${FETCHDIR}/m/" - -s ".gz" < filelist | | ||||
xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ | xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ | ||||
2>${QUIETREDIR} | 2>${QUIETREDIR} | ||||
while read Y; do | while read Y; do | ||||
if ! [ -f ${Y}.gz ]; then | if ! [ -f ${Y}.gz ]; then | ||||
echo "failed." | print_error "failed to fetch metadata files." | ||||
Done Inline ActionsSimilar. delphij: Similar. | |||||
return 1 | return 1 | ||||
fi | fi | ||||
if [ `gunzip -c < ${Y}.gz | | if [ `gunzip -c < ${Y}.gz | | ||||
${SHA256} -q` = ${Y} ]; then | ${SHA256} -q` = ${Y} ]; then | ||||
mv ${Y}.gz files/${Y}.gz | mv ${Y}.gz files/${Y}.gz | ||||
else | else | ||||
echo "metadata is corrupt." | print_error "metadata is corrupt." | ||||
return 1 | return 1 | ||||
fi | fi | ||||
done < filelist | done < filelist | ||||
echo "done." | echo "done." | ||||
fi | fi | ||||
# Sanity-check the metadata files. | # Sanity-check the metadata files. | ||||
cut -f 2 -d '|' tINDEX.new > filelist | cut -f 2 -d '|' tINDEX.new > filelist | ||||
▲ Show 20 Lines • Show All 365 Lines • ▼ Show 20 Lines | if [ -s $1 ]; then | ||||
# Actually fetch them | # Actually fetch them | ||||
lam -s "${OLDFETCHDIR}/f/" - -s ".gz" < filelist | | lam -s "${OLDFETCHDIR}/f/" - -s ".gz" < filelist | | ||||
xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ | xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ | ||||
2>${QUIETREDIR} | 2>${QUIETREDIR} | ||||
# Make sure we got them all, and move them into /files/ | # Make sure we got them all, and move them into /files/ | ||||
while read Y; do | while read Y; do | ||||
if ! [ -f ${Y}.gz ]; then | if ! [ -f ${Y}.gz ]; then | ||||
echo "failed." | print_error "failed to fetch files from ${OLDRELNUM}." | ||||
return 1 | return 1 | ||||
fi | fi | ||||
if [ `gunzip -c < ${Y}.gz | | if [ `gunzip -c < ${Y}.gz | | ||||
${SHA256} -q` = ${Y} ]; then | ${SHA256} -q` = ${Y} ]; then | ||||
mv ${Y}.gz files/${Y}.gz | mv ${Y}.gz files/${Y}.gz | ||||
else | else | ||||
echo "${Y} has incorrect hash." | print_error "${Y} from ${OLDRELNUM} has incorrect hash." | ||||
return 1 | return 1 | ||||
fi | fi | ||||
done < filelist | done < filelist | ||||
echo "done." | echo "done." | ||||
# Clean up | # Clean up | ||||
rm filelist files.wanted | rm filelist files.wanted | ||||
fi | fi | ||||
Show All 37 Lines | while read LINE; do | ||||
# Skip files we already have. | # Skip files we already have. | ||||
if [ -f files/${HASH}.gz ]; then | if [ -f files/${HASH}.gz ]; then | ||||
continue | continue | ||||
fi | fi | ||||
# Make sure the file hasn't changed. | # Make sure the file hasn't changed. | ||||
cp "${BASEDIR}/${F}" tmpfile | cp "${BASEDIR}/${F}" tmpfile | ||||
if [ `sha256 -q tmpfile` != ${HASH} ]; then | if [ `sha256 -q tmpfile` != ${HASH} ]; then | ||||
echo | print_error | ||||
echo "File changed while FreeBSD Update running: ${F}" | print_error "File changed while FreeBSD Update running: ${F}" | ||||
return 1 | return 1 | ||||
fi | fi | ||||
# Place the file into storage. | # Place the file into storage. | ||||
gzip -c < tmpfile > files/${HASH}.gz | gzip -c < tmpfile > files/${HASH}.gz | ||||
rm tmpfile | rm tmpfile | ||||
done < $2.hashes | done < $2.hashes | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | if [ -s filelist ]; then | ||||
echo -n "Fetching `wc -l < filelist | tr -d ' '` " | echo -n "Fetching `wc -l < filelist | tr -d ' '` " | ||||
echo ${NDEBUG} "files... " | echo ${NDEBUG} "files... " | ||||
lam -s "${FETCHDIR}/f/" - -s ".gz" < filelist | | lam -s "${FETCHDIR}/f/" - -s ".gz" < filelist | | ||||
xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ | xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ | ||||
2>${STATSREDIR} | fetch_progress | 2>${STATSREDIR} | fetch_progress | ||||
while read Y; do | while read Y; do | ||||
if ! [ -f ${Y}.gz ]; then | if ! [ -f ${Y}.gz ]; then | ||||
echo "failed." | print_error "failed to fetch files." | ||||
return 1 | return 1 | ||||
fi | fi | ||||
if [ `gunzip -c < ${Y}.gz | | if [ `gunzip -c < ${Y}.gz | | ||||
${SHA256} -q` = ${Y} ]; then | ${SHA256} -q` = ${Y} ]; then | ||||
mv ${Y}.gz files/${Y}.gz | mv ${Y}.gz files/${Y}.gz | ||||
else | else | ||||
echo "${Y} has incorrect hash." | print_error "${Y} has incorrect hash." | ||||
return 1 | return 1 | ||||
fi | fi | ||||
done < filelist | done < filelist | ||||
echo "done." | echo "done." | ||||
fi | fi | ||||
# Clean up | # Clean up | ||||
rm files.wanted filelist patchlist | rm files.wanted filelist patchlist | ||||
Show All 9 Lines | fetch_create_manifest () { | ||||
fi | fi | ||||
# Report to the user if any updates were avoided due to local changes | # Report to the user if any updates were avoided due to local changes | ||||
if [ -s modifiedfiles ]; then | if [ -s modifiedfiles ]; then | ||||
echo | echo | ||||
echo -n "The following files are affected by updates, " | echo -n "The following files are affected by updates, " | ||||
echo "but no changes have" | echo "but no changes have" | ||||
echo -n "been downloaded because the files have been " | echo -n "been downloaded because the files have been " | ||||
echo "modified locally:" | echo "modified locally:" | ||||
Done Inline ActionsThese are intentional. With the proposed change, the contents would no longer go to $PAGER and on typical terminals it means freebsd-update would only show a list of files, but not these descriptive messages. delphij: These are intentional. With the proposed change, the contents would no longer go to $PAGER and… | |||||
cat modifiedfiles | cat modifiedfiles | ||||
fi | $PAGER | fi | $PAGER | ||||
rm modifiedfiles | rm modifiedfiles | ||||
# If no files will be updated, tell the user and exit | # If no files will be updated, tell the user and exit | ||||
if ! [ -s INDEX-PRESENT ] && | if ! [ -s INDEX-PRESENT ] && | ||||
! [ -s INDEX-NEW ]; then | ! [ -s INDEX-NEW ]; then | ||||
rm INDEX-PRESENT INDEX-NEW | rm INDEX-PRESENT INDEX-NEW | ||||
Show All 32 Lines | fetch_create_manifest () { | ||||
fi | $PAGER | fi | $PAGER | ||||
rm files.added | rm files.added | ||||
# Report updated files, if any | # Report updated files, if any | ||||
if [ -s files.updated ]; then | if [ -s files.updated ]; then | ||||
echo | echo | ||||
echo -n "The following files will be updated " | echo -n "The following files will be updated " | ||||
echo "as part of updating to ${RELNUM}-p${RELPATCHNUM}:" | echo "as part of updating to ${RELNUM}-p${RELPATCHNUM}:" | ||||
cat files.updated | cat files.updated | ||||
fi | $PAGER | fi | $PAGER | ||||
rm files.updated | rm files.updated | ||||
# Create a directory for the install manifest. | # Create a directory for the install manifest. | ||||
MDIR=`mktemp -d install.XXXXXX` || return 1 | MDIR=`mktemp -d install.XXXXXX` || return 1 | ||||
# Populate it | # Populate it | ||||
Show All 13 Lines | fetch_warn_eol () { | ||||
if [ -f lasteolwarn ]; then | if [ -f lasteolwarn ]; then | ||||
LASTWARN=`cat lasteolwarn` | LASTWARN=`cat lasteolwarn` | ||||
else | else | ||||
LASTWARN=`expr ${NOWTIME} - 63072000` | LASTWARN=`expr ${NOWTIME} - 63072000` | ||||
fi | fi | ||||
# If the EoL time is past, warn. | # If the EoL time is past, warn. | ||||
if [ ${EOLTIME} -lt ${NOWTIME} ]; then | if [ ${EOLTIME} -lt ${NOWTIME} ]; then | ||||
echo | cat <<-EOF | print_error | ||||
cat <<-EOF | |||||
WARNING: `uname -sr` HAS PASSED ITS END-OF-LIFE DATE. | WARNING: `uname -sr` HAS PASSED ITS END-OF-LIFE DATE. | ||||
Any security issues discovered after `date -r ${EOLTIME}` | Any security issues discovered after `date -r ${EOLTIME}` | ||||
will not have been corrected. | will not have been corrected. | ||||
EOF | EOF | ||||
return 1 | return 1 | ||||
fi | fi | ||||
# Figure out how long it has been since we last warned about the | # Figure out how long it has been since we last warned about the | ||||
Show All 26 Lines | fetch_warn_eol () { | ||||
# Compute the right number of units | # Compute the right number of units | ||||
NUM=`expr ${TIMELEFT} / ${SIZE}` | NUM=`expr ${TIMELEFT} / ${SIZE}` | ||||
if [ ${NUM} != 1 ]; then | if [ ${NUM} != 1 ]; then | ||||
UNIT="${UNIT}s" | UNIT="${UNIT}s" | ||||
fi | fi | ||||
# Print the warning | # Print the warning | ||||
echo | cat <<-EOF | print_error | ||||
cat <<-EOF | |||||
WARNING: `uname -sr` is approaching its End-of-Life date. | WARNING: `uname -sr` is approaching its End-of-Life date. | ||||
It is strongly recommended that you upgrade to a newer | It is strongly recommended that you upgrade to a newer | ||||
release within the next ${NUM} ${UNIT}. | release within the next ${NUM} ${UNIT}. | ||||
EOF | EOF | ||||
# Update the stored time of last warning | # Update the stored time of last warning | ||||
echo ${NOWTIME} > lasteolwarn | echo ${NOWTIME} > lasteolwarn | ||||
} | } | ||||
▲ Show 20 Lines • Show All 626 Lines • ▼ Show 20 Lines | if [ -d $BASEDIR/$BACKUPKERNELDIR -a \ | ||||
-e $BASEDIR/$BACKUPKERNELDIR/.freebsd-update ]; then | -e $BASEDIR/$BACKUPKERNELDIR/.freebsd-update ]; then | ||||
return 0 | return 0 | ||||
fi | fi | ||||
# We could not use current directory name, so add counter to | # We could not use current directory name, so add counter to | ||||
# the end and try again. | # the end and try again. | ||||
CNT=$((CNT + 1)) | CNT=$((CNT + 1)) | ||||
if [ $CNT -gt 9 ]; then | if [ $CNT -gt 9 ]; then | ||||
echo "Could not find valid backup dir ($BASEDIR/$BACKUPKERNELDIR)" | print_error "Could not find valid backup dir ($BASEDIR/$BACKUPKERNELDIR)" | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
BACKUPKERNELDIR="`echo $BACKUPKERNELDIR | sed -Ee 's/[0-9]\$//'`" | BACKUPKERNELDIR="`echo $BACKUPKERNELDIR | sed -Ee 's/[0-9]\$//'`" | ||||
BACKUPKERNELDIR="${BACKUPKERNELDIR}${CNT}" | BACKUPKERNELDIR="${BACKUPKERNELDIR}${CNT}" | ||||
done | done | ||||
} | } | ||||
# Backup the current kernel using hardlinks, if not disabled by user. | # Backup the current kernel using hardlinks, if not disabled by user. | ||||
Show All 22 Lines | backup_kernel () { | ||||
# Create directories for backup. | # Create directories for backup. | ||||
mkdir -p $BASEDIR/$BACKUPKERNELDIR | mkdir -p $BASEDIR/$BACKUPKERNELDIR | ||||
mtree -cdn -p "${BASEDIR}/${KERNELDIR}" | \ | mtree -cdn -p "${BASEDIR}/${KERNELDIR}" | \ | ||||
mtree -Ue -p "${BASEDIR}/${BACKUPKERNELDIR}" > /dev/null | mtree -Ue -p "${BASEDIR}/${BACKUPKERNELDIR}" > /dev/null | ||||
# Mark the directory as having been created by freebsd-update. | # Mark the directory as having been created by freebsd-update. | ||||
touch $BASEDIR/$BACKUPKERNELDIR/.freebsd-update | touch $BASEDIR/$BACKUPKERNELDIR/.freebsd-update | ||||
if [ $? -ne 0 ]; then | if [ $? -ne 0 ]; then | ||||
echo "Could not create kernel backup directory" | print_error "Could not create kernel backup directory" | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
# Disable pathname expansion to be sure *.symbols is not | # Disable pathname expansion to be sure *.symbols is not | ||||
# expanded. | # expanded. | ||||
set -f | set -f | ||||
# Use find to ignore symbol files, unless disabled by user. | # Use find to ignore symbol files, unless disabled by user. | ||||
▲ Show 20 Lines • Show All 367 Lines • ▼ Show 20 Lines | done | | ||||
comm -13 - INDEX-NOTMATCHING > INDEX-NOTMATCHING.tmp | comm -13 - INDEX-NOTMATCHING > INDEX-NOTMATCHING.tmp | ||||
mv INDEX-NOTMATCHING.tmp INDEX-NOTMATCHING | mv INDEX-NOTMATCHING.tmp INDEX-NOTMATCHING | ||||
# Go through the lines and print warnings. | # Go through the lines and print warnings. | ||||
local IFS='|' | local IFS='|' | ||||
while read FPATH TYPE OWNER GROUP PERM HASH LINK P_TYPE P_OWNER P_GROUP P_PERM P_HASH P_LINK; do | while read FPATH TYPE OWNER GROUP PERM HASH LINK P_TYPE P_OWNER P_GROUP P_PERM P_HASH P_LINK; do | ||||
# Warn about different object types. | # Warn about different object types. | ||||
if ! [ "${TYPE}" = "${P_TYPE}" ]; then | if ! [ "${TYPE}" = "${P_TYPE}" ]; then | ||||
echo -n "${FPATH} is a " | echo -n "${FPATH} is a " | ||||
Done Inline ActionsThis is not needed (already redirected in line 3246). delphij: This is not needed (already redirected in line 3246). | |||||
case "${P_TYPE}" in | case "${P_TYPE}" in | ||||
f) echo -n "regular file, " | f) echo -n "regular file, " | ||||
;; | ;; | ||||
d) echo -n "directory, " | d) echo -n "directory, " | ||||
;; | ;; | ||||
L) echo -n "symlink, " | L) echo -n "symlink, " | ||||
;; | ;; | ||||
esac | esac | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | if ! [ "${HASH}" = "${P_HASH}" ]; then | ||||
echo -n "${FPATH} has SHA256 hash ${P_HASH}, " | echo -n "${FPATH} has SHA256 hash ${P_HASH}, " | ||||
echo "but should have SHA256 hash ${HASH}." | echo "but should have SHA256 hash ${HASH}." | ||||
fi | fi | ||||
fi | fi | ||||
# We don't warn about different hard links, since some | # We don't warn about different hard links, since some | ||||
# some archivers break hard links, and as long as the | # some archivers break hard links, and as long as the | ||||
# underlying data is correct they really don't matter. | # underlying data is correct they really don't matter. | ||||
done < INDEX-NOTMATCHING | done < INDEX-NOTMATCHING | print_error | ||||
# Clean up | # Clean up | ||||
rm $1 $1.noflags $1.sorted $2 INDEX-NOTMATCHING | rm $1 $1.noflags $1.sorted $2 INDEX-NOTMATCHING | ||||
} | } | ||||
# Do the work involved in comparing the system to a "known good" index | # Do the work involved in comparing the system to a "known good" index | ||||
IDS_run () { | IDS_run () { | ||||
workdir_init || return 1 | workdir_init || return 1 | ||||
# Prepare the mirror list. | # Prepare the mirror list. | ||||
fetch_pick_server_init && fetch_pick_server | fetch_pick_server_init && fetch_pick_server | ||||
# Try to fetch the public key until we run out of servers. | # Try to fetch the public key until we run out of servers. | ||||
while ! fetch_key; do | while ! fetch_key; do | ||||
fetch_pick_server || return 1 | fetch_pick_server || return 1 | ||||
done | done | ||||
# Try to fetch the metadata index signature ("tag") until we run | # Try to fetch the metadata index signature ("tag") until we run | ||||
# out of available servers; and sanity check the downloaded tag. | # out of available servers; and sanity check the downloaded tag. | ||||
while ! fetch_tag; do | while ! fetch_tag; do | ||||
fetch_pick_server || return 1 | fetch_pick_server || return 1 | ||||
done | done | ||||
fetch_tagsanity || return 1 | fetch_tagsanity || return 1 | ||||
# Fetch INDEX-OLD and INDEX-ALL. | # Fetch INDEX-OLD and INDEX-ALL. | ||||
Show All 13 Lines | IDS_run () { | ||||
fetch_filter_kernel_names INDEX-ALL ${KERNCONF} | fetch_filter_kernel_names INDEX-ALL ${KERNCONF} | ||||
# Inspect the system and generate an INDEX-PRESENT file. | # Inspect the system and generate an INDEX-PRESENT file. | ||||
fetch_inspect_system INDEX-ALL INDEX-PRESENT /dev/null || return 1 | fetch_inspect_system INDEX-ALL INDEX-PRESENT /dev/null || return 1 | ||||
# Compare INDEX-ALL and INDEX-PRESENT and print warnings about any | # Compare INDEX-ALL and INDEX-PRESENT and print warnings about any | ||||
# differences. | # differences. | ||||
IDS_compare INDEX-ALL INDEX-PRESENT | IDS_compare INDEX-ALL INDEX-PRESENT | ||||
} | } | ||||
Not Done Inline ActionsThe removal doesn't appear to be intentional? delphij: The removal doesn't appear to be intentional? | |||||
#### Main functions -- call parameter-handling and core functions | #### Main functions -- call parameter-handling and core functions | ||||
# Using the command line, configuration file, and defaults, | # Using the command line, configuration file, and defaults, | ||||
# set all the parameters which are needed later. | # set all the parameters which are needed later. | ||||
get_params () { | get_params () { | ||||
init_params | init_params | ||||
parse_cmdline $@ | parse_cmdline $@ | ||||
parse_conffile | parse_conffile | ||||
default_params | default_params | ||||
} | } | ||||
# Fetch command. Make sure that we're being called | # Fetch command. Make sure that we're being called | ||||
# interactively, then run fetch_check_params and fetch_run | # interactively, then run fetch_check_params and fetch_run | ||||
cmd_fetch () { | cmd_fetch () { | ||||
if [ ! -t 0 -a $NOTTYOK -eq 0 ]; then | if [ ! -t 0 -a $NOTTYOK -eq 0 ]; then | ||||
echo -n "`basename $0` fetch should not " | print_error -n "`basename $0` fetch should not " | ||||
echo "be run non-interactively." | print_error "be run non-interactively." | ||||
echo "Run `basename $0` cron instead." | print_error "Run `basename $0` cron instead." | ||||
exit 1 | exit 1 | ||||
fi | fi | ||||
fetch_check_params | fetch_check_params | ||||
fetch_run || exit 1 | fetch_run > ${INFOREDIR} || exit 1 | ||||
ISFETCHED=1 | ISFETCHED=1 | ||||
} | } | ||||
# Cron command. Make sure the parameters are sensible; wait | # Cron command. Make sure the parameters are sensible; wait | ||||
# rand(3600) seconds; then fetch updates. While fetching updates, | # rand(3600) seconds; then fetch updates. While fetching updates, | ||||
# send output to a temporary file; only print that file if the | # send output to a temporary file; only print that file if the | ||||
# fetching failed. | # fetching failed. | ||||
cmd_cron () { | cmd_cron () { | ||||
fetch_check_params | fetch_check_params | ||||
sleep `jot -r 1 0 3600` | sleep `jot -r 1 0 3600` | ||||
TMPFILE=`mktemp /tmp/freebsd-update.XXXXXX` || exit 1 | TMPFILE=`mktemp /tmp/freebsd-update.XXXXXX` || exit 1 | ||||
if ! fetch_run >> ${TMPFILE} || | mkfifo _fetch_results | ||||
cat _fetch_results > ${INFOREDIR} | cat - >> ${TMPFILE} & | |||||
Not Done Inline ActionsThis would probably not work in practice. Why not simply fetch_run > ${TMPFILE} 2>&1 below instead? (I don't think the >> is right in this context, because at this point the TMPFILE is guaranteed to be empty). Note that this actually could have introduced a security vulnerability, by the way. Assuming one creates a symlink called '_fetch_results', mkfifo would fail (mkfifo would EEXIST and bail out) and the output would be written with root privileges... delphij: This would probably not work in practice. Why not simply fetch_run > ${TMPFILE} 2>&1 below… | |||||
Not Done Inline ActionsYour suggestion will cause cron to ignore -q ... is this what we want? aryeeteygerald_rogers.com: Your suggestion will cause `cron` to ignore `-q` ... is this what we want? | |||||
if ! fetch_run > _fetch_results || | |||||
! grep -q "No updates needed" ${TMPFILE} || | ! grep -q "No updates needed" ${TMPFILE} || | ||||
[ ${VERBOSELEVEL} = "debug" ]; then | [ ${VERBOSELEVEL} = "debug" ]; then | ||||
mail -s "`hostname` security updates" ${MAILTO} < ${TMPFILE} | mail -s "`hostname` security updates" ${MAILTO} < ${TMPFILE} | ||||
fi | fi | ||||
rm ${TMPFILE} | rm ${TMPFILE} | ||||
} | } | ||||
Show All 13 Lines | |||||
cmd_rollback () { | cmd_rollback () { | ||||
rollback_check_params | rollback_check_params | ||||
rollback_run || exit 1 | rollback_run || exit 1 | ||||
} | } | ||||
# Compare system against a "known good" index. | # Compare system against a "known good" index. | ||||
cmd_IDS () { | cmd_IDS () { | ||||
IDS_check_params | IDS_check_params | ||||
IDS_run || exit 1 | IDS_run > ${INFOREDIR} || exit 1 | ||||
} | } | ||||
#### Entry point | #### Entry point | ||||
# Make sure we find utilities from the base system | # Make sure we find utilities from the base system | ||||
export PATH=/sbin:/bin:/usr/sbin:/usr/bin:${PATH} | export PATH=/sbin:/bin:/usr/sbin:/usr/bin:${PATH} | ||||
# Set a pager if the user doesn't | # Set a pager if the user doesn't | ||||
Show All 11 Lines |
In quiet mode, shouldn't this be omitted (also the "done." in line 1164)?