xref: /freebsd/usr.sbin/freebsd-update/freebsd-update.sh (revision 75cb6429f5ae7ead3c83a7a531561c9b36bb7dcc)
148ffe56aSColin Percival#!/bin/sh
248ffe56aSColin Percival
348ffe56aSColin Percival#-
41de7b4b8SPedro F. Giffuni# SPDX-License-Identifier: BSD-2-Clause-FreeBSD
51de7b4b8SPedro F. Giffuni#
62328d598SColin Percival# Copyright 2004-2007 Colin Percival
748ffe56aSColin Percival# All rights reserved
848ffe56aSColin Percival#
948ffe56aSColin Percival# Redistribution and use in source and binary forms, with or without
1048ffe56aSColin Percival# modification, are permitted providing that the following conditions
1148ffe56aSColin Percival# are met:
1248ffe56aSColin Percival# 1. Redistributions of source code must retain the above copyright
1348ffe56aSColin Percival#    notice, this list of conditions and the following disclaimer.
1448ffe56aSColin Percival# 2. Redistributions in binary form must reproduce the above copyright
1548ffe56aSColin Percival#    notice, this list of conditions and the following disclaimer in the
1648ffe56aSColin Percival#    documentation and/or other materials provided with the distribution.
1748ffe56aSColin Percival#
1848ffe56aSColin Percival# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1948ffe56aSColin Percival# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2048ffe56aSColin Percival# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2148ffe56aSColin Percival# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
2248ffe56aSColin Percival# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2348ffe56aSColin Percival# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2448ffe56aSColin Percival# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2548ffe56aSColin Percival# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2648ffe56aSColin Percival# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
2748ffe56aSColin Percival# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2848ffe56aSColin Percival# POSSIBILITY OF SUCH DAMAGE.
2948ffe56aSColin Percival
3048ffe56aSColin Percival# $FreeBSD$
3148ffe56aSColin Percival
3248ffe56aSColin Percival#### Usage function -- called from command-line handling code.
3348ffe56aSColin Percival
3448ffe56aSColin Percival# Usage instructions.  Options not listed:
3548ffe56aSColin Percival# --debug	-- don't filter output from utilities
3648ffe56aSColin Percival# --no-stats	-- don't show progress statistics while fetching files
3748ffe56aSColin Percivalusage () {
3848ffe56aSColin Percival	cat <<EOF
3948ffe56aSColin Percivalusage: `basename $0` [options] command ... [path]
4048ffe56aSColin Percival
4148ffe56aSColin PercivalOptions:
4248ffe56aSColin Percival  -b basedir   -- Operate on a system mounted at basedir
4348ffe56aSColin Percival                  (default: /)
4448ffe56aSColin Percival  -d workdir   -- Store working files in workdir
4548ffe56aSColin Percival                  (default: /var/db/freebsd-update/)
4648ffe56aSColin Percival  -f conffile  -- Read configuration options from conffile
4748ffe56aSColin Percival                  (default: /etc/freebsd-update.conf)
48df7e2e0dSEd Maste  -F           -- Force a fetch operation to proceed in the
49df7e2e0dSEd Maste                  case of an unfinished upgrade
5048ffe56aSColin Percival  -k KEY       -- Trust an RSA key with SHA256 hash of KEY
51dd917c79SGleb Smirnoff  -r release   -- Target for upgrade (e.g., 11.1-RELEASE)
5248ffe56aSColin Percival  -s server    -- Server from which to fetch updates
5348ffe56aSColin Percival                  (default: update.FreeBSD.org)
5448ffe56aSColin Percival  -t address   -- Mail output of cron command, if any, to address
5548ffe56aSColin Percival                  (default: root)
568935f242SAllan Jude  --not-running-from-cron
578935f242SAllan Jude               -- Run without a tty, for use by automated tools
58b39ce43eSColin Percival  --currently-running release
59b39ce43eSColin Percival               -- Update as if currently running this release
6048ffe56aSColin PercivalCommands:
6148ffe56aSColin Percival  fetch        -- Fetch updates from server
6248ffe56aSColin Percival  cron         -- Sleep rand(3600) seconds, fetch updates, and send an
6348ffe56aSColin Percival                  email if updates were found
64db6b0a61SColin Percival  upgrade      -- Fetch upgrades to FreeBSD version specified via -r option
65db6b0a61SColin Percival  install      -- Install downloaded updates or upgrades
6648ffe56aSColin Percival  rollback     -- Uninstall most recently installed updates
67*75cb6429SEd Maste  IDS          -- Compare the system against an index of "known good" files
6848ffe56aSColin PercivalEOF
6948ffe56aSColin Percival	exit 0
7048ffe56aSColin Percival}
7148ffe56aSColin Percival
7248ffe56aSColin Percival#### Configuration processing functions
7348ffe56aSColin Percival
7448ffe56aSColin Percival#-
7548ffe56aSColin Percival# Configuration options are set in the following order of priority:
7648ffe56aSColin Percival# 1. Command line options
7748ffe56aSColin Percival# 2. Configuration file options
7848ffe56aSColin Percival# 3. Default options
7948ffe56aSColin Percival# In addition, certain options (e.g., IgnorePaths) can be specified multiple
8048ffe56aSColin Percival# times and (as long as these are all in the same place, e.g., inside the
8148ffe56aSColin Percival# configuration file) they will accumulate.  Finally, because the path to the
8248ffe56aSColin Percival# configuration file can be specified at the command line, the entire command
8348ffe56aSColin Percival# line must be processed before we start reading the configuration file.
8448ffe56aSColin Percival#
8548ffe56aSColin Percival# Sound like a mess?  It is.  Here's how we handle this:
8648ffe56aSColin Percival# 1. Initialize CONFFILE and all the options to "".
8748ffe56aSColin Percival# 2. Process the command line.  Throw an error if a non-accumulating option
8848ffe56aSColin Percival#    is specified twice.
8948ffe56aSColin Percival# 3. If CONFFILE is "", set CONFFILE to /etc/freebsd-update.conf .
9048ffe56aSColin Percival# 4. For all the configuration options X, set X_saved to X.
9148ffe56aSColin Percival# 5. Initialize all the options to "".
9248ffe56aSColin Percival# 6. Read CONFFILE line by line, parsing options.
9348ffe56aSColin Percival# 7. For each configuration option X, set X to X_saved iff X_saved is not "".
9448ffe56aSColin Percival# 8. Repeat steps 4-7, except setting options to their default values at (6).
9548ffe56aSColin Percival
9648ffe56aSColin PercivalCONFIGOPTIONS="KEYPRINT WORKDIR SERVERNAME MAILTO ALLOWADD ALLOWDELETE
9748ffe56aSColin Percival    KEEPMODIFIEDMETADATA COMPONENTS IGNOREPATHS UPDATEIFUNMODIFIED
9808e23beeSColin Percival    BASEDIR VERBOSELEVEL TARGETRELEASE STRICTCOMPONENTS MERGECHANGES
9923d827efSSimon L. B. Nielsen    IDSIGNOREPATHS BACKUPKERNEL BACKUPKERNELDIR BACKUPKERNELSYMBOLFILES"
10048ffe56aSColin Percival
10148ffe56aSColin Percival# Set all the configuration options to "".
10248ffe56aSColin Percivalnullconfig () {
10348ffe56aSColin Percival	for X in ${CONFIGOPTIONS}; do
10448ffe56aSColin Percival		eval ${X}=""
10548ffe56aSColin Percival	done
10648ffe56aSColin Percival}
10748ffe56aSColin Percival
10848ffe56aSColin Percival# For each configuration option X, set X_saved to X.
10948ffe56aSColin Percivalsaveconfig () {
11048ffe56aSColin Percival	for X in ${CONFIGOPTIONS}; do
11148ffe56aSColin Percival		eval ${X}_saved=\$${X}
11248ffe56aSColin Percival	done
11348ffe56aSColin Percival}
11448ffe56aSColin Percival
11548ffe56aSColin Percival# For each configuration option X, set X to X_saved if X_saved is not "".
11648ffe56aSColin Percivalmergeconfig () {
11748ffe56aSColin Percival	for X in ${CONFIGOPTIONS}; do
11848ffe56aSColin Percival		eval _=\$${X}_saved
11948ffe56aSColin Percival		if ! [ -z "${_}" ]; then
12048ffe56aSColin Percival			eval ${X}=\$${X}_saved
12148ffe56aSColin Percival		fi
12248ffe56aSColin Percival	done
12348ffe56aSColin Percival}
12448ffe56aSColin Percival
12548ffe56aSColin Percival# Set the trusted keyprint.
12648ffe56aSColin Percivalconfig_KeyPrint () {
12748ffe56aSColin Percival	if [ -z ${KEYPRINT} ]; then
12848ffe56aSColin Percival		KEYPRINT=$1
12948ffe56aSColin Percival	else
13048ffe56aSColin Percival		return 1
13148ffe56aSColin Percival	fi
13248ffe56aSColin Percival}
13348ffe56aSColin Percival
13448ffe56aSColin Percival# Set the working directory.
13548ffe56aSColin Percivalconfig_WorkDir () {
13648ffe56aSColin Percival	if [ -z ${WORKDIR} ]; then
13748ffe56aSColin Percival		WORKDIR=$1
13848ffe56aSColin Percival	else
13948ffe56aSColin Percival		return 1
14048ffe56aSColin Percival	fi
14148ffe56aSColin Percival}
14248ffe56aSColin Percival
14348ffe56aSColin Percival# Set the name of the server (pool) from which to fetch updates
14448ffe56aSColin Percivalconfig_ServerName () {
14548ffe56aSColin Percival	if [ -z ${SERVERNAME} ]; then
14648ffe56aSColin Percival		SERVERNAME=$1
14748ffe56aSColin Percival	else
14848ffe56aSColin Percival		return 1
14948ffe56aSColin Percival	fi
15048ffe56aSColin Percival}
15148ffe56aSColin Percival
15248ffe56aSColin Percival# Set the address to which 'cron' output will be mailed.
15348ffe56aSColin Percivalconfig_MailTo () {
15448ffe56aSColin Percival	if [ -z ${MAILTO} ]; then
15548ffe56aSColin Percival		MAILTO=$1
15648ffe56aSColin Percival	else
15748ffe56aSColin Percival		return 1
15848ffe56aSColin Percival	fi
15948ffe56aSColin Percival}
16048ffe56aSColin Percival
16148ffe56aSColin Percival# Set whether FreeBSD Update is allowed to add files (or directories, or
16248ffe56aSColin Percival# symlinks) which did not previously exist.
16348ffe56aSColin Percivalconfig_AllowAdd () {
16448ffe56aSColin Percival	if [ -z ${ALLOWADD} ]; then
16548ffe56aSColin Percival		case $1 in
16648ffe56aSColin Percival		[Yy][Ee][Ss])
16748ffe56aSColin Percival			ALLOWADD=yes
16848ffe56aSColin Percival			;;
16948ffe56aSColin Percival		[Nn][Oo])
17048ffe56aSColin Percival			ALLOWADD=no
17148ffe56aSColin Percival			;;
17248ffe56aSColin Percival		*)
17348ffe56aSColin Percival			return 1
17448ffe56aSColin Percival			;;
17548ffe56aSColin Percival		esac
17648ffe56aSColin Percival	else
17748ffe56aSColin Percival		return 1
17848ffe56aSColin Percival	fi
17948ffe56aSColin Percival}
18048ffe56aSColin Percival
18148ffe56aSColin Percival# Set whether FreeBSD Update is allowed to remove files/directories/symlinks.
18248ffe56aSColin Percivalconfig_AllowDelete () {
18348ffe56aSColin Percival	if [ -z ${ALLOWDELETE} ]; then
18448ffe56aSColin Percival		case $1 in
18548ffe56aSColin Percival		[Yy][Ee][Ss])
18648ffe56aSColin Percival			ALLOWDELETE=yes
18748ffe56aSColin Percival			;;
18848ffe56aSColin Percival		[Nn][Oo])
18948ffe56aSColin Percival			ALLOWDELETE=no
19048ffe56aSColin Percival			;;
19148ffe56aSColin Percival		*)
19248ffe56aSColin Percival			return 1
19348ffe56aSColin Percival			;;
19448ffe56aSColin Percival		esac
19548ffe56aSColin Percival	else
19648ffe56aSColin Percival		return 1
19748ffe56aSColin Percival	fi
19848ffe56aSColin Percival}
19948ffe56aSColin Percival
20048ffe56aSColin Percival# Set whether FreeBSD Update should keep existing inode ownership,
20148ffe56aSColin Percival# permissions, and flags, in the event that they have been modified locally
20248ffe56aSColin Percival# after the release.
20348ffe56aSColin Percivalconfig_KeepModifiedMetadata () {
20448ffe56aSColin Percival	if [ -z ${KEEPMODIFIEDMETADATA} ]; then
20548ffe56aSColin Percival		case $1 in
20648ffe56aSColin Percival		[Yy][Ee][Ss])
20748ffe56aSColin Percival			KEEPMODIFIEDMETADATA=yes
20848ffe56aSColin Percival			;;
20948ffe56aSColin Percival		[Nn][Oo])
21048ffe56aSColin Percival			KEEPMODIFIEDMETADATA=no
21148ffe56aSColin Percival			;;
21248ffe56aSColin Percival		*)
21348ffe56aSColin Percival			return 1
21448ffe56aSColin Percival			;;
21548ffe56aSColin Percival		esac
21648ffe56aSColin Percival	else
21748ffe56aSColin Percival		return 1
21848ffe56aSColin Percival	fi
21948ffe56aSColin Percival}
22048ffe56aSColin Percival
22148ffe56aSColin Percival# Add to the list of components which should be kept updated.
22248ffe56aSColin Percivalconfig_Components () {
22348ffe56aSColin Percival	for C in $@; do
2245a74378cSXin LI		if [ "$C" = "src" ]; then
225cfd9be9cSEd Maste			if [ -e "${BASEDIR}/usr/src/COPYRIGHT" ]; then
22648ffe56aSColin Percival				COMPONENTS="${COMPONENTS} ${C}"
2275a74378cSXin LI			else
2285a74378cSXin LI				echo "src component not installed, skipped"
2295a74378cSXin LI			fi
2305a74378cSXin LI		else
2315a74378cSXin LI			COMPONENTS="${COMPONENTS} ${C}"
2325a74378cSXin LI		fi
23348ffe56aSColin Percival	done
23448ffe56aSColin Percival}
23548ffe56aSColin Percival
23648ffe56aSColin Percival# Add to the list of paths under which updates will be ignored.
23748ffe56aSColin Percivalconfig_IgnorePaths () {
23848ffe56aSColin Percival	for C in $@; do
23948ffe56aSColin Percival		IGNOREPATHS="${IGNOREPATHS} ${C}"
24048ffe56aSColin Percival	done
24148ffe56aSColin Percival}
24248ffe56aSColin Percival
24308e23beeSColin Percival# Add to the list of paths which IDS should ignore.
24408e23beeSColin Percivalconfig_IDSIgnorePaths () {
24508e23beeSColin Percival	for C in $@; do
24608e23beeSColin Percival		IDSIGNOREPATHS="${IDSIGNOREPATHS} ${C}"
24708e23beeSColin Percival	done
24808e23beeSColin Percival}
24908e23beeSColin Percival
25048ffe56aSColin Percival# Add to the list of paths within which updates will be performed only if the
25148ffe56aSColin Percival# file on disk has not been modified locally.
25248ffe56aSColin Percivalconfig_UpdateIfUnmodified () {
25348ffe56aSColin Percival	for C in $@; do
25448ffe56aSColin Percival		UPDATEIFUNMODIFIED="${UPDATEIFUNMODIFIED} ${C}"
25548ffe56aSColin Percival	done
25648ffe56aSColin Percival}
25748ffe56aSColin Percival
258db6b0a61SColin Percival# Add to the list of paths within which updates to text files will be merged
259db6b0a61SColin Percival# instead of overwritten.
260db6b0a61SColin Percivalconfig_MergeChanges () {
261db6b0a61SColin Percival	for C in $@; do
262db6b0a61SColin Percival		MERGECHANGES="${MERGECHANGES} ${C}"
263db6b0a61SColin Percival	done
264db6b0a61SColin Percival}
265db6b0a61SColin Percival
26648ffe56aSColin Percival# Work on a FreeBSD installation mounted under $1
26748ffe56aSColin Percivalconfig_BaseDir () {
26848ffe56aSColin Percival	if [ -z ${BASEDIR} ]; then
26948ffe56aSColin Percival		BASEDIR=$1
27048ffe56aSColin Percival	else
27148ffe56aSColin Percival		return 1
27248ffe56aSColin Percival	fi
27348ffe56aSColin Percival}
27448ffe56aSColin Percival
275db6b0a61SColin Percival# When fetching upgrades, should we assume the user wants exactly the
276db6b0a61SColin Percival# components listed in COMPONENTS, rather than trying to guess based on
277db6b0a61SColin Percival# what's currently installed?
278db6b0a61SColin Percivalconfig_StrictComponents () {
279db6b0a61SColin Percival	if [ -z ${STRICTCOMPONENTS} ]; then
280db6b0a61SColin Percival		case $1 in
281db6b0a61SColin Percival		[Yy][Ee][Ss])
282db6b0a61SColin Percival			STRICTCOMPONENTS=yes
283db6b0a61SColin Percival			;;
284db6b0a61SColin Percival		[Nn][Oo])
285db6b0a61SColin Percival			STRICTCOMPONENTS=no
286db6b0a61SColin Percival			;;
287db6b0a61SColin Percival		*)
288db6b0a61SColin Percival			return 1
289db6b0a61SColin Percival			;;
290db6b0a61SColin Percival		esac
291db6b0a61SColin Percival	else
292db6b0a61SColin Percival		return 1
293db6b0a61SColin Percival	fi
294db6b0a61SColin Percival}
295db6b0a61SColin Percival
296db6b0a61SColin Percival# Upgrade to FreeBSD $1
297db6b0a61SColin Percivalconfig_TargetRelease () {
298db6b0a61SColin Percival	if [ -z ${TARGETRELEASE} ]; then
299db6b0a61SColin Percival		TARGETRELEASE=$1
300db6b0a61SColin Percival	else
301db6b0a61SColin Percival		return 1
302db6b0a61SColin Percival	fi
303d23dc1eeSColin Percival	if echo ${TARGETRELEASE} | grep -qE '^[0-9.]+$'; then
304d23dc1eeSColin Percival		TARGETRELEASE="${TARGETRELEASE}-RELEASE"
305d23dc1eeSColin Percival	fi
306db6b0a61SColin Percival}
307db6b0a61SColin Percival
3080d5c5243SEd Maste# Pretend current release is FreeBSD $1
3090d5c5243SEd Masteconfig_SourceRelease () {
3100d5c5243SEd Maste	UNAME_r=$1
3110d5c5243SEd Maste	if echo ${UNAME_r} | grep -qE '^[0-9.]+$'; then
3120d5c5243SEd Maste		UNAME_r="${UNAME_r}-RELEASE"
3130d5c5243SEd Maste	fi
314b958d4b2SEd Maste	export UNAME_r
3150d5c5243SEd Maste}
3160d5c5243SEd Maste
31748ffe56aSColin Percival# Define what happens to output of utilities
31848ffe56aSColin Percivalconfig_VerboseLevel () {
31948ffe56aSColin Percival	if [ -z ${VERBOSELEVEL} ]; then
32048ffe56aSColin Percival		case $1 in
32148ffe56aSColin Percival		[Dd][Ee][Bb][Uu][Gg])
32248ffe56aSColin Percival			VERBOSELEVEL=debug
32348ffe56aSColin Percival			;;
32448ffe56aSColin Percival		[Nn][Oo][Ss][Tt][Aa][Tt][Ss])
32548ffe56aSColin Percival			VERBOSELEVEL=nostats
32648ffe56aSColin Percival			;;
32748ffe56aSColin Percival		[Ss][Tt][Aa][Tt][Ss])
32848ffe56aSColin Percival			VERBOSELEVEL=stats
32948ffe56aSColin Percival			;;
33048ffe56aSColin Percival		*)
33148ffe56aSColin Percival			return 1
33248ffe56aSColin Percival			;;
33348ffe56aSColin Percival		esac
33448ffe56aSColin Percival	else
33548ffe56aSColin Percival		return 1
33648ffe56aSColin Percival	fi
33748ffe56aSColin Percival}
33848ffe56aSColin Percival
33923d827efSSimon L. B. Nielsenconfig_BackupKernel () {
34023d827efSSimon L. B. Nielsen	if [ -z ${BACKUPKERNEL} ]; then
34123d827efSSimon L. B. Nielsen		case $1 in
34223d827efSSimon L. B. Nielsen		[Yy][Ee][Ss])
34323d827efSSimon L. B. Nielsen			BACKUPKERNEL=yes
34423d827efSSimon L. B. Nielsen			;;
34523d827efSSimon L. B. Nielsen		[Nn][Oo])
34623d827efSSimon L. B. Nielsen			BACKUPKERNEL=no
34723d827efSSimon L. B. Nielsen			;;
34823d827efSSimon L. B. Nielsen		*)
34923d827efSSimon L. B. Nielsen			return 1
35023d827efSSimon L. B. Nielsen			;;
35123d827efSSimon L. B. Nielsen		esac
35223d827efSSimon L. B. Nielsen	else
35323d827efSSimon L. B. Nielsen		return 1
35423d827efSSimon L. B. Nielsen	fi
35523d827efSSimon L. B. Nielsen}
35623d827efSSimon L. B. Nielsen
35723d827efSSimon L. B. Nielsenconfig_BackupKernelDir () {
35823d827efSSimon L. B. Nielsen	if [ -z ${BACKUPKERNELDIR} ]; then
35923d827efSSimon L. B. Nielsen		if [ -z "$1" ]; then
36023d827efSSimon L. B. Nielsen			echo "BackupKernelDir set to empty dir"
36123d827efSSimon L. B. Nielsen			return 1
36223d827efSSimon L. B. Nielsen		fi
36323d827efSSimon L. B. Nielsen
36423d827efSSimon L. B. Nielsen		# We check for some paths which would be extremely odd
36523d827efSSimon L. B. Nielsen		# to use, but which could cause a lot of problems if
36623d827efSSimon L. B. Nielsen		# used.
36723d827efSSimon L. B. Nielsen		case $1 in
36823d827efSSimon L. B. Nielsen		/|/bin|/boot|/etc|/lib|/libexec|/sbin|/usr|/var)
36923d827efSSimon L. B. Nielsen			echo "BackupKernelDir set to invalid path $1"
37023d827efSSimon L. B. Nielsen			return 1
37123d827efSSimon L. B. Nielsen			;;
37223d827efSSimon L. B. Nielsen		/*)
37323d827efSSimon L. B. Nielsen			BACKUPKERNELDIR=$1
37423d827efSSimon L. B. Nielsen			;;
37523d827efSSimon L. B. Nielsen		*)
37623d827efSSimon L. B. Nielsen			echo "BackupKernelDir ($1) is not an absolute path"
37723d827efSSimon L. B. Nielsen			return 1
37823d827efSSimon L. B. Nielsen			;;
37923d827efSSimon L. B. Nielsen		esac
38023d827efSSimon L. B. Nielsen	else
38123d827efSSimon L. B. Nielsen		return 1
38223d827efSSimon L. B. Nielsen	fi
38323d827efSSimon L. B. Nielsen}
38423d827efSSimon L. B. Nielsen
38523d827efSSimon L. B. Nielsenconfig_BackupKernelSymbolFiles () {
38623d827efSSimon L. B. Nielsen	if [ -z ${BACKUPKERNELSYMBOLFILES} ]; then
38723d827efSSimon L. B. Nielsen		case $1 in
38823d827efSSimon L. B. Nielsen		[Yy][Ee][Ss])
38923d827efSSimon L. B. Nielsen			BACKUPKERNELSYMBOLFILES=yes
39023d827efSSimon L. B. Nielsen			;;
39123d827efSSimon L. B. Nielsen		[Nn][Oo])
39223d827efSSimon L. B. Nielsen			BACKUPKERNELSYMBOLFILES=no
39323d827efSSimon L. B. Nielsen			;;
39423d827efSSimon L. B. Nielsen		*)
39523d827efSSimon L. B. Nielsen			return 1
39623d827efSSimon L. B. Nielsen			;;
39723d827efSSimon L. B. Nielsen		esac
39823d827efSSimon L. B. Nielsen	else
39923d827efSSimon L. B. Nielsen		return 1
40023d827efSSimon L. B. Nielsen	fi
40123d827efSSimon L. B. Nielsen}
40223d827efSSimon L. B. Nielsen
40348ffe56aSColin Percival# Handle one line of configuration
40448ffe56aSColin Percivalconfigline () {
40548ffe56aSColin Percival	if [ $# -eq 0 ]; then
40648ffe56aSColin Percival		return
40748ffe56aSColin Percival	fi
40848ffe56aSColin Percival
40948ffe56aSColin Percival	OPT=$1
41048ffe56aSColin Percival	shift
41148ffe56aSColin Percival	config_${OPT} $@
41248ffe56aSColin Percival}
41348ffe56aSColin Percival
41448ffe56aSColin Percival#### Parameter handling functions.
41548ffe56aSColin Percival
41648ffe56aSColin Percival# Initialize parameters to null, just in case they're
41748ffe56aSColin Percival# set in the environment.
41848ffe56aSColin Percivalinit_params () {
41948ffe56aSColin Percival	# Configration settings
42048ffe56aSColin Percival	nullconfig
42148ffe56aSColin Percival
42248ffe56aSColin Percival	# No configuration file set yet
42348ffe56aSColin Percival	CONFFILE=""
42448ffe56aSColin Percival
42548ffe56aSColin Percival	# No commands specified yet
42648ffe56aSColin Percival	COMMANDS=""
4278935f242SAllan Jude
4288935f242SAllan Jude	# Force fetch to proceed
4298935f242SAllan Jude	FORCEFETCH=0
4308935f242SAllan Jude
4318935f242SAllan Jude	# Run without a TTY
4328935f242SAllan Jude	NOTTYOK=0
43333bd05c3SGuangyuan Yang
43433bd05c3SGuangyuan Yang	# Fetched first in a chain of commands
43533bd05c3SGuangyuan Yang	ISFETCHED=0
43648ffe56aSColin Percival}
43748ffe56aSColin Percival
43848ffe56aSColin Percival# Parse the command line
43948ffe56aSColin Percivalparse_cmdline () {
44048ffe56aSColin Percival	while [ $# -gt 0 ]; do
44148ffe56aSColin Percival		case "$1" in
44248ffe56aSColin Percival		# Location of configuration file
44348ffe56aSColin Percival		-f)
44448ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi
44548ffe56aSColin Percival			if [ ! -z "${CONFFILE}" ]; then usage; fi
44648ffe56aSColin Percival			shift; CONFFILE="$1"
44748ffe56aSColin Percival			;;
4488935f242SAllan Jude		-F)
4498935f242SAllan Jude			FORCEFETCH=1
4508935f242SAllan Jude			;;
4518935f242SAllan Jude		--not-running-from-cron)
4528935f242SAllan Jude			NOTTYOK=1
4538935f242SAllan Jude			;;
454b39ce43eSColin Percival		--currently-running)
4550d5c5243SEd Maste			shift
4560d5c5243SEd Maste			config_SourceRelease $1 || usage
457b39ce43eSColin Percival			;;
45848ffe56aSColin Percival
45948ffe56aSColin Percival		# Configuration file equivalents
46048ffe56aSColin Percival		-b)
46148ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
46248ffe56aSColin Percival			config_BaseDir $1 || usage
46348ffe56aSColin Percival			;;
46448ffe56aSColin Percival		-d)
46548ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
46648ffe56aSColin Percival			config_WorkDir $1 || usage
46748ffe56aSColin Percival			;;
46848ffe56aSColin Percival		-k)
46948ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
47048ffe56aSColin Percival			config_KeyPrint $1 || usage
47148ffe56aSColin Percival			;;
47248ffe56aSColin Percival		-s)
47348ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
47448ffe56aSColin Percival			config_ServerName $1 || usage
47548ffe56aSColin Percival			;;
476db6b0a61SColin Percival		-r)
477db6b0a61SColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
478db6b0a61SColin Percival			config_TargetRelease $1 || usage
479db6b0a61SColin Percival			;;
48048ffe56aSColin Percival		-t)
48148ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
48248ffe56aSColin Percival			config_MailTo $1 || usage
48348ffe56aSColin Percival			;;
48448ffe56aSColin Percival		-v)
48548ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
48648ffe56aSColin Percival			config_VerboseLevel $1 || usage
48748ffe56aSColin Percival			;;
48848ffe56aSColin Percival
48948ffe56aSColin Percival		# Aliases for "-v debug" and "-v nostats"
49048ffe56aSColin Percival		--debug)
49148ffe56aSColin Percival			config_VerboseLevel debug || usage
49248ffe56aSColin Percival			;;
49348ffe56aSColin Percival		--no-stats)
49448ffe56aSColin Percival			config_VerboseLevel nostats || usage
49548ffe56aSColin Percival			;;
49648ffe56aSColin Percival
49748ffe56aSColin Percival		# Commands
49808e23beeSColin Percival		cron | fetch | upgrade | install | rollback | IDS)
49948ffe56aSColin Percival			COMMANDS="${COMMANDS} $1"
50048ffe56aSColin Percival			;;
50148ffe56aSColin Percival
50248ffe56aSColin Percival		# Anything else is an error
50348ffe56aSColin Percival		*)
50448ffe56aSColin Percival			usage
50548ffe56aSColin Percival			;;
50648ffe56aSColin Percival		esac
50748ffe56aSColin Percival		shift
50848ffe56aSColin Percival	done
50948ffe56aSColin Percival
51048ffe56aSColin Percival	# Make sure we have at least one command
51148ffe56aSColin Percival	if [ -z "${COMMANDS}" ]; then
51248ffe56aSColin Percival		usage
51348ffe56aSColin Percival	fi
51448ffe56aSColin Percival}
51548ffe56aSColin Percival
51648ffe56aSColin Percival# Parse the configuration file
51748ffe56aSColin Percivalparse_conffile () {
51848ffe56aSColin Percival	# If a configuration file was specified on the command line, check
51948ffe56aSColin Percival	# that it exists and is readable.
52048ffe56aSColin Percival	if [ ! -z "${CONFFILE}" ] && [ ! -r "${CONFFILE}" ]; then
52148ffe56aSColin Percival		echo -n "File does not exist "
52248ffe56aSColin Percival		echo -n "or is not readable: "
52348ffe56aSColin Percival		echo ${CONFFILE}
52448ffe56aSColin Percival		exit 1
52548ffe56aSColin Percival	fi
52648ffe56aSColin Percival
52748ffe56aSColin Percival	# If a configuration file was not specified on the command line,
52848ffe56aSColin Percival	# use the default configuration file path.  If that default does
52948ffe56aSColin Percival	# not exist, give up looking for any configuration.
53048ffe56aSColin Percival	if [ -z "${CONFFILE}" ]; then
53148ffe56aSColin Percival		CONFFILE="/etc/freebsd-update.conf"
53248ffe56aSColin Percival		if [ ! -r "${CONFFILE}" ]; then
53348ffe56aSColin Percival			return
53448ffe56aSColin Percival		fi
53548ffe56aSColin Percival	fi
53648ffe56aSColin Percival
53748ffe56aSColin Percival	# Save the configuration options specified on the command line, and
53848ffe56aSColin Percival	# clear all the options in preparation for reading the config file.
53948ffe56aSColin Percival	saveconfig
54048ffe56aSColin Percival	nullconfig
54148ffe56aSColin Percival
54248ffe56aSColin Percival	# Read the configuration file.  Anything after the first '#' is
54348ffe56aSColin Percival	# ignored, and any blank lines are ignored.
54448ffe56aSColin Percival	L=0
54548ffe56aSColin Percival	while read LINE; do
54648ffe56aSColin Percival		L=$(($L + 1))
54748ffe56aSColin Percival		LINEX=`echo "${LINE}" | cut -f 1 -d '#'`
54848ffe56aSColin Percival		if ! configline ${LINEX}; then
54948ffe56aSColin Percival			echo "Error processing configuration file, line $L:"
55048ffe56aSColin Percival			echo "==> ${LINE}"
55148ffe56aSColin Percival			exit 1
55248ffe56aSColin Percival		fi
55348ffe56aSColin Percival	done < ${CONFFILE}
55448ffe56aSColin Percival
55548ffe56aSColin Percival	# Merge the settings read from the configuration file with those
55648ffe56aSColin Percival	# provided at the command line.
55748ffe56aSColin Percival	mergeconfig
55848ffe56aSColin Percival}
55948ffe56aSColin Percival
56048ffe56aSColin Percival# Provide some default parameters
56148ffe56aSColin Percivaldefault_params () {
56248ffe56aSColin Percival	# Save any parameters already configured, and clear the slate
56348ffe56aSColin Percival	saveconfig
56448ffe56aSColin Percival	nullconfig
56548ffe56aSColin Percival
56648ffe56aSColin Percival	# Default configurations
56748ffe56aSColin Percival	config_WorkDir /var/db/freebsd-update
56848ffe56aSColin Percival	config_MailTo root
56948ffe56aSColin Percival	config_AllowAdd yes
57048ffe56aSColin Percival	config_AllowDelete yes
57148ffe56aSColin Percival	config_KeepModifiedMetadata yes
57248ffe56aSColin Percival	config_BaseDir /
57348ffe56aSColin Percival	config_VerboseLevel stats
574db6b0a61SColin Percival	config_StrictComponents no
57523d827efSSimon L. B. Nielsen	config_BackupKernel yes
57623d827efSSimon L. B. Nielsen	config_BackupKernelDir /boot/kernel.old
57723d827efSSimon L. B. Nielsen	config_BackupKernelSymbolFiles no
57848ffe56aSColin Percival
57948ffe56aSColin Percival	# Merge these defaults into the earlier-configured settings
58048ffe56aSColin Percival	mergeconfig
58148ffe56aSColin Percival}
58248ffe56aSColin Percival
58348ffe56aSColin Percival# Set utility output filtering options, based on ${VERBOSELEVEL}
58448ffe56aSColin Percivalfetch_setup_verboselevel () {
58548ffe56aSColin Percival	case ${VERBOSELEVEL} in
58648ffe56aSColin Percival	debug)
58748ffe56aSColin Percival		QUIETREDIR="/dev/stderr"
58848ffe56aSColin Percival		QUIETFLAG=" "
58948ffe56aSColin Percival		STATSREDIR="/dev/stderr"
59048ffe56aSColin Percival		DDSTATS=".."
59148ffe56aSColin Percival		XARGST="-t"
59248ffe56aSColin Percival		NDEBUG=" "
59348ffe56aSColin Percival		;;
59448ffe56aSColin Percival	nostats)
59548ffe56aSColin Percival		QUIETREDIR=""
59648ffe56aSColin Percival		QUIETFLAG=""
59748ffe56aSColin Percival		STATSREDIR="/dev/null"
59848ffe56aSColin Percival		DDSTATS=".."
59948ffe56aSColin Percival		XARGST=""
60048ffe56aSColin Percival		NDEBUG=""
60148ffe56aSColin Percival		;;
60248ffe56aSColin Percival	stats)
60348ffe56aSColin Percival		QUIETREDIR="/dev/null"
60448ffe56aSColin Percival		QUIETFLAG="-q"
60548ffe56aSColin Percival		STATSREDIR="/dev/stdout"
60648ffe56aSColin Percival		DDSTATS=""
60748ffe56aSColin Percival		XARGST=""
60848ffe56aSColin Percival		NDEBUG="-n"
60948ffe56aSColin Percival		;;
61048ffe56aSColin Percival	esac
61148ffe56aSColin Percival}
61248ffe56aSColin Percival
61348ffe56aSColin Percival# Perform sanity checks and set some final parameters
61448ffe56aSColin Percival# in preparation for fetching files.  Figure out which
61548ffe56aSColin Percival# set of updates should be downloaded: If the user is
61648ffe56aSColin Percival# running *-p[0-9]+, strip off the last part; if the
61748ffe56aSColin Percival# user is running -SECURITY, call it -RELEASE.  Chdir
61848ffe56aSColin Percival# into the working directory.
619211f2ba0SColin Percivalfetchupgrade_check_params () {
62048ffe56aSColin Percival	export HTTP_USER_AGENT="freebsd-update (${COMMAND}, `uname -r`)"
62148ffe56aSColin Percival
62248ffe56aSColin Percival	_SERVERNAME_z=\
62348ffe56aSColin Percival"SERVERNAME must be given via command line or configuration file."
62448ffe56aSColin Percival	_KEYPRINT_z="Key must be given via -k option or configuration file."
62548ffe56aSColin Percival	_KEYPRINT_bad="Invalid key fingerprint: "
62648ffe56aSColin Percival	_WORKDIR_bad="Directory does not exist or is not writable: "
627f88076f0SMark Felder	_WORKDIR_bad2="Directory is not on a persistent filesystem: "
62848ffe56aSColin Percival
62948ffe56aSColin Percival	if [ -z "${SERVERNAME}" ]; then
63048ffe56aSColin Percival		echo -n "`basename $0`: "
63148ffe56aSColin Percival		echo "${_SERVERNAME_z}"
63248ffe56aSColin Percival		exit 1
63348ffe56aSColin Percival	fi
63448ffe56aSColin Percival	if [ -z "${KEYPRINT}" ]; then
63548ffe56aSColin Percival		echo -n "`basename $0`: "
63648ffe56aSColin Percival		echo "${_KEYPRINT_z}"
63748ffe56aSColin Percival		exit 1
63848ffe56aSColin Percival	fi
63948ffe56aSColin Percival	if ! echo "${KEYPRINT}" | grep -qE "^[0-9a-f]{64}$"; then
64048ffe56aSColin Percival		echo -n "`basename $0`: "
64148ffe56aSColin Percival		echo -n "${_KEYPRINT_bad}"
64248ffe56aSColin Percival		echo ${KEYPRINT}
64348ffe56aSColin Percival		exit 1
64448ffe56aSColin Percival	fi
64548ffe56aSColin Percival	if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then
64648ffe56aSColin Percival		echo -n "`basename $0`: "
64748ffe56aSColin Percival		echo -n "${_WORKDIR_bad}"
64848ffe56aSColin Percival		echo ${WORKDIR}
64948ffe56aSColin Percival		exit 1
65048ffe56aSColin Percival	fi
651dfe9215bSMark Felder	case `df -T ${WORKDIR}` in */dev/md[0-9]* | *tmpfs*)
652f88076f0SMark Felder		echo -n "`basename $0`: "
653f88076f0SMark Felder		echo -n "${_WORKDIR_bad2}"
654f88076f0SMark Felder		echo ${WORKDIR}
655f88076f0SMark Felder		exit 1
656dfe9215bSMark Felder		;;
657dfe9215bSMark Felder	esac
658a2356430SColin Percival	chmod 700 ${WORKDIR}
65948ffe56aSColin Percival	cd ${WORKDIR} || exit 1
66048ffe56aSColin Percival
66148ffe56aSColin Percival	# Generate release number.  The s/SECURITY/RELEASE/ bit exists
66248ffe56aSColin Percival	# to provide an upgrade path for FreeBSD Update 1.x users, since
66348ffe56aSColin Percival	# the kernels provided by FreeBSD Update 1.x are always labelled
66448ffe56aSColin Percival	# as X.Y-SECURITY.
66548ffe56aSColin Percival	RELNUM=`uname -r |
66648ffe56aSColin Percival	    sed -E 's,-p[0-9]+,,' |
66748ffe56aSColin Percival	    sed -E 's,-SECURITY,-RELEASE,'`
66848ffe56aSColin Percival	ARCH=`uname -m`
66948ffe56aSColin Percival	FETCHDIR=${RELNUM}/${ARCH}
670db6b0a61SColin Percival	PATCHDIR=${RELNUM}/${ARCH}/bp
67148ffe56aSColin Percival
672d308a8bfSEd Maste	# Disallow upgrade from a version that is not a release
673d308a8bfSEd Maste	case ${RELNUM} in
674d308a8bfSEd Maste	*-RELEASE | *-ALPHA*  | *-BETA* | *-RC*)
675d308a8bfSEd Maste		;;
676d308a8bfSEd Maste	*)
6770d5c5243SEd Maste		echo -n "`basename $0`: "
6780d5c5243SEd Maste		cat <<- EOF
679d308a8bfSEd Maste			Cannot upgrade from a version that is not a release
680d308a8bfSEd Maste			(including alpha, beta and release candidates)
681d308a8bfSEd Maste			using `basename $0`. Instead, FreeBSD can be directly
682d308a8bfSEd Maste			upgraded by source or upgraded to a RELEASE/RELENG version
683d308a8bfSEd Maste			prior to running `basename $0`.
684d308a8bfSEd Maste			Currently running: ${RELNUM}
6850d5c5243SEd Maste		EOF
6860d5c5243SEd Maste		exit 1
687d308a8bfSEd Maste		;;
688d308a8bfSEd Maste	esac
6890d5c5243SEd Maste
69048ffe56aSColin Percival	# Figure out what directory contains the running kernel
69148ffe56aSColin Percival	BOOTFILE=`sysctl -n kern.bootfile`
69248ffe56aSColin Percival	KERNELDIR=${BOOTFILE%/kernel}
69348ffe56aSColin Percival	if ! [ -d ${KERNELDIR} ]; then
69448ffe56aSColin Percival		echo "Cannot identify running kernel"
69548ffe56aSColin Percival		exit 1
69648ffe56aSColin Percival	fi
69748ffe56aSColin Percival
6982c434b2cSColin Percival	# Figure out what kernel configuration is running.  We start with
6992c434b2cSColin Percival	# the output of `uname -i`, and then make the following adjustments:
7002c434b2cSColin Percival	# 1. Replace "SMP-GENERIC" with "SMP".  Why the SMP kernel config
7012c434b2cSColin Percival	# file says "ident SMP-GENERIC", I don't know...
7022c434b2cSColin Percival	# 2. If the kernel claims to be GENERIC _and_ ${ARCH} is "amd64"
7032c434b2cSColin Percival	# _and_ `sysctl kern.version` contains a line which ends "/SMP", then
7042c434b2cSColin Percival	# we're running an SMP kernel.  This mis-identification is a bug
7052c434b2cSColin Percival	# which was fixed in 6.2-STABLE.
7062c434b2cSColin Percival	KERNCONF=`uname -i`
7072c434b2cSColin Percival	if [ ${KERNCONF} = "SMP-GENERIC" ]; then
7082c434b2cSColin Percival		KERNCONF=SMP
7092c434b2cSColin Percival	fi
7102c434b2cSColin Percival	if [ ${KERNCONF} = "GENERIC" ] && [ ${ARCH} = "amd64" ]; then
7112c434b2cSColin Percival		if sysctl kern.version | grep -qE '/SMP$'; then
7122c434b2cSColin Percival			KERNCONF=SMP
7132c434b2cSColin Percival		fi
7142c434b2cSColin Percival	fi
7152c434b2cSColin Percival
71648ffe56aSColin Percival	# Define some paths
71748ffe56aSColin Percival	BSPATCH=/usr/bin/bspatch
71848ffe56aSColin Percival	SHA256=/sbin/sha256
71948ffe56aSColin Percival	PHTTPGET=/usr/libexec/phttpget
72048ffe56aSColin Percival
72148ffe56aSColin Percival	# Set up variables relating to VERBOSELEVEL
72248ffe56aSColin Percival	fetch_setup_verboselevel
72348ffe56aSColin Percival
72448ffe56aSColin Percival	# Construct a unique name from ${BASEDIR}
72548ffe56aSColin Percival	BDHASH=`echo ${BASEDIR} | sha256 -q`
72648ffe56aSColin Percival}
72748ffe56aSColin Percival
728211f2ba0SColin Percival# Perform sanity checks etc. before fetching updates.
729211f2ba0SColin Percivalfetch_check_params () {
730211f2ba0SColin Percival	fetchupgrade_check_params
731211f2ba0SColin Percival
732211f2ba0SColin Percival	if ! [ -z "${TARGETRELEASE}" ]; then
733211f2ba0SColin Percival		echo -n "`basename $0`: "
734211f2ba0SColin Percival		echo -n "-r option is meaningless with 'fetch' command.  "
735211f2ba0SColin Percival		echo "(Did you mean 'upgrade' instead?)"
736211f2ba0SColin Percival		exit 1
737211f2ba0SColin Percival	fi
7388935f242SAllan Jude
7398935f242SAllan Jude	# Check that we have updates ready to install
7408bf2dcceSAllan Jude	if [ -f ${BDHASH}-install/kerneldone -a $FORCEFETCH -eq 0 ]; then
7418935f242SAllan Jude		echo "You have a partially completed upgrade pending"
7428935f242SAllan Jude		echo "Run '$0 install' first."
7438935f242SAllan Jude		echo "Run '$0 fetch -F' to proceed anyway."
7448935f242SAllan Jude		exit 1
7458935f242SAllan Jude	fi
746211f2ba0SColin Percival}
747211f2ba0SColin Percival
748db6b0a61SColin Percival# Perform sanity checks etc. before fetching upgrades.
749db6b0a61SColin Percivalupgrade_check_params () {
750211f2ba0SColin Percival	fetchupgrade_check_params
751db6b0a61SColin Percival
752db6b0a61SColin Percival	# Unless set otherwise, we're upgrading to the same kernel config.
753db6b0a61SColin Percival	NKERNCONF=${KERNCONF}
754db6b0a61SColin Percival
755db6b0a61SColin Percival	# We need TARGETRELEASE set
756db6b0a61SColin Percival	_TARGETRELEASE_z="Release target must be specified via -r option."
757db6b0a61SColin Percival	if [ -z "${TARGETRELEASE}" ]; then
758db6b0a61SColin Percival		echo -n "`basename $0`: "
759db6b0a61SColin Percival		echo "${_TARGETRELEASE_z}"
760db6b0a61SColin Percival		exit 1
761db6b0a61SColin Percival	fi
762db6b0a61SColin Percival
763db6b0a61SColin Percival	# The target release should be != the current release.
764db6b0a61SColin Percival	if [ "${TARGETRELEASE}" = "${RELNUM}" ]; then
765db6b0a61SColin Percival		echo -n "`basename $0`: "
766db6b0a61SColin Percival		echo "Cannot upgrade from ${RELNUM} to itself"
767db6b0a61SColin Percival		exit 1
768db6b0a61SColin Percival	fi
769db6b0a61SColin Percival
770db6b0a61SColin Percival	# Turning off AllowAdd or AllowDelete is a bad idea for upgrades.
771db6b0a61SColin Percival	if [ "${ALLOWADD}" = "no" ]; then
772db6b0a61SColin Percival		echo -n "`basename $0`: "
773db6b0a61SColin Percival		echo -n "WARNING: \"AllowAdd no\" is a bad idea "
774db6b0a61SColin Percival		echo "when upgrading between releases."
775db6b0a61SColin Percival		echo
776db6b0a61SColin Percival	fi
777db6b0a61SColin Percival	if [ "${ALLOWDELETE}" = "no" ]; then
778db6b0a61SColin Percival		echo -n "`basename $0`: "
779db6b0a61SColin Percival		echo -n "WARNING: \"AllowDelete no\" is a bad idea "
780db6b0a61SColin Percival		echo "when upgrading between releases."
781db6b0a61SColin Percival		echo
782db6b0a61SColin Percival	fi
783db6b0a61SColin Percival
784db6b0a61SColin Percival	# Set EDITOR to /usr/bin/vi if it isn't already set
785db6b0a61SColin Percival	: ${EDITOR:='/usr/bin/vi'}
786db6b0a61SColin Percival}
787db6b0a61SColin Percival
78848ffe56aSColin Percival# Perform sanity checks and set some final parameters in
78948ffe56aSColin Percival# preparation for installing updates.
79048ffe56aSColin Percivalinstall_check_params () {
79148ffe56aSColin Percival	# Check that we are root.  All sorts of things won't work otherwise.
79248ffe56aSColin Percival	if [ `id -u` != 0 ]; then
79348ffe56aSColin Percival		echo "You must be root to run this."
79448ffe56aSColin Percival		exit 1
79548ffe56aSColin Percival	fi
79648ffe56aSColin Percival
7972328d598SColin Percival	# Check that securelevel <= 0.  Otherwise we can't update schg files.
7982328d598SColin Percival	if [ `sysctl -n kern.securelevel` -gt 0 ]; then
7992328d598SColin Percival		echo "Updates cannot be installed when the system securelevel"
8002328d598SColin Percival		echo "is greater than zero."
8012328d598SColin Percival		exit 1
8022328d598SColin Percival	fi
8032328d598SColin Percival
80448ffe56aSColin Percival	# Check that we have a working directory
80548ffe56aSColin Percival	_WORKDIR_bad="Directory does not exist or is not writable: "
80648ffe56aSColin Percival	if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then
80748ffe56aSColin Percival		echo -n "`basename $0`: "
80848ffe56aSColin Percival		echo -n "${_WORKDIR_bad}"
80948ffe56aSColin Percival		echo ${WORKDIR}
81048ffe56aSColin Percival		exit 1
81148ffe56aSColin Percival	fi
81248ffe56aSColin Percival	cd ${WORKDIR} || exit 1
81348ffe56aSColin Percival
81448ffe56aSColin Percival	# Construct a unique name from ${BASEDIR}
81548ffe56aSColin Percival	BDHASH=`echo ${BASEDIR} | sha256 -q`
81648ffe56aSColin Percival
81748ffe56aSColin Percival	# Check that we have updates ready to install
81848ffe56aSColin Percival	if ! [ -L ${BDHASH}-install ]; then
81948ffe56aSColin Percival		echo "No updates are available to install."
82033bd05c3SGuangyuan Yang		if [ $ISFETCHED -eq 0 ]; then
82148ffe56aSColin Percival			echo "Run '$0 fetch' first."
8225654a007SPietro Cerutti			exit 1
82333bd05c3SGuangyuan Yang		fi
82433bd05c3SGuangyuan Yang		exit 0
82548ffe56aSColin Percival	fi
82648ffe56aSColin Percival	if ! [ -f ${BDHASH}-install/INDEX-OLD ] ||
82748ffe56aSColin Percival	    ! [ -f ${BDHASH}-install/INDEX-NEW ]; then
82848ffe56aSColin Percival		echo "Update manifest is corrupt -- this should never happen."
82948ffe56aSColin Percival		echo "Re-run '$0 fetch'."
83048ffe56aSColin Percival		exit 1
83148ffe56aSColin Percival	fi
83223d827efSSimon L. B. Nielsen
83323d827efSSimon L. B. Nielsen	# Figure out what directory contains the running kernel
83423d827efSSimon L. B. Nielsen	BOOTFILE=`sysctl -n kern.bootfile`
83523d827efSSimon L. B. Nielsen	KERNELDIR=${BOOTFILE%/kernel}
83623d827efSSimon L. B. Nielsen	if ! [ -d ${KERNELDIR} ]; then
83723d827efSSimon L. B. Nielsen		echo "Cannot identify running kernel"
83823d827efSSimon L. B. Nielsen		exit 1
83923d827efSSimon L. B. Nielsen	fi
84048ffe56aSColin Percival}
84148ffe56aSColin Percival
84248ffe56aSColin Percival# Perform sanity checks and set some final parameters in
84348ffe56aSColin Percival# preparation for UNinstalling updates.
84448ffe56aSColin Percivalrollback_check_params () {
84548ffe56aSColin Percival	# Check that we are root.  All sorts of things won't work otherwise.
84648ffe56aSColin Percival	if [ `id -u` != 0 ]; then
84748ffe56aSColin Percival		echo "You must be root to run this."
84848ffe56aSColin Percival		exit 1
84948ffe56aSColin Percival	fi
85048ffe56aSColin Percival
85148ffe56aSColin Percival	# Check that we have a working directory
85248ffe56aSColin Percival	_WORKDIR_bad="Directory does not exist or is not writable: "
85348ffe56aSColin Percival	if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then
85448ffe56aSColin Percival		echo -n "`basename $0`: "
85548ffe56aSColin Percival		echo -n "${_WORKDIR_bad}"
85648ffe56aSColin Percival		echo ${WORKDIR}
85748ffe56aSColin Percival		exit 1
85848ffe56aSColin Percival	fi
85948ffe56aSColin Percival	cd ${WORKDIR} || exit 1
86048ffe56aSColin Percival
86148ffe56aSColin Percival	# Construct a unique name from ${BASEDIR}
86248ffe56aSColin Percival	BDHASH=`echo ${BASEDIR} | sha256 -q`
86348ffe56aSColin Percival
86448ffe56aSColin Percival	# Check that we have updates ready to rollback
86548ffe56aSColin Percival	if ! [ -L ${BDHASH}-rollback ]; then
86648ffe56aSColin Percival		echo "No rollback directory found."
86748ffe56aSColin Percival		exit 1
86848ffe56aSColin Percival	fi
86948ffe56aSColin Percival	if ! [ -f ${BDHASH}-rollback/INDEX-OLD ] ||
87048ffe56aSColin Percival	    ! [ -f ${BDHASH}-rollback/INDEX-NEW ]; then
87148ffe56aSColin Percival		echo "Update manifest is corrupt -- this should never happen."
87248ffe56aSColin Percival		exit 1
87348ffe56aSColin Percival	fi
87448ffe56aSColin Percival}
87548ffe56aSColin Percival
87608e23beeSColin Percival# Perform sanity checks and set some final parameters
87708e23beeSColin Percival# in preparation for comparing the system against the
87808e23beeSColin Percival# published index.  Figure out which index we should
87908e23beeSColin Percival# compare against: If the user is running *-p[0-9]+,
88008e23beeSColin Percival# strip off the last part; if the user is running
88108e23beeSColin Percival# -SECURITY, call it -RELEASE.  Chdir into the working
88208e23beeSColin Percival# directory.
88308e23beeSColin PercivalIDS_check_params () {
88408e23beeSColin Percival	export HTTP_USER_AGENT="freebsd-update (${COMMAND}, `uname -r`)"
88508e23beeSColin Percival
88608e23beeSColin Percival	_SERVERNAME_z=\
88708e23beeSColin Percival"SERVERNAME must be given via command line or configuration file."
88808e23beeSColin Percival	_KEYPRINT_z="Key must be given via -k option or configuration file."
88908e23beeSColin Percival	_KEYPRINT_bad="Invalid key fingerprint: "
89008e23beeSColin Percival	_WORKDIR_bad="Directory does not exist or is not writable: "
89108e23beeSColin Percival
89208e23beeSColin Percival	if [ -z "${SERVERNAME}" ]; then
89308e23beeSColin Percival		echo -n "`basename $0`: "
89408e23beeSColin Percival		echo "${_SERVERNAME_z}"
89508e23beeSColin Percival		exit 1
89608e23beeSColin Percival	fi
89708e23beeSColin Percival	if [ -z "${KEYPRINT}" ]; then
89808e23beeSColin Percival		echo -n "`basename $0`: "
89908e23beeSColin Percival		echo "${_KEYPRINT_z}"
90008e23beeSColin Percival		exit 1
90108e23beeSColin Percival	fi
90208e23beeSColin Percival	if ! echo "${KEYPRINT}" | grep -qE "^[0-9a-f]{64}$"; then
90308e23beeSColin Percival		echo -n "`basename $0`: "
90408e23beeSColin Percival		echo -n "${_KEYPRINT_bad}"
90508e23beeSColin Percival		echo ${KEYPRINT}
90608e23beeSColin Percival		exit 1
90708e23beeSColin Percival	fi
90808e23beeSColin Percival	if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then
90908e23beeSColin Percival		echo -n "`basename $0`: "
91008e23beeSColin Percival		echo -n "${_WORKDIR_bad}"
91108e23beeSColin Percival		echo ${WORKDIR}
91208e23beeSColin Percival		exit 1
91308e23beeSColin Percival	fi
91408e23beeSColin Percival	cd ${WORKDIR} || exit 1
91508e23beeSColin Percival
91608e23beeSColin Percival	# Generate release number.  The s/SECURITY/RELEASE/ bit exists
91708e23beeSColin Percival	# to provide an upgrade path for FreeBSD Update 1.x users, since
91808e23beeSColin Percival	# the kernels provided by FreeBSD Update 1.x are always labelled
91908e23beeSColin Percival	# as X.Y-SECURITY.
92008e23beeSColin Percival	RELNUM=`uname -r |
92108e23beeSColin Percival	    sed -E 's,-p[0-9]+,,' |
92208e23beeSColin Percival	    sed -E 's,-SECURITY,-RELEASE,'`
92308e23beeSColin Percival	ARCH=`uname -m`
92408e23beeSColin Percival	FETCHDIR=${RELNUM}/${ARCH}
92508e23beeSColin Percival	PATCHDIR=${RELNUM}/${ARCH}/bp
92608e23beeSColin Percival
92708e23beeSColin Percival	# Figure out what directory contains the running kernel
92808e23beeSColin Percival	BOOTFILE=`sysctl -n kern.bootfile`
92908e23beeSColin Percival	KERNELDIR=${BOOTFILE%/kernel}
93008e23beeSColin Percival	if ! [ -d ${KERNELDIR} ]; then
93108e23beeSColin Percival		echo "Cannot identify running kernel"
93208e23beeSColin Percival		exit 1
93308e23beeSColin Percival	fi
93408e23beeSColin Percival
93508e23beeSColin Percival	# Figure out what kernel configuration is running.  We start with
93608e23beeSColin Percival	# the output of `uname -i`, and then make the following adjustments:
93708e23beeSColin Percival	# 1. Replace "SMP-GENERIC" with "SMP".  Why the SMP kernel config
93808e23beeSColin Percival	# file says "ident SMP-GENERIC", I don't know...
93908e23beeSColin Percival	# 2. If the kernel claims to be GENERIC _and_ ${ARCH} is "amd64"
94008e23beeSColin Percival	# _and_ `sysctl kern.version` contains a line which ends "/SMP", then
94108e23beeSColin Percival	# we're running an SMP kernel.  This mis-identification is a bug
94208e23beeSColin Percival	# which was fixed in 6.2-STABLE.
94308e23beeSColin Percival	KERNCONF=`uname -i`
94408e23beeSColin Percival	if [ ${KERNCONF} = "SMP-GENERIC" ]; then
94508e23beeSColin Percival		KERNCONF=SMP
94608e23beeSColin Percival	fi
94708e23beeSColin Percival	if [ ${KERNCONF} = "GENERIC" ] && [ ${ARCH} = "amd64" ]; then
94808e23beeSColin Percival		if sysctl kern.version | grep -qE '/SMP$'; then
94908e23beeSColin Percival			KERNCONF=SMP
95008e23beeSColin Percival		fi
95108e23beeSColin Percival	fi
95208e23beeSColin Percival
95308e23beeSColin Percival	# Define some paths
95408e23beeSColin Percival	SHA256=/sbin/sha256
95508e23beeSColin Percival	PHTTPGET=/usr/libexec/phttpget
95608e23beeSColin Percival
95708e23beeSColin Percival	# Set up variables relating to VERBOSELEVEL
95808e23beeSColin Percival	fetch_setup_verboselevel
95908e23beeSColin Percival}
96008e23beeSColin Percival
96148ffe56aSColin Percival#### Core functionality -- the actual work gets done here
96248ffe56aSColin Percival
96348ffe56aSColin Percival# Use an SRV query to pick a server.  If the SRV query doesn't provide
96448ffe56aSColin Percival# a useful answer, use the server name specified by the user.
96548ffe56aSColin Percival# Put another way... look up _http._tcp.${SERVERNAME} and pick a server
96648ffe56aSColin Percival# from that; or if no servers are returned, use ${SERVERNAME}.
96748ffe56aSColin Percival# This allows a user to specify "portsnap.freebsd.org" (in which case
96848ffe56aSColin Percival# portsnap will select one of the mirrors) or "portsnap5.tld.freebsd.org"
96948ffe56aSColin Percival# (in which case portsnap will use that particular server, since there
97048ffe56aSColin Percival# won't be an SRV entry for that name).
97148ffe56aSColin Percival#
97248ffe56aSColin Percival# We ignore the Port field, since we are always going to use port 80.
97348ffe56aSColin Percival
97448ffe56aSColin Percival# Fetch the mirror list, but do not pick a mirror yet.  Returns 1 if
97548ffe56aSColin Percival# no mirrors are available for any reason.
97648ffe56aSColin Percivalfetch_pick_server_init () {
97748ffe56aSColin Percival	: > serverlist_tried
97848ffe56aSColin Percival
97948ffe56aSColin Percival# Check that host(1) exists (i.e., that the system wasn't built with the
98048ffe56aSColin Percival# WITHOUT_BIND set) and don't try to find a mirror if it doesn't exist.
98148ffe56aSColin Percival	if ! which -s host; then
98248ffe56aSColin Percival		: > serverlist_full
98348ffe56aSColin Percival		return 1
98448ffe56aSColin Percival	fi
98548ffe56aSColin Percival
98648ffe56aSColin Percival	echo -n "Looking up ${SERVERNAME} mirrors... "
98748ffe56aSColin Percival
98848ffe56aSColin Percival# Issue the SRV query and pull out the Priority, Weight, and Target fields.
98948ffe56aSColin Percival# BIND 9 prints "$name has SRV record ..." while BIND 8 prints
99048ffe56aSColin Percival# "$name server selection ..."; we allow either format.
99148ffe56aSColin Percival	MLIST="_http._tcp.${SERVERNAME}"
99248ffe56aSColin Percival	host -t srv "${MLIST}" |
993e7fd266eSColin Percival	    sed -nE "s/${MLIST} (has SRV record|server selection) //Ip" |
99448ffe56aSColin Percival	    cut -f 1,2,4 -d ' ' |
99548ffe56aSColin Percival	    sed -e 's/\.$//' |
99648ffe56aSColin Percival	    sort > serverlist_full
99748ffe56aSColin Percival
99848ffe56aSColin Percival# If no records, give up -- we'll just use the server name we were given.
99948ffe56aSColin Percival	if [ `wc -l < serverlist_full` -eq 0 ]; then
100048ffe56aSColin Percival		echo "none found."
100148ffe56aSColin Percival		return 1
100248ffe56aSColin Percival	fi
100348ffe56aSColin Percival
100448ffe56aSColin Percival# Report how many mirrors we found.
100548ffe56aSColin Percival	echo `wc -l < serverlist_full` "mirrors found."
100648ffe56aSColin Percival
100748ffe56aSColin Percival# Generate a random seed for use in picking mirrors.  If HTTP_PROXY
100848ffe56aSColin Percival# is set, this will be used to generate the seed; otherwise, the seed
100948ffe56aSColin Percival# will be random.
101048ffe56aSColin Percival	if [ -n "${HTTP_PROXY}${http_proxy}" ]; then
101148ffe56aSColin Percival		RANDVALUE=`sha256 -qs "${HTTP_PROXY}${http_proxy}" |
101248ffe56aSColin Percival		    tr -d 'a-f' |
101348ffe56aSColin Percival		    cut -c 1-9`
101448ffe56aSColin Percival	else
101548ffe56aSColin Percival		RANDVALUE=`jot -r 1 0 999999999`
101648ffe56aSColin Percival	fi
101748ffe56aSColin Percival}
101848ffe56aSColin Percival
101948ffe56aSColin Percival# Pick a mirror.  Returns 1 if we have run out of mirrors to try.
102048ffe56aSColin Percivalfetch_pick_server () {
102148ffe56aSColin Percival# Generate a list of not-yet-tried mirrors
102248ffe56aSColin Percival	sort serverlist_tried |
102348ffe56aSColin Percival	    comm -23 serverlist_full - > serverlist
102448ffe56aSColin Percival
102548ffe56aSColin Percival# Have we run out of mirrors?
102648ffe56aSColin Percival	if [ `wc -l < serverlist` -eq 0 ]; then
10279e8c28fcSEd Maste		cat <<- EOF
10289e8c28fcSEd Maste			No mirrors remaining, giving up.
10299e8c28fcSEd Maste
10309e8c28fcSEd Maste			This may be because upgrading from this platform (${ARCH})
10319e8c28fcSEd Maste			or release (${RELNUM}) is unsupported by `basename $0`. Only
10329e8c28fcSEd Maste			platforms with Tier 1 support can be upgraded by `basename $0`.
10339e8c28fcSEd Maste			See https://www.freebsd.org/platforms/index.html for more info.
10349e8c28fcSEd Maste
10359e8c28fcSEd Maste			If unsupported, FreeBSD must be upgraded by source.
10369e8c28fcSEd Maste		EOF
103748ffe56aSColin Percival		return 1
103848ffe56aSColin Percival	fi
103948ffe56aSColin Percival
104048ffe56aSColin Percival# Find the highest priority level (lowest numeric value).
104148ffe56aSColin Percival	SRV_PRIORITY=`cut -f 1 -d ' ' serverlist | sort -n | head -1`
104248ffe56aSColin Percival
104348ffe56aSColin Percival# Add up the weights of the response lines at that priority level.
104448ffe56aSColin Percival	SRV_WSUM=0;
104548ffe56aSColin Percival	while read X; do
104648ffe56aSColin Percival		case "$X" in
104748ffe56aSColin Percival		${SRV_PRIORITY}\ *)
104848ffe56aSColin Percival			SRV_W=`echo $X | cut -f 2 -d ' '`
104948ffe56aSColin Percival			SRV_WSUM=$(($SRV_WSUM + $SRV_W))
105048ffe56aSColin Percival			;;
105148ffe56aSColin Percival		esac
105248ffe56aSColin Percival	done < serverlist
105348ffe56aSColin Percival
105448ffe56aSColin Percival# If all the weights are 0, pretend that they are all 1 instead.
105548ffe56aSColin Percival	if [ ${SRV_WSUM} -eq 0 ]; then
105648ffe56aSColin Percival		SRV_WSUM=`grep -E "^${SRV_PRIORITY} " serverlist | wc -l`
105748ffe56aSColin Percival		SRV_W_ADD=1
105848ffe56aSColin Percival	else
105948ffe56aSColin Percival		SRV_W_ADD=0
106048ffe56aSColin Percival	fi
106148ffe56aSColin Percival
106248ffe56aSColin Percival# Pick a value between 0 and the sum of the weights - 1
106348ffe56aSColin Percival	SRV_RND=`expr ${RANDVALUE} % ${SRV_WSUM}`
106448ffe56aSColin Percival
106548ffe56aSColin Percival# Read through the list of mirrors and set SERVERNAME.  Write the line
106648ffe56aSColin Percival# corresponding to the mirror we selected into serverlist_tried so that
106748ffe56aSColin Percival# we won't try it again.
106848ffe56aSColin Percival	while read X; do
106948ffe56aSColin Percival		case "$X" in
107048ffe56aSColin Percival		${SRV_PRIORITY}\ *)
107148ffe56aSColin Percival			SRV_W=`echo $X | cut -f 2 -d ' '`
107248ffe56aSColin Percival			SRV_W=$(($SRV_W + $SRV_W_ADD))
107348ffe56aSColin Percival			if [ $SRV_RND -lt $SRV_W ]; then
107448ffe56aSColin Percival				SERVERNAME=`echo $X | cut -f 3 -d ' '`
107548ffe56aSColin Percival				echo "$X" >> serverlist_tried
107648ffe56aSColin Percival				break
107748ffe56aSColin Percival			else
107848ffe56aSColin Percival				SRV_RND=$(($SRV_RND - $SRV_W))
107948ffe56aSColin Percival			fi
108048ffe56aSColin Percival			;;
108148ffe56aSColin Percival		esac
108248ffe56aSColin Percival	done < serverlist
108348ffe56aSColin Percival}
108448ffe56aSColin Percival
108548ffe56aSColin Percival# Take a list of ${oldhash}|${newhash} and output a list of needed patches,
108648ffe56aSColin Percival# i.e., those for which we have ${oldhash} and don't have ${newhash}.
108748ffe56aSColin Percivalfetch_make_patchlist () {
108848ffe56aSColin Percival	grep -vE "^([0-9a-f]{64})\|\1$" |
108948ffe56aSColin Percival	    tr '|' ' ' |
109048ffe56aSColin Percival		while read X Y; do
109148ffe56aSColin Percival			if [ -f "files/${Y}.gz" ] ||
109248ffe56aSColin Percival			    [ ! -f "files/${X}.gz" ]; then
109348ffe56aSColin Percival				continue
109448ffe56aSColin Percival			fi
109548ffe56aSColin Percival			echo "${X}|${Y}"
1096f6e21461SEd Maste		done | sort -u
109748ffe56aSColin Percival}
109848ffe56aSColin Percival
109948ffe56aSColin Percival# Print user-friendly progress statistics
110048ffe56aSColin Percivalfetch_progress () {
110148ffe56aSColin Percival	LNC=0
110248ffe56aSColin Percival	while read x; do
110348ffe56aSColin Percival		LNC=$(($LNC + 1))
110448ffe56aSColin Percival		if [ $(($LNC % 10)) = 0 ]; then
110548ffe56aSColin Percival			echo -n $LNC
110648ffe56aSColin Percival		elif [ $(($LNC % 2)) = 0 ]; then
110748ffe56aSColin Percival			echo -n .
110848ffe56aSColin Percival		fi
110948ffe56aSColin Percival	done
111048ffe56aSColin Percival	echo -n " "
111148ffe56aSColin Percival}
111248ffe56aSColin Percival
1113db6b0a61SColin Percival# Function for asking the user if everything is ok
1114db6b0a61SColin Percivalcontinuep () {
1115db6b0a61SColin Percival	while read -p "Does this look reasonable (y/n)? " CONTINUE; do
1116db6b0a61SColin Percival		case "${CONTINUE}" in
1117db6b0a61SColin Percival		y*)
1118db6b0a61SColin Percival			return 0
1119db6b0a61SColin Percival			;;
1120db6b0a61SColin Percival		n*)
1121db6b0a61SColin Percival			return 1
1122db6b0a61SColin Percival			;;
1123db6b0a61SColin Percival		esac
1124db6b0a61SColin Percival	done
1125db6b0a61SColin Percival}
1126db6b0a61SColin Percival
112748ffe56aSColin Percival# Initialize the working directory
112848ffe56aSColin Percivalworkdir_init () {
112948ffe56aSColin Percival	mkdir -p files
113048ffe56aSColin Percival	touch tINDEX.present
113148ffe56aSColin Percival}
113248ffe56aSColin Percival
113348ffe56aSColin Percival# Check that we have a public key with an appropriate hash, or
113448ffe56aSColin Percival# fetch the key if it doesn't exist.  Returns 1 if the key has
113548ffe56aSColin Percival# not yet been fetched.
113648ffe56aSColin Percivalfetch_key () {
113748ffe56aSColin Percival	if [ -r pub.ssl ] && [ `${SHA256} -q pub.ssl` = ${KEYPRINT} ]; then
113848ffe56aSColin Percival		return 0
113948ffe56aSColin Percival	fi
114048ffe56aSColin Percival
114148ffe56aSColin Percival	echo -n "Fetching public key from ${SERVERNAME}... "
114248ffe56aSColin Percival	rm -f pub.ssl
114348ffe56aSColin Percival	fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/pub.ssl \
114448ffe56aSColin Percival	    2>${QUIETREDIR} || true
114548ffe56aSColin Percival	if ! [ -r pub.ssl ]; then
114648ffe56aSColin Percival		echo "failed."
114748ffe56aSColin Percival		return 1
114848ffe56aSColin Percival	fi
114948ffe56aSColin Percival	if ! [ `${SHA256} -q pub.ssl` = ${KEYPRINT} ]; then
115048ffe56aSColin Percival		echo "key has incorrect hash."
115148ffe56aSColin Percival		rm -f pub.ssl
115248ffe56aSColin Percival		return 1
115348ffe56aSColin Percival	fi
115448ffe56aSColin Percival	echo "done."
115548ffe56aSColin Percival}
115648ffe56aSColin Percival
115748ffe56aSColin Percival# Fetch metadata signature, aka "tag".
115848ffe56aSColin Percivalfetch_tag () {
1159db6b0a61SColin Percival	echo -n "Fetching metadata signature "
1160db6b0a61SColin Percival	echo ${NDEBUG} "for ${RELNUM} from ${SERVERNAME}... "
116148ffe56aSColin Percival	rm -f latest.ssl
116248ffe56aSColin Percival	fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/latest.ssl	\
116348ffe56aSColin Percival	    2>${QUIETREDIR} || true
116448ffe56aSColin Percival	if ! [ -r latest.ssl ]; then
116548ffe56aSColin Percival		echo "failed."
116648ffe56aSColin Percival		return 1
116748ffe56aSColin Percival	fi
116848ffe56aSColin Percival
116948ffe56aSColin Percival	openssl rsautl -pubin -inkey pub.ssl -verify		\
117048ffe56aSColin Percival	    < latest.ssl > tag.new 2>${QUIETREDIR} || true
117148ffe56aSColin Percival	rm latest.ssl
117248ffe56aSColin Percival
117348ffe56aSColin Percival	if ! [ `wc -l < tag.new` = 1 ] ||
117448ffe56aSColin Percival	    ! grep -qE	\
117548ffe56aSColin Percival    "^freebsd-update\|${ARCH}\|${RELNUM}\|[0-9]+\|[0-9a-f]{64}\|[0-9]{10}" \
117648ffe56aSColin Percival		tag.new; then
117748ffe56aSColin Percival		echo "invalid signature."
117848ffe56aSColin Percival		return 1
117948ffe56aSColin Percival	fi
118048ffe56aSColin Percival
118148ffe56aSColin Percival	echo "done."
118248ffe56aSColin Percival
118348ffe56aSColin Percival	RELPATCHNUM=`cut -f 4 -d '|' < tag.new`
118448ffe56aSColin Percival	TINDEXHASH=`cut -f 5 -d '|' < tag.new`
118548ffe56aSColin Percival	EOLTIME=`cut -f 6 -d '|' < tag.new`
118648ffe56aSColin Percival}
118748ffe56aSColin Percival
118848ffe56aSColin Percival# Sanity-check the patch number in a tag, to make sure that we're not
118948ffe56aSColin Percival# going to "update" backwards and to prevent replay attacks.
119048ffe56aSColin Percivalfetch_tagsanity () {
119148ffe56aSColin Percival	# Check that we're not going to move from -pX to -pY with Y < X.
119248ffe56aSColin Percival	RELPX=`uname -r | sed -E 's,.*-,,'`
119348ffe56aSColin Percival	if echo ${RELPX} | grep -qE '^p[0-9]+$'; then
119448ffe56aSColin Percival		RELPX=`echo ${RELPX} | cut -c 2-`
119548ffe56aSColin Percival	else
119648ffe56aSColin Percival		RELPX=0
119748ffe56aSColin Percival	fi
119848ffe56aSColin Percival	if [ "${RELPATCHNUM}" -lt "${RELPX}" ]; then
119948ffe56aSColin Percival		echo
120048ffe56aSColin Percival		echo -n "Files on mirror (${RELNUM}-p${RELPATCHNUM})"
120148ffe56aSColin Percival		echo " appear older than what"
120248ffe56aSColin Percival		echo "we are currently running (`uname -r`)!"
120348ffe56aSColin Percival		echo "Cowardly refusing to proceed any further."
120448ffe56aSColin Percival		return 1
120548ffe56aSColin Percival	fi
120648ffe56aSColin Percival
120748ffe56aSColin Percival	# If "tag" exists and corresponds to ${RELNUM}, make sure that
120848ffe56aSColin Percival	# it contains a patch number <= RELPATCHNUM, in order to protect
120948ffe56aSColin Percival	# against rollback (replay) attacks.
121048ffe56aSColin Percival	if [ -f tag ] &&
121148ffe56aSColin Percival	    grep -qE	\
121248ffe56aSColin Percival    "^freebsd-update\|${ARCH}\|${RELNUM}\|[0-9]+\|[0-9a-f]{64}\|[0-9]{10}" \
121348ffe56aSColin Percival		tag; then
121448ffe56aSColin Percival		LASTRELPATCHNUM=`cut -f 4 -d '|' < tag`
121548ffe56aSColin Percival
121648ffe56aSColin Percival		if [ "${RELPATCHNUM}" -lt "${LASTRELPATCHNUM}" ]; then
121748ffe56aSColin Percival			echo
121848ffe56aSColin Percival			echo -n "Files on mirror (${RELNUM}-p${RELPATCHNUM})"
121948ffe56aSColin Percival			echo " are older than the"
122048ffe56aSColin Percival			echo -n "most recently seen updates"
122148ffe56aSColin Percival			echo " (${RELNUM}-p${LASTRELPATCHNUM})."
122248ffe56aSColin Percival			echo "Cowardly refusing to proceed any further."
122348ffe56aSColin Percival			return 1
122448ffe56aSColin Percival		fi
122548ffe56aSColin Percival	fi
122648ffe56aSColin Percival}
122748ffe56aSColin Percival
122848ffe56aSColin Percival# Fetch metadata index file
122948ffe56aSColin Percivalfetch_metadata_index () {
123048ffe56aSColin Percival	echo ${NDEBUG} "Fetching metadata index... "
123148ffe56aSColin Percival	rm -f ${TINDEXHASH}
123248ffe56aSColin Percival	fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/t/${TINDEXHASH}
123348ffe56aSColin Percival	    2>${QUIETREDIR}
123448ffe56aSColin Percival	if ! [ -f ${TINDEXHASH} ]; then
123548ffe56aSColin Percival		echo "failed."
123648ffe56aSColin Percival		return 1
123748ffe56aSColin Percival	fi
123848ffe56aSColin Percival	if [ `${SHA256} -q ${TINDEXHASH}` != ${TINDEXHASH} ]; then
123948ffe56aSColin Percival		echo "update metadata index corrupt."
124048ffe56aSColin Percival		return 1
124148ffe56aSColin Percival	fi
124248ffe56aSColin Percival	echo "done."
124348ffe56aSColin Percival}
124448ffe56aSColin Percival
124548ffe56aSColin Percival# Print an error message about signed metadata being bogus.
124648ffe56aSColin Percivalfetch_metadata_bogus () {
124748ffe56aSColin Percival	echo
124848ffe56aSColin Percival	echo "The update metadata$1 is correctly signed, but"
124948ffe56aSColin Percival	echo "failed an integrity check."
125048ffe56aSColin Percival	echo "Cowardly refusing to proceed any further."
125148ffe56aSColin Percival	return 1
125248ffe56aSColin Percival}
125348ffe56aSColin Percival
125448ffe56aSColin Percival# Construct tINDEX.new by merging the lines named in $1 from ${TINDEXHASH}
125548ffe56aSColin Percival# with the lines not named in $@ from tINDEX.present (if that file exists).
125648ffe56aSColin Percivalfetch_metadata_index_merge () {
125748ffe56aSColin Percival	for METAFILE in $@; do
125848ffe56aSColin Percival		if [ `grep -E "^${METAFILE}\|" ${TINDEXHASH} | wc -l`	\
125948ffe56aSColin Percival		    -ne 1 ]; then
126048ffe56aSColin Percival			fetch_metadata_bogus " index"
126148ffe56aSColin Percival			return 1
126248ffe56aSColin Percival		fi
126348ffe56aSColin Percival
126448ffe56aSColin Percival		grep -E "${METAFILE}\|" ${TINDEXHASH}
126548ffe56aSColin Percival	done |
126648ffe56aSColin Percival	    sort > tINDEX.wanted
126748ffe56aSColin Percival
126848ffe56aSColin Percival	if [ -f tINDEX.present ]; then
126948ffe56aSColin Percival		join -t '|' -v 2 tINDEX.wanted tINDEX.present |
127048ffe56aSColin Percival		    sort -m - tINDEX.wanted > tINDEX.new
127148ffe56aSColin Percival		rm tINDEX.wanted
127248ffe56aSColin Percival	else
127348ffe56aSColin Percival		mv tINDEX.wanted tINDEX.new
127448ffe56aSColin Percival	fi
127548ffe56aSColin Percival}
127648ffe56aSColin Percival
127748ffe56aSColin Percival# Sanity check all the lines of tINDEX.new.  Even if more metadata lines
127848ffe56aSColin Percival# are added by future versions of the server, this won't cause problems,
127948ffe56aSColin Percival# since the only lines which appear in tINDEX.new are the ones which we
128048ffe56aSColin Percival# specifically grepped out of ${TINDEXHASH}.
128148ffe56aSColin Percivalfetch_metadata_index_sanity () {
128248ffe56aSColin Percival	if grep -qvE '^[0-9A-Z.-]+\|[0-9a-f]{64}$' tINDEX.new; then
128348ffe56aSColin Percival		fetch_metadata_bogus " index"
128448ffe56aSColin Percival		return 1
128548ffe56aSColin Percival	fi
128648ffe56aSColin Percival}
128748ffe56aSColin Percival
128848ffe56aSColin Percival# Sanity check the metadata file $1.
128948ffe56aSColin Percivalfetch_metadata_sanity () {
129048ffe56aSColin Percival	# Some aliases to save space later: ${P} is a character which can
129148ffe56aSColin Percival	# appear in a path; ${M} is the four numeric metadata fields; and
129248ffe56aSColin Percival	# ${H} is a sha256 hash.
12937c06c7c5SKris Moore	P="[-+./:=,%@_[~[:alnum:]]"
129448ffe56aSColin Percival	M="[0-9]+\|[0-9]+\|[0-9]+\|[0-9]+"
129548ffe56aSColin Percival	H="[0-9a-f]{64}"
129648ffe56aSColin Percival
129748ffe56aSColin Percival	# Check that the first four fields make sense.
129848ffe56aSColin Percival	if gunzip -c < files/$1.gz |
1299823c0d5fSXin LI	    grep -qvE "^[a-z]+\|[0-9a-z-]+\|${P}+\|[fdL-]\|"; then
130048ffe56aSColin Percival		fetch_metadata_bogus ""
130148ffe56aSColin Percival		return 1
130248ffe56aSColin Percival	fi
130348ffe56aSColin Percival
130448ffe56aSColin Percival	# Remove the first three fields.
130548ffe56aSColin Percival	gunzip -c < files/$1.gz |
130648ffe56aSColin Percival	    cut -f 4- -d '|' > sanitycheck.tmp
130748ffe56aSColin Percival
130848ffe56aSColin Percival	# Sanity check entries with type 'f'
130948ffe56aSColin Percival	if grep -E '^f' sanitycheck.tmp |
131048ffe56aSColin Percival	    grep -qvE "^f\|${M}\|${H}\|${P}*\$"; then
131148ffe56aSColin Percival		fetch_metadata_bogus ""
131248ffe56aSColin Percival		return 1
131348ffe56aSColin Percival	fi
131448ffe56aSColin Percival
131548ffe56aSColin Percival	# Sanity check entries with type 'd'
131648ffe56aSColin Percival	if grep -E '^d' sanitycheck.tmp |
131748ffe56aSColin Percival	    grep -qvE "^d\|${M}\|\|\$"; then
131848ffe56aSColin Percival		fetch_metadata_bogus ""
131948ffe56aSColin Percival		return 1
132048ffe56aSColin Percival	fi
132148ffe56aSColin Percival
132248ffe56aSColin Percival	# Sanity check entries with type 'L'
132348ffe56aSColin Percival	if grep -E '^L' sanitycheck.tmp |
132448ffe56aSColin Percival	    grep -qvE "^L\|${M}\|${P}*\|\$"; then
132548ffe56aSColin Percival		fetch_metadata_bogus ""
132648ffe56aSColin Percival		return 1
132748ffe56aSColin Percival	fi
132848ffe56aSColin Percival
132948ffe56aSColin Percival	# Sanity check entries with type '-'
133048ffe56aSColin Percival	if grep -E '^-' sanitycheck.tmp |
133148ffe56aSColin Percival	    grep -qvE "^-\|\|\|\|\|\|"; then
133248ffe56aSColin Percival		fetch_metadata_bogus ""
133348ffe56aSColin Percival		return 1
133448ffe56aSColin Percival	fi
133548ffe56aSColin Percival
133648ffe56aSColin Percival	# Clean up
133748ffe56aSColin Percival	rm sanitycheck.tmp
133848ffe56aSColin Percival}
133948ffe56aSColin Percival
134048ffe56aSColin Percival# Fetch the metadata index and metadata files listed in $@,
134148ffe56aSColin Percival# taking advantage of metadata patches where possible.
134248ffe56aSColin Percivalfetch_metadata () {
134348ffe56aSColin Percival	fetch_metadata_index || return 1
134448ffe56aSColin Percival	fetch_metadata_index_merge $@ || return 1
134548ffe56aSColin Percival	fetch_metadata_index_sanity || return 1
134648ffe56aSColin Percival
134748ffe56aSColin Percival	# Generate a list of wanted metadata patches
134848ffe56aSColin Percival	join -t '|' -o 1.2,2.2 tINDEX.present tINDEX.new |
134948ffe56aSColin Percival	    fetch_make_patchlist > patchlist
135048ffe56aSColin Percival
135148ffe56aSColin Percival	if [ -s patchlist ]; then
135248ffe56aSColin Percival		# Attempt to fetch metadata patches
135348ffe56aSColin Percival		echo -n "Fetching `wc -l < patchlist | tr -d ' '` "
135448ffe56aSColin Percival		echo ${NDEBUG} "metadata patches.${DDSTATS}"
135548ffe56aSColin Percival		tr '|' '-' < patchlist |
135648ffe56aSColin Percival		    lam -s "${FETCHDIR}/tp/" - -s ".gz" |
135748ffe56aSColin Percival		    xargs ${XARGST} ${PHTTPGET} ${SERVERNAME}	\
135848ffe56aSColin Percival			2>${STATSREDIR} | fetch_progress
135948ffe56aSColin Percival		echo "done."
136048ffe56aSColin Percival
136148ffe56aSColin Percival		# Attempt to apply metadata patches
136248ffe56aSColin Percival		echo -n "Applying metadata patches... "
136348ffe56aSColin Percival		tr '|' ' ' < patchlist |
136448ffe56aSColin Percival		    while read X Y; do
136548ffe56aSColin Percival			if [ ! -f "${X}-${Y}.gz" ]; then continue; fi
136648ffe56aSColin Percival			gunzip -c < ${X}-${Y}.gz > diff
136748ffe56aSColin Percival			gunzip -c < files/${X}.gz > diff-OLD
136848ffe56aSColin Percival
136948ffe56aSColin Percival			# Figure out which lines are being added and removed
137048ffe56aSColin Percival			grep -E '^-' diff |
137148ffe56aSColin Percival			    cut -c 2- |
137248ffe56aSColin Percival			    while read PREFIX; do
137348ffe56aSColin Percival				look "${PREFIX}" diff-OLD
137448ffe56aSColin Percival			    done |
137548ffe56aSColin Percival			    sort > diff-rm
137648ffe56aSColin Percival			grep -E '^\+' diff |
137748ffe56aSColin Percival			    cut -c 2- > diff-add
137848ffe56aSColin Percival
137948ffe56aSColin Percival			# Generate the new file
138048ffe56aSColin Percival			comm -23 diff-OLD diff-rm |
138148ffe56aSColin Percival			    sort - diff-add > diff-NEW
138248ffe56aSColin Percival
138348ffe56aSColin Percival			if [ `${SHA256} -q diff-NEW` = ${Y} ]; then
138448ffe56aSColin Percival				mv diff-NEW files/${Y}
138548ffe56aSColin Percival				gzip -n files/${Y}
138648ffe56aSColin Percival			else
138748ffe56aSColin Percival				mv diff-NEW ${Y}.bad
138848ffe56aSColin Percival			fi
138948ffe56aSColin Percival			rm -f ${X}-${Y}.gz diff
139048ffe56aSColin Percival			rm -f diff-OLD diff-NEW diff-add diff-rm
139148ffe56aSColin Percival		done 2>${QUIETREDIR}
139248ffe56aSColin Percival		echo "done."
139348ffe56aSColin Percival	fi
139448ffe56aSColin Percival
139548ffe56aSColin Percival	# Update metadata without patches
139648ffe56aSColin Percival	cut -f 2 -d '|' < tINDEX.new |
139748ffe56aSColin Percival	    while read Y; do
139848ffe56aSColin Percival		if [ ! -f "files/${Y}.gz" ]; then
139948ffe56aSColin Percival			echo ${Y};
140048ffe56aSColin Percival		fi
1401bce02f98SColin Percival	    done |
1402bce02f98SColin Percival	    sort -u > filelist
140348ffe56aSColin Percival
140448ffe56aSColin Percival	if [ -s filelist ]; then
140548ffe56aSColin Percival		echo -n "Fetching `wc -l < filelist | tr -d ' '` "
140648ffe56aSColin Percival		echo ${NDEBUG} "metadata files... "
140748ffe56aSColin Percival		lam -s "${FETCHDIR}/m/" - -s ".gz" < filelist |
140848ffe56aSColin Percival		    xargs ${XARGST} ${PHTTPGET} ${SERVERNAME}	\
140948ffe56aSColin Percival		    2>${QUIETREDIR}
141048ffe56aSColin Percival
141148ffe56aSColin Percival		while read Y; do
141248ffe56aSColin Percival			if ! [ -f ${Y}.gz ]; then
141348ffe56aSColin Percival				echo "failed."
141448ffe56aSColin Percival				return 1
141548ffe56aSColin Percival			fi
141648ffe56aSColin Percival			if [ `gunzip -c < ${Y}.gz |
141748ffe56aSColin Percival			    ${SHA256} -q` = ${Y} ]; then
141848ffe56aSColin Percival				mv ${Y}.gz files/${Y}.gz
141948ffe56aSColin Percival			else
142048ffe56aSColin Percival				echo "metadata is corrupt."
142148ffe56aSColin Percival				return 1
142248ffe56aSColin Percival			fi
142348ffe56aSColin Percival		done < filelist
142448ffe56aSColin Percival		echo "done."
142548ffe56aSColin Percival	fi
142648ffe56aSColin Percival
142748ffe56aSColin Percival# Sanity-check the metadata files.
142848ffe56aSColin Percival	cut -f 2 -d '|' tINDEX.new > filelist
142948ffe56aSColin Percival	while read X; do
143048ffe56aSColin Percival		fetch_metadata_sanity ${X} || return 1
143148ffe56aSColin Percival	done < filelist
143248ffe56aSColin Percival
143348ffe56aSColin Percival# Remove files which are no longer needed
143448ffe56aSColin Percival	cut -f 2 -d '|' tINDEX.present |
143548ffe56aSColin Percival	    sort > oldfiles
143648ffe56aSColin Percival	cut -f 2 -d '|' tINDEX.new |
143748ffe56aSColin Percival	    sort |
143848ffe56aSColin Percival	    comm -13 - oldfiles |
143948ffe56aSColin Percival	    lam -s "files/" - -s ".gz" |
144048ffe56aSColin Percival	    xargs rm -f
144148ffe56aSColin Percival	rm patchlist filelist oldfiles
144248ffe56aSColin Percival	rm ${TINDEXHASH}
144348ffe56aSColin Percival
144448ffe56aSColin Percival# We're done!
144548ffe56aSColin Percival	mv tINDEX.new tINDEX.present
144648ffe56aSColin Percival	mv tag.new tag
144748ffe56aSColin Percival
144848ffe56aSColin Percival	return 0
144948ffe56aSColin Percival}
145048ffe56aSColin Percival
1451db6b0a61SColin Percival# Extract a subset of a downloaded metadata file containing only the parts
1452db6b0a61SColin Percival# which are listed in COMPONENTS.
1453db6b0a61SColin Percivalfetch_filter_metadata_components () {
1454db6b0a61SColin Percival	METAHASH=`look "$1|" tINDEX.present | cut -f 2 -d '|'`
1455db6b0a61SColin Percival	gunzip -c < files/${METAHASH}.gz > $1.all
1456db6b0a61SColin Percival
1457db6b0a61SColin Percival	# Fish out the lines belonging to components we care about.
1458db6b0a61SColin Percival	for C in ${COMPONENTS}; do
1459db6b0a61SColin Percival		look "`echo ${C} | tr '/' '|'`|" $1.all
1460db6b0a61SColin Percival	done > $1
1461db6b0a61SColin Percival
1462db6b0a61SColin Percival	# Remove temporary file.
1463db6b0a61SColin Percival	rm $1.all
1464db6b0a61SColin Percival}
1465db6b0a61SColin Percival
1466b698a3abSColin Percival# Generate a filtered version of the metadata file $1 from the downloaded
146748ffe56aSColin Percival# file, by fishing out the lines corresponding to components we're trying
146848ffe56aSColin Percival# to keep updated, and then removing lines corresponding to paths we want
146948ffe56aSColin Percival# to ignore.
147048ffe56aSColin Percivalfetch_filter_metadata () {
147148ffe56aSColin Percival	# Fish out the lines belonging to components we care about.
1472db6b0a61SColin Percival	fetch_filter_metadata_components $1
1473db6b0a61SColin Percival
147448ffe56aSColin Percival	# Canonicalize directory names by removing any trailing / in
147548ffe56aSColin Percival	# order to avoid listing directories multiple times if they
147648ffe56aSColin Percival	# belong to multiple components.  Turning "/" into "" doesn't
147748ffe56aSColin Percival	# matter, since we add a leading "/" when we use paths later.
1478db6b0a61SColin Percival	cut -f 3- -d '|' $1 |
147948ffe56aSColin Percival	    sed -e 's,/|d|,|d|,' |
14807e654612SColin Percival	    sed -e 's,/|-|,|-|,' |
148148ffe56aSColin Percival	    sort -u > $1.tmp
148248ffe56aSColin Percival
148348ffe56aSColin Percival	# Figure out which lines to ignore and remove them.
148448ffe56aSColin Percival	for X in ${IGNOREPATHS}; do
148548ffe56aSColin Percival		grep -E "^${X}" $1.tmp
148648ffe56aSColin Percival	done |
148748ffe56aSColin Percival	    sort -u |
148848ffe56aSColin Percival	    comm -13 - $1.tmp > $1
148948ffe56aSColin Percival
149048ffe56aSColin Percival	# Remove temporary files.
1491db6b0a61SColin Percival	rm $1.tmp
149248ffe56aSColin Percival}
149348ffe56aSColin Percival
1494db6b0a61SColin Percival# Filter the metadata file $1 by adding lines with "/boot/$2"
1495bce02f98SColin Percival# replaced by ${KERNELDIR} (which is `sysctl -n kern.bootfile` minus the
1496db6b0a61SColin Percival# trailing "/kernel"); and if "/boot/$2" does not exist, remove
1497bce02f98SColin Percival# the original lines which start with that.
1498bce02f98SColin Percival# Put another way: Deal with the fact that the FOO kernel is sometimes
1499bce02f98SColin Percival# installed in /boot/FOO/ and is sometimes installed elsewhere.
150048ffe56aSColin Percivalfetch_filter_kernel_names () {
1501db6b0a61SColin Percival	grep ^/boot/$2 $1 |
1502db6b0a61SColin Percival	    sed -e "s,/boot/$2,${KERNELDIR},g" |
150348ffe56aSColin Percival	    sort - $1 > $1.tmp
150448ffe56aSColin Percival	mv $1.tmp $1
1505bce02f98SColin Percival
1506db6b0a61SColin Percival	if ! [ -d /boot/$2 ]; then
1507db6b0a61SColin Percival		grep -v ^/boot/$2 $1 > $1.tmp
1508bce02f98SColin Percival		mv $1.tmp $1
1509bce02f98SColin Percival	fi
151048ffe56aSColin Percival}
151148ffe56aSColin Percival
151248ffe56aSColin Percival# For all paths appearing in $1 or $3, inspect the system
151348ffe56aSColin Percival# and generate $2 describing what is currently installed.
151448ffe56aSColin Percivalfetch_inspect_system () {
151548ffe56aSColin Percival	# No errors yet...
151648ffe56aSColin Percival	rm -f .err
151748ffe56aSColin Percival
151848ffe56aSColin Percival	# Tell the user why his disk is suddenly making lots of noise
151948ffe56aSColin Percival	echo -n "Inspecting system... "
152048ffe56aSColin Percival
152148ffe56aSColin Percival	# Generate list of files to inspect
152248ffe56aSColin Percival	cat $1 $3 |
152348ffe56aSColin Percival	    cut -f 1 -d '|' |
152448ffe56aSColin Percival	    sort -u > filelist
152548ffe56aSColin Percival
152648ffe56aSColin Percival	# Examine each file and output lines of the form
152748ffe56aSColin Percival	# /path/to/file|type|device-inum|user|group|perm|flags|value
152848ffe56aSColin Percival	# sorted by device and inode number.
152948ffe56aSColin Percival	while read F; do
153048ffe56aSColin Percival		# If the symlink/file/directory does not exist, record this.
153148ffe56aSColin Percival		if ! [ -e ${BASEDIR}/${F} ]; then
153248ffe56aSColin Percival			echo "${F}|-||||||"
153348ffe56aSColin Percival			continue
153448ffe56aSColin Percival		fi
153548ffe56aSColin Percival		if ! [ -r ${BASEDIR}/${F} ]; then
153648ffe56aSColin Percival			echo "Cannot read file: ${BASEDIR}/${F}"	\
153748ffe56aSColin Percival			    >/dev/stderr
153848ffe56aSColin Percival			touch .err
153948ffe56aSColin Percival			return 1
154048ffe56aSColin Percival		fi
154148ffe56aSColin Percival
154248ffe56aSColin Percival		# Otherwise, output an index line.
154348ffe56aSColin Percival		if [ -L ${BASEDIR}/${F} ]; then
154448ffe56aSColin Percival			echo -n "${F}|L|"
154548ffe56aSColin Percival			stat -n -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F};
154648ffe56aSColin Percival			readlink ${BASEDIR}/${F};
154748ffe56aSColin Percival		elif [ -f ${BASEDIR}/${F} ]; then
154848ffe56aSColin Percival			echo -n "${F}|f|"
154948ffe56aSColin Percival			stat -n -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F};
155048ffe56aSColin Percival			sha256 -q ${BASEDIR}/${F};
155148ffe56aSColin Percival		elif [ -d ${BASEDIR}/${F} ]; then
155248ffe56aSColin Percival			echo -n "${F}|d|"
155348ffe56aSColin Percival			stat -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F};
155448ffe56aSColin Percival		else
155548ffe56aSColin Percival			echo "Unknown file type: ${BASEDIR}/${F}"	\
155648ffe56aSColin Percival			    >/dev/stderr
155748ffe56aSColin Percival			touch .err
155848ffe56aSColin Percival			return 1
155948ffe56aSColin Percival		fi
156048ffe56aSColin Percival	done < filelist |
156148ffe56aSColin Percival	    sort -k 3,3 -t '|' > $2.tmp
156248ffe56aSColin Percival	rm filelist
156348ffe56aSColin Percival
15646dcc68c8SBenedict Reuschling	# Check if an error occurred during system inspection
156548ffe56aSColin Percival	if [ -f .err ]; then
156648ffe56aSColin Percival		return 1
156748ffe56aSColin Percival	fi
156848ffe56aSColin Percival
156948ffe56aSColin Percival	# Convert to the form
157048ffe56aSColin Percival	# /path/to/file|type|user|group|perm|flags|value|hlink
157148ffe56aSColin Percival	# by resolving identical device and inode numbers into hard links.
157248ffe56aSColin Percival	cut -f 1,3 -d '|' $2.tmp |
157348ffe56aSColin Percival	    sort -k 1,1 -t '|' |
157448ffe56aSColin Percival	    sort -s -u -k 2,2 -t '|' |
157548ffe56aSColin Percival	    join -1 2 -2 3 -t '|' - $2.tmp |
157648ffe56aSColin Percival	    awk -F \| -v OFS=\|		\
157748ffe56aSColin Percival		'{
157848ffe56aSColin Percival		    if (($2 == $3) || ($4 == "-"))
157948ffe56aSColin Percival			print $3,$4,$5,$6,$7,$8,$9,""
158048ffe56aSColin Percival		    else
158148ffe56aSColin Percival			print $3,$4,$5,$6,$7,$8,$9,$2
158248ffe56aSColin Percival		}' |
158348ffe56aSColin Percival	    sort > $2
158448ffe56aSColin Percival	rm $2.tmp
158548ffe56aSColin Percival
158648ffe56aSColin Percival	# We're finished looking around
158748ffe56aSColin Percival	echo "done."
158848ffe56aSColin Percival}
158948ffe56aSColin Percival
1590db6b0a61SColin Percival# For any paths matching ${MERGECHANGES}, compare $1 and $2 and find any
1591db6b0a61SColin Percival# files which differ; generate $3 containing these paths and the old hashes.
1592db6b0a61SColin Percivalfetch_filter_mergechanges () {
1593db6b0a61SColin Percival	# Pull out the paths and hashes of the files matching ${MERGECHANGES}.
1594db6b0a61SColin Percival	for F in $1 $2; do
1595db6b0a61SColin Percival		for X in ${MERGECHANGES}; do
1596db6b0a61SColin Percival			grep -E "^${X}" ${F}
1597db6b0a61SColin Percival		done |
1598db6b0a61SColin Percival		    cut -f 1,2,7 -d '|' |
1599db6b0a61SColin Percival		    sort > ${F}-values
1600db6b0a61SColin Percival	done
1601db6b0a61SColin Percival
1602db6b0a61SColin Percival	# Any line in $2-values which doesn't appear in $1-values and is a
1603db6b0a61SColin Percival	# file means that we should list the path in $3.
1604db6b0a61SColin Percival	comm -13 $1-values $2-values |
1605db6b0a61SColin Percival	    fgrep '|f|' |
1606db6b0a61SColin Percival	    cut -f 1 -d '|' > $2-paths
1607db6b0a61SColin Percival
1608db6b0a61SColin Percival	# For each path, pull out one (and only one!) entry from $1-values.
1609db6b0a61SColin Percival	# Note that we cannot distinguish which "old" version the user made
1610db6b0a61SColin Percival	# changes to; but hopefully any changes which occur due to security
1611db6b0a61SColin Percival	# updates will exist in both the "new" version and the version which
1612db6b0a61SColin Percival	# the user has installed, so the merging will still work.
1613db6b0a61SColin Percival	while read X; do
1614db6b0a61SColin Percival		look "${X}|" $1-values |
1615db6b0a61SColin Percival		    head -1
1616db6b0a61SColin Percival	done < $2-paths > $3
1617db6b0a61SColin Percival
1618db6b0a61SColin Percival	# Clean up
1619db6b0a61SColin Percival	rm $1-values $2-values $2-paths
1620db6b0a61SColin Percival}
1621db6b0a61SColin Percival
162248ffe56aSColin Percival# For any paths matching ${UPDATEIFUNMODIFIED}, remove lines from $[123]
1623db6b0a61SColin Percival# which correspond to lines in $2 with hashes not matching $1 or $3, unless
1624db6b0a61SColin Percival# the paths are listed in $4.  For entries in $2 marked "not present"
1625db6b0a61SColin Percival# (aka. type -), remove lines from $[123] unless there is a corresponding
1626db6b0a61SColin Percival# entry in $1.
162748ffe56aSColin Percivalfetch_filter_unmodified_notpresent () {
162848ffe56aSColin Percival	# Figure out which lines of $1 and $3 correspond to bits which
162948ffe56aSColin Percival	# should only be updated if they haven't changed, and fish out
163048ffe56aSColin Percival	# the (path, type, value) tuples.
163148ffe56aSColin Percival	# NOTE: We don't consider a file to be "modified" if it matches
163248ffe56aSColin Percival	# the hash from $3.
163348ffe56aSColin Percival	for X in ${UPDATEIFUNMODIFIED}; do
163448ffe56aSColin Percival		grep -E "^${X}" $1
163548ffe56aSColin Percival		grep -E "^${X}" $3
163648ffe56aSColin Percival	done |
163748ffe56aSColin Percival	    cut -f 1,2,7 -d '|' |
163848ffe56aSColin Percival	    sort > $1-values
163948ffe56aSColin Percival
164048ffe56aSColin Percival	# Do the same for $2.
164148ffe56aSColin Percival	for X in ${UPDATEIFUNMODIFIED}; do
164248ffe56aSColin Percival		grep -E "^${X}" $2
164348ffe56aSColin Percival	done |
164448ffe56aSColin Percival	    cut -f 1,2,7 -d '|' |
164548ffe56aSColin Percival	    sort > $2-values
164648ffe56aSColin Percival
164748ffe56aSColin Percival	# Any entry in $2-values which is not in $1-values corresponds to
1648db6b0a61SColin Percival	# a path which we need to remove from $1, $2, and $3, unless it
1649db6b0a61SColin Percival	# that path appears in $4.
1650db6b0a61SColin Percival	comm -13 $1-values $2-values |
1651db6b0a61SColin Percival	    sort -t '|' -k 1,1 > mlines.tmp
1652db6b0a61SColin Percival	cut -f 1 -d '|' $4 |
1653db6b0a61SColin Percival	    sort |
1654db6b0a61SColin Percival	    join -v 2 -t '|' - mlines.tmp |
1655db6b0a61SColin Percival	    sort > mlines
1656db6b0a61SColin Percival	rm $1-values $2-values mlines.tmp
165748ffe56aSColin Percival
165848ffe56aSColin Percival	# Any lines in $2 which are not in $1 AND are "not present" lines
165948ffe56aSColin Percival	# also belong in mlines.
166048ffe56aSColin Percival	comm -13 $1 $2 |
166148ffe56aSColin Percival	    cut -f 1,2,7 -d '|' |
166248ffe56aSColin Percival	    fgrep '|-|' >> mlines
166348ffe56aSColin Percival
166448ffe56aSColin Percival	# Remove lines from $1, $2, and $3
166548ffe56aSColin Percival	for X in $1 $2 $3; do
166648ffe56aSColin Percival		sort -t '|' -k 1,1 ${X} > ${X}.tmp
166748ffe56aSColin Percival		cut -f 1 -d '|' < mlines |
166848ffe56aSColin Percival		    sort |
166948ffe56aSColin Percival		    join -v 2 -t '|' - ${X}.tmp |
167048ffe56aSColin Percival		    sort > ${X}
167148ffe56aSColin Percival		rm ${X}.tmp
167248ffe56aSColin Percival	done
167348ffe56aSColin Percival
167448ffe56aSColin Percival	# Store a list of the modified files, for future reference
167548ffe56aSColin Percival	fgrep -v '|-|' mlines |
167648ffe56aSColin Percival	    cut -f 1 -d '|' > modifiedfiles
167748ffe56aSColin Percival	rm mlines
167848ffe56aSColin Percival}
167948ffe56aSColin Percival
168048ffe56aSColin Percival# For each entry in $1 of type -, remove any corresponding
168148ffe56aSColin Percival# entry from $2 if ${ALLOWADD} != "yes".  Remove all entries
168248ffe56aSColin Percival# of type - from $1.
168348ffe56aSColin Percivalfetch_filter_allowadd () {
168448ffe56aSColin Percival	cut -f 1,2 -d '|' < $1 |
168548ffe56aSColin Percival	    fgrep '|-' |
168648ffe56aSColin Percival	    cut -f 1 -d '|' > filesnotpresent
168748ffe56aSColin Percival
168848ffe56aSColin Percival	if [ ${ALLOWADD} != "yes" ]; then
168948ffe56aSColin Percival		sort < $2 |
169048ffe56aSColin Percival		    join -v 1 -t '|' - filesnotpresent |
169148ffe56aSColin Percival		    sort > $2.tmp
169248ffe56aSColin Percival		mv $2.tmp $2
169348ffe56aSColin Percival	fi
169448ffe56aSColin Percival
169548ffe56aSColin Percival	sort < $1 |
169648ffe56aSColin Percival	    join -v 1 -t '|' - filesnotpresent |
169748ffe56aSColin Percival	    sort > $1.tmp
169848ffe56aSColin Percival	mv $1.tmp $1
169948ffe56aSColin Percival	rm filesnotpresent
170048ffe56aSColin Percival}
170148ffe56aSColin Percival
170248ffe56aSColin Percival# If ${ALLOWDELETE} != "yes", then remove any entries from $1
170348ffe56aSColin Percival# which don't correspond to entries in $2.
170448ffe56aSColin Percivalfetch_filter_allowdelete () {
170548ffe56aSColin Percival	# Produce a lists ${PATH}|${TYPE}
170648ffe56aSColin Percival	for X in $1 $2; do
170748ffe56aSColin Percival		cut -f 1-2 -d '|' < ${X} |
170848ffe56aSColin Percival		    sort -u > ${X}.nodes
170948ffe56aSColin Percival	done
171048ffe56aSColin Percival
171148ffe56aSColin Percival	# Figure out which lines need to be removed from $1.
171248ffe56aSColin Percival	if [ ${ALLOWDELETE} != "yes" ]; then
171348ffe56aSColin Percival		comm -23 $1.nodes $2.nodes > $1.badnodes
171448ffe56aSColin Percival	else
171548ffe56aSColin Percival		: > $1.badnodes
171648ffe56aSColin Percival	fi
171748ffe56aSColin Percival
171848ffe56aSColin Percival	# Remove the relevant lines from $1
171948ffe56aSColin Percival	while read X; do
172048ffe56aSColin Percival		look "${X}|" $1
172148ffe56aSColin Percival	done < $1.badnodes |
172248ffe56aSColin Percival	    comm -13 - $1 > $1.tmp
172348ffe56aSColin Percival	mv $1.tmp $1
172448ffe56aSColin Percival
172548ffe56aSColin Percival	rm $1.badnodes $1.nodes $2.nodes
172648ffe56aSColin Percival}
172748ffe56aSColin Percival
172848ffe56aSColin Percival# If ${KEEPMODIFIEDMETADATA} == "yes", then for each entry in $2
172948ffe56aSColin Percival# with metadata not matching any entry in $1, replace the corresponding
173048ffe56aSColin Percival# line of $3 with one having the same metadata as the entry in $2.
173148ffe56aSColin Percivalfetch_filter_modified_metadata () {
173248ffe56aSColin Percival	# Fish out the metadata from $1 and $2
173348ffe56aSColin Percival	for X in $1 $2; do
173448ffe56aSColin Percival		cut -f 1-6 -d '|' < ${X} > ${X}.metadata
173548ffe56aSColin Percival	done
173648ffe56aSColin Percival
173748ffe56aSColin Percival	# Find the metadata we need to keep
173848ffe56aSColin Percival	if [ ${KEEPMODIFIEDMETADATA} = "yes" ]; then
173948ffe56aSColin Percival		comm -13 $1.metadata $2.metadata > keepmeta
174048ffe56aSColin Percival	else
174148ffe56aSColin Percival		: > keepmeta
174248ffe56aSColin Percival	fi
174348ffe56aSColin Percival
174448ffe56aSColin Percival	# Extract the lines which we need to remove from $3, and
174548ffe56aSColin Percival	# construct the lines which we need to add to $3.
174648ffe56aSColin Percival	: > $3.remove
174748ffe56aSColin Percival	: > $3.add
174848ffe56aSColin Percival	while read LINE; do
174948ffe56aSColin Percival		NODE=`echo "${LINE}" | cut -f 1-2 -d '|'`
175048ffe56aSColin Percival		look "${NODE}|" $3 >> $3.remove
175148ffe56aSColin Percival		look "${NODE}|" $3 |
175248ffe56aSColin Percival		    cut -f 7- -d '|' |
175348ffe56aSColin Percival		    lam -s "${LINE}|" - >> $3.add
175448ffe56aSColin Percival	done < keepmeta
175548ffe56aSColin Percival
175648ffe56aSColin Percival	# Remove the specified lines and add the new lines.
175748ffe56aSColin Percival	sort $3.remove |
175848ffe56aSColin Percival	    comm -13 - $3 |
175948ffe56aSColin Percival	    sort -u - $3.add > $3.tmp
176048ffe56aSColin Percival	mv $3.tmp $3
176148ffe56aSColin Percival
176248ffe56aSColin Percival	rm keepmeta $1.metadata $2.metadata $3.add $3.remove
176348ffe56aSColin Percival}
176448ffe56aSColin Percival
176548ffe56aSColin Percival# Remove lines from $1 and $2 which are identical;
176648ffe56aSColin Percival# no need to update a file if it isn't changing.
176748ffe56aSColin Percivalfetch_filter_uptodate () {
176848ffe56aSColin Percival	comm -23 $1 $2 > $1.tmp
176948ffe56aSColin Percival	comm -13 $1 $2 > $2.tmp
177048ffe56aSColin Percival
177148ffe56aSColin Percival	mv $1.tmp $1
177248ffe56aSColin Percival	mv $2.tmp $2
177348ffe56aSColin Percival}
177448ffe56aSColin Percival
1775db6b0a61SColin Percival# Fetch any "clean" old versions of files we need for merging changes.
1776db6b0a61SColin Percivalfetch_files_premerge () {
1777db6b0a61SColin Percival	# We only need to do anything if $1 is non-empty.
1778db6b0a61SColin Percival	if [ -s $1 ]; then
1779db6b0a61SColin Percival		# Tell the user what we're doing
1780db6b0a61SColin Percival		echo -n "Fetching files from ${OLDRELNUM} for merging... "
1781db6b0a61SColin Percival
1782db6b0a61SColin Percival		# List of files wanted
1783db6b0a61SColin Percival		fgrep '|f|' < $1 |
1784db6b0a61SColin Percival		    cut -f 3 -d '|' |
1785db6b0a61SColin Percival		    sort -u > files.wanted
1786db6b0a61SColin Percival
1787db6b0a61SColin Percival		# Only fetch the files we don't already have
1788db6b0a61SColin Percival		while read Y; do
1789db6b0a61SColin Percival			if [ ! -f "files/${Y}.gz" ]; then
1790db6b0a61SColin Percival				echo ${Y};
1791db6b0a61SColin Percival			fi
1792db6b0a61SColin Percival		done < files.wanted > filelist
1793db6b0a61SColin Percival
1794db6b0a61SColin Percival		# Actually fetch them
1795db6b0a61SColin Percival		lam -s "${OLDFETCHDIR}/f/" - -s ".gz" < filelist |
1796db6b0a61SColin Percival		    xargs ${XARGST} ${PHTTPGET} ${SERVERNAME}	\
1797db6b0a61SColin Percival		    2>${QUIETREDIR}
1798db6b0a61SColin Percival
1799db6b0a61SColin Percival		# Make sure we got them all, and move them into /files/
1800db6b0a61SColin Percival		while read Y; do
1801db6b0a61SColin Percival			if ! [ -f ${Y}.gz ]; then
1802db6b0a61SColin Percival				echo "failed."
1803db6b0a61SColin Percival				return 1
1804db6b0a61SColin Percival			fi
1805db6b0a61SColin Percival			if [ `gunzip -c < ${Y}.gz |
1806db6b0a61SColin Percival			    ${SHA256} -q` = ${Y} ]; then
1807db6b0a61SColin Percival				mv ${Y}.gz files/${Y}.gz
1808db6b0a61SColin Percival			else
1809db6b0a61SColin Percival				echo "${Y} has incorrect hash."
1810db6b0a61SColin Percival				return 1
1811db6b0a61SColin Percival			fi
1812db6b0a61SColin Percival		done < filelist
1813db6b0a61SColin Percival		echo "done."
1814db6b0a61SColin Percival
1815db6b0a61SColin Percival		# Clean up
1816db6b0a61SColin Percival		rm filelist files.wanted
1817db6b0a61SColin Percival	fi
1818db6b0a61SColin Percival}
1819db6b0a61SColin Percival
182048ffe56aSColin Percival# Prepare to fetch files: Generate a list of the files we need,
182148ffe56aSColin Percival# copy the unmodified files we have into /files/, and generate
182248ffe56aSColin Percival# a list of patches to download.
182348ffe56aSColin Percivalfetch_files_prepare () {
182448ffe56aSColin Percival	# Tell the user why his disk is suddenly making lots of noise
182548ffe56aSColin Percival	echo -n "Preparing to download files... "
182648ffe56aSColin Percival
182748ffe56aSColin Percival	# Reduce indices to ${PATH}|${HASH} pairs
182848ffe56aSColin Percival	for X in $1 $2 $3; do
182948ffe56aSColin Percival		cut -f 1,2,7 -d '|' < ${X} |
183048ffe56aSColin Percival		    fgrep '|f|' |
183148ffe56aSColin Percival		    cut -f 1,3 -d '|' |
183248ffe56aSColin Percival		    sort > ${X}.hashes
183348ffe56aSColin Percival	done
183448ffe56aSColin Percival
183548ffe56aSColin Percival	# List of files wanted
183648ffe56aSColin Percival	cut -f 2 -d '|' < $3.hashes |
18372328d598SColin Percival	    sort -u |
18382328d598SColin Percival	    while read HASH; do
18392328d598SColin Percival		if ! [ -f files/${HASH}.gz ]; then
18402328d598SColin Percival			echo ${HASH}
18412328d598SColin Percival		fi
18422328d598SColin Percival	done > files.wanted
184348ffe56aSColin Percival
184448ffe56aSColin Percival	# Generate a list of unmodified files
184548ffe56aSColin Percival	comm -12 $1.hashes $2.hashes |
184648ffe56aSColin Percival	    sort -k 1,1 -t '|' > unmodified.files
184748ffe56aSColin Percival
184848ffe56aSColin Percival	# Copy all files into /files/.  We only need the unmodified files
184948ffe56aSColin Percival	# for use in patching; but we'll want all of them if the user asks
185048ffe56aSColin Percival	# to rollback the updates later.
1851210b8123SColin Percival	while read LINE; do
1852210b8123SColin Percival		F=`echo "${LINE}" | cut -f 1 -d '|'`
1853210b8123SColin Percival		HASH=`echo "${LINE}" | cut -f 2 -d '|'`
1854210b8123SColin Percival
1855210b8123SColin Percival		# Skip files we already have.
1856210b8123SColin Percival		if [ -f files/${HASH}.gz ]; then
1857210b8123SColin Percival			continue
1858210b8123SColin Percival		fi
1859210b8123SColin Percival
1860210b8123SColin Percival		# Make sure the file hasn't changed.
186148ffe56aSColin Percival		cp "${BASEDIR}/${F}" tmpfile
1862210b8123SColin Percival		if [ `sha256 -q tmpfile` != ${HASH} ]; then
1863210b8123SColin Percival			echo
1864210b8123SColin Percival			echo "File changed while FreeBSD Update running: ${F}"
1865210b8123SColin Percival			return 1
1866210b8123SColin Percival		fi
1867210b8123SColin Percival
1868210b8123SColin Percival		# Place the file into storage.
1869210b8123SColin Percival		gzip -c < tmpfile > files/${HASH}.gz
187048ffe56aSColin Percival		rm tmpfile
1871210b8123SColin Percival	done < $2.hashes
187248ffe56aSColin Percival
187348ffe56aSColin Percival	# Produce a list of patches to download
187448ffe56aSColin Percival	sort -k 1,1 -t '|' $3.hashes |
187548ffe56aSColin Percival	    join -t '|' -o 2.2,1.2 - unmodified.files |
187648ffe56aSColin Percival	    fetch_make_patchlist > patchlist
187748ffe56aSColin Percival
187848ffe56aSColin Percival	# Garbage collect
187948ffe56aSColin Percival	rm unmodified.files $1.hashes $2.hashes $3.hashes
188048ffe56aSColin Percival
188148ffe56aSColin Percival	# We don't need the list of possible old files any more.
188248ffe56aSColin Percival	rm $1
188348ffe56aSColin Percival
188448ffe56aSColin Percival	# We're finished making noise
188548ffe56aSColin Percival	echo "done."
188648ffe56aSColin Percival}
188748ffe56aSColin Percival
188848ffe56aSColin Percival# Fetch files.
188948ffe56aSColin Percivalfetch_files () {
189048ffe56aSColin Percival	# Attempt to fetch patches
189148ffe56aSColin Percival	if [ -s patchlist ]; then
189248ffe56aSColin Percival		echo -n "Fetching `wc -l < patchlist | tr -d ' '` "
189348ffe56aSColin Percival		echo ${NDEBUG} "patches.${DDSTATS}"
189448ffe56aSColin Percival		tr '|' '-' < patchlist |
1895db6b0a61SColin Percival		    lam -s "${PATCHDIR}/" - |
189648ffe56aSColin Percival		    xargs ${XARGST} ${PHTTPGET} ${SERVERNAME}	\
189748ffe56aSColin Percival			2>${STATSREDIR} | fetch_progress
189848ffe56aSColin Percival		echo "done."
189948ffe56aSColin Percival
190048ffe56aSColin Percival		# Attempt to apply patches
190148ffe56aSColin Percival		echo -n "Applying patches... "
190248ffe56aSColin Percival		tr '|' ' ' < patchlist |
190348ffe56aSColin Percival		    while read X Y; do
190448ffe56aSColin Percival			if [ ! -f "${X}-${Y}" ]; then continue; fi
190548ffe56aSColin Percival			gunzip -c < files/${X}.gz > OLD
190648ffe56aSColin Percival
190748ffe56aSColin Percival			bspatch OLD NEW ${X}-${Y}
190848ffe56aSColin Percival
190948ffe56aSColin Percival			if [ `${SHA256} -q NEW` = ${Y} ]; then
191048ffe56aSColin Percival				mv NEW files/${Y}
191148ffe56aSColin Percival				gzip -n files/${Y}
191248ffe56aSColin Percival			fi
191348ffe56aSColin Percival			rm -f diff OLD NEW ${X}-${Y}
191448ffe56aSColin Percival		done 2>${QUIETREDIR}
191548ffe56aSColin Percival		echo "done."
191648ffe56aSColin Percival	fi
191748ffe56aSColin Percival
191848ffe56aSColin Percival	# Download files which couldn't be generate via patching
191948ffe56aSColin Percival	while read Y; do
192048ffe56aSColin Percival		if [ ! -f "files/${Y}.gz" ]; then
192148ffe56aSColin Percival			echo ${Y};
192248ffe56aSColin Percival		fi
192348ffe56aSColin Percival	done < files.wanted > filelist
192448ffe56aSColin Percival
192548ffe56aSColin Percival	if [ -s filelist ]; then
192648ffe56aSColin Percival		echo -n "Fetching `wc -l < filelist | tr -d ' '` "
192748ffe56aSColin Percival		echo ${NDEBUG} "files... "
192848ffe56aSColin Percival		lam -s "${FETCHDIR}/f/" - -s ".gz" < filelist |
192948ffe56aSColin Percival		    xargs ${XARGST} ${PHTTPGET} ${SERVERNAME}	\
1930d6e1e31aSConrad Meyer			2>${STATSREDIR} | fetch_progress
193148ffe56aSColin Percival
193248ffe56aSColin Percival		while read Y; do
193348ffe56aSColin Percival			if ! [ -f ${Y}.gz ]; then
193448ffe56aSColin Percival				echo "failed."
193548ffe56aSColin Percival				return 1
193648ffe56aSColin Percival			fi
193748ffe56aSColin Percival			if [ `gunzip -c < ${Y}.gz |
193848ffe56aSColin Percival			    ${SHA256} -q` = ${Y} ]; then
193948ffe56aSColin Percival				mv ${Y}.gz files/${Y}.gz
194048ffe56aSColin Percival			else
194148ffe56aSColin Percival				echo "${Y} has incorrect hash."
194248ffe56aSColin Percival				return 1
194348ffe56aSColin Percival			fi
194448ffe56aSColin Percival		done < filelist
194548ffe56aSColin Percival		echo "done."
194648ffe56aSColin Percival	fi
194748ffe56aSColin Percival
194848ffe56aSColin Percival	# Clean up
194948ffe56aSColin Percival	rm files.wanted filelist patchlist
195048ffe56aSColin Percival}
195148ffe56aSColin Percival
195248ffe56aSColin Percival# Create and populate install manifest directory; and report what updates
195348ffe56aSColin Percival# are available.
195448ffe56aSColin Percivalfetch_create_manifest () {
195548ffe56aSColin Percival	# If we have an existing install manifest, nuke it.
195648ffe56aSColin Percival	if [ -L "${BDHASH}-install" ]; then
195748ffe56aSColin Percival		rm -r ${BDHASH}-install/
195848ffe56aSColin Percival		rm ${BDHASH}-install
195948ffe56aSColin Percival	fi
196048ffe56aSColin Percival
196148ffe56aSColin Percival	# Report to the user if any updates were avoided due to local changes
196248ffe56aSColin Percival	if [ -s modifiedfiles ]; then
1963fc24ba59SEd Maste		cat - modifiedfiles <<- EOF | ${PAGER}
1964b882e02bSEnji Cooper			The following files are affected by updates. No changes have
1965b882e02bSEnji Cooper			been downloaded, however, because the files have been modified
1966b882e02bSEnji Cooper			locally:
1967fc24ba59SEd Maste		EOF
1968fc24ba59SEd Maste	fi
196948ffe56aSColin Percival	rm modifiedfiles
197048ffe56aSColin Percival
197148ffe56aSColin Percival	# If no files will be updated, tell the user and exit
197248ffe56aSColin Percival	if ! [ -s INDEX-PRESENT ] &&
197348ffe56aSColin Percival	    ! [ -s INDEX-NEW ]; then
197448ffe56aSColin Percival		rm INDEX-PRESENT INDEX-NEW
197548ffe56aSColin Percival		echo
197648ffe56aSColin Percival		echo -n "No updates needed to update system to "
197748ffe56aSColin Percival		echo "${RELNUM}-p${RELPATCHNUM}."
197848ffe56aSColin Percival		return
197948ffe56aSColin Percival	fi
198048ffe56aSColin Percival
198148ffe56aSColin Percival	# Divide files into (a) removed files, (b) added files, and
198248ffe56aSColin Percival	# (c) updated files.
198348ffe56aSColin Percival	cut -f 1 -d '|' < INDEX-PRESENT |
198448ffe56aSColin Percival	    sort > INDEX-PRESENT.flist
198548ffe56aSColin Percival	cut -f 1 -d '|' < INDEX-NEW |
198648ffe56aSColin Percival	    sort > INDEX-NEW.flist
198748ffe56aSColin Percival	comm -23 INDEX-PRESENT.flist INDEX-NEW.flist > files.removed
198848ffe56aSColin Percival	comm -13 INDEX-PRESENT.flist INDEX-NEW.flist > files.added
198948ffe56aSColin Percival	comm -12 INDEX-PRESENT.flist INDEX-NEW.flist > files.updated
199048ffe56aSColin Percival	rm INDEX-PRESENT.flist INDEX-NEW.flist
199148ffe56aSColin Percival
199248ffe56aSColin Percival	# Report removed files, if any
199348ffe56aSColin Percival	if [ -s files.removed ]; then
1994fc24ba59SEd Maste		cat - files.removed <<- EOF | ${PAGER}
1995fc24ba59SEd Maste			The following files will be removed as part of updating to
1996fc24ba59SEd Maste			${RELNUM}-p${RELPATCHNUM}:
1997fc24ba59SEd Maste		EOF
1998fc24ba59SEd Maste	fi
199948ffe56aSColin Percival	rm files.removed
200048ffe56aSColin Percival
200148ffe56aSColin Percival	# Report added files, if any
200248ffe56aSColin Percival	if [ -s files.added ]; then
2003fc24ba59SEd Maste		cat - files.added <<- EOF | ${PAGER}
2004fc24ba59SEd Maste			The following files will be added as part of updating to
2005fc24ba59SEd Maste			${RELNUM}-p${RELPATCHNUM}:
2006fc24ba59SEd Maste		EOF
2007fc24ba59SEd Maste	fi
200848ffe56aSColin Percival	rm files.added
200948ffe56aSColin Percival
201048ffe56aSColin Percival	# Report updated files, if any
201148ffe56aSColin Percival	if [ -s files.updated ]; then
2012fc24ba59SEd Maste		cat - files.updated <<- EOF | ${PAGER}
2013fc24ba59SEd Maste			The following files will be updated as part of updating to
2014fc24ba59SEd Maste			${RELNUM}-p${RELPATCHNUM}:
2015fc24ba59SEd Maste		EOF
2016fc24ba59SEd Maste	fi
201748ffe56aSColin Percival	rm files.updated
201848ffe56aSColin Percival
201948ffe56aSColin Percival	# Create a directory for the install manifest.
202048ffe56aSColin Percival	MDIR=`mktemp -d install.XXXXXX` || return 1
202148ffe56aSColin Percival
202248ffe56aSColin Percival	# Populate it
202348ffe56aSColin Percival	mv INDEX-PRESENT ${MDIR}/INDEX-OLD
202448ffe56aSColin Percival	mv INDEX-NEW ${MDIR}/INDEX-NEW
202548ffe56aSColin Percival
202648ffe56aSColin Percival	# Link it into place
202748ffe56aSColin Percival	ln -s ${MDIR} ${BDHASH}-install
202848ffe56aSColin Percival}
202948ffe56aSColin Percival
203048ffe56aSColin Percival# Warn about any upcoming EoL
203148ffe56aSColin Percivalfetch_warn_eol () {
203248ffe56aSColin Percival	# What's the current time?
203348ffe56aSColin Percival	NOWTIME=`date "+%s"`
203448ffe56aSColin Percival
203548ffe56aSColin Percival	# When did we last warn about the EoL date?
203648ffe56aSColin Percival	if [ -f lasteolwarn ]; then
203748ffe56aSColin Percival		LASTWARN=`cat lasteolwarn`
203848ffe56aSColin Percival	else
203948ffe56aSColin Percival		LASTWARN=`expr ${NOWTIME} - 63072000`
204048ffe56aSColin Percival	fi
204148ffe56aSColin Percival
204248ffe56aSColin Percival	# If the EoL time is past, warn.
204348ffe56aSColin Percival	if [ ${EOLTIME} -lt ${NOWTIME} ]; then
204448ffe56aSColin Percival		echo
204548ffe56aSColin Percival		cat <<-EOF
2046b698a3abSColin Percival		WARNING: `uname -sr` HAS PASSED ITS END-OF-LIFE DATE.
204748ffe56aSColin Percival		Any security issues discovered after `date -r ${EOLTIME}`
204848ffe56aSColin Percival		will not have been corrected.
204948ffe56aSColin Percival		EOF
205048ffe56aSColin Percival		return 1
205148ffe56aSColin Percival	fi
205248ffe56aSColin Percival
205348ffe56aSColin Percival	# Figure out how long it has been since we last warned about the
205448ffe56aSColin Percival	# upcoming EoL, and how much longer we have left.
205548ffe56aSColin Percival	SINCEWARN=`expr ${NOWTIME} - ${LASTWARN}`
205648ffe56aSColin Percival	TIMELEFT=`expr ${EOLTIME} - ${NOWTIME}`
205748ffe56aSColin Percival
205889b14566SColin Percival	# Don't warn if the EoL is more than 3 months away
205989b14566SColin Percival	if [ ${TIMELEFT} -gt 7884000 ]; then
206048ffe56aSColin Percival		return 0
206148ffe56aSColin Percival	fi
206248ffe56aSColin Percival
206348ffe56aSColin Percival	# Don't warn if the time remaining is more than 3 times the time
206448ffe56aSColin Percival	# since the last warning.
206548ffe56aSColin Percival	if [ ${TIMELEFT} -gt `expr ${SINCEWARN} \* 3` ]; then
206648ffe56aSColin Percival		return 0
206748ffe56aSColin Percival	fi
206848ffe56aSColin Percival
206948ffe56aSColin Percival	# Figure out what time units to use.
207048ffe56aSColin Percival	if [ ${TIMELEFT} -lt 604800 ]; then
207148ffe56aSColin Percival		UNIT="day"
207248ffe56aSColin Percival		SIZE=86400
207348ffe56aSColin Percival	elif [ ${TIMELEFT} -lt 2678400 ]; then
207448ffe56aSColin Percival		UNIT="week"
207548ffe56aSColin Percival		SIZE=604800
207648ffe56aSColin Percival	else
207748ffe56aSColin Percival		UNIT="month"
207848ffe56aSColin Percival		SIZE=2678400
207948ffe56aSColin Percival	fi
208048ffe56aSColin Percival
208148ffe56aSColin Percival	# Compute the right number of units
208248ffe56aSColin Percival	NUM=`expr ${TIMELEFT} / ${SIZE}`
208348ffe56aSColin Percival	if [ ${NUM} != 1 ]; then
208448ffe56aSColin Percival		UNIT="${UNIT}s"
208548ffe56aSColin Percival	fi
208648ffe56aSColin Percival
208748ffe56aSColin Percival	# Print the warning
208848ffe56aSColin Percival	echo
208948ffe56aSColin Percival	cat <<-EOF
209048ffe56aSColin Percival		WARNING: `uname -sr` is approaching its End-of-Life date.
209148ffe56aSColin Percival		It is strongly recommended that you upgrade to a newer
209248ffe56aSColin Percival		release within the next ${NUM} ${UNIT}.
209348ffe56aSColin Percival	EOF
209448ffe56aSColin Percival
209548ffe56aSColin Percival	# Update the stored time of last warning
209648ffe56aSColin Percival	echo ${NOWTIME} > lasteolwarn
209748ffe56aSColin Percival}
209848ffe56aSColin Percival
209948ffe56aSColin Percival# Do the actual work involved in "fetch" / "cron".
210048ffe56aSColin Percivalfetch_run () {
210148ffe56aSColin Percival	workdir_init || return 1
210248ffe56aSColin Percival
210348ffe56aSColin Percival	# Prepare the mirror list.
210448ffe56aSColin Percival	fetch_pick_server_init && fetch_pick_server
210548ffe56aSColin Percival
210648ffe56aSColin Percival	# Try to fetch the public key until we run out of servers.
210748ffe56aSColin Percival	while ! fetch_key; do
210848ffe56aSColin Percival		fetch_pick_server || return 1
210948ffe56aSColin Percival	done
211048ffe56aSColin Percival
211148ffe56aSColin Percival	# Try to fetch the metadata index signature ("tag") until we run
211248ffe56aSColin Percival	# out of available servers; and sanity check the downloaded tag.
211348ffe56aSColin Percival	while ! fetch_tag; do
211448ffe56aSColin Percival		fetch_pick_server || return 1
211548ffe56aSColin Percival	done
211648ffe56aSColin Percival	fetch_tagsanity || return 1
211748ffe56aSColin Percival
211848ffe56aSColin Percival	# Fetch the latest INDEX-NEW and INDEX-OLD files.
211948ffe56aSColin Percival	fetch_metadata INDEX-NEW INDEX-OLD || return 1
212048ffe56aSColin Percival
212148ffe56aSColin Percival	# Generate filtered INDEX-NEW and INDEX-OLD files containing only
212248ffe56aSColin Percival	# the lines which (a) belong to components we care about, and (b)
212348ffe56aSColin Percival	# don't correspond to paths we're explicitly ignoring.
212448ffe56aSColin Percival	fetch_filter_metadata INDEX-NEW || return 1
212548ffe56aSColin Percival	fetch_filter_metadata INDEX-OLD || return 1
212648ffe56aSColin Percival
2127db6b0a61SColin Percival	# Translate /boot/${KERNCONF} into ${KERNELDIR}
2128db6b0a61SColin Percival	fetch_filter_kernel_names INDEX-NEW ${KERNCONF}
2129db6b0a61SColin Percival	fetch_filter_kernel_names INDEX-OLD ${KERNCONF}
213048ffe56aSColin Percival
213148ffe56aSColin Percival	# For all paths appearing in INDEX-OLD or INDEX-NEW, inspect the
213248ffe56aSColin Percival	# system and generate an INDEX-PRESENT file.
213348ffe56aSColin Percival	fetch_inspect_system INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1
213448ffe56aSColin Percival
213548ffe56aSColin Percival	# Based on ${UPDATEIFUNMODIFIED}, remove lines from INDEX-* which
213648ffe56aSColin Percival	# correspond to lines in INDEX-PRESENT with hashes not appearing
213748ffe56aSColin Percival	# in INDEX-OLD or INDEX-NEW.  Also remove lines where the entry in
213848ffe56aSColin Percival	# INDEX-PRESENT has type - and there isn't a corresponding entry in
213948ffe56aSColin Percival	# INDEX-OLD with type -.
2140db6b0a61SColin Percival	fetch_filter_unmodified_notpresent	\
2141db6b0a61SColin Percival	    INDEX-OLD INDEX-PRESENT INDEX-NEW /dev/null
214248ffe56aSColin Percival
214348ffe56aSColin Percival	# For each entry in INDEX-PRESENT of type -, remove any corresponding
214448ffe56aSColin Percival	# entry from INDEX-NEW if ${ALLOWADD} != "yes".  Remove all entries
214548ffe56aSColin Percival	# of type - from INDEX-PRESENT.
214648ffe56aSColin Percival	fetch_filter_allowadd INDEX-PRESENT INDEX-NEW
214748ffe56aSColin Percival
214848ffe56aSColin Percival	# If ${ALLOWDELETE} != "yes", then remove any entries from
214948ffe56aSColin Percival	# INDEX-PRESENT which don't correspond to entries in INDEX-NEW.
215048ffe56aSColin Percival	fetch_filter_allowdelete INDEX-PRESENT INDEX-NEW
215148ffe56aSColin Percival
215248ffe56aSColin Percival	# If ${KEEPMODIFIEDMETADATA} == "yes", then for each entry in
215348ffe56aSColin Percival	# INDEX-PRESENT with metadata not matching any entry in INDEX-OLD,
215448ffe56aSColin Percival	# replace the corresponding line of INDEX-NEW with one having the
215548ffe56aSColin Percival	# same metadata as the entry in INDEX-PRESENT.
215648ffe56aSColin Percival	fetch_filter_modified_metadata INDEX-OLD INDEX-PRESENT INDEX-NEW
215748ffe56aSColin Percival
215848ffe56aSColin Percival	# Remove lines from INDEX-PRESENT and INDEX-NEW which are identical;
215948ffe56aSColin Percival	# no need to update a file if it isn't changing.
216048ffe56aSColin Percival	fetch_filter_uptodate INDEX-PRESENT INDEX-NEW
216148ffe56aSColin Percival
216248ffe56aSColin Percival	# Prepare to fetch files: Generate a list of the files we need,
216348ffe56aSColin Percival	# copy the unmodified files we have into /files/, and generate
216448ffe56aSColin Percival	# a list of patches to download.
2165210b8123SColin Percival	fetch_files_prepare INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1
216648ffe56aSColin Percival
216748ffe56aSColin Percival	# Fetch files.
216848ffe56aSColin Percival	fetch_files || return 1
216948ffe56aSColin Percival
217048ffe56aSColin Percival	# Create and populate install manifest directory; and report what
217148ffe56aSColin Percival	# updates are available.
217248ffe56aSColin Percival	fetch_create_manifest || return 1
217348ffe56aSColin Percival
217448ffe56aSColin Percival	# Warn about any upcoming EoL
217548ffe56aSColin Percival	fetch_warn_eol || return 1
217648ffe56aSColin Percival}
217748ffe56aSColin Percival
2178db6b0a61SColin Percival# If StrictComponents is not "yes", generate a new components list
2179db6b0a61SColin Percival# with only the components which appear to be installed.
2180db6b0a61SColin Percivalupgrade_guess_components () {
2181db6b0a61SColin Percival	if [ "${STRICTCOMPONENTS}" = "no" ]; then
2182db6b0a61SColin Percival		# Generate filtered INDEX-ALL with only the components listed
2183db6b0a61SColin Percival		# in COMPONENTS.
2184db6b0a61SColin Percival		fetch_filter_metadata_components $1 || return 1
2185db6b0a61SColin Percival
2186db6b0a61SColin Percival		# Tell the user why his disk is suddenly making lots of noise
2187db6b0a61SColin Percival		echo -n "Inspecting system... "
2188db6b0a61SColin Percival
2189db6b0a61SColin Percival		# Look at the files on disk, and assume that a component is
2190db6b0a61SColin Percival		# supposed to be present if it is more than half-present.
2191db6b0a61SColin Percival		cut -f 1-3 -d '|' < INDEX-ALL |
2192db6b0a61SColin Percival		    tr '|' ' ' |
2193db6b0a61SColin Percival		    while read C S F; do
2194db6b0a61SColin Percival			if [ -e ${BASEDIR}/${F} ]; then
2195db6b0a61SColin Percival				echo "+ ${C}|${S}"
2196db6b0a61SColin Percival			fi
2197db6b0a61SColin Percival			echo "= ${C}|${S}"
2198db6b0a61SColin Percival		    done |
2199db6b0a61SColin Percival		    sort |
2200db6b0a61SColin Percival		    uniq -c |
2201db6b0a61SColin Percival		    sed -E 's,^ +,,' > compfreq
2202db6b0a61SColin Percival		grep ' = ' compfreq |
2203db6b0a61SColin Percival		    cut -f 1,3 -d ' ' |
2204db6b0a61SColin Percival		    sort -k 2,2 -t ' ' > compfreq.total
2205db6b0a61SColin Percival		grep ' + ' compfreq |
2206db6b0a61SColin Percival		    cut -f 1,3 -d ' ' |
2207db6b0a61SColin Percival		    sort -k 2,2 -t ' ' > compfreq.present
2208db6b0a61SColin Percival		join -t ' ' -1 2 -2 2 compfreq.present compfreq.total |
2209db6b0a61SColin Percival		    while read S P T; do
2210ae97aa98SEd Maste			if [ ${T} -ne 0 -a ${P} -gt `expr ${T} / 2` ]; then
2211db6b0a61SColin Percival				echo ${S}
2212db6b0a61SColin Percival			fi
2213db6b0a61SColin Percival		    done > comp.present
2214db6b0a61SColin Percival		cut -f 2 -d ' ' < compfreq.total > comp.total
2215db6b0a61SColin Percival		rm INDEX-ALL compfreq compfreq.total compfreq.present
2216db6b0a61SColin Percival
2217db6b0a61SColin Percival		# We're done making noise.
2218db6b0a61SColin Percival		echo "done."
2219db6b0a61SColin Percival
2220db6b0a61SColin Percival		# Sometimes the kernel isn't installed where INDEX-ALL
2221db6b0a61SColin Percival		# thinks that it should be: In particular, it is often in
2222db6b0a61SColin Percival		# /boot/kernel instead of /boot/GENERIC or /boot/SMP.  To
2223db6b0a61SColin Percival		# deal with this, if "kernel|X" is listed in comp.total
2224db6b0a61SColin Percival		# (i.e., is a component which would be upgraded if it is
2225db6b0a61SColin Percival		# found to be present) we will add it to comp.present.
2226db6b0a61SColin Percival		# If "kernel|<anything>" is in comp.total but "kernel|X" is
2227db6b0a61SColin Percival		# not, we print a warning -- the user is running a kernel
2228db6b0a61SColin Percival		# which isn't part of the release.
2229db6b0a61SColin Percival		KCOMP=`echo ${KERNCONF} | tr 'A-Z' 'a-z'`
2230db6b0a61SColin Percival		grep -E "^kernel\|${KCOMP}\$" comp.total >> comp.present
2231db6b0a61SColin Percival
2232db6b0a61SColin Percival		if grep -qE "^kernel\|" comp.total &&
2233db6b0a61SColin Percival		    ! grep -qE "^kernel\|${KCOMP}\$" comp.total; then
2234db6b0a61SColin Percival			cat <<-EOF
2235db6b0a61SColin Percival
2236db6b0a61SColin PercivalWARNING: This system is running a "${KCOMP}" kernel, which is not a
2237db6b0a61SColin Percivalkernel configuration distributed as part of FreeBSD ${RELNUM}.
2238db6b0a61SColin PercivalThis kernel will not be updated: you MUST update the kernel manually
2239db6b0a61SColin Percivalbefore running "$0 install".
2240db6b0a61SColin Percival			EOF
2241db6b0a61SColin Percival		fi
2242db6b0a61SColin Percival
2243db6b0a61SColin Percival		# Re-sort the list of installed components and generate
2244db6b0a61SColin Percival		# the list of non-installed components.
2245db6b0a61SColin Percival		sort -u < comp.present > comp.present.tmp
2246db6b0a61SColin Percival		mv comp.present.tmp comp.present
2247db6b0a61SColin Percival		comm -13 comp.present comp.total > comp.absent
2248db6b0a61SColin Percival
2249db6b0a61SColin Percival		# Ask the user to confirm that what we have is correct.  To
2250db6b0a61SColin Percival		# reduce user confusion, translate "X|Y" back to "X/Y" (as
2251db6b0a61SColin Percival		# subcomponents must be listed in the configuration file).
2252db6b0a61SColin Percival		echo
2253db6b0a61SColin Percival		echo -n "The following components of FreeBSD "
2254db6b0a61SColin Percival		echo "seem to be installed:"
2255db6b0a61SColin Percival		tr '|' '/' < comp.present |
2256db6b0a61SColin Percival		    fmt -72
2257db6b0a61SColin Percival		echo
2258db6b0a61SColin Percival		echo -n "The following components of FreeBSD "
2259db6b0a61SColin Percival		echo "do not seem to be installed:"
2260db6b0a61SColin Percival		tr '|' '/' < comp.absent |
2261db6b0a61SColin Percival		    fmt -72
2262db6b0a61SColin Percival		echo
2263db6b0a61SColin Percival		continuep || return 1
2264db6b0a61SColin Percival		echo
2265db6b0a61SColin Percival
2266db6b0a61SColin Percival		# Suck the generated list of components into ${COMPONENTS}.
2267db6b0a61SColin Percival		# Note that comp.present.tmp is used due to issues with
2268db6b0a61SColin Percival		# pipelines and setting variables.
2269db6b0a61SColin Percival		COMPONENTS=""
2270db6b0a61SColin Percival		tr '|' '/' < comp.present > comp.present.tmp
2271db6b0a61SColin Percival		while read C; do
2272db6b0a61SColin Percival			COMPONENTS="${COMPONENTS} ${C}"
2273db6b0a61SColin Percival		done < comp.present.tmp
2274db6b0a61SColin Percival
2275db6b0a61SColin Percival		# Delete temporary files
2276db6b0a61SColin Percival		rm comp.present comp.present.tmp comp.absent comp.total
2277db6b0a61SColin Percival	fi
2278db6b0a61SColin Percival}
2279db6b0a61SColin Percival
2280db6b0a61SColin Percival# If StrictComponents is not "yes", COMPONENTS contains an entry
2281db6b0a61SColin Percival# corresponding to the currently running kernel, and said kernel
2282db6b0a61SColin Percival# does not exist in the new release, add "kernel/generic" to the
2283db6b0a61SColin Percival# list of components.
2284db6b0a61SColin Percivalupgrade_guess_new_kernel () {
2285db6b0a61SColin Percival	if [ "${STRICTCOMPONENTS}" = "no" ]; then
2286db6b0a61SColin Percival		# Grab the unfiltered metadata file.
2287db6b0a61SColin Percival		METAHASH=`look "$1|" tINDEX.present | cut -f 2 -d '|'`
2288db6b0a61SColin Percival		gunzip -c < files/${METAHASH}.gz > $1.all
2289db6b0a61SColin Percival
2290db6b0a61SColin Percival		# If "kernel/${KCOMP}" is in ${COMPONENTS} and that component
2291db6b0a61SColin Percival		# isn't in $1.all, we need to add kernel/generic.
2292db6b0a61SColin Percival		for C in ${COMPONENTS}; do
2293db6b0a61SColin Percival			if [ ${C} = "kernel/${KCOMP}" ] &&
2294db6b0a61SColin Percival			    ! grep -qE "^kernel\|${KCOMP}\|" $1.all; then
2295db6b0a61SColin Percival				COMPONENTS="${COMPONENTS} kernel/generic"
2296db6b0a61SColin Percival				NKERNCONF="GENERIC"
2297db6b0a61SColin Percival				cat <<-EOF
2298db6b0a61SColin Percival
2299db6b0a61SColin PercivalWARNING: This system is running a "${KCOMP}" kernel, which is not a
2300db6b0a61SColin Percivalkernel configuration distributed as part of FreeBSD ${RELNUM}.
2301db6b0a61SColin PercivalAs part of upgrading to FreeBSD ${RELNUM}, this kernel will be
2302db6b0a61SColin Percivalreplaced with a "generic" kernel.
2303db6b0a61SColin Percival				EOF
2304db6b0a61SColin Percival				continuep || return 1
2305db6b0a61SColin Percival			fi
2306db6b0a61SColin Percival		done
2307db6b0a61SColin Percival
2308db6b0a61SColin Percival		# Don't need this any more...
2309db6b0a61SColin Percival		rm $1.all
2310db6b0a61SColin Percival	fi
2311db6b0a61SColin Percival}
2312db6b0a61SColin Percival
2313db6b0a61SColin Percival# Convert INDEX-OLD (last release) and INDEX-ALL (new release) into
2314db6b0a61SColin Percival# INDEX-OLD and INDEX-NEW files (in the sense of normal upgrades).
2315db6b0a61SColin Percivalupgrade_oldall_to_oldnew () {
2316db6b0a61SColin Percival	# For each ${F}|... which appears in INDEX-ALL but does not appear
2317db6b0a61SColin Percival	# in INDEX-OLD, add ${F}|-|||||| to INDEX-OLD.
2318db6b0a61SColin Percival	cut -f 1 -d '|' < $1 |
2319db6b0a61SColin Percival	    sort -u > $1.paths
2320db6b0a61SColin Percival	cut -f 1 -d '|' < $2 |
2321db6b0a61SColin Percival	    sort -u |
2322db6b0a61SColin Percival	    comm -13 $1.paths - |
2323db6b0a61SColin Percival	    lam - -s "|-||||||" |
2324db6b0a61SColin Percival	    sort - $1 > $1.tmp
2325db6b0a61SColin Percival	mv $1.tmp $1
2326db6b0a61SColin Percival
2327db6b0a61SColin Percival	# Remove lines from INDEX-OLD which also appear in INDEX-ALL
2328db6b0a61SColin Percival	comm -23 $1 $2 > $1.tmp
2329db6b0a61SColin Percival	mv $1.tmp $1
2330db6b0a61SColin Percival
2331db6b0a61SColin Percival	# Remove lines from INDEX-ALL which have a file name not appearing
2332db6b0a61SColin Percival	# anywhere in INDEX-OLD (since these must be files which haven't
2333db6b0a61SColin Percival	# changed -- if they were new, there would be an entry of type "-").
2334db6b0a61SColin Percival	cut -f 1 -d '|' < $1 |
2335db6b0a61SColin Percival	    sort -u > $1.paths
2336db6b0a61SColin Percival	sort -k 1,1 -t '|' < $2 |
2337db6b0a61SColin Percival	    join -t '|' - $1.paths |
2338db6b0a61SColin Percival	    sort > $2.tmp
2339db6b0a61SColin Percival	rm $1.paths
2340db6b0a61SColin Percival	mv $2.tmp $2
2341db6b0a61SColin Percival
2342db6b0a61SColin Percival	# Rename INDEX-ALL to INDEX-NEW.
2343db6b0a61SColin Percival	mv $2 $3
2344db6b0a61SColin Percival}
2345db6b0a61SColin Percival
23467449d2f5SColin Percival# Helper for upgrade_merge: Return zero true iff the two files differ only
23476d514f10SDag-Erling Smørgrav# in the contents of their RCS tags.
23487449d2f5SColin Percivalsamef () {
23497449d2f5SColin Percival	X=`sed -E 's/\\$FreeBSD.*\\$/\$FreeBSD\$/' < $1 | ${SHA256}`
23507449d2f5SColin Percival	Y=`sed -E 's/\\$FreeBSD.*\\$/\$FreeBSD\$/' < $2 | ${SHA256}`
23517449d2f5SColin Percival
23527449d2f5SColin Percival	if [ $X = $Y ]; then
23537449d2f5SColin Percival		return 0;
23547449d2f5SColin Percival	else
23557449d2f5SColin Percival		return 1;
23567449d2f5SColin Percival	fi
23577449d2f5SColin Percival}
23587449d2f5SColin Percival
2359db6b0a61SColin Percival# From the list of "old" files in $1, merge changes in $2 with those in $3,
2360db6b0a61SColin Percival# and update $3 to reflect the hashes of merged files.
2361db6b0a61SColin Percivalupgrade_merge () {
2362db6b0a61SColin Percival	# We only need to do anything if $1 is non-empty.
2363db6b0a61SColin Percival	if [ -s $1 ]; then
2364db6b0a61SColin Percival		cut -f 1 -d '|' $1 |
2365db6b0a61SColin Percival		    sort > $1-paths
2366db6b0a61SColin Percival
2367db6b0a61SColin Percival		# Create staging area for merging files
2368db6b0a61SColin Percival		rm -rf merge/
2369db6b0a61SColin Percival		while read F; do
2370db6b0a61SColin Percival			D=`dirname ${F}`
2371db6b0a61SColin Percival			mkdir -p merge/old/${D}
2372db6b0a61SColin Percival			mkdir -p merge/${OLDRELNUM}/${D}
2373db6b0a61SColin Percival			mkdir -p merge/${RELNUM}/${D}
2374db6b0a61SColin Percival			mkdir -p merge/new/${D}
2375db6b0a61SColin Percival		done < $1-paths
2376db6b0a61SColin Percival
2377db6b0a61SColin Percival		# Copy in files
2378db6b0a61SColin Percival		while read F; do
2379db6b0a61SColin Percival			# Currently installed file
2380db6b0a61SColin Percival			V=`look "${F}|" $2 | cut -f 7 -d '|'`
2381db6b0a61SColin Percival			gunzip < files/${V}.gz > merge/old/${F}
2382db6b0a61SColin Percival
2383db6b0a61SColin Percival			# Old release
2384db6b0a61SColin Percival			if look "${F}|" $1 | fgrep -q "|f|"; then
2385db6b0a61SColin Percival				V=`look "${F}|" $1 | cut -f 3 -d '|'`
2386db6b0a61SColin Percival				gunzip < files/${V}.gz		\
2387db6b0a61SColin Percival				    > merge/${OLDRELNUM}/${F}
2388db6b0a61SColin Percival			fi
2389db6b0a61SColin Percival
2390db6b0a61SColin Percival			# New release
2391db6b0a61SColin Percival			if look "${F}|" $3 | cut -f 1,2,7 -d '|' |
2392db6b0a61SColin Percival			    fgrep -q "|f|"; then
2393db6b0a61SColin Percival				V=`look "${F}|" $3 | cut -f 7 -d '|'`
2394db6b0a61SColin Percival				gunzip < files/${V}.gz		\
2395db6b0a61SColin Percival				    > merge/${RELNUM}/${F}
2396db6b0a61SColin Percival			fi
2397db6b0a61SColin Percival		done < $1-paths
2398db6b0a61SColin Percival
2399db6b0a61SColin Percival		# Attempt to automatically merge changes
2400db6b0a61SColin Percival		echo -n "Attempting to automatically merge "
2401db6b0a61SColin Percival		echo -n "changes in files..."
2402db6b0a61SColin Percival		: > failed.merges
2403db6b0a61SColin Percival		while read F; do
2404db6b0a61SColin Percival			# If the file doesn't exist in the new release,
2405db6b0a61SColin Percival			# the result of "merging changes" is having the file
2406db6b0a61SColin Percival			# not exist.
2407db6b0a61SColin Percival			if ! [ -f merge/${RELNUM}/${F} ]; then
2408db6b0a61SColin Percival				continue
2409db6b0a61SColin Percival			fi
2410db6b0a61SColin Percival
2411db6b0a61SColin Percival			# If the file didn't exist in the old release, we're
2412db6b0a61SColin Percival			# going to throw away the existing file and hope that
2413db6b0a61SColin Percival			# the version from the new release is what we want.
2414db6b0a61SColin Percival			if ! [ -f merge/${OLDRELNUM}/${F} ]; then
2415db6b0a61SColin Percival				cp merge/${RELNUM}/${F} merge/new/${F}
2416db6b0a61SColin Percival				continue
2417db6b0a61SColin Percival			fi
2418db6b0a61SColin Percival
2419db6b0a61SColin Percival			# Some files need special treatment.
2420db6b0a61SColin Percival			case ${F} in
2421db6b0a61SColin Percival			/etc/spwd.db | /etc/pwd.db | /etc/login.conf.db)
2422db6b0a61SColin Percival				# Don't merge these -- we're rebuild them
2423db6b0a61SColin Percival				# after updates are installed.
2424db6b0a61SColin Percival				cp merge/old/${F} merge/new/${F}
2425db6b0a61SColin Percival				;;
2426db6b0a61SColin Percival			*)
2427073dd712SBaptiste Daroussin				if ! diff3 -E -m -L "current version"	\
2428db6b0a61SColin Percival				    -L "${OLDRELNUM}" -L "${RELNUM}"	\
2429db6b0a61SColin Percival				    merge/old/${F}			\
2430db6b0a61SColin Percival				    merge/${OLDRELNUM}/${F}		\
2431db6b0a61SColin Percival				    merge/${RELNUM}/${F}		\
2432db6b0a61SColin Percival				    > merge/new/${F} 2>/dev/null; then
2433db6b0a61SColin Percival					echo ${F} >> failed.merges
2434db6b0a61SColin Percival				fi
2435db6b0a61SColin Percival				;;
2436db6b0a61SColin Percival			esac
2437db6b0a61SColin Percival		done < $1-paths
2438db6b0a61SColin Percival		echo " done."
2439db6b0a61SColin Percival
2440db6b0a61SColin Percival		# Ask the user to handle any files which didn't merge.
2441db6b0a61SColin Percival		while read F; do
24427449d2f5SColin Percival			# If the installed file differs from the version in
24436d514f10SDag-Erling Smørgrav			# the old release only due to RCS tag expansion
24447449d2f5SColin Percival			# then just use the version in the new release.
24457449d2f5SColin Percival			if samef merge/old/${F} merge/${OLDRELNUM}/${F}; then
24467449d2f5SColin Percival				cp merge/${RELNUM}/${F} merge/new/${F}
24477449d2f5SColin Percival				continue
24487449d2f5SColin Percival			fi
24497449d2f5SColin Percival
2450db6b0a61SColin Percival			cat <<-EOF
2451db6b0a61SColin Percival
2452db6b0a61SColin PercivalThe following file could not be merged automatically: ${F}
2453db6b0a61SColin PercivalPress Enter to edit this file in ${EDITOR} and resolve the conflicts
2454db6b0a61SColin Percivalmanually...
2455db6b0a61SColin Percival			EOF
2456db6b0a61SColin Percival			read dummy </dev/tty
2457db6b0a61SColin Percival			${EDITOR} `pwd`/merge/new/${F} < /dev/tty
2458db6b0a61SColin Percival		done < failed.merges
2459db6b0a61SColin Percival		rm failed.merges
2460db6b0a61SColin Percival
2461db6b0a61SColin Percival		# Ask the user to confirm that he likes how the result
2462db6b0a61SColin Percival		# of merging files.
2463db6b0a61SColin Percival		while read F; do
24647449d2f5SColin Percival			# Skip files which haven't changed except possibly
24656d514f10SDag-Erling Smørgrav			# in their RCS tags.
24667449d2f5SColin Percival			if [ -f merge/old/${F} ] && [ -f merge/new/${F} ] &&
24677449d2f5SColin Percival			    samef merge/old/${F} merge/new/${F}; then
24687449d2f5SColin Percival				continue
24697449d2f5SColin Percival			fi
24707449d2f5SColin Percival
24717449d2f5SColin Percival			# Skip files where the installed file differs from
24726d514f10SDag-Erling Smørgrav			# the old file only due to RCS tags.
24737449d2f5SColin Percival			if [ -f merge/old/${F} ] &&
24747449d2f5SColin Percival			    [ -f merge/${OLDRELNUM}/${F} ] &&
24757449d2f5SColin Percival			    samef merge/old/${F} merge/${OLDRELNUM}/${F}; then
2476db6b0a61SColin Percival				continue
2477db6b0a61SColin Percival			fi
2478db6b0a61SColin Percival
2479db6b0a61SColin Percival			# Warn about files which are ceasing to exist.
2480db6b0a61SColin Percival			if ! [ -f merge/new/${F} ]; then
2481db6b0a61SColin Percival				cat <<-EOF
2482db6b0a61SColin Percival
2483db6b0a61SColin PercivalThe following file will be removed, as it no longer exists in
2484db6b0a61SColin PercivalFreeBSD ${RELNUM}: ${F}
2485db6b0a61SColin Percival				EOF
2486db6b0a61SColin Percival				continuep < /dev/tty || return 1
2487db6b0a61SColin Percival				continue
2488db6b0a61SColin Percival			fi
2489db6b0a61SColin Percival
2490db6b0a61SColin Percival			# Print changes for the user's approval.
2491db6b0a61SColin Percival			cat <<-EOF
2492db6b0a61SColin Percival
2493db6b0a61SColin PercivalThe following changes, which occurred between FreeBSD ${OLDRELNUM} and
2494db6b0a61SColin PercivalFreeBSD ${RELNUM} have been merged into ${F}:
2495db6b0a61SColin PercivalEOF
2496db6b0a61SColin Percival			diff -U 5 -L "current version" -L "new version"	\
2497db6b0a61SColin Percival			    merge/old/${F} merge/new/${F} || true
2498db6b0a61SColin Percival			continuep < /dev/tty || return 1
2499db6b0a61SColin Percival		done < $1-paths
2500db6b0a61SColin Percival
2501db6b0a61SColin Percival		# Store merged files.
2502db6b0a61SColin Percival		while read F; do
2503c58b62efSColin Percival			if [ -f merge/new/${F} ]; then
2504db6b0a61SColin Percival				V=`${SHA256} -q merge/new/${F}`
2505db6b0a61SColin Percival
2506db6b0a61SColin Percival				gzip -c < merge/new/${F} > files/${V}.gz
2507db6b0a61SColin Percival				echo "${F}|${V}"
2508db6b0a61SColin Percival			fi
2509db6b0a61SColin Percival		done < $1-paths > newhashes
2510db6b0a61SColin Percival
2511db6b0a61SColin Percival		# Pull lines out from $3 which need to be updated to
2512db6b0a61SColin Percival		# reflect merged files.
2513db6b0a61SColin Percival		while read F; do
2514db6b0a61SColin Percival			look "${F}|" $3
2515db6b0a61SColin Percival		done < $1-paths > $3-oldlines
2516db6b0a61SColin Percival
2517db6b0a61SColin Percival		# Update lines to reflect merged files
2518db6b0a61SColin Percival		join -t '|' -o 1.1,1.2,1.3,1.4,1.5,1.6,2.2,1.8		\
2519db6b0a61SColin Percival		    $3-oldlines newhashes > $3-newlines
2520db6b0a61SColin Percival
2521db6b0a61SColin Percival		# Remove old lines from $3 and add new lines.
2522db6b0a61SColin Percival		sort $3-oldlines |
2523db6b0a61SColin Percival		    comm -13 - $3 |
2524db6b0a61SColin Percival		    sort - $3-newlines > $3.tmp
2525db6b0a61SColin Percival		mv $3.tmp $3
2526db6b0a61SColin Percival
2527db6b0a61SColin Percival		# Clean up
2528db6b0a61SColin Percival		rm $1-paths newhashes $3-oldlines $3-newlines
2529db6b0a61SColin Percival		rm -rf merge/
2530db6b0a61SColin Percival	fi
2531db6b0a61SColin Percival
2532db6b0a61SColin Percival	# We're done with merging files.
2533db6b0a61SColin Percival	rm $1
2534db6b0a61SColin Percival}
2535db6b0a61SColin Percival
2536db6b0a61SColin Percival# Do the work involved in fetching upgrades to a new release
2537db6b0a61SColin Percivalupgrade_run () {
2538db6b0a61SColin Percival	workdir_init || return 1
2539db6b0a61SColin Percival
2540db6b0a61SColin Percival	# Prepare the mirror list.
2541db6b0a61SColin Percival	fetch_pick_server_init && fetch_pick_server
2542db6b0a61SColin Percival
2543db6b0a61SColin Percival	# Try to fetch the public key until we run out of servers.
2544db6b0a61SColin Percival	while ! fetch_key; do
2545db6b0a61SColin Percival		fetch_pick_server || return 1
2546db6b0a61SColin Percival	done
2547db6b0a61SColin Percival
2548db6b0a61SColin Percival	# Try to fetch the metadata index signature ("tag") until we run
2549db6b0a61SColin Percival	# out of available servers; and sanity check the downloaded tag.
2550db6b0a61SColin Percival	while ! fetch_tag; do
2551db6b0a61SColin Percival		fetch_pick_server || return 1
2552db6b0a61SColin Percival	done
2553db6b0a61SColin Percival	fetch_tagsanity || return 1
2554db6b0a61SColin Percival
2555db6b0a61SColin Percival	# Fetch the INDEX-OLD and INDEX-ALL.
2556db6b0a61SColin Percival	fetch_metadata INDEX-OLD INDEX-ALL || return 1
2557db6b0a61SColin Percival
2558db6b0a61SColin Percival	# If StrictComponents is not "yes", generate a new components list
2559db6b0a61SColin Percival	# with only the components which appear to be installed.
2560db6b0a61SColin Percival	upgrade_guess_components INDEX-ALL || return 1
2561db6b0a61SColin Percival
2562db6b0a61SColin Percival	# Generate filtered INDEX-OLD and INDEX-ALL files containing only
2563db6b0a61SColin Percival	# the components we want and without anything marked as "Ignore".
2564db6b0a61SColin Percival	fetch_filter_metadata INDEX-OLD || return 1
2565db6b0a61SColin Percival	fetch_filter_metadata INDEX-ALL || return 1
2566db6b0a61SColin Percival
2567db6b0a61SColin Percival	# Merge the INDEX-OLD and INDEX-ALL files into INDEX-OLD.
2568db6b0a61SColin Percival	sort INDEX-OLD INDEX-ALL > INDEX-OLD.tmp
2569db6b0a61SColin Percival	mv INDEX-OLD.tmp INDEX-OLD
2570db6b0a61SColin Percival	rm INDEX-ALL
2571db6b0a61SColin Percival
2572db6b0a61SColin Percival	# Adjust variables for fetching files from the new release.
2573db6b0a61SColin Percival	OLDRELNUM=${RELNUM}
2574db6b0a61SColin Percival	RELNUM=${TARGETRELEASE}
2575db6b0a61SColin Percival	OLDFETCHDIR=${FETCHDIR}
2576db6b0a61SColin Percival	FETCHDIR=${RELNUM}/${ARCH}
2577db6b0a61SColin Percival
2578db6b0a61SColin Percival	# Try to fetch the NEW metadata index signature ("tag") until we run
2579db6b0a61SColin Percival	# out of available servers; and sanity check the downloaded tag.
2580db6b0a61SColin Percival	while ! fetch_tag; do
2581db6b0a61SColin Percival		fetch_pick_server || return 1
2582db6b0a61SColin Percival	done
2583db6b0a61SColin Percival
2584db6b0a61SColin Percival	# Fetch the new INDEX-ALL.
2585db6b0a61SColin Percival	fetch_metadata INDEX-ALL || return 1
2586db6b0a61SColin Percival
2587db6b0a61SColin Percival	# If StrictComponents is not "yes", COMPONENTS contains an entry
2588db6b0a61SColin Percival	# corresponding to the currently running kernel, and said kernel
2589db6b0a61SColin Percival	# does not exist in the new release, add "kernel/generic" to the
2590db6b0a61SColin Percival	# list of components.
2591db6b0a61SColin Percival	upgrade_guess_new_kernel INDEX-ALL || return 1
2592db6b0a61SColin Percival
2593db6b0a61SColin Percival	# Filter INDEX-ALL to contain only the components we want and without
2594db6b0a61SColin Percival	# anything marked as "Ignore".
2595db6b0a61SColin Percival	fetch_filter_metadata INDEX-ALL || return 1
2596db6b0a61SColin Percival
2597db6b0a61SColin Percival	# Convert INDEX-OLD (last release) and INDEX-ALL (new release) into
2598db6b0a61SColin Percival	# INDEX-OLD and INDEX-NEW files (in the sense of normal upgrades).
2599db6b0a61SColin Percival	upgrade_oldall_to_oldnew INDEX-OLD INDEX-ALL INDEX-NEW
2600db6b0a61SColin Percival
2601db6b0a61SColin Percival	# Translate /boot/${KERNCONF} or /boot/${NKERNCONF} into ${KERNELDIR}
2602db6b0a61SColin Percival	fetch_filter_kernel_names INDEX-NEW ${NKERNCONF}
2603db6b0a61SColin Percival	fetch_filter_kernel_names INDEX-OLD ${KERNCONF}
2604db6b0a61SColin Percival
2605db6b0a61SColin Percival	# For all paths appearing in INDEX-OLD or INDEX-NEW, inspect the
2606db6b0a61SColin Percival	# system and generate an INDEX-PRESENT file.
2607db6b0a61SColin Percival	fetch_inspect_system INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1
2608db6b0a61SColin Percival
2609db6b0a61SColin Percival	# Based on ${MERGECHANGES}, generate a file tomerge-old with the
2610db6b0a61SColin Percival	# paths and hashes of old versions of files to merge.
2611db6b0a61SColin Percival	fetch_filter_mergechanges INDEX-OLD INDEX-PRESENT tomerge-old
2612db6b0a61SColin Percival
2613db6b0a61SColin Percival	# Based on ${UPDATEIFUNMODIFIED}, remove lines from INDEX-* which
2614db6b0a61SColin Percival	# correspond to lines in INDEX-PRESENT with hashes not appearing
2615db6b0a61SColin Percival	# in INDEX-OLD or INDEX-NEW.  Also remove lines where the entry in
2616db6b0a61SColin Percival	# INDEX-PRESENT has type - and there isn't a corresponding entry in
2617db6b0a61SColin Percival	# INDEX-OLD with type -.
2618db6b0a61SColin Percival	fetch_filter_unmodified_notpresent	\
2619db6b0a61SColin Percival	    INDEX-OLD INDEX-PRESENT INDEX-NEW tomerge-old
2620db6b0a61SColin Percival
2621db6b0a61SColin Percival	# For each entry in INDEX-PRESENT of type -, remove any corresponding
2622db6b0a61SColin Percival	# entry from INDEX-NEW if ${ALLOWADD} != "yes".  Remove all entries
2623db6b0a61SColin Percival	# of type - from INDEX-PRESENT.
2624db6b0a61SColin Percival	fetch_filter_allowadd INDEX-PRESENT INDEX-NEW
2625db6b0a61SColin Percival
2626db6b0a61SColin Percival	# If ${ALLOWDELETE} != "yes", then remove any entries from
2627db6b0a61SColin Percival	# INDEX-PRESENT which don't correspond to entries in INDEX-NEW.
2628db6b0a61SColin Percival	fetch_filter_allowdelete INDEX-PRESENT INDEX-NEW
2629db6b0a61SColin Percival
2630db6b0a61SColin Percival	# If ${KEEPMODIFIEDMETADATA} == "yes", then for each entry in
2631db6b0a61SColin Percival	# INDEX-PRESENT with metadata not matching any entry in INDEX-OLD,
2632db6b0a61SColin Percival	# replace the corresponding line of INDEX-NEW with one having the
2633db6b0a61SColin Percival	# same metadata as the entry in INDEX-PRESENT.
2634db6b0a61SColin Percival	fetch_filter_modified_metadata INDEX-OLD INDEX-PRESENT INDEX-NEW
2635db6b0a61SColin Percival
2636db6b0a61SColin Percival	# Remove lines from INDEX-PRESENT and INDEX-NEW which are identical;
2637db6b0a61SColin Percival	# no need to update a file if it isn't changing.
2638db6b0a61SColin Percival	fetch_filter_uptodate INDEX-PRESENT INDEX-NEW
2639db6b0a61SColin Percival
2640db6b0a61SColin Percival	# Fetch "clean" files from the old release for merging changes.
2641db6b0a61SColin Percival	fetch_files_premerge tomerge-old
2642db6b0a61SColin Percival
2643db6b0a61SColin Percival	# Prepare to fetch files: Generate a list of the files we need,
2644db6b0a61SColin Percival	# copy the unmodified files we have into /files/, and generate
2645db6b0a61SColin Percival	# a list of patches to download.
2646db6b0a61SColin Percival	fetch_files_prepare INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1
2647db6b0a61SColin Percival
2648db6b0a61SColin Percival	# Fetch patches from to-${RELNUM}/${ARCH}/bp/
2649db6b0a61SColin Percival	PATCHDIR=to-${RELNUM}/${ARCH}/bp
2650db6b0a61SColin Percival	fetch_files || return 1
2651db6b0a61SColin Percival
2652db6b0a61SColin Percival	# Merge configuration file changes.
2653db6b0a61SColin Percival	upgrade_merge tomerge-old INDEX-PRESENT INDEX-NEW || return 1
2654db6b0a61SColin Percival
2655db6b0a61SColin Percival	# Create and populate install manifest directory; and report what
2656db6b0a61SColin Percival	# updates are available.
2657db6b0a61SColin Percival	fetch_create_manifest || return 1
2658db6b0a61SColin Percival
2659db6b0a61SColin Percival	# Leave a note behind to tell the "install" command that the kernel
2660db6b0a61SColin Percival	# needs to be installed before the world.
2661db6b0a61SColin Percival	touch ${BDHASH}-install/kernelfirst
266285451f90SColin Percival
266385451f90SColin Percival	# Remind the user that they need to run "freebsd-update install"
266485451f90SColin Percival	# to install the downloaded bits, in case they didn't RTFM.
266585451f90SColin Percival	echo "To install the downloaded upgrades, run \"$0 install\"."
2666db6b0a61SColin Percival}
2667db6b0a61SColin Percival
266848ffe56aSColin Percival# Make sure that all the file hashes mentioned in $@ have corresponding
266948ffe56aSColin Percival# gzipped files stored in /files/.
267048ffe56aSColin Percivalinstall_verify () {
267148ffe56aSColin Percival	# Generate a list of hashes
267248ffe56aSColin Percival	cat $@ |
267348ffe56aSColin Percival	    cut -f 2,7 -d '|' |
267448ffe56aSColin Percival	    grep -E '^f' |
267548ffe56aSColin Percival	    cut -f 2 -d '|' |
267648ffe56aSColin Percival	    sort -u > filelist
267748ffe56aSColin Percival
267848ffe56aSColin Percival	# Make sure all the hashes exist
267948ffe56aSColin Percival	while read HASH; do
268048ffe56aSColin Percival		if ! [ -f files/${HASH}.gz ]; then
268148ffe56aSColin Percival			echo -n "Update files missing -- "
268248ffe56aSColin Percival			echo "this should never happen."
268348ffe56aSColin Percival			echo "Re-run '$0 fetch'."
268448ffe56aSColin Percival			return 1
268548ffe56aSColin Percival		fi
268648ffe56aSColin Percival	done < filelist
268748ffe56aSColin Percival
268848ffe56aSColin Percival	# Clean up
268948ffe56aSColin Percival	rm filelist
269048ffe56aSColin Percival}
269148ffe56aSColin Percival
269248ffe56aSColin Percival# Remove the system immutable flag from files
269348ffe56aSColin Percivalinstall_unschg () {
269448ffe56aSColin Percival	# Generate file list
269548ffe56aSColin Percival	cat $@ |
269648ffe56aSColin Percival	    cut -f 1 -d '|' > filelist
269748ffe56aSColin Percival
269848ffe56aSColin Percival	# Remove flags
269948ffe56aSColin Percival	while read F; do
2700e829ed67SColin Percival		if ! [ -e ${BASEDIR}/${F} ]; then
270148ffe56aSColin Percival			continue
27025a74378cSXin LI		else
27035a74378cSXin LI			echo ${BASEDIR}/${F}
270448ffe56aSColin Percival		fi
27055a74378cSXin LI	done < filelist | xargs chflags noschg || return 1
270648ffe56aSColin Percival
270748ffe56aSColin Percival	# Clean up
270848ffe56aSColin Percival	rm filelist
270948ffe56aSColin Percival}
271048ffe56aSColin Percival
271123d827efSSimon L. B. Nielsen# Decide which directory name to use for kernel backups.
271223d827efSSimon L. B. Nielsenbackup_kernel_finddir () {
271323d827efSSimon L. B. Nielsen	CNT=0
271423d827efSSimon L. B. Nielsen	while true ; do
271523d827efSSimon L. B. Nielsen		# Pathname does not exist, so it is OK use that name
271623d827efSSimon L. B. Nielsen		# for backup directory.
2717c4a0c62cSThomas Quinot		if [ ! -e $BASEDIR/$BACKUPKERNELDIR ]; then
271823d827efSSimon L. B. Nielsen			return 0
271923d827efSSimon L. B. Nielsen		fi
272023d827efSSimon L. B. Nielsen
272123d827efSSimon L. B. Nielsen		# If directory do exist, we only use if it has our
272223d827efSSimon L. B. Nielsen		# marker file.
2723c4a0c62cSThomas Quinot		if [ -d $BASEDIR/$BACKUPKERNELDIR -a \
2724c4a0c62cSThomas Quinot			-e $BASEDIR/$BACKUPKERNELDIR/.freebsd-update ]; then
272523d827efSSimon L. B. Nielsen			return 0
272623d827efSSimon L. B. Nielsen		fi
272723d827efSSimon L. B. Nielsen
272823d827efSSimon L. B. Nielsen		# We could not use current directory name, so add counter to
272923d827efSSimon L. B. Nielsen		# the end and try again.
273023d827efSSimon L. B. Nielsen		CNT=$((CNT + 1))
273123d827efSSimon L. B. Nielsen		if [ $CNT -gt 9 ]; then
2732c4a0c62cSThomas Quinot			echo "Could not find valid backup dir ($BASEDIR/$BACKUPKERNELDIR)"
273323d827efSSimon L. B. Nielsen			exit 1
273423d827efSSimon L. B. Nielsen		fi
273523d827efSSimon L. B. Nielsen		BACKUPKERNELDIR="`echo $BACKUPKERNELDIR | sed -Ee 's/[0-9]\$//'`"
273623d827efSSimon L. B. Nielsen		BACKUPKERNELDIR="${BACKUPKERNELDIR}${CNT}"
273723d827efSSimon L. B. Nielsen	done
273823d827efSSimon L. B. Nielsen}
273923d827efSSimon L. B. Nielsen
274023d827efSSimon L. B. Nielsen# Backup the current kernel using hardlinks, if not disabled by user.
274123d827efSSimon L. B. Nielsen# Since we delete all files in the directory used for previous backups
274223d827efSSimon L. B. Nielsen# we create a marker file called ".freebsd-update" in the directory so
274323d827efSSimon L. B. Nielsen# we can determine on the next run that the directory was created by
274423d827efSSimon L. B. Nielsen# freebsd-update and we then do not accidentally remove user files in
274523d827efSSimon L. B. Nielsen# the unlikely case that the user has created a directory with a
274623d827efSSimon L. B. Nielsen# conflicting name.
274723d827efSSimon L. B. Nielsenbackup_kernel () {
274823d827efSSimon L. B. Nielsen	# Only make kernel backup is so configured.
274923d827efSSimon L. B. Nielsen	if [ $BACKUPKERNEL != yes ]; then
275023d827efSSimon L. B. Nielsen		return 0
275123d827efSSimon L. B. Nielsen	fi
275223d827efSSimon L. B. Nielsen
275323d827efSSimon L. B. Nielsen	# Decide which directory name to use for kernel backups.
275423d827efSSimon L. B. Nielsen	backup_kernel_finddir
275523d827efSSimon L. B. Nielsen
275623d827efSSimon L. B. Nielsen	# Remove old kernel backup files.  If $BACKUPKERNELDIR was
275723d827efSSimon L. B. Nielsen	# "not ours", backup_kernel_finddir would have exited, so
275823d827efSSimon L. B. Nielsen	# deleting the directory content is as safe as we can make it.
2759c4a0c62cSThomas Quinot	if [ -d $BASEDIR/$BACKUPKERNELDIR ]; then
2760c4a0c62cSThomas Quinot		rm -fr $BASEDIR/$BACKUPKERNELDIR
276123d827efSSimon L. B. Nielsen	fi
276223d827efSSimon L. B. Nielsen
2763ab7d0151SJaakko Heinonen	# Create directories for backup.
2764c4a0c62cSThomas Quinot	mkdir -p $BASEDIR/$BACKUPKERNELDIR
2765c4a0c62cSThomas Quinot	mtree -cdn -p "${BASEDIR}/${KERNELDIR}" | \
2766c4a0c62cSThomas Quinot	    mtree -Ue -p "${BASEDIR}/${BACKUPKERNELDIR}" > /dev/null
276723d827efSSimon L. B. Nielsen
276823d827efSSimon L. B. Nielsen	# Mark the directory as having been created by freebsd-update.
2769c4a0c62cSThomas Quinot	touch $BASEDIR/$BACKUPKERNELDIR/.freebsd-update
277023d827efSSimon L. B. Nielsen	if [ $? -ne 0 ]; then
277123d827efSSimon L. B. Nielsen		echo "Could not create kernel backup directory"
277223d827efSSimon L. B. Nielsen		exit 1
277323d827efSSimon L. B. Nielsen	fi
277423d827efSSimon L. B. Nielsen
277523d827efSSimon L. B. Nielsen	# Disable pathname expansion to be sure *.symbols is not
277623d827efSSimon L. B. Nielsen	# expanded.
277723d827efSSimon L. B. Nielsen	set -f
277823d827efSSimon L. B. Nielsen
277923d827efSSimon L. B. Nielsen	# Use find to ignore symbol files, unless disabled by user.
278023d827efSSimon L. B. Nielsen	if [ $BACKUPKERNELSYMBOLFILES = yes ]; then
278123d827efSSimon L. B. Nielsen		FINDFILTER=""
278223d827efSSimon L. B. Nielsen	else
27837e1ed2c7SEd Maste		FINDFILTER="-a ! -name *.debug -a ! -name *.symbols"
278423d827efSSimon L. B. Nielsen	fi
278523d827efSSimon L. B. Nielsen
278623d827efSSimon L. B. Nielsen	# Backup all the kernel files using hardlinks.
2787c4a0c62cSThomas Quinot	(cd ${BASEDIR}/${KERNELDIR} && find . -type f $FINDFILTER -exec \
2788c4a0c62cSThomas Quinot	    cp -pl '{}' ${BASEDIR}/${BACKUPKERNELDIR}/'{}' \;)
278923d827efSSimon L. B. Nielsen
279023d827efSSimon L. B. Nielsen	# Re-enable patchname expansion.
279123d827efSSimon L. B. Nielsen	set +f
279223d827efSSimon L. B. Nielsen}
279323d827efSSimon L. B. Nielsen
279448ffe56aSColin Percival# Install new files
279548ffe56aSColin Percivalinstall_from_index () {
279648ffe56aSColin Percival	# First pass: Do everything apart from setting file flags.  We
279748ffe56aSColin Percival	# can't set flags yet, because schg inhibits hard linking.
279848ffe56aSColin Percival	sort -k 1,1 -t '|' $1 |
279948ffe56aSColin Percival	    tr '|' ' ' |
280048ffe56aSColin Percival	    while read FPATH TYPE OWNER GROUP PERM FLAGS HASH LINK; do
280148ffe56aSColin Percival		case ${TYPE} in
280248ffe56aSColin Percival		d)
280348ffe56aSColin Percival			# Create a directory
280448ffe56aSColin Percival			install -d -o ${OWNER} -g ${GROUP}		\
280548ffe56aSColin Percival			    -m ${PERM} ${BASEDIR}/${FPATH}
280648ffe56aSColin Percival			;;
280748ffe56aSColin Percival		f)
280848ffe56aSColin Percival			if [ -z "${LINK}" ]; then
280948ffe56aSColin Percival				# Create a file, without setting flags.
281048ffe56aSColin Percival				gunzip < files/${HASH}.gz > ${HASH}
281148ffe56aSColin Percival				install -S -o ${OWNER} -g ${GROUP}	\
281248ffe56aSColin Percival				    -m ${PERM} ${HASH} ${BASEDIR}/${FPATH}
281348ffe56aSColin Percival				rm ${HASH}
281448ffe56aSColin Percival			else
281548ffe56aSColin Percival				# Create a hard link.
2816e829ed67SColin Percival				ln -f ${BASEDIR}/${LINK} ${BASEDIR}/${FPATH}
281748ffe56aSColin Percival			fi
281848ffe56aSColin Percival			;;
281948ffe56aSColin Percival		L)
282048ffe56aSColin Percival			# Create a symlink
282148ffe56aSColin Percival			ln -sfh ${HASH} ${BASEDIR}/${FPATH}
282248ffe56aSColin Percival			;;
282348ffe56aSColin Percival		esac
282448ffe56aSColin Percival	    done
282548ffe56aSColin Percival
282648ffe56aSColin Percival	# Perform a second pass, adding file flags.
282748ffe56aSColin Percival	tr '|' ' ' < $1 |
282848ffe56aSColin Percival	    while read FPATH TYPE OWNER GROUP PERM FLAGS HASH LINK; do
282948ffe56aSColin Percival		if [ ${TYPE} = "f" ] &&
283048ffe56aSColin Percival		    ! [ ${FLAGS} = "0" ]; then
283148ffe56aSColin Percival			chflags ${FLAGS} ${BASEDIR}/${FPATH}
283248ffe56aSColin Percival		fi
283348ffe56aSColin Percival	    done
283448ffe56aSColin Percival}
283548ffe56aSColin Percival
283648ffe56aSColin Percival# Remove files which we want to delete
283748ffe56aSColin Percivalinstall_delete () {
283848ffe56aSColin Percival	# Generate list of new files
283948ffe56aSColin Percival	cut -f 1 -d '|' < $2 |
284048ffe56aSColin Percival	    sort > newfiles
284148ffe56aSColin Percival
284248ffe56aSColin Percival	# Generate subindex of old files we want to nuke
284348ffe56aSColin Percival	sort -k 1,1 -t '|' $1 |
284448ffe56aSColin Percival	    join -t '|' -v 1 - newfiles |
2845bce02f98SColin Percival	    sort -r -k 1,1 -t '|' |
284648ffe56aSColin Percival	    cut -f 1,2 -d '|' |
284748ffe56aSColin Percival	    tr '|' ' ' > killfiles
284848ffe56aSColin Percival
284948ffe56aSColin Percival	# Remove the offending bits
285048ffe56aSColin Percival	while read FPATH TYPE; do
285148ffe56aSColin Percival		case ${TYPE} in
285248ffe56aSColin Percival		d)
285348ffe56aSColin Percival			rmdir ${BASEDIR}/${FPATH}
285448ffe56aSColin Percival			;;
285548ffe56aSColin Percival		f)
285648ffe56aSColin Percival			rm ${BASEDIR}/${FPATH}
285748ffe56aSColin Percival			;;
285848ffe56aSColin Percival		L)
285948ffe56aSColin Percival			rm ${BASEDIR}/${FPATH}
286048ffe56aSColin Percival			;;
286148ffe56aSColin Percival		esac
286248ffe56aSColin Percival	done < killfiles
286348ffe56aSColin Percival
286448ffe56aSColin Percival	# Clean up
286548ffe56aSColin Percival	rm newfiles killfiles
286648ffe56aSColin Percival}
286748ffe56aSColin Percival
2868db6b0a61SColin Percival# Install new files, delete old files, and update linker.hints
2869db6b0a61SColin Percivalinstall_files () {
2870db6b0a61SColin Percival	# If we haven't already dealt with the kernel, deal with it.
2871db6b0a61SColin Percival	if ! [ -f $1/kerneldone ]; then
2872db6b0a61SColin Percival		grep -E '^/boot/' $1/INDEX-OLD > INDEX-OLD
2873db6b0a61SColin Percival		grep -E '^/boot/' $1/INDEX-NEW > INDEX-NEW
2874db6b0a61SColin Percival
287523d827efSSimon L. B. Nielsen		# Backup current kernel before installing a new one
287623d827efSSimon L. B. Nielsen		backup_kernel || return 1
287723d827efSSimon L. B. Nielsen
2878db6b0a61SColin Percival		# Install new files
2879db6b0a61SColin Percival		install_from_index INDEX-NEW || return 1
2880db6b0a61SColin Percival
2881db6b0a61SColin Percival		# Remove files which need to be deleted
2882db6b0a61SColin Percival		install_delete INDEX-OLD INDEX-NEW || return 1
2883db6b0a61SColin Percival
2884db6b0a61SColin Percival		# Update linker.hints if necessary
2885db6b0a61SColin Percival		if [ -s INDEX-OLD -o -s INDEX-NEW ]; then
2886c4a0c62cSThomas Quinot			kldxref -R ${BASEDIR}/boot/ 2>/dev/null
288748ffe56aSColin Percival		fi
2888db6b0a61SColin Percival
2889db6b0a61SColin Percival		# We've finished updating the kernel.
2890db6b0a61SColin Percival		touch $1/kerneldone
2891db6b0a61SColin Percival
2892db6b0a61SColin Percival		# Do we need to ask for a reboot now?
2893db6b0a61SColin Percival		if [ -f $1/kernelfirst ] &&
2894db6b0a61SColin Percival		    [ -s INDEX-OLD -o -s INDEX-NEW ]; then
2895db6b0a61SColin Percival			cat <<-EOF
2896db6b0a61SColin Percival
2897db6b0a61SColin PercivalKernel updates have been installed.  Please reboot and run
2898db6b0a61SColin Percival"$0 install" again to finish installing updates.
2899db6b0a61SColin Percival			EOF
2900db6b0a61SColin Percival			exit 0
2901db6b0a61SColin Percival		fi
2902db6b0a61SColin Percival	fi
2903db6b0a61SColin Percival
2904db6b0a61SColin Percival	# If we haven't already dealt with the world, deal with it.
2905db6b0a61SColin Percival	if ! [ -f $1/worlddone ]; then
2906cd1ab228SColin Percival		# Create any necessary directories first
2907cd1ab228SColin Percival		grep -vE '^/boot/' $1/INDEX-NEW |
2908cd1ab228SColin Percival		    grep -E '^[^|]+\|d\|' > INDEX-NEW
2909cd1ab228SColin Percival		install_from_index INDEX-NEW || return 1
2910cd1ab228SColin Percival
2911722d81b5SBrooks Davis		# Install new runtime linker
2912722d81b5SBrooks Davis		grep -vE '^/boot/' $1/INDEX-NEW |
2913722d81b5SBrooks Davis		    grep -vE '^[^|]+\|d\|' |
2914722d81b5SBrooks Davis		    grep -E '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' > INDEX-NEW
2915722d81b5SBrooks Davis		install_from_index INDEX-NEW || return 1
2916722d81b5SBrooks Davis
2917db6b0a61SColin Percival		# Install new shared libraries next
2918db6b0a61SColin Percival		grep -vE '^/boot/' $1/INDEX-NEW |
2919cd1ab228SColin Percival		    grep -vE '^[^|]+\|d\|' |
2920722d81b5SBrooks Davis		    grep -vE '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' |
29219546dbd1SColin Percival		    grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-NEW
2922db6b0a61SColin Percival		install_from_index INDEX-NEW || return 1
2923db6b0a61SColin Percival
2924db6b0a61SColin Percival		# Deal with everything else
2925db6b0a61SColin Percival		grep -vE '^/boot/' $1/INDEX-OLD |
2926cd1ab228SColin Percival		    grep -vE '^[^|]+\|d\|' |
2927722d81b5SBrooks Davis		    grep -vE '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' |
29289546dbd1SColin Percival		    grep -vE '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-OLD
2929db6b0a61SColin Percival		grep -vE '^/boot/' $1/INDEX-NEW |
2930cd1ab228SColin Percival		    grep -vE '^[^|]+\|d\|' |
2931722d81b5SBrooks Davis		    grep -vE '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' |
29329546dbd1SColin Percival		    grep -vE '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-NEW
2933db6b0a61SColin Percival		install_from_index INDEX-NEW || return 1
2934db6b0a61SColin Percival		install_delete INDEX-OLD INDEX-NEW || return 1
2935db6b0a61SColin Percival
29369b659110SEd Maste		# Rebuild generated pwd files.
2937c4a0c62cSThomas Quinot		if [ ${BASEDIR}/etc/master.passwd -nt ${BASEDIR}/etc/spwd.db ] ||
29389b659110SEd Maste		    [ ${BASEDIR}/etc/master.passwd -nt ${BASEDIR}/etc/pwd.db ] ||
29399b659110SEd Maste		    [ ${BASEDIR}/etc/master.passwd -nt ${BASEDIR}/etc/passwd ]; then
29409b659110SEd Maste			pwd_mkdb -d ${BASEDIR}/etc -p ${BASEDIR}/etc/master.passwd
2941db6b0a61SColin Percival		fi
2942db6b0a61SColin Percival
2943db6b0a61SColin Percival		# Rebuild /etc/login.conf.db if necessary.
2944c4a0c62cSThomas Quinot		if [ ${BASEDIR}/etc/login.conf -nt ${BASEDIR}/etc/login.conf.db ]; then
2945c4a0c62cSThomas Quinot			cap_mkdb ${BASEDIR}/etc/login.conf
2946db6b0a61SColin Percival		fi
2947db6b0a61SColin Percival
29489c812c8dSEd Maste		# Rebuild man page databases, if necessary.
29499c812c8dSEd Maste		for D in /usr/share/man /usr/share/openssl/man; do
29509c812c8dSEd Maste			if [ ! -d ${BASEDIR}/$D ]; then
29519c812c8dSEd Maste				continue
29529c812c8dSEd Maste			fi
29539c812c8dSEd Maste			if [ -z "$(find ${BASEDIR}/$D -type f -newer ${BASEDIR}/$D/mandoc.db)" ]; then
29549c812c8dSEd Maste				continue;
29559c812c8dSEd Maste			fi
29569c812c8dSEd Maste			makewhatis ${BASEDIR}/$D
29579c812c8dSEd Maste		done
29589c812c8dSEd Maste
2959db6b0a61SColin Percival		# We've finished installing the world and deleting old files
2960db6b0a61SColin Percival		# which are not shared libraries.
2961db6b0a61SColin Percival		touch $1/worlddone
2962db6b0a61SColin Percival
2963db6b0a61SColin Percival		# Do we need to ask the user to portupgrade now?
2964db6b0a61SColin Percival		grep -vE '^/boot/' $1/INDEX-NEW |
29659546dbd1SColin Percival		    grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' |
2966db6b0a61SColin Percival		    cut -f 1 -d '|' |
2967db6b0a61SColin Percival		    sort > newfiles
2968db6b0a61SColin Percival		if grep -vE '^/boot/' $1/INDEX-OLD |
29699546dbd1SColin Percival		    grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' |
2970db6b0a61SColin Percival		    cut -f 1 -d '|' |
2971db6b0a61SColin Percival		    sort |
2972db6b0a61SColin Percival		    join -v 1 - newfiles |
2973db6b0a61SColin Percival		    grep -q .; then
2974db6b0a61SColin Percival			cat <<-EOF
2975db6b0a61SColin Percival
2976db6b0a61SColin PercivalCompleting this upgrade requires removing old shared object files.
2977db6b0a61SColin PercivalPlease rebuild all installed 3rd party software (e.g., programs
2978db6b0a61SColin Percivalinstalled from the ports tree) and then run "$0 install"
2979db6b0a61SColin Percivalagain to finish installing updates.
2980db6b0a61SColin Percival			EOF
2981db6b0a61SColin Percival			rm newfiles
2982db6b0a61SColin Percival			exit 0
2983db6b0a61SColin Percival		fi
2984db6b0a61SColin Percival		rm newfiles
2985db6b0a61SColin Percival	fi
2986db6b0a61SColin Percival
2987db6b0a61SColin Percival	# Remove old shared libraries
2988db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-NEW |
2989cd1ab228SColin Percival	    grep -vE '^[^|]+\|d\|' |
29909546dbd1SColin Percival	    grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-NEW
2991db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
2992cd1ab228SColin Percival	    grep -vE '^[^|]+\|d\|' |
29939546dbd1SColin Percival	    grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-OLD
2994db6b0a61SColin Percival	install_delete INDEX-OLD INDEX-NEW || return 1
2995db6b0a61SColin Percival
2996cd1ab228SColin Percival	# Remove old directories
2997ebc1d19cSColin Percival	grep -vE '^/boot/' $1/INDEX-NEW |
2998ebc1d19cSColin Percival	    grep -E '^[^|]+\|d\|' > INDEX-NEW
2999cd1ab228SColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
3000cd1ab228SColin Percival	    grep -E '^[^|]+\|d\|' > INDEX-OLD
3001cd1ab228SColin Percival	install_delete INDEX-OLD INDEX-NEW || return 1
3002cd1ab228SColin Percival
3003db6b0a61SColin Percival	# Remove temporary files
3004db6b0a61SColin Percival	rm INDEX-OLD INDEX-NEW
300548ffe56aSColin Percival}
300648ffe56aSColin Percival
300748ffe56aSColin Percival# Rearrange bits to allow the installed updates to be rolled back
300848ffe56aSColin Percivalinstall_setup_rollback () {
3009db6b0a61SColin Percival	# Remove the "reboot after installing kernel", "kernel updated", and
3010db6b0a61SColin Percival	# "finished installing the world" flags if present -- they are
3011db6b0a61SColin Percival	# irrelevant when rolling back updates.
3012db6b0a61SColin Percival	if [ -f ${BDHASH}-install/kernelfirst ]; then
3013db6b0a61SColin Percival		rm ${BDHASH}-install/kernelfirst
3014db6b0a61SColin Percival		rm ${BDHASH}-install/kerneldone
3015db6b0a61SColin Percival	fi
3016db6b0a61SColin Percival	if [ -f ${BDHASH}-install/worlddone ]; then
3017db6b0a61SColin Percival		rm ${BDHASH}-install/worlddone
3018db6b0a61SColin Percival	fi
3019db6b0a61SColin Percival
302048ffe56aSColin Percival	if [ -L ${BDHASH}-rollback ]; then
302148ffe56aSColin Percival		mv ${BDHASH}-rollback ${BDHASH}-install/rollback
302248ffe56aSColin Percival	fi
302348ffe56aSColin Percival
302448ffe56aSColin Percival	mv ${BDHASH}-install ${BDHASH}-rollback
302548ffe56aSColin Percival}
302648ffe56aSColin Percival
302748ffe56aSColin Percival# Actually install updates
302848ffe56aSColin Percivalinstall_run () {
302948ffe56aSColin Percival	echo -n "Installing updates..."
303048ffe56aSColin Percival
303148ffe56aSColin Percival	# Make sure we have all the files we should have
303248ffe56aSColin Percival	install_verify ${BDHASH}-install/INDEX-OLD	\
303348ffe56aSColin Percival	    ${BDHASH}-install/INDEX-NEW || return 1
303448ffe56aSColin Percival
303548ffe56aSColin Percival	# Remove system immutable flag from files
303648ffe56aSColin Percival	install_unschg ${BDHASH}-install/INDEX-OLD	\
303748ffe56aSColin Percival	    ${BDHASH}-install/INDEX-NEW || return 1
303848ffe56aSColin Percival
3039db6b0a61SColin Percival	# Install new files, delete old files, and update linker.hints
3040db6b0a61SColin Percival	install_files ${BDHASH}-install || return 1
304148ffe56aSColin Percival
304248ffe56aSColin Percival	# Rearrange bits to allow the installed updates to be rolled back
304348ffe56aSColin Percival	install_setup_rollback
304448ffe56aSColin Percival
304548ffe56aSColin Percival	echo " done."
304648ffe56aSColin Percival}
304748ffe56aSColin Percival
304848ffe56aSColin Percival# Rearrange bits to allow the previous set of updates to be rolled back next.
304948ffe56aSColin Percivalrollback_setup_rollback () {
305048ffe56aSColin Percival	if [ -L ${BDHASH}-rollback/rollback ]; then
305148ffe56aSColin Percival		mv ${BDHASH}-rollback/rollback rollback-tmp
305248ffe56aSColin Percival		rm -r ${BDHASH}-rollback/
305348ffe56aSColin Percival		rm ${BDHASH}-rollback
305448ffe56aSColin Percival		mv rollback-tmp ${BDHASH}-rollback
305548ffe56aSColin Percival	else
305648ffe56aSColin Percival		rm -r ${BDHASH}-rollback/
305748ffe56aSColin Percival		rm ${BDHASH}-rollback
305848ffe56aSColin Percival	fi
305948ffe56aSColin Percival}
306048ffe56aSColin Percival
3061db6b0a61SColin Percival# Install old files, delete new files, and update linker.hints
3062db6b0a61SColin Percivalrollback_files () {
30631ec4fb3aSColin Percival	# Install old shared library files which don't have the same path as
30641ec4fb3aSColin Percival	# a new shared library file.
30651ec4fb3aSColin Percival	grep -vE '^/boot/' $1/INDEX-NEW |
3066fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' |
30671ec4fb3aSColin Percival	    cut -f 1 -d '|' |
30681ec4fb3aSColin Percival	    sort > INDEX-NEW.libs.flist
3069db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
3070fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' |
30711ec4fb3aSColin Percival	    sort -k 1,1 -t '|' - |
30721ec4fb3aSColin Percival	    join -t '|' -v 1 - INDEX-NEW.libs.flist > INDEX-OLD
3073db6b0a61SColin Percival	install_from_index INDEX-OLD || return 1
3074db6b0a61SColin Percival
3075db6b0a61SColin Percival	# Deal with files which are neither kernel nor shared library
3076db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
3077fd0963d1SColin Percival	    grep -vE '/lib/.*\.so\.[0-9]+\|' > INDEX-OLD
3078db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-NEW |
3079fd0963d1SColin Percival	    grep -vE '/lib/.*\.so\.[0-9]+\|' > INDEX-NEW
3080db6b0a61SColin Percival	install_from_index INDEX-OLD || return 1
3081db6b0a61SColin Percival	install_delete INDEX-NEW INDEX-OLD || return 1
3082db6b0a61SColin Percival
30831ec4fb3aSColin Percival	# Install any old shared library files which we didn't install above.
30841ec4fb3aSColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
3085fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' |
30861ec4fb3aSColin Percival	    sort -k 1,1 -t '|' - |
30871ec4fb3aSColin Percival	    join -t '|' - INDEX-NEW.libs.flist > INDEX-OLD
30881ec4fb3aSColin Percival	install_from_index INDEX-OLD || return 1
30891ec4fb3aSColin Percival
3090db6b0a61SColin Percival	# Delete unneeded shared library files
3091db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
3092fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' > INDEX-OLD
3093db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-NEW |
3094fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' > INDEX-NEW
3095db6b0a61SColin Percival	install_delete INDEX-NEW INDEX-OLD || return 1
3096db6b0a61SColin Percival
3097db6b0a61SColin Percival	# Deal with kernel files
3098db6b0a61SColin Percival	grep -E '^/boot/' $1/INDEX-OLD > INDEX-OLD
3099db6b0a61SColin Percival	grep -E '^/boot/' $1/INDEX-NEW > INDEX-NEW
3100db6b0a61SColin Percival	install_from_index INDEX-OLD || return 1
3101db6b0a61SColin Percival	install_delete INDEX-NEW INDEX-OLD || return 1
3102db6b0a61SColin Percival	if [ -s INDEX-OLD -o -s INDEX-NEW ]; then
3103db6b0a61SColin Percival		kldxref -R /boot/ 2>/dev/null
3104db6b0a61SColin Percival	fi
3105db6b0a61SColin Percival
3106db6b0a61SColin Percival	# Remove temporary files
31070e0d8d5aSColin Percival	rm INDEX-OLD INDEX-NEW INDEX-NEW.libs.flist
3108db6b0a61SColin Percival}
3109db6b0a61SColin Percival
311048ffe56aSColin Percival# Actually rollback updates
311148ffe56aSColin Percivalrollback_run () {
311248ffe56aSColin Percival	echo -n "Uninstalling updates..."
311348ffe56aSColin Percival
311448ffe56aSColin Percival	# If there are updates waiting to be installed, remove them; we
311548ffe56aSColin Percival	# want the user to re-run 'fetch' after rolling back updates.
311648ffe56aSColin Percival	if [ -L ${BDHASH}-install ]; then
311748ffe56aSColin Percival		rm -r ${BDHASH}-install/
311848ffe56aSColin Percival		rm ${BDHASH}-install
311948ffe56aSColin Percival	fi
312048ffe56aSColin Percival
312148ffe56aSColin Percival	# Make sure we have all the files we should have
312248ffe56aSColin Percival	install_verify ${BDHASH}-rollback/INDEX-NEW	\
312348ffe56aSColin Percival	    ${BDHASH}-rollback/INDEX-OLD || return 1
312448ffe56aSColin Percival
312548ffe56aSColin Percival	# Remove system immutable flag from files
312648ffe56aSColin Percival	install_unschg ${BDHASH}-rollback/INDEX-NEW	\
312748ffe56aSColin Percival	    ${BDHASH}-rollback/INDEX-OLD || return 1
312848ffe56aSColin Percival
3129db6b0a61SColin Percival	# Install old files, delete new files, and update linker.hints
3130db6b0a61SColin Percival	rollback_files ${BDHASH}-rollback || return 1
313148ffe56aSColin Percival
313248ffe56aSColin Percival	# Remove the rollback directory and the symlink pointing to it; and
313348ffe56aSColin Percival	# rearrange bits to allow the previous set of updates to be rolled
313448ffe56aSColin Percival	# back next.
313548ffe56aSColin Percival	rollback_setup_rollback
313648ffe56aSColin Percival
313748ffe56aSColin Percival	echo " done."
313848ffe56aSColin Percival}
313948ffe56aSColin Percival
314008e23beeSColin Percival# Compare INDEX-ALL and INDEX-PRESENT and print warnings about differences.
314108e23beeSColin PercivalIDS_compare () {
3142bb10a826SColin Percival	# Get all the lines which mismatch in something other than file
3143bb10a826SColin Percival	# flags.  We ignore file flags because sysinstall doesn't seem to
3144bb10a826SColin Percival	# set them when it installs FreeBSD; warning about these adds a
3145bb10a826SColin Percival	# very large amount of noise.
3146bb10a826SColin Percival	cut -f 1-5,7-8 -d '|' $1 > $1.noflags
3147bb10a826SColin Percival	sort -k 1,1 -t '|' $1.noflags > $1.sorted
3148bb10a826SColin Percival	cut -f 1-5,7-8 -d '|' $2 |
3149bb10a826SColin Percival	    comm -13 $1.noflags - |
3150bb10a826SColin Percival	    fgrep -v '|-|||||' |
315108e23beeSColin Percival	    sort -k 1,1 -t '|' |
315208e23beeSColin Percival	    join -t '|' $1.sorted - > INDEX-NOTMATCHING
315308e23beeSColin Percival
315408e23beeSColin Percival	# Ignore files which match IDSIGNOREPATHS.
315508e23beeSColin Percival	for X in ${IDSIGNOREPATHS}; do
315608e23beeSColin Percival		grep -E "^${X}" INDEX-NOTMATCHING
315708e23beeSColin Percival	done |
315808e23beeSColin Percival	    sort -u |
315908e23beeSColin Percival	    comm -13 - INDEX-NOTMATCHING > INDEX-NOTMATCHING.tmp
316008e23beeSColin Percival	mv INDEX-NOTMATCHING.tmp INDEX-NOTMATCHING
316108e23beeSColin Percival
316208e23beeSColin Percival	# Go through the lines and print warnings.
3163aa60062eSColin Percival	local IFS='|'
3164aa60062eSColin Percival	while read FPATH TYPE OWNER GROUP PERM HASH LINK P_TYPE P_OWNER P_GROUP P_PERM P_HASH P_LINK; do
316508e23beeSColin Percival		# Warn about different object types.
316608e23beeSColin Percival		if ! [ "${TYPE}" = "${P_TYPE}" ]; then
316708e23beeSColin Percival			echo -n "${FPATH} is a "
316808e23beeSColin Percival			case "${P_TYPE}" in
316908e23beeSColin Percival			f)	echo -n "regular file, "
317008e23beeSColin Percival				;;
317108e23beeSColin Percival			d)	echo -n "directory, "
317208e23beeSColin Percival				;;
317308e23beeSColin Percival			L)	echo -n "symlink, "
317408e23beeSColin Percival				;;
317508e23beeSColin Percival			esac
317608e23beeSColin Percival			echo -n "but should be a "
317708e23beeSColin Percival			case "${TYPE}" in
317808e23beeSColin Percival			f)	echo -n "regular file."
317908e23beeSColin Percival				;;
318008e23beeSColin Percival			d)	echo -n "directory."
318108e23beeSColin Percival				;;
318208e23beeSColin Percival			L)	echo -n "symlink."
318308e23beeSColin Percival				;;
318408e23beeSColin Percival			esac
318508e23beeSColin Percival			echo
318608e23beeSColin Percival
318708e23beeSColin Percival			# Skip other tests, since they don't make sense if
318808e23beeSColin Percival			# we're comparing different object types.
318908e23beeSColin Percival			continue
319008e23beeSColin Percival		fi
319108e23beeSColin Percival
319208e23beeSColin Percival		# Warn about different owners.
319308e23beeSColin Percival		if ! [ "${OWNER}" = "${P_OWNER}" ]; then
319408e23beeSColin Percival			echo -n "${FPATH} is owned by user id ${P_OWNER}, "
319508e23beeSColin Percival			echo "but should be owned by user id ${OWNER}."
319608e23beeSColin Percival		fi
319708e23beeSColin Percival
319808e23beeSColin Percival		# Warn about different groups.
319908e23beeSColin Percival		if ! [ "${GROUP}" = "${P_GROUP}" ]; then
320008e23beeSColin Percival			echo -n "${FPATH} is owned by group id ${P_GROUP}, "
320108e23beeSColin Percival			echo "but should be owned by group id ${GROUP}."
320208e23beeSColin Percival		fi
320308e23beeSColin Percival
320408e23beeSColin Percival		# Warn about different permissions.  We do not warn about
320508e23beeSColin Percival		# different permissions on symlinks, since some archivers
320608e23beeSColin Percival		# don't extract symlink permissions correctly and they are
320708e23beeSColin Percival		# ignored anyway.
320808e23beeSColin Percival		if ! [ "${PERM}" = "${P_PERM}" ] &&
320908e23beeSColin Percival		    ! [ "${TYPE}" = "L" ]; then
321008e23beeSColin Percival			echo -n "${FPATH} has ${P_PERM} permissions, "
321108e23beeSColin Percival			echo "but should have ${PERM} permissions."
321208e23beeSColin Percival		fi
321308e23beeSColin Percival
321408e23beeSColin Percival		# Warn about different file hashes / symlink destinations.
321508e23beeSColin Percival		if ! [ "${HASH}" = "${P_HASH}" ]; then
321608e23beeSColin Percival			if [ "${TYPE}" = "L" ]; then
321708e23beeSColin Percival				echo -n "${FPATH} is a symlink to ${P_HASH}, "
321808e23beeSColin Percival				echo "but should be a symlink to ${HASH}."
321908e23beeSColin Percival			fi
322008e23beeSColin Percival			if [ "${TYPE}" = "f" ]; then
322108e23beeSColin Percival				echo -n "${FPATH} has SHA256 hash ${P_HASH}, "
322208e23beeSColin Percival				echo "but should have SHA256 hash ${HASH}."
322308e23beeSColin Percival			fi
322408e23beeSColin Percival		fi
322508e23beeSColin Percival
322608e23beeSColin Percival		# We don't warn about different hard links, since some
322708e23beeSColin Percival		# some archivers break hard links, and as long as the
322808e23beeSColin Percival		# underlying data is correct they really don't matter.
322908e23beeSColin Percival	done < INDEX-NOTMATCHING
323008e23beeSColin Percival
323108e23beeSColin Percival	# Clean up
3232bb10a826SColin Percival	rm $1 $1.noflags $1.sorted $2 INDEX-NOTMATCHING
323308e23beeSColin Percival}
323408e23beeSColin Percival
323508e23beeSColin Percival# Do the work involved in comparing the system to a "known good" index
323608e23beeSColin PercivalIDS_run () {
323708e23beeSColin Percival	workdir_init || return 1
323808e23beeSColin Percival
323908e23beeSColin Percival	# Prepare the mirror list.
324008e23beeSColin Percival	fetch_pick_server_init && fetch_pick_server
324108e23beeSColin Percival
324208e23beeSColin Percival	# Try to fetch the public key until we run out of servers.
324308e23beeSColin Percival	while ! fetch_key; do
324408e23beeSColin Percival		fetch_pick_server || return 1
324508e23beeSColin Percival	done
324608e23beeSColin Percival
324708e23beeSColin Percival	# Try to fetch the metadata index signature ("tag") until we run
324808e23beeSColin Percival	# out of available servers; and sanity check the downloaded tag.
324908e23beeSColin Percival	while ! fetch_tag; do
325008e23beeSColin Percival		fetch_pick_server || return 1
325108e23beeSColin Percival	done
325208e23beeSColin Percival	fetch_tagsanity || return 1
325308e23beeSColin Percival
325408e23beeSColin Percival	# Fetch INDEX-OLD and INDEX-ALL.
325508e23beeSColin Percival	fetch_metadata INDEX-OLD INDEX-ALL || return 1
325608e23beeSColin Percival
325708e23beeSColin Percival	# Generate filtered INDEX-OLD and INDEX-ALL files containing only
325808e23beeSColin Percival	# the components we want and without anything marked as "Ignore".
325908e23beeSColin Percival	fetch_filter_metadata INDEX-OLD || return 1
326008e23beeSColin Percival	fetch_filter_metadata INDEX-ALL || return 1
326108e23beeSColin Percival
326208e23beeSColin Percival	# Merge the INDEX-OLD and INDEX-ALL files into INDEX-ALL.
326308e23beeSColin Percival	sort INDEX-OLD INDEX-ALL > INDEX-ALL.tmp
326408e23beeSColin Percival	mv INDEX-ALL.tmp INDEX-ALL
326508e23beeSColin Percival	rm INDEX-OLD
326608e23beeSColin Percival
326708e23beeSColin Percival	# Translate /boot/${KERNCONF} to ${KERNELDIR}
326808e23beeSColin Percival	fetch_filter_kernel_names INDEX-ALL ${KERNCONF}
326908e23beeSColin Percival
327008e23beeSColin Percival	# Inspect the system and generate an INDEX-PRESENT file.
327108e23beeSColin Percival	fetch_inspect_system INDEX-ALL INDEX-PRESENT /dev/null || return 1
327208e23beeSColin Percival
327308e23beeSColin Percival	# Compare INDEX-ALL and INDEX-PRESENT and print warnings about any
327408e23beeSColin Percival	# differences.
327508e23beeSColin Percival	IDS_compare INDEX-ALL INDEX-PRESENT
327608e23beeSColin Percival}
327708e23beeSColin Percival
327848ffe56aSColin Percival#### Main functions -- call parameter-handling and core functions
327948ffe56aSColin Percival
328048ffe56aSColin Percival# Using the command line, configuration file, and defaults,
328148ffe56aSColin Percival# set all the parameters which are needed later.
328248ffe56aSColin Percivalget_params () {
328348ffe56aSColin Percival	init_params
328448ffe56aSColin Percival	parse_cmdline $@
328548ffe56aSColin Percival	parse_conffile
328648ffe56aSColin Percival	default_params
328748ffe56aSColin Percival}
328848ffe56aSColin Percival
328948ffe56aSColin Percival# Fetch command.  Make sure that we're being called
329048ffe56aSColin Percival# interactively, then run fetch_check_params and fetch_run
329148ffe56aSColin Percivalcmd_fetch () {
32928bf2dcceSAllan Jude	if [ ! -t 0 -a $NOTTYOK -eq 0 ]; then
329348ffe56aSColin Percival		echo -n "`basename $0` fetch should not "
329448ffe56aSColin Percival		echo "be run non-interactively."
329548ffe56aSColin Percival		echo "Run `basename $0` cron instead."
329648ffe56aSColin Percival		exit 1
329748ffe56aSColin Percival	fi
329848ffe56aSColin Percival	fetch_check_params
329948ffe56aSColin Percival	fetch_run || exit 1
330033bd05c3SGuangyuan Yang	ISFETCHED=1
330148ffe56aSColin Percival}
330248ffe56aSColin Percival
330348ffe56aSColin Percival# Cron command.  Make sure the parameters are sensible; wait
330448ffe56aSColin Percival# rand(3600) seconds; then fetch updates.  While fetching updates,
330548ffe56aSColin Percival# send output to a temporary file; only print that file if the
330648ffe56aSColin Percival# fetching failed.
330748ffe56aSColin Percivalcmd_cron () {
330848ffe56aSColin Percival	fetch_check_params
330948ffe56aSColin Percival	sleep `jot -r 1 0 3600`
331048ffe56aSColin Percival
331148ffe56aSColin Percival	TMPFILE=`mktemp /tmp/freebsd-update.XXXXXX` || exit 1
331248ffe56aSColin Percival	if ! fetch_run >> ${TMPFILE} ||
331348ffe56aSColin Percival	    ! grep -q "No updates needed" ${TMPFILE} ||
331448ffe56aSColin Percival	    [ ${VERBOSELEVEL} = "debug" ]; then
331548ffe56aSColin Percival		mail -s "`hostname` security updates" ${MAILTO} < ${TMPFILE}
331648ffe56aSColin Percival	fi
331748ffe56aSColin Percival
331848ffe56aSColin Percival	rm ${TMPFILE}
331948ffe56aSColin Percival}
332048ffe56aSColin Percival
3321db6b0a61SColin Percival# Fetch files for upgrading to a new release.
3322db6b0a61SColin Percivalcmd_upgrade () {
3323db6b0a61SColin Percival	upgrade_check_params
3324db6b0a61SColin Percival	upgrade_run || exit 1
3325db6b0a61SColin Percival}
3326db6b0a61SColin Percival
332748ffe56aSColin Percival# Install downloaded updates.
332848ffe56aSColin Percivalcmd_install () {
332948ffe56aSColin Percival	install_check_params
333048ffe56aSColin Percival	install_run || exit 1
333148ffe56aSColin Percival}
333248ffe56aSColin Percival
333348ffe56aSColin Percival# Rollback most recently installed updates.
333448ffe56aSColin Percivalcmd_rollback () {
333548ffe56aSColin Percival	rollback_check_params
333648ffe56aSColin Percival	rollback_run || exit 1
333748ffe56aSColin Percival}
333848ffe56aSColin Percival
333908e23beeSColin Percival# Compare system against a "known good" index.
334008e23beeSColin Percivalcmd_IDS () {
334108e23beeSColin Percival	IDS_check_params
334208e23beeSColin Percival	IDS_run || exit 1
334308e23beeSColin Percival}
334408e23beeSColin Percival
334548ffe56aSColin Percival#### Entry point
334648ffe56aSColin Percival
334748ffe56aSColin Percival# Make sure we find utilities from the base system
334848ffe56aSColin Percivalexport PATH=/sbin:/bin:/usr/sbin:/usr/bin:${PATH}
334948ffe56aSColin Percival
33509c990fb2SGordon Tetlow# Set a pager if the user doesn't
33519c990fb2SGordon Tetlowif [ -z "$PAGER" ]; then
335247cc9ee1SAlan Somers	PAGER=/usr/bin/less
33539c990fb2SGordon Tetlowfi
33549c990fb2SGordon Tetlow
3355f2890dbdSColin Percival# Set LC_ALL in order to avoid problems with character ranges like [A-Z].
3356f2890dbdSColin Percivalexport LC_ALL=C
3357f2890dbdSColin Percival
335848ffe56aSColin Percivalget_params $@
335948ffe56aSColin Percivalfor COMMAND in ${COMMANDS}; do
336048ffe56aSColin Percival	cmd_${COMMAND}
336148ffe56aSColin Percivaldone
3362