xref: /freebsd/usr.sbin/freebsd-update/freebsd-update.sh (revision 8cfda118cbdadb3f1529dbc5e95722f0006ceb4e)
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
65*8cfda118SMichael Gmelin  updatesready -- Check if there are fetched updates ready to install
66db6b0a61SColin Percival  install      -- Install downloaded updates or upgrades
6748ffe56aSColin Percival  rollback     -- Uninstall most recently installed updates
6875cb6429SEd Maste  IDS          -- Compare the system against an index of "known good" files
69*8cfda118SMichael Gmelin  showconfig   -- Show configuration
7048ffe56aSColin PercivalEOF
7148ffe56aSColin Percival	exit 0
7248ffe56aSColin Percival}
7348ffe56aSColin Percival
7448ffe56aSColin Percival#### Configuration processing functions
7548ffe56aSColin Percival
7648ffe56aSColin Percival#-
7748ffe56aSColin Percival# Configuration options are set in the following order of priority:
7848ffe56aSColin Percival# 1. Command line options
7948ffe56aSColin Percival# 2. Configuration file options
8048ffe56aSColin Percival# 3. Default options
8148ffe56aSColin Percival# In addition, certain options (e.g., IgnorePaths) can be specified multiple
8248ffe56aSColin Percival# times and (as long as these are all in the same place, e.g., inside the
8348ffe56aSColin Percival# configuration file) they will accumulate.  Finally, because the path to the
8448ffe56aSColin Percival# configuration file can be specified at the command line, the entire command
8548ffe56aSColin Percival# line must be processed before we start reading the configuration file.
8648ffe56aSColin Percival#
8748ffe56aSColin Percival# Sound like a mess?  It is.  Here's how we handle this:
8848ffe56aSColin Percival# 1. Initialize CONFFILE and all the options to "".
8948ffe56aSColin Percival# 2. Process the command line.  Throw an error if a non-accumulating option
9048ffe56aSColin Percival#    is specified twice.
9148ffe56aSColin Percival# 3. If CONFFILE is "", set CONFFILE to /etc/freebsd-update.conf .
9248ffe56aSColin Percival# 4. For all the configuration options X, set X_saved to X.
9348ffe56aSColin Percival# 5. Initialize all the options to "".
9448ffe56aSColin Percival# 6. Read CONFFILE line by line, parsing options.
9548ffe56aSColin Percival# 7. For each configuration option X, set X to X_saved iff X_saved is not "".
9648ffe56aSColin Percival# 8. Repeat steps 4-7, except setting options to their default values at (6).
9748ffe56aSColin Percival
9848ffe56aSColin PercivalCONFIGOPTIONS="KEYPRINT WORKDIR SERVERNAME MAILTO ALLOWADD ALLOWDELETE
9948ffe56aSColin Percival    KEEPMODIFIEDMETADATA COMPONENTS IGNOREPATHS UPDATEIFUNMODIFIED
10008e23beeSColin Percival    BASEDIR VERBOSELEVEL TARGETRELEASE STRICTCOMPONENTS MERGECHANGES
10123d827efSSimon L. B. Nielsen    IDSIGNOREPATHS BACKUPKERNEL BACKUPKERNELDIR BACKUPKERNELSYMBOLFILES"
10248ffe56aSColin Percival
10348ffe56aSColin Percival# Set all the configuration options to "".
10448ffe56aSColin Percivalnullconfig () {
10548ffe56aSColin Percival	for X in ${CONFIGOPTIONS}; do
10648ffe56aSColin Percival		eval ${X}=""
10748ffe56aSColin Percival	done
10848ffe56aSColin Percival}
10948ffe56aSColin Percival
11048ffe56aSColin Percival# For each configuration option X, set X_saved to X.
11148ffe56aSColin Percivalsaveconfig () {
11248ffe56aSColin Percival	for X in ${CONFIGOPTIONS}; do
11348ffe56aSColin Percival		eval ${X}_saved=\$${X}
11448ffe56aSColin Percival	done
11548ffe56aSColin Percival}
11648ffe56aSColin Percival
11748ffe56aSColin Percival# For each configuration option X, set X to X_saved if X_saved is not "".
11848ffe56aSColin Percivalmergeconfig () {
11948ffe56aSColin Percival	for X in ${CONFIGOPTIONS}; do
12048ffe56aSColin Percival		eval _=\$${X}_saved
12148ffe56aSColin Percival		if ! [ -z "${_}" ]; then
12248ffe56aSColin Percival			eval ${X}=\$${X}_saved
12348ffe56aSColin Percival		fi
12448ffe56aSColin Percival	done
12548ffe56aSColin Percival}
12648ffe56aSColin Percival
12748ffe56aSColin Percival# Set the trusted keyprint.
12848ffe56aSColin Percivalconfig_KeyPrint () {
12948ffe56aSColin Percival	if [ -z ${KEYPRINT} ]; then
13048ffe56aSColin Percival		KEYPRINT=$1
13148ffe56aSColin Percival	else
13248ffe56aSColin Percival		return 1
13348ffe56aSColin Percival	fi
13448ffe56aSColin Percival}
13548ffe56aSColin Percival
13648ffe56aSColin Percival# Set the working directory.
13748ffe56aSColin Percivalconfig_WorkDir () {
13848ffe56aSColin Percival	if [ -z ${WORKDIR} ]; then
13948ffe56aSColin Percival		WORKDIR=$1
14048ffe56aSColin Percival	else
14148ffe56aSColin Percival		return 1
14248ffe56aSColin Percival	fi
14348ffe56aSColin Percival}
14448ffe56aSColin Percival
14548ffe56aSColin Percival# Set the name of the server (pool) from which to fetch updates
14648ffe56aSColin Percivalconfig_ServerName () {
14748ffe56aSColin Percival	if [ -z ${SERVERNAME} ]; then
14848ffe56aSColin Percival		SERVERNAME=$1
14948ffe56aSColin Percival	else
15048ffe56aSColin Percival		return 1
15148ffe56aSColin Percival	fi
15248ffe56aSColin Percival}
15348ffe56aSColin Percival
15448ffe56aSColin Percival# Set the address to which 'cron' output will be mailed.
15548ffe56aSColin Percivalconfig_MailTo () {
15648ffe56aSColin Percival	if [ -z ${MAILTO} ]; then
15748ffe56aSColin Percival		MAILTO=$1
15848ffe56aSColin Percival	else
15948ffe56aSColin Percival		return 1
16048ffe56aSColin Percival	fi
16148ffe56aSColin Percival}
16248ffe56aSColin Percival
16348ffe56aSColin Percival# Set whether FreeBSD Update is allowed to add files (or directories, or
16448ffe56aSColin Percival# symlinks) which did not previously exist.
16548ffe56aSColin Percivalconfig_AllowAdd () {
16648ffe56aSColin Percival	if [ -z ${ALLOWADD} ]; then
16748ffe56aSColin Percival		case $1 in
16848ffe56aSColin Percival		[Yy][Ee][Ss])
16948ffe56aSColin Percival			ALLOWADD=yes
17048ffe56aSColin Percival			;;
17148ffe56aSColin Percival		[Nn][Oo])
17248ffe56aSColin Percival			ALLOWADD=no
17348ffe56aSColin Percival			;;
17448ffe56aSColin Percival		*)
17548ffe56aSColin Percival			return 1
17648ffe56aSColin Percival			;;
17748ffe56aSColin Percival		esac
17848ffe56aSColin Percival	else
17948ffe56aSColin Percival		return 1
18048ffe56aSColin Percival	fi
18148ffe56aSColin Percival}
18248ffe56aSColin Percival
18348ffe56aSColin Percival# Set whether FreeBSD Update is allowed to remove files/directories/symlinks.
18448ffe56aSColin Percivalconfig_AllowDelete () {
18548ffe56aSColin Percival	if [ -z ${ALLOWDELETE} ]; then
18648ffe56aSColin Percival		case $1 in
18748ffe56aSColin Percival		[Yy][Ee][Ss])
18848ffe56aSColin Percival			ALLOWDELETE=yes
18948ffe56aSColin Percival			;;
19048ffe56aSColin Percival		[Nn][Oo])
19148ffe56aSColin Percival			ALLOWDELETE=no
19248ffe56aSColin Percival			;;
19348ffe56aSColin Percival		*)
19448ffe56aSColin Percival			return 1
19548ffe56aSColin Percival			;;
19648ffe56aSColin Percival		esac
19748ffe56aSColin Percival	else
19848ffe56aSColin Percival		return 1
19948ffe56aSColin Percival	fi
20048ffe56aSColin Percival}
20148ffe56aSColin Percival
20248ffe56aSColin Percival# Set whether FreeBSD Update should keep existing inode ownership,
20348ffe56aSColin Percival# permissions, and flags, in the event that they have been modified locally
20448ffe56aSColin Percival# after the release.
20548ffe56aSColin Percivalconfig_KeepModifiedMetadata () {
20648ffe56aSColin Percival	if [ -z ${KEEPMODIFIEDMETADATA} ]; then
20748ffe56aSColin Percival		case $1 in
20848ffe56aSColin Percival		[Yy][Ee][Ss])
20948ffe56aSColin Percival			KEEPMODIFIEDMETADATA=yes
21048ffe56aSColin Percival			;;
21148ffe56aSColin Percival		[Nn][Oo])
21248ffe56aSColin Percival			KEEPMODIFIEDMETADATA=no
21348ffe56aSColin Percival			;;
21448ffe56aSColin Percival		*)
21548ffe56aSColin Percival			return 1
21648ffe56aSColin Percival			;;
21748ffe56aSColin Percival		esac
21848ffe56aSColin Percival	else
21948ffe56aSColin Percival		return 1
22048ffe56aSColin Percival	fi
22148ffe56aSColin Percival}
22248ffe56aSColin Percival
22348ffe56aSColin Percival# Add to the list of components which should be kept updated.
22448ffe56aSColin Percivalconfig_Components () {
22548ffe56aSColin Percival	for C in $@; do
22612294db4SMichael Gmelin		COMPONENTS="${COMPONENTS} ${C}"
22712294db4SMichael Gmelin	done
22812294db4SMichael Gmelin}
22912294db4SMichael Gmelin
23012294db4SMichael Gmelin# Remove src component from list if it isn't installed
23112294db4SMichael Gmelinfinalize_components_config () {
23212294db4SMichael Gmelin	COMPONENTS=""
23312294db4SMichael Gmelin	for C in $@; do
2345a74378cSXin LI		if [ "$C" = "src" ]; then
235cfd9be9cSEd Maste			if [ -e "${BASEDIR}/usr/src/COPYRIGHT" ]; then
23648ffe56aSColin Percival				COMPONENTS="${COMPONENTS} ${C}"
2375a74378cSXin LI			else
2385a74378cSXin LI				echo "src component not installed, skipped"
2395a74378cSXin LI			fi
2405a74378cSXin LI		else
2415a74378cSXin LI			COMPONENTS="${COMPONENTS} ${C}"
2425a74378cSXin LI		fi
24348ffe56aSColin Percival	done
24448ffe56aSColin Percival}
24548ffe56aSColin Percival
24648ffe56aSColin Percival# Add to the list of paths under which updates will be ignored.
24748ffe56aSColin Percivalconfig_IgnorePaths () {
24848ffe56aSColin Percival	for C in $@; do
24948ffe56aSColin Percival		IGNOREPATHS="${IGNOREPATHS} ${C}"
25048ffe56aSColin Percival	done
25148ffe56aSColin Percival}
25248ffe56aSColin Percival
25308e23beeSColin Percival# Add to the list of paths which IDS should ignore.
25408e23beeSColin Percivalconfig_IDSIgnorePaths () {
25508e23beeSColin Percival	for C in $@; do
25608e23beeSColin Percival		IDSIGNOREPATHS="${IDSIGNOREPATHS} ${C}"
25708e23beeSColin Percival	done
25808e23beeSColin Percival}
25908e23beeSColin Percival
26048ffe56aSColin Percival# Add to the list of paths within which updates will be performed only if the
26148ffe56aSColin Percival# file on disk has not been modified locally.
26248ffe56aSColin Percivalconfig_UpdateIfUnmodified () {
26348ffe56aSColin Percival	for C in $@; do
26448ffe56aSColin Percival		UPDATEIFUNMODIFIED="${UPDATEIFUNMODIFIED} ${C}"
26548ffe56aSColin Percival	done
26648ffe56aSColin Percival}
26748ffe56aSColin Percival
268db6b0a61SColin Percival# Add to the list of paths within which updates to text files will be merged
269db6b0a61SColin Percival# instead of overwritten.
270db6b0a61SColin Percivalconfig_MergeChanges () {
271db6b0a61SColin Percival	for C in $@; do
272db6b0a61SColin Percival		MERGECHANGES="${MERGECHANGES} ${C}"
273db6b0a61SColin Percival	done
274db6b0a61SColin Percival}
275db6b0a61SColin Percival
27648ffe56aSColin Percival# Work on a FreeBSD installation mounted under $1
27748ffe56aSColin Percivalconfig_BaseDir () {
27848ffe56aSColin Percival	if [ -z ${BASEDIR} ]; then
27948ffe56aSColin Percival		BASEDIR=$1
28048ffe56aSColin Percival	else
28148ffe56aSColin Percival		return 1
28248ffe56aSColin Percival	fi
28348ffe56aSColin Percival}
28448ffe56aSColin Percival
285db6b0a61SColin Percival# When fetching upgrades, should we assume the user wants exactly the
286db6b0a61SColin Percival# components listed in COMPONENTS, rather than trying to guess based on
287db6b0a61SColin Percival# what's currently installed?
288db6b0a61SColin Percivalconfig_StrictComponents () {
289db6b0a61SColin Percival	if [ -z ${STRICTCOMPONENTS} ]; then
290db6b0a61SColin Percival		case $1 in
291db6b0a61SColin Percival		[Yy][Ee][Ss])
292db6b0a61SColin Percival			STRICTCOMPONENTS=yes
293db6b0a61SColin Percival			;;
294db6b0a61SColin Percival		[Nn][Oo])
295db6b0a61SColin Percival			STRICTCOMPONENTS=no
296db6b0a61SColin Percival			;;
297db6b0a61SColin Percival		*)
298db6b0a61SColin Percival			return 1
299db6b0a61SColin Percival			;;
300db6b0a61SColin Percival		esac
301db6b0a61SColin Percival	else
302db6b0a61SColin Percival		return 1
303db6b0a61SColin Percival	fi
304db6b0a61SColin Percival}
305db6b0a61SColin Percival
306db6b0a61SColin Percival# Upgrade to FreeBSD $1
307db6b0a61SColin Percivalconfig_TargetRelease () {
308db6b0a61SColin Percival	if [ -z ${TARGETRELEASE} ]; then
309db6b0a61SColin Percival		TARGETRELEASE=$1
310db6b0a61SColin Percival	else
311db6b0a61SColin Percival		return 1
312db6b0a61SColin Percival	fi
313d23dc1eeSColin Percival	if echo ${TARGETRELEASE} | grep -qE '^[0-9.]+$'; then
314d23dc1eeSColin Percival		TARGETRELEASE="${TARGETRELEASE}-RELEASE"
315d23dc1eeSColin Percival	fi
316db6b0a61SColin Percival}
317db6b0a61SColin Percival
3180d5c5243SEd Maste# Pretend current release is FreeBSD $1
3190d5c5243SEd Masteconfig_SourceRelease () {
3200d5c5243SEd Maste	UNAME_r=$1
3210d5c5243SEd Maste	if echo ${UNAME_r} | grep -qE '^[0-9.]+$'; then
3220d5c5243SEd Maste		UNAME_r="${UNAME_r}-RELEASE"
3230d5c5243SEd Maste	fi
324b958d4b2SEd Maste	export UNAME_r
3250d5c5243SEd Maste}
3260d5c5243SEd Maste
32748ffe56aSColin Percival# Define what happens to output of utilities
32848ffe56aSColin Percivalconfig_VerboseLevel () {
32948ffe56aSColin Percival	if [ -z ${VERBOSELEVEL} ]; then
33048ffe56aSColin Percival		case $1 in
33148ffe56aSColin Percival		[Dd][Ee][Bb][Uu][Gg])
33248ffe56aSColin Percival			VERBOSELEVEL=debug
33348ffe56aSColin Percival			;;
33448ffe56aSColin Percival		[Nn][Oo][Ss][Tt][Aa][Tt][Ss])
33548ffe56aSColin Percival			VERBOSELEVEL=nostats
33648ffe56aSColin Percival			;;
33748ffe56aSColin Percival		[Ss][Tt][Aa][Tt][Ss])
33848ffe56aSColin Percival			VERBOSELEVEL=stats
33948ffe56aSColin Percival			;;
34048ffe56aSColin Percival		*)
34148ffe56aSColin Percival			return 1
34248ffe56aSColin Percival			;;
34348ffe56aSColin Percival		esac
34448ffe56aSColin Percival	else
34548ffe56aSColin Percival		return 1
34648ffe56aSColin Percival	fi
34748ffe56aSColin Percival}
34848ffe56aSColin Percival
34923d827efSSimon L. B. Nielsenconfig_BackupKernel () {
35023d827efSSimon L. B. Nielsen	if [ -z ${BACKUPKERNEL} ]; then
35123d827efSSimon L. B. Nielsen		case $1 in
35223d827efSSimon L. B. Nielsen		[Yy][Ee][Ss])
35323d827efSSimon L. B. Nielsen			BACKUPKERNEL=yes
35423d827efSSimon L. B. Nielsen			;;
35523d827efSSimon L. B. Nielsen		[Nn][Oo])
35623d827efSSimon L. B. Nielsen			BACKUPKERNEL=no
35723d827efSSimon L. B. Nielsen			;;
35823d827efSSimon L. B. Nielsen		*)
35923d827efSSimon L. B. Nielsen			return 1
36023d827efSSimon L. B. Nielsen			;;
36123d827efSSimon L. B. Nielsen		esac
36223d827efSSimon L. B. Nielsen	else
36323d827efSSimon L. B. Nielsen		return 1
36423d827efSSimon L. B. Nielsen	fi
36523d827efSSimon L. B. Nielsen}
36623d827efSSimon L. B. Nielsen
36723d827efSSimon L. B. Nielsenconfig_BackupKernelDir () {
36823d827efSSimon L. B. Nielsen	if [ -z ${BACKUPKERNELDIR} ]; then
36923d827efSSimon L. B. Nielsen		if [ -z "$1" ]; then
37023d827efSSimon L. B. Nielsen			echo "BackupKernelDir set to empty dir"
37123d827efSSimon L. B. Nielsen			return 1
37223d827efSSimon L. B. Nielsen		fi
37323d827efSSimon L. B. Nielsen
37423d827efSSimon L. B. Nielsen		# We check for some paths which would be extremely odd
37523d827efSSimon L. B. Nielsen		# to use, but which could cause a lot of problems if
37623d827efSSimon L. B. Nielsen		# used.
37723d827efSSimon L. B. Nielsen		case $1 in
37823d827efSSimon L. B. Nielsen		/|/bin|/boot|/etc|/lib|/libexec|/sbin|/usr|/var)
37923d827efSSimon L. B. Nielsen			echo "BackupKernelDir set to invalid path $1"
38023d827efSSimon L. B. Nielsen			return 1
38123d827efSSimon L. B. Nielsen			;;
38223d827efSSimon L. B. Nielsen		/*)
38323d827efSSimon L. B. Nielsen			BACKUPKERNELDIR=$1
38423d827efSSimon L. B. Nielsen			;;
38523d827efSSimon L. B. Nielsen		*)
38623d827efSSimon L. B. Nielsen			echo "BackupKernelDir ($1) is not an absolute path"
38723d827efSSimon L. B. Nielsen			return 1
38823d827efSSimon L. B. Nielsen			;;
38923d827efSSimon L. B. Nielsen		esac
39023d827efSSimon L. B. Nielsen	else
39123d827efSSimon L. B. Nielsen		return 1
39223d827efSSimon L. B. Nielsen	fi
39323d827efSSimon L. B. Nielsen}
39423d827efSSimon L. B. Nielsen
39523d827efSSimon L. B. Nielsenconfig_BackupKernelSymbolFiles () {
39623d827efSSimon L. B. Nielsen	if [ -z ${BACKUPKERNELSYMBOLFILES} ]; then
39723d827efSSimon L. B. Nielsen		case $1 in
39823d827efSSimon L. B. Nielsen		[Yy][Ee][Ss])
39923d827efSSimon L. B. Nielsen			BACKUPKERNELSYMBOLFILES=yes
40023d827efSSimon L. B. Nielsen			;;
40123d827efSSimon L. B. Nielsen		[Nn][Oo])
40223d827efSSimon L. B. Nielsen			BACKUPKERNELSYMBOLFILES=no
40323d827efSSimon L. B. Nielsen			;;
40423d827efSSimon L. B. Nielsen		*)
40523d827efSSimon L. B. Nielsen			return 1
40623d827efSSimon L. B. Nielsen			;;
40723d827efSSimon L. B. Nielsen		esac
40823d827efSSimon L. B. Nielsen	else
40923d827efSSimon L. B. Nielsen		return 1
41023d827efSSimon L. B. Nielsen	fi
41123d827efSSimon L. B. Nielsen}
41223d827efSSimon L. B. Nielsen
41348ffe56aSColin Percival# Handle one line of configuration
41448ffe56aSColin Percivalconfigline () {
41548ffe56aSColin Percival	if [ $# -eq 0 ]; then
41648ffe56aSColin Percival		return
41748ffe56aSColin Percival	fi
41848ffe56aSColin Percival
41948ffe56aSColin Percival	OPT=$1
42048ffe56aSColin Percival	shift
42148ffe56aSColin Percival	config_${OPT} $@
42248ffe56aSColin Percival}
42348ffe56aSColin Percival
42448ffe56aSColin Percival#### Parameter handling functions.
42548ffe56aSColin Percival
42648ffe56aSColin Percival# Initialize parameters to null, just in case they're
42748ffe56aSColin Percival# set in the environment.
42848ffe56aSColin Percivalinit_params () {
42948ffe56aSColin Percival	# Configration settings
43048ffe56aSColin Percival	nullconfig
43148ffe56aSColin Percival
43248ffe56aSColin Percival	# No configuration file set yet
43348ffe56aSColin Percival	CONFFILE=""
43448ffe56aSColin Percival
43548ffe56aSColin Percival	# No commands specified yet
43648ffe56aSColin Percival	COMMANDS=""
4378935f242SAllan Jude
4388935f242SAllan Jude	# Force fetch to proceed
4398935f242SAllan Jude	FORCEFETCH=0
4408935f242SAllan Jude
4418935f242SAllan Jude	# Run without a TTY
4428935f242SAllan Jude	NOTTYOK=0
44333bd05c3SGuangyuan Yang
44433bd05c3SGuangyuan Yang	# Fetched first in a chain of commands
44533bd05c3SGuangyuan Yang	ISFETCHED=0
44648ffe56aSColin Percival}
44748ffe56aSColin Percival
44848ffe56aSColin Percival# Parse the command line
44948ffe56aSColin Percivalparse_cmdline () {
45048ffe56aSColin Percival	while [ $# -gt 0 ]; do
45148ffe56aSColin Percival		case "$1" in
45248ffe56aSColin Percival		# Location of configuration file
45348ffe56aSColin Percival		-f)
45448ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi
45548ffe56aSColin Percival			if [ ! -z "${CONFFILE}" ]; then usage; fi
45648ffe56aSColin Percival			shift; CONFFILE="$1"
45748ffe56aSColin Percival			;;
4588935f242SAllan Jude		-F)
4598935f242SAllan Jude			FORCEFETCH=1
4608935f242SAllan Jude			;;
4618935f242SAllan Jude		--not-running-from-cron)
4628935f242SAllan Jude			NOTTYOK=1
4638935f242SAllan Jude			;;
464b39ce43eSColin Percival		--currently-running)
4650d5c5243SEd Maste			shift
4660d5c5243SEd Maste			config_SourceRelease $1 || usage
467b39ce43eSColin Percival			;;
46848ffe56aSColin Percival
46948ffe56aSColin Percival		# Configuration file equivalents
47048ffe56aSColin Percival		-b)
47148ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
47248ffe56aSColin Percival			config_BaseDir $1 || usage
47348ffe56aSColin Percival			;;
47448ffe56aSColin Percival		-d)
47548ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
47648ffe56aSColin Percival			config_WorkDir $1 || usage
47748ffe56aSColin Percival			;;
47848ffe56aSColin Percival		-k)
47948ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
48048ffe56aSColin Percival			config_KeyPrint $1 || usage
48148ffe56aSColin Percival			;;
48248ffe56aSColin Percival		-s)
48348ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
48448ffe56aSColin Percival			config_ServerName $1 || usage
48548ffe56aSColin Percival			;;
486db6b0a61SColin Percival		-r)
487db6b0a61SColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
488db6b0a61SColin Percival			config_TargetRelease $1 || usage
489db6b0a61SColin Percival			;;
49048ffe56aSColin Percival		-t)
49148ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
49248ffe56aSColin Percival			config_MailTo $1 || usage
49348ffe56aSColin Percival			;;
49448ffe56aSColin Percival		-v)
49548ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
49648ffe56aSColin Percival			config_VerboseLevel $1 || usage
49748ffe56aSColin Percival			;;
49848ffe56aSColin Percival
49948ffe56aSColin Percival		# Aliases for "-v debug" and "-v nostats"
50048ffe56aSColin Percival		--debug)
50148ffe56aSColin Percival			config_VerboseLevel debug || usage
50248ffe56aSColin Percival			;;
50348ffe56aSColin Percival		--no-stats)
50448ffe56aSColin Percival			config_VerboseLevel nostats || usage
50548ffe56aSColin Percival			;;
50648ffe56aSColin Percival
50748ffe56aSColin Percival		# Commands
508*8cfda118SMichael Gmelin		cron | fetch | upgrade | updatesready | install | rollback |\
509*8cfda118SMichael Gmelin		IDS | showconfig)
51048ffe56aSColin Percival			COMMANDS="${COMMANDS} $1"
51148ffe56aSColin Percival			;;
51248ffe56aSColin Percival
51348ffe56aSColin Percival		# Anything else is an error
51448ffe56aSColin Percival		*)
51548ffe56aSColin Percival			usage
51648ffe56aSColin Percival			;;
51748ffe56aSColin Percival		esac
51848ffe56aSColin Percival		shift
51948ffe56aSColin Percival	done
52048ffe56aSColin Percival
52148ffe56aSColin Percival	# Make sure we have at least one command
52248ffe56aSColin Percival	if [ -z "${COMMANDS}" ]; then
52348ffe56aSColin Percival		usage
52448ffe56aSColin Percival	fi
52548ffe56aSColin Percival}
52648ffe56aSColin Percival
52748ffe56aSColin Percival# Parse the configuration file
52848ffe56aSColin Percivalparse_conffile () {
52948ffe56aSColin Percival	# If a configuration file was specified on the command line, check
53048ffe56aSColin Percival	# that it exists and is readable.
53148ffe56aSColin Percival	if [ ! -z "${CONFFILE}" ] && [ ! -r "${CONFFILE}" ]; then
53248ffe56aSColin Percival		echo -n "File does not exist "
53348ffe56aSColin Percival		echo -n "or is not readable: "
53448ffe56aSColin Percival		echo ${CONFFILE}
53548ffe56aSColin Percival		exit 1
53648ffe56aSColin Percival	fi
53748ffe56aSColin Percival
53848ffe56aSColin Percival	# If a configuration file was not specified on the command line,
53948ffe56aSColin Percival	# use the default configuration file path.  If that default does
54048ffe56aSColin Percival	# not exist, give up looking for any configuration.
54148ffe56aSColin Percival	if [ -z "${CONFFILE}" ]; then
54248ffe56aSColin Percival		CONFFILE="/etc/freebsd-update.conf"
54348ffe56aSColin Percival		if [ ! -r "${CONFFILE}" ]; then
54448ffe56aSColin Percival			return
54548ffe56aSColin Percival		fi
54648ffe56aSColin Percival	fi
54748ffe56aSColin Percival
54848ffe56aSColin Percival	# Save the configuration options specified on the command line, and
54948ffe56aSColin Percival	# clear all the options in preparation for reading the config file.
55048ffe56aSColin Percival	saveconfig
55148ffe56aSColin Percival	nullconfig
55248ffe56aSColin Percival
55348ffe56aSColin Percival	# Read the configuration file.  Anything after the first '#' is
55448ffe56aSColin Percival	# ignored, and any blank lines are ignored.
55548ffe56aSColin Percival	L=0
55648ffe56aSColin Percival	while read LINE; do
55748ffe56aSColin Percival		L=$(($L + 1))
55848ffe56aSColin Percival		LINEX=`echo "${LINE}" | cut -f 1 -d '#'`
55948ffe56aSColin Percival		if ! configline ${LINEX}; then
56048ffe56aSColin Percival			echo "Error processing configuration file, line $L:"
56148ffe56aSColin Percival			echo "==> ${LINE}"
56248ffe56aSColin Percival			exit 1
56348ffe56aSColin Percival		fi
56448ffe56aSColin Percival	done < ${CONFFILE}
56548ffe56aSColin Percival
56648ffe56aSColin Percival	# Merge the settings read from the configuration file with those
56748ffe56aSColin Percival	# provided at the command line.
56848ffe56aSColin Percival	mergeconfig
56948ffe56aSColin Percival}
57048ffe56aSColin Percival
57148ffe56aSColin Percival# Provide some default parameters
57248ffe56aSColin Percivaldefault_params () {
57348ffe56aSColin Percival	# Save any parameters already configured, and clear the slate
57448ffe56aSColin Percival	saveconfig
57548ffe56aSColin Percival	nullconfig
57648ffe56aSColin Percival
57748ffe56aSColin Percival	# Default configurations
57848ffe56aSColin Percival	config_WorkDir /var/db/freebsd-update
57948ffe56aSColin Percival	config_MailTo root
58048ffe56aSColin Percival	config_AllowAdd yes
58148ffe56aSColin Percival	config_AllowDelete yes
58248ffe56aSColin Percival	config_KeepModifiedMetadata yes
58348ffe56aSColin Percival	config_BaseDir /
58448ffe56aSColin Percival	config_VerboseLevel stats
585db6b0a61SColin Percival	config_StrictComponents no
58623d827efSSimon L. B. Nielsen	config_BackupKernel yes
58723d827efSSimon L. B. Nielsen	config_BackupKernelDir /boot/kernel.old
58823d827efSSimon L. B. Nielsen	config_BackupKernelSymbolFiles no
58948ffe56aSColin Percival
59048ffe56aSColin Percival	# Merge these defaults into the earlier-configured settings
59148ffe56aSColin Percival	mergeconfig
59248ffe56aSColin Percival}
59348ffe56aSColin Percival
59448ffe56aSColin Percival# Set utility output filtering options, based on ${VERBOSELEVEL}
59548ffe56aSColin Percivalfetch_setup_verboselevel () {
59648ffe56aSColin Percival	case ${VERBOSELEVEL} in
59748ffe56aSColin Percival	debug)
59848ffe56aSColin Percival		QUIETREDIR="/dev/stderr"
59948ffe56aSColin Percival		QUIETFLAG=" "
60048ffe56aSColin Percival		STATSREDIR="/dev/stderr"
60148ffe56aSColin Percival		DDSTATS=".."
60248ffe56aSColin Percival		XARGST="-t"
60348ffe56aSColin Percival		NDEBUG=" "
60448ffe56aSColin Percival		;;
60548ffe56aSColin Percival	nostats)
60648ffe56aSColin Percival		QUIETREDIR=""
60748ffe56aSColin Percival		QUIETFLAG=""
60848ffe56aSColin Percival		STATSREDIR="/dev/null"
60948ffe56aSColin Percival		DDSTATS=".."
61048ffe56aSColin Percival		XARGST=""
61148ffe56aSColin Percival		NDEBUG=""
61248ffe56aSColin Percival		;;
61348ffe56aSColin Percival	stats)
61448ffe56aSColin Percival		QUIETREDIR="/dev/null"
61548ffe56aSColin Percival		QUIETFLAG="-q"
61648ffe56aSColin Percival		STATSREDIR="/dev/stdout"
61748ffe56aSColin Percival		DDSTATS=""
61848ffe56aSColin Percival		XARGST=""
61948ffe56aSColin Percival		NDEBUG="-n"
62048ffe56aSColin Percival		;;
62148ffe56aSColin Percival	esac
62248ffe56aSColin Percival}
62348ffe56aSColin Percival
62448ffe56aSColin Percival# Perform sanity checks and set some final parameters
62548ffe56aSColin Percival# in preparation for fetching files.  Figure out which
62648ffe56aSColin Percival# set of updates should be downloaded: If the user is
62748ffe56aSColin Percival# running *-p[0-9]+, strip off the last part; if the
62848ffe56aSColin Percival# user is running -SECURITY, call it -RELEASE.  Chdir
62948ffe56aSColin Percival# into the working directory.
630211f2ba0SColin Percivalfetchupgrade_check_params () {
63148ffe56aSColin Percival	export HTTP_USER_AGENT="freebsd-update (${COMMAND}, `uname -r`)"
63248ffe56aSColin Percival
63348ffe56aSColin Percival	_SERVERNAME_z=\
63448ffe56aSColin Percival"SERVERNAME must be given via command line or configuration file."
63548ffe56aSColin Percival	_KEYPRINT_z="Key must be given via -k option or configuration file."
63648ffe56aSColin Percival	_KEYPRINT_bad="Invalid key fingerprint: "
63748ffe56aSColin Percival	_WORKDIR_bad="Directory does not exist or is not writable: "
638f88076f0SMark Felder	_WORKDIR_bad2="Directory is not on a persistent filesystem: "
63948ffe56aSColin Percival
64048ffe56aSColin Percival	if [ -z "${SERVERNAME}" ]; then
64148ffe56aSColin Percival		echo -n "`basename $0`: "
64248ffe56aSColin Percival		echo "${_SERVERNAME_z}"
64348ffe56aSColin Percival		exit 1
64448ffe56aSColin Percival	fi
64548ffe56aSColin Percival	if [ -z "${KEYPRINT}" ]; then
64648ffe56aSColin Percival		echo -n "`basename $0`: "
64748ffe56aSColin Percival		echo "${_KEYPRINT_z}"
64848ffe56aSColin Percival		exit 1
64948ffe56aSColin Percival	fi
65048ffe56aSColin Percival	if ! echo "${KEYPRINT}" | grep -qE "^[0-9a-f]{64}$"; then
65148ffe56aSColin Percival		echo -n "`basename $0`: "
65248ffe56aSColin Percival		echo -n "${_KEYPRINT_bad}"
65348ffe56aSColin Percival		echo ${KEYPRINT}
65448ffe56aSColin Percival		exit 1
65548ffe56aSColin Percival	fi
65648ffe56aSColin Percival	if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then
65748ffe56aSColin Percival		echo -n "`basename $0`: "
65848ffe56aSColin Percival		echo -n "${_WORKDIR_bad}"
65948ffe56aSColin Percival		echo ${WORKDIR}
66048ffe56aSColin Percival		exit 1
66148ffe56aSColin Percival	fi
662dfe9215bSMark Felder	case `df -T ${WORKDIR}` in */dev/md[0-9]* | *tmpfs*)
663f88076f0SMark Felder		echo -n "`basename $0`: "
664f88076f0SMark Felder		echo -n "${_WORKDIR_bad2}"
665f88076f0SMark Felder		echo ${WORKDIR}
666f88076f0SMark Felder		exit 1
667dfe9215bSMark Felder		;;
668dfe9215bSMark Felder	esac
669a2356430SColin Percival	chmod 700 ${WORKDIR}
67048ffe56aSColin Percival	cd ${WORKDIR} || exit 1
67148ffe56aSColin Percival
67248ffe56aSColin Percival	# Generate release number.  The s/SECURITY/RELEASE/ bit exists
67348ffe56aSColin Percival	# to provide an upgrade path for FreeBSD Update 1.x users, since
67448ffe56aSColin Percival	# the kernels provided by FreeBSD Update 1.x are always labelled
67548ffe56aSColin Percival	# as X.Y-SECURITY.
67648ffe56aSColin Percival	RELNUM=`uname -r |
67748ffe56aSColin Percival	    sed -E 's,-p[0-9]+,,' |
67848ffe56aSColin Percival	    sed -E 's,-SECURITY,-RELEASE,'`
67948ffe56aSColin Percival	ARCH=`uname -m`
68048ffe56aSColin Percival	FETCHDIR=${RELNUM}/${ARCH}
681db6b0a61SColin Percival	PATCHDIR=${RELNUM}/${ARCH}/bp
68248ffe56aSColin Percival
683d308a8bfSEd Maste	# Disallow upgrade from a version that is not a release
684d308a8bfSEd Maste	case ${RELNUM} in
685d308a8bfSEd Maste	*-RELEASE | *-ALPHA*  | *-BETA* | *-RC*)
686d308a8bfSEd Maste		;;
687d308a8bfSEd Maste	*)
6880d5c5243SEd Maste		echo -n "`basename $0`: "
6890d5c5243SEd Maste		cat <<- EOF
690d308a8bfSEd Maste			Cannot upgrade from a version that is not a release
691d308a8bfSEd Maste			(including alpha, beta and release candidates)
692d308a8bfSEd Maste			using `basename $0`. Instead, FreeBSD can be directly
693d308a8bfSEd Maste			upgraded by source or upgraded to a RELEASE/RELENG version
694d308a8bfSEd Maste			prior to running `basename $0`.
695d308a8bfSEd Maste			Currently running: ${RELNUM}
6960d5c5243SEd Maste		EOF
6970d5c5243SEd Maste		exit 1
698d308a8bfSEd Maste		;;
699d308a8bfSEd Maste	esac
7000d5c5243SEd Maste
70148ffe56aSColin Percival	# Figure out what directory contains the running kernel
70248ffe56aSColin Percival	BOOTFILE=`sysctl -n kern.bootfile`
70348ffe56aSColin Percival	KERNELDIR=${BOOTFILE%/kernel}
70448ffe56aSColin Percival	if ! [ -d ${KERNELDIR} ]; then
70548ffe56aSColin Percival		echo "Cannot identify running kernel"
70648ffe56aSColin Percival		exit 1
70748ffe56aSColin Percival	fi
70848ffe56aSColin Percival
7092c434b2cSColin Percival	# Figure out what kernel configuration is running.  We start with
7102c434b2cSColin Percival	# the output of `uname -i`, and then make the following adjustments:
7112c434b2cSColin Percival	# 1. Replace "SMP-GENERIC" with "SMP".  Why the SMP kernel config
7122c434b2cSColin Percival	# file says "ident SMP-GENERIC", I don't know...
7132c434b2cSColin Percival	# 2. If the kernel claims to be GENERIC _and_ ${ARCH} is "amd64"
7142c434b2cSColin Percival	# _and_ `sysctl kern.version` contains a line which ends "/SMP", then
7152c434b2cSColin Percival	# we're running an SMP kernel.  This mis-identification is a bug
7162c434b2cSColin Percival	# which was fixed in 6.2-STABLE.
7172c434b2cSColin Percival	KERNCONF=`uname -i`
7182c434b2cSColin Percival	if [ ${KERNCONF} = "SMP-GENERIC" ]; then
7192c434b2cSColin Percival		KERNCONF=SMP
7202c434b2cSColin Percival	fi
7212c434b2cSColin Percival	if [ ${KERNCONF} = "GENERIC" ] && [ ${ARCH} = "amd64" ]; then
7222c434b2cSColin Percival		if sysctl kern.version | grep -qE '/SMP$'; then
7232c434b2cSColin Percival			KERNCONF=SMP
7242c434b2cSColin Percival		fi
7252c434b2cSColin Percival	fi
7262c434b2cSColin Percival
72748ffe56aSColin Percival	# Define some paths
72848ffe56aSColin Percival	BSPATCH=/usr/bin/bspatch
72948ffe56aSColin Percival	SHA256=/sbin/sha256
73048ffe56aSColin Percival	PHTTPGET=/usr/libexec/phttpget
73148ffe56aSColin Percival
73248ffe56aSColin Percival	# Set up variables relating to VERBOSELEVEL
73348ffe56aSColin Percival	fetch_setup_verboselevel
73448ffe56aSColin Percival
73548ffe56aSColin Percival	# Construct a unique name from ${BASEDIR}
73648ffe56aSColin Percival	BDHASH=`echo ${BASEDIR} | sha256 -q`
73748ffe56aSColin Percival}
73848ffe56aSColin Percival
739211f2ba0SColin Percival# Perform sanity checks etc. before fetching updates.
740211f2ba0SColin Percivalfetch_check_params () {
741211f2ba0SColin Percival	fetchupgrade_check_params
742211f2ba0SColin Percival
743211f2ba0SColin Percival	if ! [ -z "${TARGETRELEASE}" ]; then
744211f2ba0SColin Percival		echo -n "`basename $0`: "
745211f2ba0SColin Percival		echo -n "-r option is meaningless with 'fetch' command.  "
746211f2ba0SColin Percival		echo "(Did you mean 'upgrade' instead?)"
747211f2ba0SColin Percival		exit 1
748211f2ba0SColin Percival	fi
7498935f242SAllan Jude
7508935f242SAllan Jude	# Check that we have updates ready to install
7518bf2dcceSAllan Jude	if [ -f ${BDHASH}-install/kerneldone -a $FORCEFETCH -eq 0 ]; then
7528935f242SAllan Jude		echo "You have a partially completed upgrade pending"
7538935f242SAllan Jude		echo "Run '$0 install' first."
7548935f242SAllan Jude		echo "Run '$0 fetch -F' to proceed anyway."
7558935f242SAllan Jude		exit 1
7568935f242SAllan Jude	fi
757211f2ba0SColin Percival}
758211f2ba0SColin Percival
759db6b0a61SColin Percival# Perform sanity checks etc. before fetching upgrades.
760db6b0a61SColin Percivalupgrade_check_params () {
761211f2ba0SColin Percival	fetchupgrade_check_params
762db6b0a61SColin Percival
763db6b0a61SColin Percival	# Unless set otherwise, we're upgrading to the same kernel config.
764db6b0a61SColin Percival	NKERNCONF=${KERNCONF}
765db6b0a61SColin Percival
766db6b0a61SColin Percival	# We need TARGETRELEASE set
767db6b0a61SColin Percival	_TARGETRELEASE_z="Release target must be specified via -r option."
768db6b0a61SColin Percival	if [ -z "${TARGETRELEASE}" ]; then
769db6b0a61SColin Percival		echo -n "`basename $0`: "
770db6b0a61SColin Percival		echo "${_TARGETRELEASE_z}"
771db6b0a61SColin Percival		exit 1
772db6b0a61SColin Percival	fi
773db6b0a61SColin Percival
774db6b0a61SColin Percival	# The target release should be != the current release.
775db6b0a61SColin Percival	if [ "${TARGETRELEASE}" = "${RELNUM}" ]; then
776db6b0a61SColin Percival		echo -n "`basename $0`: "
777db6b0a61SColin Percival		echo "Cannot upgrade from ${RELNUM} to itself"
778db6b0a61SColin Percival		exit 1
779db6b0a61SColin Percival	fi
780db6b0a61SColin Percival
781db6b0a61SColin Percival	# Turning off AllowAdd or AllowDelete is a bad idea for upgrades.
782db6b0a61SColin Percival	if [ "${ALLOWADD}" = "no" ]; then
783db6b0a61SColin Percival		echo -n "`basename $0`: "
784db6b0a61SColin Percival		echo -n "WARNING: \"AllowAdd no\" is a bad idea "
785db6b0a61SColin Percival		echo "when upgrading between releases."
786db6b0a61SColin Percival		echo
787db6b0a61SColin Percival	fi
788db6b0a61SColin Percival	if [ "${ALLOWDELETE}" = "no" ]; then
789db6b0a61SColin Percival		echo -n "`basename $0`: "
790db6b0a61SColin Percival		echo -n "WARNING: \"AllowDelete no\" is a bad idea "
791db6b0a61SColin Percival		echo "when upgrading between releases."
792db6b0a61SColin Percival		echo
793db6b0a61SColin Percival	fi
794db6b0a61SColin Percival
795db6b0a61SColin Percival	# Set EDITOR to /usr/bin/vi if it isn't already set
796db6b0a61SColin Percival	: ${EDITOR:='/usr/bin/vi'}
797db6b0a61SColin Percival}
798db6b0a61SColin Percival
79948ffe56aSColin Percival# Perform sanity checks and set some final parameters in
80048ffe56aSColin Percival# preparation for installing updates.
80148ffe56aSColin Percivalinstall_check_params () {
80248ffe56aSColin Percival	# Check that we are root.  All sorts of things won't work otherwise.
80348ffe56aSColin Percival	if [ `id -u` != 0 ]; then
80448ffe56aSColin Percival		echo "You must be root to run this."
80548ffe56aSColin Percival		exit 1
80648ffe56aSColin Percival	fi
80748ffe56aSColin Percival
8082328d598SColin Percival	# Check that securelevel <= 0.  Otherwise we can't update schg files.
8092328d598SColin Percival	if [ `sysctl -n kern.securelevel` -gt 0 ]; then
8102328d598SColin Percival		echo "Updates cannot be installed when the system securelevel"
8112328d598SColin Percival		echo "is greater than zero."
8122328d598SColin Percival		exit 1
8132328d598SColin Percival	fi
8142328d598SColin Percival
81548ffe56aSColin Percival	# Check that we have a working directory
81648ffe56aSColin Percival	_WORKDIR_bad="Directory does not exist or is not writable: "
81748ffe56aSColin Percival	if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then
81848ffe56aSColin Percival		echo -n "`basename $0`: "
81948ffe56aSColin Percival		echo -n "${_WORKDIR_bad}"
82048ffe56aSColin Percival		echo ${WORKDIR}
82148ffe56aSColin Percival		exit 1
82248ffe56aSColin Percival	fi
82348ffe56aSColin Percival	cd ${WORKDIR} || exit 1
82448ffe56aSColin Percival
82548ffe56aSColin Percival	# Construct a unique name from ${BASEDIR}
82648ffe56aSColin Percival	BDHASH=`echo ${BASEDIR} | sha256 -q`
82748ffe56aSColin Percival
82848ffe56aSColin Percival	# Check that we have updates ready to install
82948ffe56aSColin Percival	if ! [ -L ${BDHASH}-install ]; then
83048ffe56aSColin Percival		echo "No updates are available to install."
83133bd05c3SGuangyuan Yang		if [ $ISFETCHED -eq 0 ]; then
83248ffe56aSColin Percival			echo "Run '$0 fetch' first."
833*8cfda118SMichael Gmelin			exit 2
83433bd05c3SGuangyuan Yang		fi
83533bd05c3SGuangyuan Yang		exit 0
83648ffe56aSColin Percival	fi
83748ffe56aSColin Percival	if ! [ -f ${BDHASH}-install/INDEX-OLD ] ||
83848ffe56aSColin Percival	    ! [ -f ${BDHASH}-install/INDEX-NEW ]; then
83948ffe56aSColin Percival		echo "Update manifest is corrupt -- this should never happen."
84048ffe56aSColin Percival		echo "Re-run '$0 fetch'."
84148ffe56aSColin Percival		exit 1
84248ffe56aSColin Percival	fi
84323d827efSSimon L. B. Nielsen
84423d827efSSimon L. B. Nielsen	# Figure out what directory contains the running kernel
84523d827efSSimon L. B. Nielsen	BOOTFILE=`sysctl -n kern.bootfile`
84623d827efSSimon L. B. Nielsen	KERNELDIR=${BOOTFILE%/kernel}
84723d827efSSimon L. B. Nielsen	if ! [ -d ${KERNELDIR} ]; then
84823d827efSSimon L. B. Nielsen		echo "Cannot identify running kernel"
84923d827efSSimon L. B. Nielsen		exit 1
85023d827efSSimon L. B. Nielsen	fi
85148ffe56aSColin Percival}
85248ffe56aSColin Percival
85348ffe56aSColin Percival# Perform sanity checks and set some final parameters in
85448ffe56aSColin Percival# preparation for UNinstalling updates.
85548ffe56aSColin Percivalrollback_check_params () {
85648ffe56aSColin Percival	# Check that we are root.  All sorts of things won't work otherwise.
85748ffe56aSColin Percival	if [ `id -u` != 0 ]; then
85848ffe56aSColin Percival		echo "You must be root to run this."
85948ffe56aSColin Percival		exit 1
86048ffe56aSColin Percival	fi
86148ffe56aSColin Percival
86248ffe56aSColin Percival	# Check that we have a working directory
86348ffe56aSColin Percival	_WORKDIR_bad="Directory does not exist or is not writable: "
86448ffe56aSColin Percival	if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then
86548ffe56aSColin Percival		echo -n "`basename $0`: "
86648ffe56aSColin Percival		echo -n "${_WORKDIR_bad}"
86748ffe56aSColin Percival		echo ${WORKDIR}
86848ffe56aSColin Percival		exit 1
86948ffe56aSColin Percival	fi
87048ffe56aSColin Percival	cd ${WORKDIR} || exit 1
87148ffe56aSColin Percival
87248ffe56aSColin Percival	# Construct a unique name from ${BASEDIR}
87348ffe56aSColin Percival	BDHASH=`echo ${BASEDIR} | sha256 -q`
87448ffe56aSColin Percival
87548ffe56aSColin Percival	# Check that we have updates ready to rollback
87648ffe56aSColin Percival	if ! [ -L ${BDHASH}-rollback ]; then
87748ffe56aSColin Percival		echo "No rollback directory found."
87848ffe56aSColin Percival		exit 1
87948ffe56aSColin Percival	fi
88048ffe56aSColin Percival	if ! [ -f ${BDHASH}-rollback/INDEX-OLD ] ||
88148ffe56aSColin Percival	    ! [ -f ${BDHASH}-rollback/INDEX-NEW ]; then
88248ffe56aSColin Percival		echo "Update manifest is corrupt -- this should never happen."
88348ffe56aSColin Percival		exit 1
88448ffe56aSColin Percival	fi
88548ffe56aSColin Percival}
88648ffe56aSColin Percival
88708e23beeSColin Percival# Perform sanity checks and set some final parameters
88808e23beeSColin Percival# in preparation for comparing the system against the
88908e23beeSColin Percival# published index.  Figure out which index we should
89008e23beeSColin Percival# compare against: If the user is running *-p[0-9]+,
89108e23beeSColin Percival# strip off the last part; if the user is running
89208e23beeSColin Percival# -SECURITY, call it -RELEASE.  Chdir into the working
89308e23beeSColin Percival# directory.
89408e23beeSColin PercivalIDS_check_params () {
89508e23beeSColin Percival	export HTTP_USER_AGENT="freebsd-update (${COMMAND}, `uname -r`)"
89608e23beeSColin Percival
89708e23beeSColin Percival	_SERVERNAME_z=\
89808e23beeSColin Percival"SERVERNAME must be given via command line or configuration file."
89908e23beeSColin Percival	_KEYPRINT_z="Key must be given via -k option or configuration file."
90008e23beeSColin Percival	_KEYPRINT_bad="Invalid key fingerprint: "
90108e23beeSColin Percival	_WORKDIR_bad="Directory does not exist or is not writable: "
90208e23beeSColin Percival
90308e23beeSColin Percival	if [ -z "${SERVERNAME}" ]; then
90408e23beeSColin Percival		echo -n "`basename $0`: "
90508e23beeSColin Percival		echo "${_SERVERNAME_z}"
90608e23beeSColin Percival		exit 1
90708e23beeSColin Percival	fi
90808e23beeSColin Percival	if [ -z "${KEYPRINT}" ]; then
90908e23beeSColin Percival		echo -n "`basename $0`: "
91008e23beeSColin Percival		echo "${_KEYPRINT_z}"
91108e23beeSColin Percival		exit 1
91208e23beeSColin Percival	fi
91308e23beeSColin Percival	if ! echo "${KEYPRINT}" | grep -qE "^[0-9a-f]{64}$"; then
91408e23beeSColin Percival		echo -n "`basename $0`: "
91508e23beeSColin Percival		echo -n "${_KEYPRINT_bad}"
91608e23beeSColin Percival		echo ${KEYPRINT}
91708e23beeSColin Percival		exit 1
91808e23beeSColin Percival	fi
91908e23beeSColin Percival	if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then
92008e23beeSColin Percival		echo -n "`basename $0`: "
92108e23beeSColin Percival		echo -n "${_WORKDIR_bad}"
92208e23beeSColin Percival		echo ${WORKDIR}
92308e23beeSColin Percival		exit 1
92408e23beeSColin Percival	fi
92508e23beeSColin Percival	cd ${WORKDIR} || exit 1
92608e23beeSColin Percival
92708e23beeSColin Percival	# Generate release number.  The s/SECURITY/RELEASE/ bit exists
92808e23beeSColin Percival	# to provide an upgrade path for FreeBSD Update 1.x users, since
92908e23beeSColin Percival	# the kernels provided by FreeBSD Update 1.x are always labelled
93008e23beeSColin Percival	# as X.Y-SECURITY.
93108e23beeSColin Percival	RELNUM=`uname -r |
93208e23beeSColin Percival	    sed -E 's,-p[0-9]+,,' |
93308e23beeSColin Percival	    sed -E 's,-SECURITY,-RELEASE,'`
93408e23beeSColin Percival	ARCH=`uname -m`
93508e23beeSColin Percival	FETCHDIR=${RELNUM}/${ARCH}
93608e23beeSColin Percival	PATCHDIR=${RELNUM}/${ARCH}/bp
93708e23beeSColin Percival
93808e23beeSColin Percival	# Figure out what directory contains the running kernel
93908e23beeSColin Percival	BOOTFILE=`sysctl -n kern.bootfile`
94008e23beeSColin Percival	KERNELDIR=${BOOTFILE%/kernel}
94108e23beeSColin Percival	if ! [ -d ${KERNELDIR} ]; then
94208e23beeSColin Percival		echo "Cannot identify running kernel"
94308e23beeSColin Percival		exit 1
94408e23beeSColin Percival	fi
94508e23beeSColin Percival
94608e23beeSColin Percival	# Figure out what kernel configuration is running.  We start with
94708e23beeSColin Percival	# the output of `uname -i`, and then make the following adjustments:
94808e23beeSColin Percival	# 1. Replace "SMP-GENERIC" with "SMP".  Why the SMP kernel config
94908e23beeSColin Percival	# file says "ident SMP-GENERIC", I don't know...
95008e23beeSColin Percival	# 2. If the kernel claims to be GENERIC _and_ ${ARCH} is "amd64"
95108e23beeSColin Percival	# _and_ `sysctl kern.version` contains a line which ends "/SMP", then
95208e23beeSColin Percival	# we're running an SMP kernel.  This mis-identification is a bug
95308e23beeSColin Percival	# which was fixed in 6.2-STABLE.
95408e23beeSColin Percival	KERNCONF=`uname -i`
95508e23beeSColin Percival	if [ ${KERNCONF} = "SMP-GENERIC" ]; then
95608e23beeSColin Percival		KERNCONF=SMP
95708e23beeSColin Percival	fi
95808e23beeSColin Percival	if [ ${KERNCONF} = "GENERIC" ] && [ ${ARCH} = "amd64" ]; then
95908e23beeSColin Percival		if sysctl kern.version | grep -qE '/SMP$'; then
96008e23beeSColin Percival			KERNCONF=SMP
96108e23beeSColin Percival		fi
96208e23beeSColin Percival	fi
96308e23beeSColin Percival
96408e23beeSColin Percival	# Define some paths
96508e23beeSColin Percival	SHA256=/sbin/sha256
96608e23beeSColin Percival	PHTTPGET=/usr/libexec/phttpget
96708e23beeSColin Percival
96808e23beeSColin Percival	# Set up variables relating to VERBOSELEVEL
96908e23beeSColin Percival	fetch_setup_verboselevel
97008e23beeSColin Percival}
97108e23beeSColin Percival
97248ffe56aSColin Percival#### Core functionality -- the actual work gets done here
97348ffe56aSColin Percival
97448ffe56aSColin Percival# Use an SRV query to pick a server.  If the SRV query doesn't provide
97548ffe56aSColin Percival# a useful answer, use the server name specified by the user.
97648ffe56aSColin Percival# Put another way... look up _http._tcp.${SERVERNAME} and pick a server
97748ffe56aSColin Percival# from that; or if no servers are returned, use ${SERVERNAME}.
97848ffe56aSColin Percival# This allows a user to specify "portsnap.freebsd.org" (in which case
97948ffe56aSColin Percival# portsnap will select one of the mirrors) or "portsnap5.tld.freebsd.org"
98048ffe56aSColin Percival# (in which case portsnap will use that particular server, since there
98148ffe56aSColin Percival# won't be an SRV entry for that name).
98248ffe56aSColin Percival#
98348ffe56aSColin Percival# We ignore the Port field, since we are always going to use port 80.
98448ffe56aSColin Percival
98548ffe56aSColin Percival# Fetch the mirror list, but do not pick a mirror yet.  Returns 1 if
98648ffe56aSColin Percival# no mirrors are available for any reason.
98748ffe56aSColin Percivalfetch_pick_server_init () {
98848ffe56aSColin Percival	: > serverlist_tried
98948ffe56aSColin Percival
99048ffe56aSColin Percival# Check that host(1) exists (i.e., that the system wasn't built with the
99148ffe56aSColin Percival# WITHOUT_BIND set) and don't try to find a mirror if it doesn't exist.
99248ffe56aSColin Percival	if ! which -s host; then
99348ffe56aSColin Percival		: > serverlist_full
99448ffe56aSColin Percival		return 1
99548ffe56aSColin Percival	fi
99648ffe56aSColin Percival
99748ffe56aSColin Percival	echo -n "Looking up ${SERVERNAME} mirrors... "
99848ffe56aSColin Percival
99948ffe56aSColin Percival# Issue the SRV query and pull out the Priority, Weight, and Target fields.
100048ffe56aSColin Percival# BIND 9 prints "$name has SRV record ..." while BIND 8 prints
100148ffe56aSColin Percival# "$name server selection ..."; we allow either format.
100248ffe56aSColin Percival	MLIST="_http._tcp.${SERVERNAME}"
100348ffe56aSColin Percival	host -t srv "${MLIST}" |
1004e7fd266eSColin Percival	    sed -nE "s/${MLIST} (has SRV record|server selection) //Ip" |
100548ffe56aSColin Percival	    cut -f 1,2,4 -d ' ' |
100648ffe56aSColin Percival	    sed -e 's/\.$//' |
100748ffe56aSColin Percival	    sort > serverlist_full
100848ffe56aSColin Percival
100948ffe56aSColin Percival# If no records, give up -- we'll just use the server name we were given.
101048ffe56aSColin Percival	if [ `wc -l < serverlist_full` -eq 0 ]; then
101148ffe56aSColin Percival		echo "none found."
101248ffe56aSColin Percival		return 1
101348ffe56aSColin Percival	fi
101448ffe56aSColin Percival
101548ffe56aSColin Percival# Report how many mirrors we found.
101648ffe56aSColin Percival	echo `wc -l < serverlist_full` "mirrors found."
101748ffe56aSColin Percival
101848ffe56aSColin Percival# Generate a random seed for use in picking mirrors.  If HTTP_PROXY
101948ffe56aSColin Percival# is set, this will be used to generate the seed; otherwise, the seed
102048ffe56aSColin Percival# will be random.
102148ffe56aSColin Percival	if [ -n "${HTTP_PROXY}${http_proxy}" ]; then
102248ffe56aSColin Percival		RANDVALUE=`sha256 -qs "${HTTP_PROXY}${http_proxy}" |
102348ffe56aSColin Percival		    tr -d 'a-f' |
102448ffe56aSColin Percival		    cut -c 1-9`
102548ffe56aSColin Percival	else
102648ffe56aSColin Percival		RANDVALUE=`jot -r 1 0 999999999`
102748ffe56aSColin Percival	fi
102848ffe56aSColin Percival}
102948ffe56aSColin Percival
103048ffe56aSColin Percival# Pick a mirror.  Returns 1 if we have run out of mirrors to try.
103148ffe56aSColin Percivalfetch_pick_server () {
103248ffe56aSColin Percival# Generate a list of not-yet-tried mirrors
103348ffe56aSColin Percival	sort serverlist_tried |
103448ffe56aSColin Percival	    comm -23 serverlist_full - > serverlist
103548ffe56aSColin Percival
103648ffe56aSColin Percival# Have we run out of mirrors?
103748ffe56aSColin Percival	if [ `wc -l < serverlist` -eq 0 ]; then
10389e8c28fcSEd Maste		cat <<- EOF
10399e8c28fcSEd Maste			No mirrors remaining, giving up.
10409e8c28fcSEd Maste
10419e8c28fcSEd Maste			This may be because upgrading from this platform (${ARCH})
10429e8c28fcSEd Maste			or release (${RELNUM}) is unsupported by `basename $0`. Only
10439e8c28fcSEd Maste			platforms with Tier 1 support can be upgraded by `basename $0`.
10449e8c28fcSEd Maste			See https://www.freebsd.org/platforms/index.html for more info.
10459e8c28fcSEd Maste
10469e8c28fcSEd Maste			If unsupported, FreeBSD must be upgraded by source.
10479e8c28fcSEd Maste		EOF
104848ffe56aSColin Percival		return 1
104948ffe56aSColin Percival	fi
105048ffe56aSColin Percival
105148ffe56aSColin Percival# Find the highest priority level (lowest numeric value).
105248ffe56aSColin Percival	SRV_PRIORITY=`cut -f 1 -d ' ' serverlist | sort -n | head -1`
105348ffe56aSColin Percival
105448ffe56aSColin Percival# Add up the weights of the response lines at that priority level.
105548ffe56aSColin Percival	SRV_WSUM=0;
105648ffe56aSColin Percival	while read X; do
105748ffe56aSColin Percival		case "$X" in
105848ffe56aSColin Percival		${SRV_PRIORITY}\ *)
105948ffe56aSColin Percival			SRV_W=`echo $X | cut -f 2 -d ' '`
106048ffe56aSColin Percival			SRV_WSUM=$(($SRV_WSUM + $SRV_W))
106148ffe56aSColin Percival			;;
106248ffe56aSColin Percival		esac
106348ffe56aSColin Percival	done < serverlist
106448ffe56aSColin Percival
106548ffe56aSColin Percival# If all the weights are 0, pretend that they are all 1 instead.
106648ffe56aSColin Percival	if [ ${SRV_WSUM} -eq 0 ]; then
106748ffe56aSColin Percival		SRV_WSUM=`grep -E "^${SRV_PRIORITY} " serverlist | wc -l`
106848ffe56aSColin Percival		SRV_W_ADD=1
106948ffe56aSColin Percival	else
107048ffe56aSColin Percival		SRV_W_ADD=0
107148ffe56aSColin Percival	fi
107248ffe56aSColin Percival
107348ffe56aSColin Percival# Pick a value between 0 and the sum of the weights - 1
107448ffe56aSColin Percival	SRV_RND=`expr ${RANDVALUE} % ${SRV_WSUM}`
107548ffe56aSColin Percival
107648ffe56aSColin Percival# Read through the list of mirrors and set SERVERNAME.  Write the line
107748ffe56aSColin Percival# corresponding to the mirror we selected into serverlist_tried so that
107848ffe56aSColin Percival# we won't try it again.
107948ffe56aSColin Percival	while read X; do
108048ffe56aSColin Percival		case "$X" in
108148ffe56aSColin Percival		${SRV_PRIORITY}\ *)
108248ffe56aSColin Percival			SRV_W=`echo $X | cut -f 2 -d ' '`
108348ffe56aSColin Percival			SRV_W=$(($SRV_W + $SRV_W_ADD))
108448ffe56aSColin Percival			if [ $SRV_RND -lt $SRV_W ]; then
108548ffe56aSColin Percival				SERVERNAME=`echo $X | cut -f 3 -d ' '`
108648ffe56aSColin Percival				echo "$X" >> serverlist_tried
108748ffe56aSColin Percival				break
108848ffe56aSColin Percival			else
108948ffe56aSColin Percival				SRV_RND=$(($SRV_RND - $SRV_W))
109048ffe56aSColin Percival			fi
109148ffe56aSColin Percival			;;
109248ffe56aSColin Percival		esac
109348ffe56aSColin Percival	done < serverlist
109448ffe56aSColin Percival}
109548ffe56aSColin Percival
109648ffe56aSColin Percival# Take a list of ${oldhash}|${newhash} and output a list of needed patches,
109748ffe56aSColin Percival# i.e., those for which we have ${oldhash} and don't have ${newhash}.
109848ffe56aSColin Percivalfetch_make_patchlist () {
109948ffe56aSColin Percival	grep -vE "^([0-9a-f]{64})\|\1$" |
110048ffe56aSColin Percival	    tr '|' ' ' |
110148ffe56aSColin Percival		while read X Y; do
110248ffe56aSColin Percival			if [ -f "files/${Y}.gz" ] ||
110348ffe56aSColin Percival			    [ ! -f "files/${X}.gz" ]; then
110448ffe56aSColin Percival				continue
110548ffe56aSColin Percival			fi
110648ffe56aSColin Percival			echo "${X}|${Y}"
1107f6e21461SEd Maste		done | sort -u
110848ffe56aSColin Percival}
110948ffe56aSColin Percival
111048ffe56aSColin Percival# Print user-friendly progress statistics
111148ffe56aSColin Percivalfetch_progress () {
111248ffe56aSColin Percival	LNC=0
111348ffe56aSColin Percival	while read x; do
111448ffe56aSColin Percival		LNC=$(($LNC + 1))
111548ffe56aSColin Percival		if [ $(($LNC % 10)) = 0 ]; then
111648ffe56aSColin Percival			echo -n $LNC
111748ffe56aSColin Percival		elif [ $(($LNC % 2)) = 0 ]; then
111848ffe56aSColin Percival			echo -n .
111948ffe56aSColin Percival		fi
112048ffe56aSColin Percival	done
112148ffe56aSColin Percival	echo -n " "
112248ffe56aSColin Percival}
112348ffe56aSColin Percival
1124db6b0a61SColin Percival# Function for asking the user if everything is ok
1125db6b0a61SColin Percivalcontinuep () {
1126db6b0a61SColin Percival	while read -p "Does this look reasonable (y/n)? " CONTINUE; do
1127db6b0a61SColin Percival		case "${CONTINUE}" in
1128db6b0a61SColin Percival		y*)
1129db6b0a61SColin Percival			return 0
1130db6b0a61SColin Percival			;;
1131db6b0a61SColin Percival		n*)
1132db6b0a61SColin Percival			return 1
1133db6b0a61SColin Percival			;;
1134db6b0a61SColin Percival		esac
1135db6b0a61SColin Percival	done
1136db6b0a61SColin Percival}
1137db6b0a61SColin Percival
113848ffe56aSColin Percival# Initialize the working directory
113948ffe56aSColin Percivalworkdir_init () {
114048ffe56aSColin Percival	mkdir -p files
114148ffe56aSColin Percival	touch tINDEX.present
114248ffe56aSColin Percival}
114348ffe56aSColin Percival
114448ffe56aSColin Percival# Check that we have a public key with an appropriate hash, or
114548ffe56aSColin Percival# fetch the key if it doesn't exist.  Returns 1 if the key has
114648ffe56aSColin Percival# not yet been fetched.
114748ffe56aSColin Percivalfetch_key () {
114848ffe56aSColin Percival	if [ -r pub.ssl ] && [ `${SHA256} -q pub.ssl` = ${KEYPRINT} ]; then
114948ffe56aSColin Percival		return 0
115048ffe56aSColin Percival	fi
115148ffe56aSColin Percival
115248ffe56aSColin Percival	echo -n "Fetching public key from ${SERVERNAME}... "
115348ffe56aSColin Percival	rm -f pub.ssl
115448ffe56aSColin Percival	fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/pub.ssl \
115548ffe56aSColin Percival	    2>${QUIETREDIR} || true
115648ffe56aSColin Percival	if ! [ -r pub.ssl ]; then
115748ffe56aSColin Percival		echo "failed."
115848ffe56aSColin Percival		return 1
115948ffe56aSColin Percival	fi
116048ffe56aSColin Percival	if ! [ `${SHA256} -q pub.ssl` = ${KEYPRINT} ]; then
116148ffe56aSColin Percival		echo "key has incorrect hash."
116248ffe56aSColin Percival		rm -f pub.ssl
116348ffe56aSColin Percival		return 1
116448ffe56aSColin Percival	fi
116548ffe56aSColin Percival	echo "done."
116648ffe56aSColin Percival}
116748ffe56aSColin Percival
116848ffe56aSColin Percival# Fetch metadata signature, aka "tag".
116948ffe56aSColin Percivalfetch_tag () {
1170db6b0a61SColin Percival	echo -n "Fetching metadata signature "
1171db6b0a61SColin Percival	echo ${NDEBUG} "for ${RELNUM} from ${SERVERNAME}... "
117248ffe56aSColin Percival	rm -f latest.ssl
117348ffe56aSColin Percival	fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/latest.ssl	\
117448ffe56aSColin Percival	    2>${QUIETREDIR} || true
117548ffe56aSColin Percival	if ! [ -r latest.ssl ]; then
117648ffe56aSColin Percival		echo "failed."
117748ffe56aSColin Percival		return 1
117848ffe56aSColin Percival	fi
117948ffe56aSColin Percival
118048ffe56aSColin Percival	openssl rsautl -pubin -inkey pub.ssl -verify		\
118148ffe56aSColin Percival	    < latest.ssl > tag.new 2>${QUIETREDIR} || true
118248ffe56aSColin Percival	rm latest.ssl
118348ffe56aSColin Percival
118448ffe56aSColin Percival	if ! [ `wc -l < tag.new` = 1 ] ||
118548ffe56aSColin Percival	    ! grep -qE	\
118648ffe56aSColin Percival    "^freebsd-update\|${ARCH}\|${RELNUM}\|[0-9]+\|[0-9a-f]{64}\|[0-9]{10}" \
118748ffe56aSColin Percival		tag.new; then
118848ffe56aSColin Percival		echo "invalid signature."
118948ffe56aSColin Percival		return 1
119048ffe56aSColin Percival	fi
119148ffe56aSColin Percival
119248ffe56aSColin Percival	echo "done."
119348ffe56aSColin Percival
119448ffe56aSColin Percival	RELPATCHNUM=`cut -f 4 -d '|' < tag.new`
119548ffe56aSColin Percival	TINDEXHASH=`cut -f 5 -d '|' < tag.new`
119648ffe56aSColin Percival	EOLTIME=`cut -f 6 -d '|' < tag.new`
119748ffe56aSColin Percival}
119848ffe56aSColin Percival
119948ffe56aSColin Percival# Sanity-check the patch number in a tag, to make sure that we're not
120048ffe56aSColin Percival# going to "update" backwards and to prevent replay attacks.
120148ffe56aSColin Percivalfetch_tagsanity () {
120248ffe56aSColin Percival	# Check that we're not going to move from -pX to -pY with Y < X.
120348ffe56aSColin Percival	RELPX=`uname -r | sed -E 's,.*-,,'`
120448ffe56aSColin Percival	if echo ${RELPX} | grep -qE '^p[0-9]+$'; then
120548ffe56aSColin Percival		RELPX=`echo ${RELPX} | cut -c 2-`
120648ffe56aSColin Percival	else
120748ffe56aSColin Percival		RELPX=0
120848ffe56aSColin Percival	fi
120948ffe56aSColin Percival	if [ "${RELPATCHNUM}" -lt "${RELPX}" ]; then
121048ffe56aSColin Percival		echo
121148ffe56aSColin Percival		echo -n "Files on mirror (${RELNUM}-p${RELPATCHNUM})"
121248ffe56aSColin Percival		echo " appear older than what"
121348ffe56aSColin Percival		echo "we are currently running (`uname -r`)!"
121448ffe56aSColin Percival		echo "Cowardly refusing to proceed any further."
121548ffe56aSColin Percival		return 1
121648ffe56aSColin Percival	fi
121748ffe56aSColin Percival
121848ffe56aSColin Percival	# If "tag" exists and corresponds to ${RELNUM}, make sure that
121948ffe56aSColin Percival	# it contains a patch number <= RELPATCHNUM, in order to protect
122048ffe56aSColin Percival	# against rollback (replay) attacks.
122148ffe56aSColin Percival	if [ -f tag ] &&
122248ffe56aSColin Percival	    grep -qE	\
122348ffe56aSColin Percival    "^freebsd-update\|${ARCH}\|${RELNUM}\|[0-9]+\|[0-9a-f]{64}\|[0-9]{10}" \
122448ffe56aSColin Percival		tag; then
122548ffe56aSColin Percival		LASTRELPATCHNUM=`cut -f 4 -d '|' < tag`
122648ffe56aSColin Percival
122748ffe56aSColin Percival		if [ "${RELPATCHNUM}" -lt "${LASTRELPATCHNUM}" ]; then
122848ffe56aSColin Percival			echo
122948ffe56aSColin Percival			echo -n "Files on mirror (${RELNUM}-p${RELPATCHNUM})"
123048ffe56aSColin Percival			echo " are older than the"
123148ffe56aSColin Percival			echo -n "most recently seen updates"
123248ffe56aSColin Percival			echo " (${RELNUM}-p${LASTRELPATCHNUM})."
123348ffe56aSColin Percival			echo "Cowardly refusing to proceed any further."
123448ffe56aSColin Percival			return 1
123548ffe56aSColin Percival		fi
123648ffe56aSColin Percival	fi
123748ffe56aSColin Percival}
123848ffe56aSColin Percival
123948ffe56aSColin Percival# Fetch metadata index file
124048ffe56aSColin Percivalfetch_metadata_index () {
124148ffe56aSColin Percival	echo ${NDEBUG} "Fetching metadata index... "
124248ffe56aSColin Percival	rm -f ${TINDEXHASH}
124348ffe56aSColin Percival	fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/t/${TINDEXHASH}
124448ffe56aSColin Percival	    2>${QUIETREDIR}
124548ffe56aSColin Percival	if ! [ -f ${TINDEXHASH} ]; then
124648ffe56aSColin Percival		echo "failed."
124748ffe56aSColin Percival		return 1
124848ffe56aSColin Percival	fi
124948ffe56aSColin Percival	if [ `${SHA256} -q ${TINDEXHASH}` != ${TINDEXHASH} ]; then
125048ffe56aSColin Percival		echo "update metadata index corrupt."
125148ffe56aSColin Percival		return 1
125248ffe56aSColin Percival	fi
125348ffe56aSColin Percival	echo "done."
125448ffe56aSColin Percival}
125548ffe56aSColin Percival
125648ffe56aSColin Percival# Print an error message about signed metadata being bogus.
125748ffe56aSColin Percivalfetch_metadata_bogus () {
125848ffe56aSColin Percival	echo
125948ffe56aSColin Percival	echo "The update metadata$1 is correctly signed, but"
126048ffe56aSColin Percival	echo "failed an integrity check."
126148ffe56aSColin Percival	echo "Cowardly refusing to proceed any further."
126248ffe56aSColin Percival	return 1
126348ffe56aSColin Percival}
126448ffe56aSColin Percival
126548ffe56aSColin Percival# Construct tINDEX.new by merging the lines named in $1 from ${TINDEXHASH}
126648ffe56aSColin Percival# with the lines not named in $@ from tINDEX.present (if that file exists).
126748ffe56aSColin Percivalfetch_metadata_index_merge () {
126848ffe56aSColin Percival	for METAFILE in $@; do
126948ffe56aSColin Percival		if [ `grep -E "^${METAFILE}\|" ${TINDEXHASH} | wc -l`	\
127048ffe56aSColin Percival		    -ne 1 ]; then
127148ffe56aSColin Percival			fetch_metadata_bogus " index"
127248ffe56aSColin Percival			return 1
127348ffe56aSColin Percival		fi
127448ffe56aSColin Percival
127548ffe56aSColin Percival		grep -E "${METAFILE}\|" ${TINDEXHASH}
127648ffe56aSColin Percival	done |
127748ffe56aSColin Percival	    sort > tINDEX.wanted
127848ffe56aSColin Percival
127948ffe56aSColin Percival	if [ -f tINDEX.present ]; then
128048ffe56aSColin Percival		join -t '|' -v 2 tINDEX.wanted tINDEX.present |
128148ffe56aSColin Percival		    sort -m - tINDEX.wanted > tINDEX.new
128248ffe56aSColin Percival		rm tINDEX.wanted
128348ffe56aSColin Percival	else
128448ffe56aSColin Percival		mv tINDEX.wanted tINDEX.new
128548ffe56aSColin Percival	fi
128648ffe56aSColin Percival}
128748ffe56aSColin Percival
128848ffe56aSColin Percival# Sanity check all the lines of tINDEX.new.  Even if more metadata lines
128948ffe56aSColin Percival# are added by future versions of the server, this won't cause problems,
129048ffe56aSColin Percival# since the only lines which appear in tINDEX.new are the ones which we
129148ffe56aSColin Percival# specifically grepped out of ${TINDEXHASH}.
129248ffe56aSColin Percivalfetch_metadata_index_sanity () {
129348ffe56aSColin Percival	if grep -qvE '^[0-9A-Z.-]+\|[0-9a-f]{64}$' tINDEX.new; then
129448ffe56aSColin Percival		fetch_metadata_bogus " index"
129548ffe56aSColin Percival		return 1
129648ffe56aSColin Percival	fi
129748ffe56aSColin Percival}
129848ffe56aSColin Percival
129948ffe56aSColin Percival# Sanity check the metadata file $1.
130048ffe56aSColin Percivalfetch_metadata_sanity () {
130148ffe56aSColin Percival	# Some aliases to save space later: ${P} is a character which can
130248ffe56aSColin Percival	# appear in a path; ${M} is the four numeric metadata fields; and
130348ffe56aSColin Percival	# ${H} is a sha256 hash.
13047c06c7c5SKris Moore	P="[-+./:=,%@_[~[:alnum:]]"
130548ffe56aSColin Percival	M="[0-9]+\|[0-9]+\|[0-9]+\|[0-9]+"
130648ffe56aSColin Percival	H="[0-9a-f]{64}"
130748ffe56aSColin Percival
130848ffe56aSColin Percival	# Check that the first four fields make sense.
130948ffe56aSColin Percival	if gunzip -c < files/$1.gz |
1310823c0d5fSXin LI	    grep -qvE "^[a-z]+\|[0-9a-z-]+\|${P}+\|[fdL-]\|"; then
131148ffe56aSColin Percival		fetch_metadata_bogus ""
131248ffe56aSColin Percival		return 1
131348ffe56aSColin Percival	fi
131448ffe56aSColin Percival
131548ffe56aSColin Percival	# Remove the first three fields.
131648ffe56aSColin Percival	gunzip -c < files/$1.gz |
131748ffe56aSColin Percival	    cut -f 4- -d '|' > sanitycheck.tmp
131848ffe56aSColin Percival
131948ffe56aSColin Percival	# Sanity check entries with type 'f'
132048ffe56aSColin Percival	if grep -E '^f' sanitycheck.tmp |
132148ffe56aSColin Percival	    grep -qvE "^f\|${M}\|${H}\|${P}*\$"; then
132248ffe56aSColin Percival		fetch_metadata_bogus ""
132348ffe56aSColin Percival		return 1
132448ffe56aSColin Percival	fi
132548ffe56aSColin Percival
132648ffe56aSColin Percival	# Sanity check entries with type 'd'
132748ffe56aSColin Percival	if grep -E '^d' sanitycheck.tmp |
132848ffe56aSColin Percival	    grep -qvE "^d\|${M}\|\|\$"; then
132948ffe56aSColin Percival		fetch_metadata_bogus ""
133048ffe56aSColin Percival		return 1
133148ffe56aSColin Percival	fi
133248ffe56aSColin Percival
133348ffe56aSColin Percival	# Sanity check entries with type 'L'
133448ffe56aSColin Percival	if grep -E '^L' sanitycheck.tmp |
133548ffe56aSColin Percival	    grep -qvE "^L\|${M}\|${P}*\|\$"; then
133648ffe56aSColin Percival		fetch_metadata_bogus ""
133748ffe56aSColin Percival		return 1
133848ffe56aSColin Percival	fi
133948ffe56aSColin Percival
134048ffe56aSColin Percival	# Sanity check entries with type '-'
134148ffe56aSColin Percival	if grep -E '^-' sanitycheck.tmp |
134248ffe56aSColin Percival	    grep -qvE "^-\|\|\|\|\|\|"; then
134348ffe56aSColin Percival		fetch_metadata_bogus ""
134448ffe56aSColin Percival		return 1
134548ffe56aSColin Percival	fi
134648ffe56aSColin Percival
134748ffe56aSColin Percival	# Clean up
134848ffe56aSColin Percival	rm sanitycheck.tmp
134948ffe56aSColin Percival}
135048ffe56aSColin Percival
135148ffe56aSColin Percival# Fetch the metadata index and metadata files listed in $@,
135248ffe56aSColin Percival# taking advantage of metadata patches where possible.
135348ffe56aSColin Percivalfetch_metadata () {
135448ffe56aSColin Percival	fetch_metadata_index || return 1
135548ffe56aSColin Percival	fetch_metadata_index_merge $@ || return 1
135648ffe56aSColin Percival	fetch_metadata_index_sanity || return 1
135748ffe56aSColin Percival
135848ffe56aSColin Percival	# Generate a list of wanted metadata patches
135948ffe56aSColin Percival	join -t '|' -o 1.2,2.2 tINDEX.present tINDEX.new |
136048ffe56aSColin Percival	    fetch_make_patchlist > patchlist
136148ffe56aSColin Percival
136248ffe56aSColin Percival	if [ -s patchlist ]; then
136348ffe56aSColin Percival		# Attempt to fetch metadata patches
136448ffe56aSColin Percival		echo -n "Fetching `wc -l < patchlist | tr -d ' '` "
136548ffe56aSColin Percival		echo ${NDEBUG} "metadata patches.${DDSTATS}"
136648ffe56aSColin Percival		tr '|' '-' < patchlist |
136748ffe56aSColin Percival		    lam -s "${FETCHDIR}/tp/" - -s ".gz" |
136848ffe56aSColin Percival		    xargs ${XARGST} ${PHTTPGET} ${SERVERNAME}	\
136948ffe56aSColin Percival			2>${STATSREDIR} | fetch_progress
137048ffe56aSColin Percival		echo "done."
137148ffe56aSColin Percival
137248ffe56aSColin Percival		# Attempt to apply metadata patches
137348ffe56aSColin Percival		echo -n "Applying metadata patches... "
137448ffe56aSColin Percival		tr '|' ' ' < patchlist |
137548ffe56aSColin Percival		    while read X Y; do
137648ffe56aSColin Percival			if [ ! -f "${X}-${Y}.gz" ]; then continue; fi
137748ffe56aSColin Percival			gunzip -c < ${X}-${Y}.gz > diff
137848ffe56aSColin Percival			gunzip -c < files/${X}.gz > diff-OLD
137948ffe56aSColin Percival
138048ffe56aSColin Percival			# Figure out which lines are being added and removed
138148ffe56aSColin Percival			grep -E '^-' diff |
138248ffe56aSColin Percival			    cut -c 2- |
138348ffe56aSColin Percival			    while read PREFIX; do
138448ffe56aSColin Percival				look "${PREFIX}" diff-OLD
138548ffe56aSColin Percival			    done |
138648ffe56aSColin Percival			    sort > diff-rm
138748ffe56aSColin Percival			grep -E '^\+' diff |
138848ffe56aSColin Percival			    cut -c 2- > diff-add
138948ffe56aSColin Percival
139048ffe56aSColin Percival			# Generate the new file
139148ffe56aSColin Percival			comm -23 diff-OLD diff-rm |
139248ffe56aSColin Percival			    sort - diff-add > diff-NEW
139348ffe56aSColin Percival
139448ffe56aSColin Percival			if [ `${SHA256} -q diff-NEW` = ${Y} ]; then
139548ffe56aSColin Percival				mv diff-NEW files/${Y}
139648ffe56aSColin Percival				gzip -n files/${Y}
139748ffe56aSColin Percival			else
139848ffe56aSColin Percival				mv diff-NEW ${Y}.bad
139948ffe56aSColin Percival			fi
140048ffe56aSColin Percival			rm -f ${X}-${Y}.gz diff
140148ffe56aSColin Percival			rm -f diff-OLD diff-NEW diff-add diff-rm
140248ffe56aSColin Percival		done 2>${QUIETREDIR}
140348ffe56aSColin Percival		echo "done."
140448ffe56aSColin Percival	fi
140548ffe56aSColin Percival
140648ffe56aSColin Percival	# Update metadata without patches
140748ffe56aSColin Percival	cut -f 2 -d '|' < tINDEX.new |
140848ffe56aSColin Percival	    while read Y; do
140948ffe56aSColin Percival		if [ ! -f "files/${Y}.gz" ]; then
141048ffe56aSColin Percival			echo ${Y};
141148ffe56aSColin Percival		fi
1412bce02f98SColin Percival	    done |
1413bce02f98SColin Percival	    sort -u > filelist
141448ffe56aSColin Percival
141548ffe56aSColin Percival	if [ -s filelist ]; then
141648ffe56aSColin Percival		echo -n "Fetching `wc -l < filelist | tr -d ' '` "
141748ffe56aSColin Percival		echo ${NDEBUG} "metadata files... "
141848ffe56aSColin Percival		lam -s "${FETCHDIR}/m/" - -s ".gz" < filelist |
141948ffe56aSColin Percival		    xargs ${XARGST} ${PHTTPGET} ${SERVERNAME}	\
142048ffe56aSColin Percival		    2>${QUIETREDIR}
142148ffe56aSColin Percival
142248ffe56aSColin Percival		while read Y; do
142348ffe56aSColin Percival			if ! [ -f ${Y}.gz ]; then
142448ffe56aSColin Percival				echo "failed."
142548ffe56aSColin Percival				return 1
142648ffe56aSColin Percival			fi
142748ffe56aSColin Percival			if [ `gunzip -c < ${Y}.gz |
142848ffe56aSColin Percival			    ${SHA256} -q` = ${Y} ]; then
142948ffe56aSColin Percival				mv ${Y}.gz files/${Y}.gz
143048ffe56aSColin Percival			else
143148ffe56aSColin Percival				echo "metadata is corrupt."
143248ffe56aSColin Percival				return 1
143348ffe56aSColin Percival			fi
143448ffe56aSColin Percival		done < filelist
143548ffe56aSColin Percival		echo "done."
143648ffe56aSColin Percival	fi
143748ffe56aSColin Percival
143848ffe56aSColin Percival# Sanity-check the metadata files.
143948ffe56aSColin Percival	cut -f 2 -d '|' tINDEX.new > filelist
144048ffe56aSColin Percival	while read X; do
144148ffe56aSColin Percival		fetch_metadata_sanity ${X} || return 1
144248ffe56aSColin Percival	done < filelist
144348ffe56aSColin Percival
144448ffe56aSColin Percival# Remove files which are no longer needed
144548ffe56aSColin Percival	cut -f 2 -d '|' tINDEX.present |
144648ffe56aSColin Percival	    sort > oldfiles
144748ffe56aSColin Percival	cut -f 2 -d '|' tINDEX.new |
144848ffe56aSColin Percival	    sort |
144948ffe56aSColin Percival	    comm -13 - oldfiles |
145048ffe56aSColin Percival	    lam -s "files/" - -s ".gz" |
145148ffe56aSColin Percival	    xargs rm -f
145248ffe56aSColin Percival	rm patchlist filelist oldfiles
145348ffe56aSColin Percival	rm ${TINDEXHASH}
145448ffe56aSColin Percival
145548ffe56aSColin Percival# We're done!
145648ffe56aSColin Percival	mv tINDEX.new tINDEX.present
145748ffe56aSColin Percival	mv tag.new tag
145848ffe56aSColin Percival
145948ffe56aSColin Percival	return 0
146048ffe56aSColin Percival}
146148ffe56aSColin Percival
1462db6b0a61SColin Percival# Extract a subset of a downloaded metadata file containing only the parts
1463db6b0a61SColin Percival# which are listed in COMPONENTS.
1464db6b0a61SColin Percivalfetch_filter_metadata_components () {
1465db6b0a61SColin Percival	METAHASH=`look "$1|" tINDEX.present | cut -f 2 -d '|'`
1466db6b0a61SColin Percival	gunzip -c < files/${METAHASH}.gz > $1.all
1467db6b0a61SColin Percival
1468db6b0a61SColin Percival	# Fish out the lines belonging to components we care about.
1469db6b0a61SColin Percival	for C in ${COMPONENTS}; do
1470db6b0a61SColin Percival		look "`echo ${C} | tr '/' '|'`|" $1.all
1471db6b0a61SColin Percival	done > $1
1472db6b0a61SColin Percival
1473db6b0a61SColin Percival	# Remove temporary file.
1474db6b0a61SColin Percival	rm $1.all
1475db6b0a61SColin Percival}
1476db6b0a61SColin Percival
1477b698a3abSColin Percival# Generate a filtered version of the metadata file $1 from the downloaded
147848ffe56aSColin Percival# file, by fishing out the lines corresponding to components we're trying
147948ffe56aSColin Percival# to keep updated, and then removing lines corresponding to paths we want
148048ffe56aSColin Percival# to ignore.
148148ffe56aSColin Percivalfetch_filter_metadata () {
148248ffe56aSColin Percival	# Fish out the lines belonging to components we care about.
1483db6b0a61SColin Percival	fetch_filter_metadata_components $1
1484db6b0a61SColin Percival
148548ffe56aSColin Percival	# Canonicalize directory names by removing any trailing / in
148648ffe56aSColin Percival	# order to avoid listing directories multiple times if they
148748ffe56aSColin Percival	# belong to multiple components.  Turning "/" into "" doesn't
148848ffe56aSColin Percival	# matter, since we add a leading "/" when we use paths later.
1489db6b0a61SColin Percival	cut -f 3- -d '|' $1 |
149048ffe56aSColin Percival	    sed -e 's,/|d|,|d|,' |
14917e654612SColin Percival	    sed -e 's,/|-|,|-|,' |
149248ffe56aSColin Percival	    sort -u > $1.tmp
149348ffe56aSColin Percival
149448ffe56aSColin Percival	# Figure out which lines to ignore and remove them.
149548ffe56aSColin Percival	for X in ${IGNOREPATHS}; do
149648ffe56aSColin Percival		grep -E "^${X}" $1.tmp
149748ffe56aSColin Percival	done |
149848ffe56aSColin Percival	    sort -u |
149948ffe56aSColin Percival	    comm -13 - $1.tmp > $1
150048ffe56aSColin Percival
150148ffe56aSColin Percival	# Remove temporary files.
1502db6b0a61SColin Percival	rm $1.tmp
150348ffe56aSColin Percival}
150448ffe56aSColin Percival
1505db6b0a61SColin Percival# Filter the metadata file $1 by adding lines with "/boot/$2"
1506bce02f98SColin Percival# replaced by ${KERNELDIR} (which is `sysctl -n kern.bootfile` minus the
1507db6b0a61SColin Percival# trailing "/kernel"); and if "/boot/$2" does not exist, remove
1508bce02f98SColin Percival# the original lines which start with that.
1509bce02f98SColin Percival# Put another way: Deal with the fact that the FOO kernel is sometimes
1510bce02f98SColin Percival# installed in /boot/FOO/ and is sometimes installed elsewhere.
151148ffe56aSColin Percivalfetch_filter_kernel_names () {
1512db6b0a61SColin Percival	grep ^/boot/$2 $1 |
1513db6b0a61SColin Percival	    sed -e "s,/boot/$2,${KERNELDIR},g" |
151448ffe56aSColin Percival	    sort - $1 > $1.tmp
151548ffe56aSColin Percival	mv $1.tmp $1
1516bce02f98SColin Percival
1517db6b0a61SColin Percival	if ! [ -d /boot/$2 ]; then
1518db6b0a61SColin Percival		grep -v ^/boot/$2 $1 > $1.tmp
1519bce02f98SColin Percival		mv $1.tmp $1
1520bce02f98SColin Percival	fi
152148ffe56aSColin Percival}
152248ffe56aSColin Percival
152348ffe56aSColin Percival# For all paths appearing in $1 or $3, inspect the system
152448ffe56aSColin Percival# and generate $2 describing what is currently installed.
152548ffe56aSColin Percivalfetch_inspect_system () {
152648ffe56aSColin Percival	# No errors yet...
152748ffe56aSColin Percival	rm -f .err
152848ffe56aSColin Percival
152948ffe56aSColin Percival	# Tell the user why his disk is suddenly making lots of noise
153048ffe56aSColin Percival	echo -n "Inspecting system... "
153148ffe56aSColin Percival
153248ffe56aSColin Percival	# Generate list of files to inspect
153348ffe56aSColin Percival	cat $1 $3 |
153448ffe56aSColin Percival	    cut -f 1 -d '|' |
153548ffe56aSColin Percival	    sort -u > filelist
153648ffe56aSColin Percival
153748ffe56aSColin Percival	# Examine each file and output lines of the form
153848ffe56aSColin Percival	# /path/to/file|type|device-inum|user|group|perm|flags|value
153948ffe56aSColin Percival	# sorted by device and inode number.
154048ffe56aSColin Percival	while read F; do
154148ffe56aSColin Percival		# If the symlink/file/directory does not exist, record this.
154248ffe56aSColin Percival		if ! [ -e ${BASEDIR}/${F} ]; then
154348ffe56aSColin Percival			echo "${F}|-||||||"
154448ffe56aSColin Percival			continue
154548ffe56aSColin Percival		fi
154648ffe56aSColin Percival		if ! [ -r ${BASEDIR}/${F} ]; then
154748ffe56aSColin Percival			echo "Cannot read file: ${BASEDIR}/${F}"	\
154848ffe56aSColin Percival			    >/dev/stderr
154948ffe56aSColin Percival			touch .err
155048ffe56aSColin Percival			return 1
155148ffe56aSColin Percival		fi
155248ffe56aSColin Percival
155348ffe56aSColin Percival		# Otherwise, output an index line.
155448ffe56aSColin Percival		if [ -L ${BASEDIR}/${F} ]; then
155548ffe56aSColin Percival			echo -n "${F}|L|"
155648ffe56aSColin Percival			stat -n -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F};
155748ffe56aSColin Percival			readlink ${BASEDIR}/${F};
155848ffe56aSColin Percival		elif [ -f ${BASEDIR}/${F} ]; then
155948ffe56aSColin Percival			echo -n "${F}|f|"
156048ffe56aSColin Percival			stat -n -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F};
156148ffe56aSColin Percival			sha256 -q ${BASEDIR}/${F};
156248ffe56aSColin Percival		elif [ -d ${BASEDIR}/${F} ]; then
156348ffe56aSColin Percival			echo -n "${F}|d|"
156448ffe56aSColin Percival			stat -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F};
156548ffe56aSColin Percival		else
156648ffe56aSColin Percival			echo "Unknown file type: ${BASEDIR}/${F}"	\
156748ffe56aSColin Percival			    >/dev/stderr
156848ffe56aSColin Percival			touch .err
156948ffe56aSColin Percival			return 1
157048ffe56aSColin Percival		fi
157148ffe56aSColin Percival	done < filelist |
157248ffe56aSColin Percival	    sort -k 3,3 -t '|' > $2.tmp
157348ffe56aSColin Percival	rm filelist
157448ffe56aSColin Percival
15756dcc68c8SBenedict Reuschling	# Check if an error occurred during system inspection
157648ffe56aSColin Percival	if [ -f .err ]; then
157748ffe56aSColin Percival		return 1
157848ffe56aSColin Percival	fi
157948ffe56aSColin Percival
158048ffe56aSColin Percival	# Convert to the form
158148ffe56aSColin Percival	# /path/to/file|type|user|group|perm|flags|value|hlink
158248ffe56aSColin Percival	# by resolving identical device and inode numbers into hard links.
158348ffe56aSColin Percival	cut -f 1,3 -d '|' $2.tmp |
158448ffe56aSColin Percival	    sort -k 1,1 -t '|' |
158548ffe56aSColin Percival	    sort -s -u -k 2,2 -t '|' |
158648ffe56aSColin Percival	    join -1 2 -2 3 -t '|' - $2.tmp |
158748ffe56aSColin Percival	    awk -F \| -v OFS=\|		\
158848ffe56aSColin Percival		'{
158948ffe56aSColin Percival		    if (($2 == $3) || ($4 == "-"))
159048ffe56aSColin Percival			print $3,$4,$5,$6,$7,$8,$9,""
159148ffe56aSColin Percival		    else
159248ffe56aSColin Percival			print $3,$4,$5,$6,$7,$8,$9,$2
159348ffe56aSColin Percival		}' |
159448ffe56aSColin Percival	    sort > $2
159548ffe56aSColin Percival	rm $2.tmp
159648ffe56aSColin Percival
159748ffe56aSColin Percival	# We're finished looking around
159848ffe56aSColin Percival	echo "done."
159948ffe56aSColin Percival}
160048ffe56aSColin Percival
1601db6b0a61SColin Percival# For any paths matching ${MERGECHANGES}, compare $1 and $2 and find any
1602db6b0a61SColin Percival# files which differ; generate $3 containing these paths and the old hashes.
1603db6b0a61SColin Percivalfetch_filter_mergechanges () {
1604db6b0a61SColin Percival	# Pull out the paths and hashes of the files matching ${MERGECHANGES}.
1605db6b0a61SColin Percival	for F in $1 $2; do
1606db6b0a61SColin Percival		for X in ${MERGECHANGES}; do
1607db6b0a61SColin Percival			grep -E "^${X}" ${F}
1608db6b0a61SColin Percival		done |
1609db6b0a61SColin Percival		    cut -f 1,2,7 -d '|' |
1610db6b0a61SColin Percival		    sort > ${F}-values
1611db6b0a61SColin Percival	done
1612db6b0a61SColin Percival
1613db6b0a61SColin Percival	# Any line in $2-values which doesn't appear in $1-values and is a
1614db6b0a61SColin Percival	# file means that we should list the path in $3.
1615db6b0a61SColin Percival	comm -13 $1-values $2-values |
1616db6b0a61SColin Percival	    fgrep '|f|' |
1617db6b0a61SColin Percival	    cut -f 1 -d '|' > $2-paths
1618db6b0a61SColin Percival
1619db6b0a61SColin Percival	# For each path, pull out one (and only one!) entry from $1-values.
1620db6b0a61SColin Percival	# Note that we cannot distinguish which "old" version the user made
1621db6b0a61SColin Percival	# changes to; but hopefully any changes which occur due to security
1622db6b0a61SColin Percival	# updates will exist in both the "new" version and the version which
1623db6b0a61SColin Percival	# the user has installed, so the merging will still work.
1624db6b0a61SColin Percival	while read X; do
1625db6b0a61SColin Percival		look "${X}|" $1-values |
1626db6b0a61SColin Percival		    head -1
1627db6b0a61SColin Percival	done < $2-paths > $3
1628db6b0a61SColin Percival
1629db6b0a61SColin Percival	# Clean up
1630db6b0a61SColin Percival	rm $1-values $2-values $2-paths
1631db6b0a61SColin Percival}
1632db6b0a61SColin Percival
163348ffe56aSColin Percival# For any paths matching ${UPDATEIFUNMODIFIED}, remove lines from $[123]
1634db6b0a61SColin Percival# which correspond to lines in $2 with hashes not matching $1 or $3, unless
1635db6b0a61SColin Percival# the paths are listed in $4.  For entries in $2 marked "not present"
1636db6b0a61SColin Percival# (aka. type -), remove lines from $[123] unless there is a corresponding
1637db6b0a61SColin Percival# entry in $1.
163848ffe56aSColin Percivalfetch_filter_unmodified_notpresent () {
163948ffe56aSColin Percival	# Figure out which lines of $1 and $3 correspond to bits which
164048ffe56aSColin Percival	# should only be updated if they haven't changed, and fish out
164148ffe56aSColin Percival	# the (path, type, value) tuples.
164248ffe56aSColin Percival	# NOTE: We don't consider a file to be "modified" if it matches
164348ffe56aSColin Percival	# the hash from $3.
164448ffe56aSColin Percival	for X in ${UPDATEIFUNMODIFIED}; do
164548ffe56aSColin Percival		grep -E "^${X}" $1
164648ffe56aSColin Percival		grep -E "^${X}" $3
164748ffe56aSColin Percival	done |
164848ffe56aSColin Percival	    cut -f 1,2,7 -d '|' |
164948ffe56aSColin Percival	    sort > $1-values
165048ffe56aSColin Percival
165148ffe56aSColin Percival	# Do the same for $2.
165248ffe56aSColin Percival	for X in ${UPDATEIFUNMODIFIED}; do
165348ffe56aSColin Percival		grep -E "^${X}" $2
165448ffe56aSColin Percival	done |
165548ffe56aSColin Percival	    cut -f 1,2,7 -d '|' |
165648ffe56aSColin Percival	    sort > $2-values
165748ffe56aSColin Percival
165848ffe56aSColin Percival	# Any entry in $2-values which is not in $1-values corresponds to
1659db6b0a61SColin Percival	# a path which we need to remove from $1, $2, and $3, unless it
1660db6b0a61SColin Percival	# that path appears in $4.
1661db6b0a61SColin Percival	comm -13 $1-values $2-values |
1662db6b0a61SColin Percival	    sort -t '|' -k 1,1 > mlines.tmp
1663db6b0a61SColin Percival	cut -f 1 -d '|' $4 |
1664db6b0a61SColin Percival	    sort |
1665db6b0a61SColin Percival	    join -v 2 -t '|' - mlines.tmp |
1666db6b0a61SColin Percival	    sort > mlines
1667db6b0a61SColin Percival	rm $1-values $2-values mlines.tmp
166848ffe56aSColin Percival
166948ffe56aSColin Percival	# Any lines in $2 which are not in $1 AND are "not present" lines
167048ffe56aSColin Percival	# also belong in mlines.
167148ffe56aSColin Percival	comm -13 $1 $2 |
167248ffe56aSColin Percival	    cut -f 1,2,7 -d '|' |
167348ffe56aSColin Percival	    fgrep '|-|' >> mlines
167448ffe56aSColin Percival
167548ffe56aSColin Percival	# Remove lines from $1, $2, and $3
167648ffe56aSColin Percival	for X in $1 $2 $3; do
167748ffe56aSColin Percival		sort -t '|' -k 1,1 ${X} > ${X}.tmp
167848ffe56aSColin Percival		cut -f 1 -d '|' < mlines |
167948ffe56aSColin Percival		    sort |
168048ffe56aSColin Percival		    join -v 2 -t '|' - ${X}.tmp |
168148ffe56aSColin Percival		    sort > ${X}
168248ffe56aSColin Percival		rm ${X}.tmp
168348ffe56aSColin Percival	done
168448ffe56aSColin Percival
168548ffe56aSColin Percival	# Store a list of the modified files, for future reference
168648ffe56aSColin Percival	fgrep -v '|-|' mlines |
168748ffe56aSColin Percival	    cut -f 1 -d '|' > modifiedfiles
168848ffe56aSColin Percival	rm mlines
168948ffe56aSColin Percival}
169048ffe56aSColin Percival
169148ffe56aSColin Percival# For each entry in $1 of type -, remove any corresponding
169248ffe56aSColin Percival# entry from $2 if ${ALLOWADD} != "yes".  Remove all entries
169348ffe56aSColin Percival# of type - from $1.
169448ffe56aSColin Percivalfetch_filter_allowadd () {
169548ffe56aSColin Percival	cut -f 1,2 -d '|' < $1 |
169648ffe56aSColin Percival	    fgrep '|-' |
169748ffe56aSColin Percival	    cut -f 1 -d '|' > filesnotpresent
169848ffe56aSColin Percival
169948ffe56aSColin Percival	if [ ${ALLOWADD} != "yes" ]; then
170048ffe56aSColin Percival		sort < $2 |
170148ffe56aSColin Percival		    join -v 1 -t '|' - filesnotpresent |
170248ffe56aSColin Percival		    sort > $2.tmp
170348ffe56aSColin Percival		mv $2.tmp $2
170448ffe56aSColin Percival	fi
170548ffe56aSColin Percival
170648ffe56aSColin Percival	sort < $1 |
170748ffe56aSColin Percival	    join -v 1 -t '|' - filesnotpresent |
170848ffe56aSColin Percival	    sort > $1.tmp
170948ffe56aSColin Percival	mv $1.tmp $1
171048ffe56aSColin Percival	rm filesnotpresent
171148ffe56aSColin Percival}
171248ffe56aSColin Percival
171348ffe56aSColin Percival# If ${ALLOWDELETE} != "yes", then remove any entries from $1
171448ffe56aSColin Percival# which don't correspond to entries in $2.
171548ffe56aSColin Percivalfetch_filter_allowdelete () {
171648ffe56aSColin Percival	# Produce a lists ${PATH}|${TYPE}
171748ffe56aSColin Percival	for X in $1 $2; do
171848ffe56aSColin Percival		cut -f 1-2 -d '|' < ${X} |
171948ffe56aSColin Percival		    sort -u > ${X}.nodes
172048ffe56aSColin Percival	done
172148ffe56aSColin Percival
172248ffe56aSColin Percival	# Figure out which lines need to be removed from $1.
172348ffe56aSColin Percival	if [ ${ALLOWDELETE} != "yes" ]; then
172448ffe56aSColin Percival		comm -23 $1.nodes $2.nodes > $1.badnodes
172548ffe56aSColin Percival	else
172648ffe56aSColin Percival		: > $1.badnodes
172748ffe56aSColin Percival	fi
172848ffe56aSColin Percival
172948ffe56aSColin Percival	# Remove the relevant lines from $1
173048ffe56aSColin Percival	while read X; do
173148ffe56aSColin Percival		look "${X}|" $1
173248ffe56aSColin Percival	done < $1.badnodes |
173348ffe56aSColin Percival	    comm -13 - $1 > $1.tmp
173448ffe56aSColin Percival	mv $1.tmp $1
173548ffe56aSColin Percival
173648ffe56aSColin Percival	rm $1.badnodes $1.nodes $2.nodes
173748ffe56aSColin Percival}
173848ffe56aSColin Percival
173948ffe56aSColin Percival# If ${KEEPMODIFIEDMETADATA} == "yes", then for each entry in $2
174048ffe56aSColin Percival# with metadata not matching any entry in $1, replace the corresponding
174148ffe56aSColin Percival# line of $3 with one having the same metadata as the entry in $2.
174248ffe56aSColin Percivalfetch_filter_modified_metadata () {
174348ffe56aSColin Percival	# Fish out the metadata from $1 and $2
174448ffe56aSColin Percival	for X in $1 $2; do
174548ffe56aSColin Percival		cut -f 1-6 -d '|' < ${X} > ${X}.metadata
174648ffe56aSColin Percival	done
174748ffe56aSColin Percival
174848ffe56aSColin Percival	# Find the metadata we need to keep
174948ffe56aSColin Percival	if [ ${KEEPMODIFIEDMETADATA} = "yes" ]; then
175048ffe56aSColin Percival		comm -13 $1.metadata $2.metadata > keepmeta
175148ffe56aSColin Percival	else
175248ffe56aSColin Percival		: > keepmeta
175348ffe56aSColin Percival	fi
175448ffe56aSColin Percival
175548ffe56aSColin Percival	# Extract the lines which we need to remove from $3, and
175648ffe56aSColin Percival	# construct the lines which we need to add to $3.
175748ffe56aSColin Percival	: > $3.remove
175848ffe56aSColin Percival	: > $3.add
175948ffe56aSColin Percival	while read LINE; do
176048ffe56aSColin Percival		NODE=`echo "${LINE}" | cut -f 1-2 -d '|'`
176148ffe56aSColin Percival		look "${NODE}|" $3 >> $3.remove
176248ffe56aSColin Percival		look "${NODE}|" $3 |
176348ffe56aSColin Percival		    cut -f 7- -d '|' |
176448ffe56aSColin Percival		    lam -s "${LINE}|" - >> $3.add
176548ffe56aSColin Percival	done < keepmeta
176648ffe56aSColin Percival
176748ffe56aSColin Percival	# Remove the specified lines and add the new lines.
176848ffe56aSColin Percival	sort $3.remove |
176948ffe56aSColin Percival	    comm -13 - $3 |
177048ffe56aSColin Percival	    sort -u - $3.add > $3.tmp
177148ffe56aSColin Percival	mv $3.tmp $3
177248ffe56aSColin Percival
177348ffe56aSColin Percival	rm keepmeta $1.metadata $2.metadata $3.add $3.remove
177448ffe56aSColin Percival}
177548ffe56aSColin Percival
177648ffe56aSColin Percival# Remove lines from $1 and $2 which are identical;
177748ffe56aSColin Percival# no need to update a file if it isn't changing.
177848ffe56aSColin Percivalfetch_filter_uptodate () {
177948ffe56aSColin Percival	comm -23 $1 $2 > $1.tmp
178048ffe56aSColin Percival	comm -13 $1 $2 > $2.tmp
178148ffe56aSColin Percival
178248ffe56aSColin Percival	mv $1.tmp $1
178348ffe56aSColin Percival	mv $2.tmp $2
178448ffe56aSColin Percival}
178548ffe56aSColin Percival
1786db6b0a61SColin Percival# Fetch any "clean" old versions of files we need for merging changes.
1787db6b0a61SColin Percivalfetch_files_premerge () {
1788db6b0a61SColin Percival	# We only need to do anything if $1 is non-empty.
1789db6b0a61SColin Percival	if [ -s $1 ]; then
1790db6b0a61SColin Percival		# Tell the user what we're doing
1791db6b0a61SColin Percival		echo -n "Fetching files from ${OLDRELNUM} for merging... "
1792db6b0a61SColin Percival
1793db6b0a61SColin Percival		# List of files wanted
1794db6b0a61SColin Percival		fgrep '|f|' < $1 |
1795db6b0a61SColin Percival		    cut -f 3 -d '|' |
1796db6b0a61SColin Percival		    sort -u > files.wanted
1797db6b0a61SColin Percival
1798db6b0a61SColin Percival		# Only fetch the files we don't already have
1799db6b0a61SColin Percival		while read Y; do
1800db6b0a61SColin Percival			if [ ! -f "files/${Y}.gz" ]; then
1801db6b0a61SColin Percival				echo ${Y};
1802db6b0a61SColin Percival			fi
1803db6b0a61SColin Percival		done < files.wanted > filelist
1804db6b0a61SColin Percival
1805db6b0a61SColin Percival		# Actually fetch them
1806db6b0a61SColin Percival		lam -s "${OLDFETCHDIR}/f/" - -s ".gz" < filelist |
1807db6b0a61SColin Percival		    xargs ${XARGST} ${PHTTPGET} ${SERVERNAME}	\
1808db6b0a61SColin Percival		    2>${QUIETREDIR}
1809db6b0a61SColin Percival
1810db6b0a61SColin Percival		# Make sure we got them all, and move them into /files/
1811db6b0a61SColin Percival		while read Y; do
1812db6b0a61SColin Percival			if ! [ -f ${Y}.gz ]; then
1813db6b0a61SColin Percival				echo "failed."
1814db6b0a61SColin Percival				return 1
1815db6b0a61SColin Percival			fi
1816db6b0a61SColin Percival			if [ `gunzip -c < ${Y}.gz |
1817db6b0a61SColin Percival			    ${SHA256} -q` = ${Y} ]; then
1818db6b0a61SColin Percival				mv ${Y}.gz files/${Y}.gz
1819db6b0a61SColin Percival			else
1820db6b0a61SColin Percival				echo "${Y} has incorrect hash."
1821db6b0a61SColin Percival				return 1
1822db6b0a61SColin Percival			fi
1823db6b0a61SColin Percival		done < filelist
1824db6b0a61SColin Percival		echo "done."
1825db6b0a61SColin Percival
1826db6b0a61SColin Percival		# Clean up
1827db6b0a61SColin Percival		rm filelist files.wanted
1828db6b0a61SColin Percival	fi
1829db6b0a61SColin Percival}
1830db6b0a61SColin Percival
183148ffe56aSColin Percival# Prepare to fetch files: Generate a list of the files we need,
183248ffe56aSColin Percival# copy the unmodified files we have into /files/, and generate
183348ffe56aSColin Percival# a list of patches to download.
183448ffe56aSColin Percivalfetch_files_prepare () {
183548ffe56aSColin Percival	# Tell the user why his disk is suddenly making lots of noise
183648ffe56aSColin Percival	echo -n "Preparing to download files... "
183748ffe56aSColin Percival
183848ffe56aSColin Percival	# Reduce indices to ${PATH}|${HASH} pairs
183948ffe56aSColin Percival	for X in $1 $2 $3; do
184048ffe56aSColin Percival		cut -f 1,2,7 -d '|' < ${X} |
184148ffe56aSColin Percival		    fgrep '|f|' |
184248ffe56aSColin Percival		    cut -f 1,3 -d '|' |
184348ffe56aSColin Percival		    sort > ${X}.hashes
184448ffe56aSColin Percival	done
184548ffe56aSColin Percival
184648ffe56aSColin Percival	# List of files wanted
184748ffe56aSColin Percival	cut -f 2 -d '|' < $3.hashes |
18482328d598SColin Percival	    sort -u |
18492328d598SColin Percival	    while read HASH; do
18502328d598SColin Percival		if ! [ -f files/${HASH}.gz ]; then
18512328d598SColin Percival			echo ${HASH}
18522328d598SColin Percival		fi
18532328d598SColin Percival	done > files.wanted
185448ffe56aSColin Percival
185548ffe56aSColin Percival	# Generate a list of unmodified files
185648ffe56aSColin Percival	comm -12 $1.hashes $2.hashes |
185748ffe56aSColin Percival	    sort -k 1,1 -t '|' > unmodified.files
185848ffe56aSColin Percival
185948ffe56aSColin Percival	# Copy all files into /files/.  We only need the unmodified files
186048ffe56aSColin Percival	# for use in patching; but we'll want all of them if the user asks
186148ffe56aSColin Percival	# to rollback the updates later.
1862210b8123SColin Percival	while read LINE; do
1863210b8123SColin Percival		F=`echo "${LINE}" | cut -f 1 -d '|'`
1864210b8123SColin Percival		HASH=`echo "${LINE}" | cut -f 2 -d '|'`
1865210b8123SColin Percival
1866210b8123SColin Percival		# Skip files we already have.
1867210b8123SColin Percival		if [ -f files/${HASH}.gz ]; then
1868210b8123SColin Percival			continue
1869210b8123SColin Percival		fi
1870210b8123SColin Percival
1871210b8123SColin Percival		# Make sure the file hasn't changed.
187248ffe56aSColin Percival		cp "${BASEDIR}/${F}" tmpfile
1873210b8123SColin Percival		if [ `sha256 -q tmpfile` != ${HASH} ]; then
1874210b8123SColin Percival			echo
1875210b8123SColin Percival			echo "File changed while FreeBSD Update running: ${F}"
1876210b8123SColin Percival			return 1
1877210b8123SColin Percival		fi
1878210b8123SColin Percival
1879210b8123SColin Percival		# Place the file into storage.
1880210b8123SColin Percival		gzip -c < tmpfile > files/${HASH}.gz
188148ffe56aSColin Percival		rm tmpfile
1882210b8123SColin Percival	done < $2.hashes
188348ffe56aSColin Percival
188448ffe56aSColin Percival	# Produce a list of patches to download
188548ffe56aSColin Percival	sort -k 1,1 -t '|' $3.hashes |
188648ffe56aSColin Percival	    join -t '|' -o 2.2,1.2 - unmodified.files |
188748ffe56aSColin Percival	    fetch_make_patchlist > patchlist
188848ffe56aSColin Percival
188948ffe56aSColin Percival	# Garbage collect
189048ffe56aSColin Percival	rm unmodified.files $1.hashes $2.hashes $3.hashes
189148ffe56aSColin Percival
189248ffe56aSColin Percival	# We don't need the list of possible old files any more.
189348ffe56aSColin Percival	rm $1
189448ffe56aSColin Percival
189548ffe56aSColin Percival	# We're finished making noise
189648ffe56aSColin Percival	echo "done."
189748ffe56aSColin Percival}
189848ffe56aSColin Percival
189948ffe56aSColin Percival# Fetch files.
190048ffe56aSColin Percivalfetch_files () {
190148ffe56aSColin Percival	# Attempt to fetch patches
190248ffe56aSColin Percival	if [ -s patchlist ]; then
190348ffe56aSColin Percival		echo -n "Fetching `wc -l < patchlist | tr -d ' '` "
190448ffe56aSColin Percival		echo ${NDEBUG} "patches.${DDSTATS}"
190548ffe56aSColin Percival		tr '|' '-' < patchlist |
1906db6b0a61SColin Percival		    lam -s "${PATCHDIR}/" - |
190748ffe56aSColin Percival		    xargs ${XARGST} ${PHTTPGET} ${SERVERNAME}	\
190848ffe56aSColin Percival			2>${STATSREDIR} | fetch_progress
190948ffe56aSColin Percival		echo "done."
191048ffe56aSColin Percival
191148ffe56aSColin Percival		# Attempt to apply patches
191248ffe56aSColin Percival		echo -n "Applying patches... "
191348ffe56aSColin Percival		tr '|' ' ' < patchlist |
191448ffe56aSColin Percival		    while read X Y; do
191548ffe56aSColin Percival			if [ ! -f "${X}-${Y}" ]; then continue; fi
191648ffe56aSColin Percival			gunzip -c < files/${X}.gz > OLD
191748ffe56aSColin Percival
191848ffe56aSColin Percival			bspatch OLD NEW ${X}-${Y}
191948ffe56aSColin Percival
192048ffe56aSColin Percival			if [ `${SHA256} -q NEW` = ${Y} ]; then
192148ffe56aSColin Percival				mv NEW files/${Y}
192248ffe56aSColin Percival				gzip -n files/${Y}
192348ffe56aSColin Percival			fi
192448ffe56aSColin Percival			rm -f diff OLD NEW ${X}-${Y}
192548ffe56aSColin Percival		done 2>${QUIETREDIR}
192648ffe56aSColin Percival		echo "done."
192748ffe56aSColin Percival	fi
192848ffe56aSColin Percival
192948ffe56aSColin Percival	# Download files which couldn't be generate via patching
193048ffe56aSColin Percival	while read Y; do
193148ffe56aSColin Percival		if [ ! -f "files/${Y}.gz" ]; then
193248ffe56aSColin Percival			echo ${Y};
193348ffe56aSColin Percival		fi
193448ffe56aSColin Percival	done < files.wanted > filelist
193548ffe56aSColin Percival
193648ffe56aSColin Percival	if [ -s filelist ]; then
193748ffe56aSColin Percival		echo -n "Fetching `wc -l < filelist | tr -d ' '` "
193848ffe56aSColin Percival		echo ${NDEBUG} "files... "
193948ffe56aSColin Percival		lam -s "${FETCHDIR}/f/" - -s ".gz" < filelist |
194048ffe56aSColin Percival		    xargs ${XARGST} ${PHTTPGET} ${SERVERNAME}	\
1941d6e1e31aSConrad Meyer			2>${STATSREDIR} | fetch_progress
194248ffe56aSColin Percival
194348ffe56aSColin Percival		while read Y; do
194448ffe56aSColin Percival			if ! [ -f ${Y}.gz ]; then
194548ffe56aSColin Percival				echo "failed."
194648ffe56aSColin Percival				return 1
194748ffe56aSColin Percival			fi
194848ffe56aSColin Percival			if [ `gunzip -c < ${Y}.gz |
194948ffe56aSColin Percival			    ${SHA256} -q` = ${Y} ]; then
195048ffe56aSColin Percival				mv ${Y}.gz files/${Y}.gz
195148ffe56aSColin Percival			else
195248ffe56aSColin Percival				echo "${Y} has incorrect hash."
195348ffe56aSColin Percival				return 1
195448ffe56aSColin Percival			fi
195548ffe56aSColin Percival		done < filelist
195648ffe56aSColin Percival		echo "done."
195748ffe56aSColin Percival	fi
195848ffe56aSColin Percival
195948ffe56aSColin Percival	# Clean up
196048ffe56aSColin Percival	rm files.wanted filelist patchlist
196148ffe56aSColin Percival}
196248ffe56aSColin Percival
196348ffe56aSColin Percival# Create and populate install manifest directory; and report what updates
196448ffe56aSColin Percival# are available.
196548ffe56aSColin Percivalfetch_create_manifest () {
196648ffe56aSColin Percival	# If we have an existing install manifest, nuke it.
196748ffe56aSColin Percival	if [ -L "${BDHASH}-install" ]; then
196848ffe56aSColin Percival		rm -r ${BDHASH}-install/
196948ffe56aSColin Percival		rm ${BDHASH}-install
197048ffe56aSColin Percival	fi
197148ffe56aSColin Percival
197248ffe56aSColin Percival	# Report to the user if any updates were avoided due to local changes
197348ffe56aSColin Percival	if [ -s modifiedfiles ]; then
1974fc24ba59SEd Maste		cat - modifiedfiles <<- EOF | ${PAGER}
1975b882e02bSEnji Cooper			The following files are affected by updates. No changes have
1976b882e02bSEnji Cooper			been downloaded, however, because the files have been modified
1977b882e02bSEnji Cooper			locally:
1978fc24ba59SEd Maste		EOF
1979fc24ba59SEd Maste	fi
198048ffe56aSColin Percival	rm modifiedfiles
198148ffe56aSColin Percival
198248ffe56aSColin Percival	# If no files will be updated, tell the user and exit
198348ffe56aSColin Percival	if ! [ -s INDEX-PRESENT ] &&
198448ffe56aSColin Percival	    ! [ -s INDEX-NEW ]; then
198548ffe56aSColin Percival		rm INDEX-PRESENT INDEX-NEW
198648ffe56aSColin Percival		echo
198748ffe56aSColin Percival		echo -n "No updates needed to update system to "
198848ffe56aSColin Percival		echo "${RELNUM}-p${RELPATCHNUM}."
198948ffe56aSColin Percival		return
199048ffe56aSColin Percival	fi
199148ffe56aSColin Percival
199248ffe56aSColin Percival	# Divide files into (a) removed files, (b) added files, and
199348ffe56aSColin Percival	# (c) updated files.
199448ffe56aSColin Percival	cut -f 1 -d '|' < INDEX-PRESENT |
199548ffe56aSColin Percival	    sort > INDEX-PRESENT.flist
199648ffe56aSColin Percival	cut -f 1 -d '|' < INDEX-NEW |
199748ffe56aSColin Percival	    sort > INDEX-NEW.flist
199848ffe56aSColin Percival	comm -23 INDEX-PRESENT.flist INDEX-NEW.flist > files.removed
199948ffe56aSColin Percival	comm -13 INDEX-PRESENT.flist INDEX-NEW.flist > files.added
200048ffe56aSColin Percival	comm -12 INDEX-PRESENT.flist INDEX-NEW.flist > files.updated
200148ffe56aSColin Percival	rm INDEX-PRESENT.flist INDEX-NEW.flist
200248ffe56aSColin Percival
200348ffe56aSColin Percival	# Report removed files, if any
200448ffe56aSColin Percival	if [ -s files.removed ]; then
2005fc24ba59SEd Maste		cat - files.removed <<- EOF | ${PAGER}
2006fc24ba59SEd Maste			The following files will be removed as part of updating to
2007fc24ba59SEd Maste			${RELNUM}-p${RELPATCHNUM}:
2008fc24ba59SEd Maste		EOF
2009fc24ba59SEd Maste	fi
201048ffe56aSColin Percival	rm files.removed
201148ffe56aSColin Percival
201248ffe56aSColin Percival	# Report added files, if any
201348ffe56aSColin Percival	if [ -s files.added ]; then
2014fc24ba59SEd Maste		cat - files.added <<- EOF | ${PAGER}
2015fc24ba59SEd Maste			The following files will be added as part of updating to
2016fc24ba59SEd Maste			${RELNUM}-p${RELPATCHNUM}:
2017fc24ba59SEd Maste		EOF
2018fc24ba59SEd Maste	fi
201948ffe56aSColin Percival	rm files.added
202048ffe56aSColin Percival
202148ffe56aSColin Percival	# Report updated files, if any
202248ffe56aSColin Percival	if [ -s files.updated ]; then
2023fc24ba59SEd Maste		cat - files.updated <<- EOF | ${PAGER}
2024fc24ba59SEd Maste			The following files will be updated as part of updating to
2025fc24ba59SEd Maste			${RELNUM}-p${RELPATCHNUM}:
2026fc24ba59SEd Maste		EOF
2027fc24ba59SEd Maste	fi
202848ffe56aSColin Percival	rm files.updated
202948ffe56aSColin Percival
203048ffe56aSColin Percival	# Create a directory for the install manifest.
203148ffe56aSColin Percival	MDIR=`mktemp -d install.XXXXXX` || return 1
203248ffe56aSColin Percival
203348ffe56aSColin Percival	# Populate it
203448ffe56aSColin Percival	mv INDEX-PRESENT ${MDIR}/INDEX-OLD
203548ffe56aSColin Percival	mv INDEX-NEW ${MDIR}/INDEX-NEW
203648ffe56aSColin Percival
203748ffe56aSColin Percival	# Link it into place
203848ffe56aSColin Percival	ln -s ${MDIR} ${BDHASH}-install
203948ffe56aSColin Percival}
204048ffe56aSColin Percival
204148ffe56aSColin Percival# Warn about any upcoming EoL
204248ffe56aSColin Percivalfetch_warn_eol () {
204348ffe56aSColin Percival	# What's the current time?
204448ffe56aSColin Percival	NOWTIME=`date "+%s"`
204548ffe56aSColin Percival
204648ffe56aSColin Percival	# When did we last warn about the EoL date?
204748ffe56aSColin Percival	if [ -f lasteolwarn ]; then
204848ffe56aSColin Percival		LASTWARN=`cat lasteolwarn`
204948ffe56aSColin Percival	else
205048ffe56aSColin Percival		LASTWARN=`expr ${NOWTIME} - 63072000`
205148ffe56aSColin Percival	fi
205248ffe56aSColin Percival
205348ffe56aSColin Percival	# If the EoL time is past, warn.
205448ffe56aSColin Percival	if [ ${EOLTIME} -lt ${NOWTIME} ]; then
205548ffe56aSColin Percival		echo
205648ffe56aSColin Percival		cat <<-EOF
2057b698a3abSColin Percival		WARNING: `uname -sr` HAS PASSED ITS END-OF-LIFE DATE.
205848ffe56aSColin Percival		Any security issues discovered after `date -r ${EOLTIME}`
205948ffe56aSColin Percival		will not have been corrected.
206048ffe56aSColin Percival		EOF
206148ffe56aSColin Percival		return 1
206248ffe56aSColin Percival	fi
206348ffe56aSColin Percival
206448ffe56aSColin Percival	# Figure out how long it has been since we last warned about the
206548ffe56aSColin Percival	# upcoming EoL, and how much longer we have left.
206648ffe56aSColin Percival	SINCEWARN=`expr ${NOWTIME} - ${LASTWARN}`
206748ffe56aSColin Percival	TIMELEFT=`expr ${EOLTIME} - ${NOWTIME}`
206848ffe56aSColin Percival
206989b14566SColin Percival	# Don't warn if the EoL is more than 3 months away
207089b14566SColin Percival	if [ ${TIMELEFT} -gt 7884000 ]; then
207148ffe56aSColin Percival		return 0
207248ffe56aSColin Percival	fi
207348ffe56aSColin Percival
207448ffe56aSColin Percival	# Don't warn if the time remaining is more than 3 times the time
207548ffe56aSColin Percival	# since the last warning.
207648ffe56aSColin Percival	if [ ${TIMELEFT} -gt `expr ${SINCEWARN} \* 3` ]; then
207748ffe56aSColin Percival		return 0
207848ffe56aSColin Percival	fi
207948ffe56aSColin Percival
208048ffe56aSColin Percival	# Figure out what time units to use.
208148ffe56aSColin Percival	if [ ${TIMELEFT} -lt 604800 ]; then
208248ffe56aSColin Percival		UNIT="day"
208348ffe56aSColin Percival		SIZE=86400
208448ffe56aSColin Percival	elif [ ${TIMELEFT} -lt 2678400 ]; then
208548ffe56aSColin Percival		UNIT="week"
208648ffe56aSColin Percival		SIZE=604800
208748ffe56aSColin Percival	else
208848ffe56aSColin Percival		UNIT="month"
208948ffe56aSColin Percival		SIZE=2678400
209048ffe56aSColin Percival	fi
209148ffe56aSColin Percival
209248ffe56aSColin Percival	# Compute the right number of units
209348ffe56aSColin Percival	NUM=`expr ${TIMELEFT} / ${SIZE}`
209448ffe56aSColin Percival	if [ ${NUM} != 1 ]; then
209548ffe56aSColin Percival		UNIT="${UNIT}s"
209648ffe56aSColin Percival	fi
209748ffe56aSColin Percival
209848ffe56aSColin Percival	# Print the warning
209948ffe56aSColin Percival	echo
210048ffe56aSColin Percival	cat <<-EOF
210148ffe56aSColin Percival		WARNING: `uname -sr` is approaching its End-of-Life date.
210248ffe56aSColin Percival		It is strongly recommended that you upgrade to a newer
210348ffe56aSColin Percival		release within the next ${NUM} ${UNIT}.
210448ffe56aSColin Percival	EOF
210548ffe56aSColin Percival
210648ffe56aSColin Percival	# Update the stored time of last warning
210748ffe56aSColin Percival	echo ${NOWTIME} > lasteolwarn
210848ffe56aSColin Percival}
210948ffe56aSColin Percival
211048ffe56aSColin Percival# Do the actual work involved in "fetch" / "cron".
211148ffe56aSColin Percivalfetch_run () {
211248ffe56aSColin Percival	workdir_init || return 1
211348ffe56aSColin Percival
211448ffe56aSColin Percival	# Prepare the mirror list.
211548ffe56aSColin Percival	fetch_pick_server_init && fetch_pick_server
211648ffe56aSColin Percival
211748ffe56aSColin Percival	# Try to fetch the public key until we run out of servers.
211848ffe56aSColin Percival	while ! fetch_key; do
211948ffe56aSColin Percival		fetch_pick_server || return 1
212048ffe56aSColin Percival	done
212148ffe56aSColin Percival
212248ffe56aSColin Percival	# Try to fetch the metadata index signature ("tag") until we run
212348ffe56aSColin Percival	# out of available servers; and sanity check the downloaded tag.
212448ffe56aSColin Percival	while ! fetch_tag; do
212548ffe56aSColin Percival		fetch_pick_server || return 1
212648ffe56aSColin Percival	done
212748ffe56aSColin Percival	fetch_tagsanity || return 1
212848ffe56aSColin Percival
212948ffe56aSColin Percival	# Fetch the latest INDEX-NEW and INDEX-OLD files.
213048ffe56aSColin Percival	fetch_metadata INDEX-NEW INDEX-OLD || return 1
213148ffe56aSColin Percival
213248ffe56aSColin Percival	# Generate filtered INDEX-NEW and INDEX-OLD files containing only
213348ffe56aSColin Percival	# the lines which (a) belong to components we care about, and (b)
213448ffe56aSColin Percival	# don't correspond to paths we're explicitly ignoring.
213548ffe56aSColin Percival	fetch_filter_metadata INDEX-NEW || return 1
213648ffe56aSColin Percival	fetch_filter_metadata INDEX-OLD || return 1
213748ffe56aSColin Percival
2138db6b0a61SColin Percival	# Translate /boot/${KERNCONF} into ${KERNELDIR}
2139db6b0a61SColin Percival	fetch_filter_kernel_names INDEX-NEW ${KERNCONF}
2140db6b0a61SColin Percival	fetch_filter_kernel_names INDEX-OLD ${KERNCONF}
214148ffe56aSColin Percival
214248ffe56aSColin Percival	# For all paths appearing in INDEX-OLD or INDEX-NEW, inspect the
214348ffe56aSColin Percival	# system and generate an INDEX-PRESENT file.
214448ffe56aSColin Percival	fetch_inspect_system INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1
214548ffe56aSColin Percival
214648ffe56aSColin Percival	# Based on ${UPDATEIFUNMODIFIED}, remove lines from INDEX-* which
214748ffe56aSColin Percival	# correspond to lines in INDEX-PRESENT with hashes not appearing
214848ffe56aSColin Percival	# in INDEX-OLD or INDEX-NEW.  Also remove lines where the entry in
214948ffe56aSColin Percival	# INDEX-PRESENT has type - and there isn't a corresponding entry in
215048ffe56aSColin Percival	# INDEX-OLD with type -.
2151db6b0a61SColin Percival	fetch_filter_unmodified_notpresent	\
2152db6b0a61SColin Percival	    INDEX-OLD INDEX-PRESENT INDEX-NEW /dev/null
215348ffe56aSColin Percival
215448ffe56aSColin Percival	# For each entry in INDEX-PRESENT of type -, remove any corresponding
215548ffe56aSColin Percival	# entry from INDEX-NEW if ${ALLOWADD} != "yes".  Remove all entries
215648ffe56aSColin Percival	# of type - from INDEX-PRESENT.
215748ffe56aSColin Percival	fetch_filter_allowadd INDEX-PRESENT INDEX-NEW
215848ffe56aSColin Percival
215948ffe56aSColin Percival	# If ${ALLOWDELETE} != "yes", then remove any entries from
216048ffe56aSColin Percival	# INDEX-PRESENT which don't correspond to entries in INDEX-NEW.
216148ffe56aSColin Percival	fetch_filter_allowdelete INDEX-PRESENT INDEX-NEW
216248ffe56aSColin Percival
216348ffe56aSColin Percival	# If ${KEEPMODIFIEDMETADATA} == "yes", then for each entry in
216448ffe56aSColin Percival	# INDEX-PRESENT with metadata not matching any entry in INDEX-OLD,
216548ffe56aSColin Percival	# replace the corresponding line of INDEX-NEW with one having the
216648ffe56aSColin Percival	# same metadata as the entry in INDEX-PRESENT.
216748ffe56aSColin Percival	fetch_filter_modified_metadata INDEX-OLD INDEX-PRESENT INDEX-NEW
216848ffe56aSColin Percival
216948ffe56aSColin Percival	# Remove lines from INDEX-PRESENT and INDEX-NEW which are identical;
217048ffe56aSColin Percival	# no need to update a file if it isn't changing.
217148ffe56aSColin Percival	fetch_filter_uptodate INDEX-PRESENT INDEX-NEW
217248ffe56aSColin Percival
217348ffe56aSColin Percival	# Prepare to fetch files: Generate a list of the files we need,
217448ffe56aSColin Percival	# copy the unmodified files we have into /files/, and generate
217548ffe56aSColin Percival	# a list of patches to download.
2176210b8123SColin Percival	fetch_files_prepare INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1
217748ffe56aSColin Percival
217848ffe56aSColin Percival	# Fetch files.
217948ffe56aSColin Percival	fetch_files || return 1
218048ffe56aSColin Percival
218148ffe56aSColin Percival	# Create and populate install manifest directory; and report what
218248ffe56aSColin Percival	# updates are available.
218348ffe56aSColin Percival	fetch_create_manifest || return 1
218448ffe56aSColin Percival
218548ffe56aSColin Percival	# Warn about any upcoming EoL
218648ffe56aSColin Percival	fetch_warn_eol || return 1
218748ffe56aSColin Percival}
218848ffe56aSColin Percival
2189db6b0a61SColin Percival# If StrictComponents is not "yes", generate a new components list
2190db6b0a61SColin Percival# with only the components which appear to be installed.
2191db6b0a61SColin Percivalupgrade_guess_components () {
2192db6b0a61SColin Percival	if [ "${STRICTCOMPONENTS}" = "no" ]; then
2193db6b0a61SColin Percival		# Generate filtered INDEX-ALL with only the components listed
2194db6b0a61SColin Percival		# in COMPONENTS.
2195db6b0a61SColin Percival		fetch_filter_metadata_components $1 || return 1
2196db6b0a61SColin Percival
2197db6b0a61SColin Percival		# Tell the user why his disk is suddenly making lots of noise
2198db6b0a61SColin Percival		echo -n "Inspecting system... "
2199db6b0a61SColin Percival
2200db6b0a61SColin Percival		# Look at the files on disk, and assume that a component is
2201db6b0a61SColin Percival		# supposed to be present if it is more than half-present.
2202db6b0a61SColin Percival		cut -f 1-3 -d '|' < INDEX-ALL |
2203db6b0a61SColin Percival		    tr '|' ' ' |
2204db6b0a61SColin Percival		    while read C S F; do
2205db6b0a61SColin Percival			if [ -e ${BASEDIR}/${F} ]; then
2206db6b0a61SColin Percival				echo "+ ${C}|${S}"
2207db6b0a61SColin Percival			fi
2208db6b0a61SColin Percival			echo "= ${C}|${S}"
2209db6b0a61SColin Percival		    done |
2210db6b0a61SColin Percival		    sort |
2211db6b0a61SColin Percival		    uniq -c |
2212db6b0a61SColin Percival		    sed -E 's,^ +,,' > compfreq
2213db6b0a61SColin Percival		grep ' = ' compfreq |
2214db6b0a61SColin Percival		    cut -f 1,3 -d ' ' |
2215db6b0a61SColin Percival		    sort -k 2,2 -t ' ' > compfreq.total
2216db6b0a61SColin Percival		grep ' + ' compfreq |
2217db6b0a61SColin Percival		    cut -f 1,3 -d ' ' |
2218db6b0a61SColin Percival		    sort -k 2,2 -t ' ' > compfreq.present
2219db6b0a61SColin Percival		join -t ' ' -1 2 -2 2 compfreq.present compfreq.total |
2220db6b0a61SColin Percival		    while read S P T; do
2221ae97aa98SEd Maste			if [ ${T} -ne 0 -a ${P} -gt `expr ${T} / 2` ]; then
2222db6b0a61SColin Percival				echo ${S}
2223db6b0a61SColin Percival			fi
2224db6b0a61SColin Percival		    done > comp.present
2225db6b0a61SColin Percival		cut -f 2 -d ' ' < compfreq.total > comp.total
2226db6b0a61SColin Percival		rm INDEX-ALL compfreq compfreq.total compfreq.present
2227db6b0a61SColin Percival
2228db6b0a61SColin Percival		# We're done making noise.
2229db6b0a61SColin Percival		echo "done."
2230db6b0a61SColin Percival
2231db6b0a61SColin Percival		# Sometimes the kernel isn't installed where INDEX-ALL
2232db6b0a61SColin Percival		# thinks that it should be: In particular, it is often in
2233db6b0a61SColin Percival		# /boot/kernel instead of /boot/GENERIC or /boot/SMP.  To
2234db6b0a61SColin Percival		# deal with this, if "kernel|X" is listed in comp.total
2235db6b0a61SColin Percival		# (i.e., is a component which would be upgraded if it is
2236db6b0a61SColin Percival		# found to be present) we will add it to comp.present.
2237db6b0a61SColin Percival		# If "kernel|<anything>" is in comp.total but "kernel|X" is
2238db6b0a61SColin Percival		# not, we print a warning -- the user is running a kernel
2239db6b0a61SColin Percival		# which isn't part of the release.
2240db6b0a61SColin Percival		KCOMP=`echo ${KERNCONF} | tr 'A-Z' 'a-z'`
2241db6b0a61SColin Percival		grep -E "^kernel\|${KCOMP}\$" comp.total >> comp.present
2242db6b0a61SColin Percival
2243db6b0a61SColin Percival		if grep -qE "^kernel\|" comp.total &&
2244db6b0a61SColin Percival		    ! grep -qE "^kernel\|${KCOMP}\$" comp.total; then
2245db6b0a61SColin Percival			cat <<-EOF
2246db6b0a61SColin Percival
2247db6b0a61SColin PercivalWARNING: This system is running a "${KCOMP}" kernel, which is not a
2248db6b0a61SColin Percivalkernel configuration distributed as part of FreeBSD ${RELNUM}.
2249db6b0a61SColin PercivalThis kernel will not be updated: you MUST update the kernel manually
2250db6b0a61SColin Percivalbefore running "$0 install".
2251db6b0a61SColin Percival			EOF
2252db6b0a61SColin Percival		fi
2253db6b0a61SColin Percival
2254db6b0a61SColin Percival		# Re-sort the list of installed components and generate
2255db6b0a61SColin Percival		# the list of non-installed components.
2256db6b0a61SColin Percival		sort -u < comp.present > comp.present.tmp
2257db6b0a61SColin Percival		mv comp.present.tmp comp.present
2258db6b0a61SColin Percival		comm -13 comp.present comp.total > comp.absent
2259db6b0a61SColin Percival
2260db6b0a61SColin Percival		# Ask the user to confirm that what we have is correct.  To
2261db6b0a61SColin Percival		# reduce user confusion, translate "X|Y" back to "X/Y" (as
2262db6b0a61SColin Percival		# subcomponents must be listed in the configuration file).
2263db6b0a61SColin Percival		echo
2264db6b0a61SColin Percival		echo -n "The following components of FreeBSD "
2265db6b0a61SColin Percival		echo "seem to be installed:"
2266db6b0a61SColin Percival		tr '|' '/' < comp.present |
2267db6b0a61SColin Percival		    fmt -72
2268db6b0a61SColin Percival		echo
2269db6b0a61SColin Percival		echo -n "The following components of FreeBSD "
2270db6b0a61SColin Percival		echo "do not seem to be installed:"
2271db6b0a61SColin Percival		tr '|' '/' < comp.absent |
2272db6b0a61SColin Percival		    fmt -72
2273db6b0a61SColin Percival		echo
2274db6b0a61SColin Percival		continuep || return 1
2275db6b0a61SColin Percival		echo
2276db6b0a61SColin Percival
2277db6b0a61SColin Percival		# Suck the generated list of components into ${COMPONENTS}.
2278db6b0a61SColin Percival		# Note that comp.present.tmp is used due to issues with
2279db6b0a61SColin Percival		# pipelines and setting variables.
2280db6b0a61SColin Percival		COMPONENTS=""
2281db6b0a61SColin Percival		tr '|' '/' < comp.present > comp.present.tmp
2282db6b0a61SColin Percival		while read C; do
2283db6b0a61SColin Percival			COMPONENTS="${COMPONENTS} ${C}"
2284db6b0a61SColin Percival		done < comp.present.tmp
2285db6b0a61SColin Percival
2286db6b0a61SColin Percival		# Delete temporary files
2287db6b0a61SColin Percival		rm comp.present comp.present.tmp comp.absent comp.total
2288db6b0a61SColin Percival	fi
2289db6b0a61SColin Percival}
2290db6b0a61SColin Percival
2291db6b0a61SColin Percival# If StrictComponents is not "yes", COMPONENTS contains an entry
2292db6b0a61SColin Percival# corresponding to the currently running kernel, and said kernel
2293db6b0a61SColin Percival# does not exist in the new release, add "kernel/generic" to the
2294db6b0a61SColin Percival# list of components.
2295db6b0a61SColin Percivalupgrade_guess_new_kernel () {
2296db6b0a61SColin Percival	if [ "${STRICTCOMPONENTS}" = "no" ]; then
2297db6b0a61SColin Percival		# Grab the unfiltered metadata file.
2298db6b0a61SColin Percival		METAHASH=`look "$1|" tINDEX.present | cut -f 2 -d '|'`
2299db6b0a61SColin Percival		gunzip -c < files/${METAHASH}.gz > $1.all
2300db6b0a61SColin Percival
2301db6b0a61SColin Percival		# If "kernel/${KCOMP}" is in ${COMPONENTS} and that component
2302db6b0a61SColin Percival		# isn't in $1.all, we need to add kernel/generic.
2303db6b0a61SColin Percival		for C in ${COMPONENTS}; do
2304db6b0a61SColin Percival			if [ ${C} = "kernel/${KCOMP}" ] &&
2305db6b0a61SColin Percival			    ! grep -qE "^kernel\|${KCOMP}\|" $1.all; then
2306db6b0a61SColin Percival				COMPONENTS="${COMPONENTS} kernel/generic"
2307db6b0a61SColin Percival				NKERNCONF="GENERIC"
2308db6b0a61SColin Percival				cat <<-EOF
2309db6b0a61SColin Percival
2310db6b0a61SColin PercivalWARNING: This system is running a "${KCOMP}" kernel, which is not a
2311db6b0a61SColin Percivalkernel configuration distributed as part of FreeBSD ${RELNUM}.
2312db6b0a61SColin PercivalAs part of upgrading to FreeBSD ${RELNUM}, this kernel will be
2313db6b0a61SColin Percivalreplaced with a "generic" kernel.
2314db6b0a61SColin Percival				EOF
2315db6b0a61SColin Percival				continuep || return 1
2316db6b0a61SColin Percival			fi
2317db6b0a61SColin Percival		done
2318db6b0a61SColin Percival
2319db6b0a61SColin Percival		# Don't need this any more...
2320db6b0a61SColin Percival		rm $1.all
2321db6b0a61SColin Percival	fi
2322db6b0a61SColin Percival}
2323db6b0a61SColin Percival
2324db6b0a61SColin Percival# Convert INDEX-OLD (last release) and INDEX-ALL (new release) into
2325db6b0a61SColin Percival# INDEX-OLD and INDEX-NEW files (in the sense of normal upgrades).
2326db6b0a61SColin Percivalupgrade_oldall_to_oldnew () {
2327db6b0a61SColin Percival	# For each ${F}|... which appears in INDEX-ALL but does not appear
2328db6b0a61SColin Percival	# in INDEX-OLD, add ${F}|-|||||| to INDEX-OLD.
2329db6b0a61SColin Percival	cut -f 1 -d '|' < $1 |
2330db6b0a61SColin Percival	    sort -u > $1.paths
2331db6b0a61SColin Percival	cut -f 1 -d '|' < $2 |
2332db6b0a61SColin Percival	    sort -u |
2333db6b0a61SColin Percival	    comm -13 $1.paths - |
2334db6b0a61SColin Percival	    lam - -s "|-||||||" |
2335db6b0a61SColin Percival	    sort - $1 > $1.tmp
2336db6b0a61SColin Percival	mv $1.tmp $1
2337db6b0a61SColin Percival
2338db6b0a61SColin Percival	# Remove lines from INDEX-OLD which also appear in INDEX-ALL
2339db6b0a61SColin Percival	comm -23 $1 $2 > $1.tmp
2340db6b0a61SColin Percival	mv $1.tmp $1
2341db6b0a61SColin Percival
2342db6b0a61SColin Percival	# Remove lines from INDEX-ALL which have a file name not appearing
2343db6b0a61SColin Percival	# anywhere in INDEX-OLD (since these must be files which haven't
2344db6b0a61SColin Percival	# changed -- if they were new, there would be an entry of type "-").
2345db6b0a61SColin Percival	cut -f 1 -d '|' < $1 |
2346db6b0a61SColin Percival	    sort -u > $1.paths
2347db6b0a61SColin Percival	sort -k 1,1 -t '|' < $2 |
2348db6b0a61SColin Percival	    join -t '|' - $1.paths |
2349db6b0a61SColin Percival	    sort > $2.tmp
2350db6b0a61SColin Percival	rm $1.paths
2351db6b0a61SColin Percival	mv $2.tmp $2
2352db6b0a61SColin Percival
2353db6b0a61SColin Percival	# Rename INDEX-ALL to INDEX-NEW.
2354db6b0a61SColin Percival	mv $2 $3
2355db6b0a61SColin Percival}
2356db6b0a61SColin Percival
23577449d2f5SColin Percival# Helper for upgrade_merge: Return zero true iff the two files differ only
23586d514f10SDag-Erling Smørgrav# in the contents of their RCS tags.
23597449d2f5SColin Percivalsamef () {
23607449d2f5SColin Percival	X=`sed -E 's/\\$FreeBSD.*\\$/\$FreeBSD\$/' < $1 | ${SHA256}`
23617449d2f5SColin Percival	Y=`sed -E 's/\\$FreeBSD.*\\$/\$FreeBSD\$/' < $2 | ${SHA256}`
23627449d2f5SColin Percival
23637449d2f5SColin Percival	if [ $X = $Y ]; then
23647449d2f5SColin Percival		return 0;
23657449d2f5SColin Percival	else
23667449d2f5SColin Percival		return 1;
23677449d2f5SColin Percival	fi
23687449d2f5SColin Percival}
23697449d2f5SColin Percival
2370db6b0a61SColin Percival# From the list of "old" files in $1, merge changes in $2 with those in $3,
2371db6b0a61SColin Percival# and update $3 to reflect the hashes of merged files.
2372db6b0a61SColin Percivalupgrade_merge () {
2373db6b0a61SColin Percival	# We only need to do anything if $1 is non-empty.
2374db6b0a61SColin Percival	if [ -s $1 ]; then
2375db6b0a61SColin Percival		cut -f 1 -d '|' $1 |
2376db6b0a61SColin Percival		    sort > $1-paths
2377db6b0a61SColin Percival
2378db6b0a61SColin Percival		# Create staging area for merging files
2379db6b0a61SColin Percival		rm -rf merge/
2380db6b0a61SColin Percival		while read F; do
2381db6b0a61SColin Percival			D=`dirname ${F}`
2382db6b0a61SColin Percival			mkdir -p merge/old/${D}
2383db6b0a61SColin Percival			mkdir -p merge/${OLDRELNUM}/${D}
2384db6b0a61SColin Percival			mkdir -p merge/${RELNUM}/${D}
2385db6b0a61SColin Percival			mkdir -p merge/new/${D}
2386db6b0a61SColin Percival		done < $1-paths
2387db6b0a61SColin Percival
2388db6b0a61SColin Percival		# Copy in files
2389db6b0a61SColin Percival		while read F; do
2390db6b0a61SColin Percival			# Currently installed file
2391db6b0a61SColin Percival			V=`look "${F}|" $2 | cut -f 7 -d '|'`
2392db6b0a61SColin Percival			gunzip < files/${V}.gz > merge/old/${F}
2393db6b0a61SColin Percival
2394db6b0a61SColin Percival			# Old release
2395db6b0a61SColin Percival			if look "${F}|" $1 | fgrep -q "|f|"; then
2396db6b0a61SColin Percival				V=`look "${F}|" $1 | cut -f 3 -d '|'`
2397db6b0a61SColin Percival				gunzip < files/${V}.gz		\
2398db6b0a61SColin Percival				    > merge/${OLDRELNUM}/${F}
2399db6b0a61SColin Percival			fi
2400db6b0a61SColin Percival
2401db6b0a61SColin Percival			# New release
2402db6b0a61SColin Percival			if look "${F}|" $3 | cut -f 1,2,7 -d '|' |
2403db6b0a61SColin Percival			    fgrep -q "|f|"; then
2404db6b0a61SColin Percival				V=`look "${F}|" $3 | cut -f 7 -d '|'`
2405db6b0a61SColin Percival				gunzip < files/${V}.gz		\
2406db6b0a61SColin Percival				    > merge/${RELNUM}/${F}
2407db6b0a61SColin Percival			fi
2408db6b0a61SColin Percival		done < $1-paths
2409db6b0a61SColin Percival
2410db6b0a61SColin Percival		# Attempt to automatically merge changes
2411db6b0a61SColin Percival		echo -n "Attempting to automatically merge "
2412db6b0a61SColin Percival		echo -n "changes in files..."
2413db6b0a61SColin Percival		: > failed.merges
2414db6b0a61SColin Percival		while read F; do
2415db6b0a61SColin Percival			# If the file doesn't exist in the new release,
2416db6b0a61SColin Percival			# the result of "merging changes" is having the file
2417db6b0a61SColin Percival			# not exist.
2418db6b0a61SColin Percival			if ! [ -f merge/${RELNUM}/${F} ]; then
2419db6b0a61SColin Percival				continue
2420db6b0a61SColin Percival			fi
2421db6b0a61SColin Percival
2422db6b0a61SColin Percival			# If the file didn't exist in the old release, we're
2423db6b0a61SColin Percival			# going to throw away the existing file and hope that
2424db6b0a61SColin Percival			# the version from the new release is what we want.
2425db6b0a61SColin Percival			if ! [ -f merge/${OLDRELNUM}/${F} ]; then
2426db6b0a61SColin Percival				cp merge/${RELNUM}/${F} merge/new/${F}
2427db6b0a61SColin Percival				continue
2428db6b0a61SColin Percival			fi
2429db6b0a61SColin Percival
2430db6b0a61SColin Percival			# Some files need special treatment.
2431db6b0a61SColin Percival			case ${F} in
2432db6b0a61SColin Percival			/etc/spwd.db | /etc/pwd.db | /etc/login.conf.db)
2433db6b0a61SColin Percival				# Don't merge these -- we're rebuild them
2434db6b0a61SColin Percival				# after updates are installed.
2435db6b0a61SColin Percival				cp merge/old/${F} merge/new/${F}
2436db6b0a61SColin Percival				;;
2437db6b0a61SColin Percival			*)
2438073dd712SBaptiste Daroussin				if ! diff3 -E -m -L "current version"	\
2439db6b0a61SColin Percival				    -L "${OLDRELNUM}" -L "${RELNUM}"	\
2440db6b0a61SColin Percival				    merge/old/${F}			\
2441db6b0a61SColin Percival				    merge/${OLDRELNUM}/${F}		\
2442db6b0a61SColin Percival				    merge/${RELNUM}/${F}		\
2443db6b0a61SColin Percival				    > merge/new/${F} 2>/dev/null; then
2444db6b0a61SColin Percival					echo ${F} >> failed.merges
2445db6b0a61SColin Percival				fi
2446db6b0a61SColin Percival				;;
2447db6b0a61SColin Percival			esac
2448db6b0a61SColin Percival		done < $1-paths
2449db6b0a61SColin Percival		echo " done."
2450db6b0a61SColin Percival
2451db6b0a61SColin Percival		# Ask the user to handle any files which didn't merge.
2452db6b0a61SColin Percival		while read F; do
24537449d2f5SColin Percival			# If the installed file differs from the version in
24546d514f10SDag-Erling Smørgrav			# the old release only due to RCS tag expansion
24557449d2f5SColin Percival			# then just use the version in the new release.
24567449d2f5SColin Percival			if samef merge/old/${F} merge/${OLDRELNUM}/${F}; then
24577449d2f5SColin Percival				cp merge/${RELNUM}/${F} merge/new/${F}
24587449d2f5SColin Percival				continue
24597449d2f5SColin Percival			fi
24607449d2f5SColin Percival
2461db6b0a61SColin Percival			cat <<-EOF
2462db6b0a61SColin Percival
2463db6b0a61SColin PercivalThe following file could not be merged automatically: ${F}
2464db6b0a61SColin PercivalPress Enter to edit this file in ${EDITOR} and resolve the conflicts
2465db6b0a61SColin Percivalmanually...
2466db6b0a61SColin Percival			EOF
2467db6b0a61SColin Percival			read dummy </dev/tty
2468db6b0a61SColin Percival			${EDITOR} `pwd`/merge/new/${F} < /dev/tty
2469db6b0a61SColin Percival		done < failed.merges
2470db6b0a61SColin Percival		rm failed.merges
2471db6b0a61SColin Percival
2472db6b0a61SColin Percival		# Ask the user to confirm that he likes how the result
2473db6b0a61SColin Percival		# of merging files.
2474db6b0a61SColin Percival		while read F; do
24757449d2f5SColin Percival			# Skip files which haven't changed except possibly
24766d514f10SDag-Erling Smørgrav			# in their RCS tags.
24777449d2f5SColin Percival			if [ -f merge/old/${F} ] && [ -f merge/new/${F} ] &&
24787449d2f5SColin Percival			    samef merge/old/${F} merge/new/${F}; then
24797449d2f5SColin Percival				continue
24807449d2f5SColin Percival			fi
24817449d2f5SColin Percival
24827449d2f5SColin Percival			# Skip files where the installed file differs from
24836d514f10SDag-Erling Smørgrav			# the old file only due to RCS tags.
24847449d2f5SColin Percival			if [ -f merge/old/${F} ] &&
24857449d2f5SColin Percival			    [ -f merge/${OLDRELNUM}/${F} ] &&
24867449d2f5SColin Percival			    samef merge/old/${F} merge/${OLDRELNUM}/${F}; then
2487db6b0a61SColin Percival				continue
2488db6b0a61SColin Percival			fi
2489db6b0a61SColin Percival
2490db6b0a61SColin Percival			# Warn about files which are ceasing to exist.
2491db6b0a61SColin Percival			if ! [ -f merge/new/${F} ]; then
2492db6b0a61SColin Percival				cat <<-EOF
2493db6b0a61SColin Percival
2494db6b0a61SColin PercivalThe following file will be removed, as it no longer exists in
2495db6b0a61SColin PercivalFreeBSD ${RELNUM}: ${F}
2496db6b0a61SColin Percival				EOF
2497db6b0a61SColin Percival				continuep < /dev/tty || return 1
2498db6b0a61SColin Percival				continue
2499db6b0a61SColin Percival			fi
2500db6b0a61SColin Percival
2501db6b0a61SColin Percival			# Print changes for the user's approval.
2502db6b0a61SColin Percival			cat <<-EOF
2503db6b0a61SColin Percival
2504db6b0a61SColin PercivalThe following changes, which occurred between FreeBSD ${OLDRELNUM} and
2505db6b0a61SColin PercivalFreeBSD ${RELNUM} have been merged into ${F}:
2506db6b0a61SColin PercivalEOF
2507db6b0a61SColin Percival			diff -U 5 -L "current version" -L "new version"	\
2508db6b0a61SColin Percival			    merge/old/${F} merge/new/${F} || true
2509db6b0a61SColin Percival			continuep < /dev/tty || return 1
2510db6b0a61SColin Percival		done < $1-paths
2511db6b0a61SColin Percival
2512db6b0a61SColin Percival		# Store merged files.
2513db6b0a61SColin Percival		while read F; do
2514c58b62efSColin Percival			if [ -f merge/new/${F} ]; then
2515db6b0a61SColin Percival				V=`${SHA256} -q merge/new/${F}`
2516db6b0a61SColin Percival
2517db6b0a61SColin Percival				gzip -c < merge/new/${F} > files/${V}.gz
2518db6b0a61SColin Percival				echo "${F}|${V}"
2519db6b0a61SColin Percival			fi
2520db6b0a61SColin Percival		done < $1-paths > newhashes
2521db6b0a61SColin Percival
2522db6b0a61SColin Percival		# Pull lines out from $3 which need to be updated to
2523db6b0a61SColin Percival		# reflect merged files.
2524db6b0a61SColin Percival		while read F; do
2525db6b0a61SColin Percival			look "${F}|" $3
2526db6b0a61SColin Percival		done < $1-paths > $3-oldlines
2527db6b0a61SColin Percival
2528db6b0a61SColin Percival		# Update lines to reflect merged files
2529db6b0a61SColin Percival		join -t '|' -o 1.1,1.2,1.3,1.4,1.5,1.6,2.2,1.8		\
2530db6b0a61SColin Percival		    $3-oldlines newhashes > $3-newlines
2531db6b0a61SColin Percival
2532db6b0a61SColin Percival		# Remove old lines from $3 and add new lines.
2533db6b0a61SColin Percival		sort $3-oldlines |
2534db6b0a61SColin Percival		    comm -13 - $3 |
2535db6b0a61SColin Percival		    sort - $3-newlines > $3.tmp
2536db6b0a61SColin Percival		mv $3.tmp $3
2537db6b0a61SColin Percival
2538db6b0a61SColin Percival		# Clean up
2539db6b0a61SColin Percival		rm $1-paths newhashes $3-oldlines $3-newlines
2540db6b0a61SColin Percival		rm -rf merge/
2541db6b0a61SColin Percival	fi
2542db6b0a61SColin Percival
2543db6b0a61SColin Percival	# We're done with merging files.
2544db6b0a61SColin Percival	rm $1
2545db6b0a61SColin Percival}
2546db6b0a61SColin Percival
2547db6b0a61SColin Percival# Do the work involved in fetching upgrades to a new release
2548db6b0a61SColin Percivalupgrade_run () {
2549db6b0a61SColin Percival	workdir_init || return 1
2550db6b0a61SColin Percival
2551db6b0a61SColin Percival	# Prepare the mirror list.
2552db6b0a61SColin Percival	fetch_pick_server_init && fetch_pick_server
2553db6b0a61SColin Percival
2554db6b0a61SColin Percival	# Try to fetch the public key until we run out of servers.
2555db6b0a61SColin Percival	while ! fetch_key; do
2556db6b0a61SColin Percival		fetch_pick_server || return 1
2557db6b0a61SColin Percival	done
2558db6b0a61SColin Percival
2559db6b0a61SColin Percival	# Try to fetch the metadata index signature ("tag") until we run
2560db6b0a61SColin Percival	# out of available servers; and sanity check the downloaded tag.
2561db6b0a61SColin Percival	while ! fetch_tag; do
2562db6b0a61SColin Percival		fetch_pick_server || return 1
2563db6b0a61SColin Percival	done
2564db6b0a61SColin Percival	fetch_tagsanity || return 1
2565db6b0a61SColin Percival
2566db6b0a61SColin Percival	# Fetch the INDEX-OLD and INDEX-ALL.
2567db6b0a61SColin Percival	fetch_metadata INDEX-OLD INDEX-ALL || return 1
2568db6b0a61SColin Percival
2569db6b0a61SColin Percival	# If StrictComponents is not "yes", generate a new components list
2570db6b0a61SColin Percival	# with only the components which appear to be installed.
2571db6b0a61SColin Percival	upgrade_guess_components INDEX-ALL || return 1
2572db6b0a61SColin Percival
2573db6b0a61SColin Percival	# Generate filtered INDEX-OLD and INDEX-ALL files containing only
2574db6b0a61SColin Percival	# the components we want and without anything marked as "Ignore".
2575db6b0a61SColin Percival	fetch_filter_metadata INDEX-OLD || return 1
2576db6b0a61SColin Percival	fetch_filter_metadata INDEX-ALL || return 1
2577db6b0a61SColin Percival
2578db6b0a61SColin Percival	# Merge the INDEX-OLD and INDEX-ALL files into INDEX-OLD.
2579db6b0a61SColin Percival	sort INDEX-OLD INDEX-ALL > INDEX-OLD.tmp
2580db6b0a61SColin Percival	mv INDEX-OLD.tmp INDEX-OLD
2581db6b0a61SColin Percival	rm INDEX-ALL
2582db6b0a61SColin Percival
2583db6b0a61SColin Percival	# Adjust variables for fetching files from the new release.
2584db6b0a61SColin Percival	OLDRELNUM=${RELNUM}
2585db6b0a61SColin Percival	RELNUM=${TARGETRELEASE}
2586db6b0a61SColin Percival	OLDFETCHDIR=${FETCHDIR}
2587db6b0a61SColin Percival	FETCHDIR=${RELNUM}/${ARCH}
2588db6b0a61SColin Percival
2589db6b0a61SColin Percival	# Try to fetch the NEW metadata index signature ("tag") until we run
2590db6b0a61SColin Percival	# out of available servers; and sanity check the downloaded tag.
2591db6b0a61SColin Percival	while ! fetch_tag; do
2592db6b0a61SColin Percival		fetch_pick_server || return 1
2593db6b0a61SColin Percival	done
2594db6b0a61SColin Percival
2595db6b0a61SColin Percival	# Fetch the new INDEX-ALL.
2596db6b0a61SColin Percival	fetch_metadata INDEX-ALL || return 1
2597db6b0a61SColin Percival
2598db6b0a61SColin Percival	# If StrictComponents is not "yes", COMPONENTS contains an entry
2599db6b0a61SColin Percival	# corresponding to the currently running kernel, and said kernel
2600db6b0a61SColin Percival	# does not exist in the new release, add "kernel/generic" to the
2601db6b0a61SColin Percival	# list of components.
2602db6b0a61SColin Percival	upgrade_guess_new_kernel INDEX-ALL || return 1
2603db6b0a61SColin Percival
2604db6b0a61SColin Percival	# Filter INDEX-ALL to contain only the components we want and without
2605db6b0a61SColin Percival	# anything marked as "Ignore".
2606db6b0a61SColin Percival	fetch_filter_metadata INDEX-ALL || return 1
2607db6b0a61SColin Percival
2608db6b0a61SColin Percival	# Convert INDEX-OLD (last release) and INDEX-ALL (new release) into
2609db6b0a61SColin Percival	# INDEX-OLD and INDEX-NEW files (in the sense of normal upgrades).
2610db6b0a61SColin Percival	upgrade_oldall_to_oldnew INDEX-OLD INDEX-ALL INDEX-NEW
2611db6b0a61SColin Percival
2612db6b0a61SColin Percival	# Translate /boot/${KERNCONF} or /boot/${NKERNCONF} into ${KERNELDIR}
2613db6b0a61SColin Percival	fetch_filter_kernel_names INDEX-NEW ${NKERNCONF}
2614db6b0a61SColin Percival	fetch_filter_kernel_names INDEX-OLD ${KERNCONF}
2615db6b0a61SColin Percival
2616db6b0a61SColin Percival	# For all paths appearing in INDEX-OLD or INDEX-NEW, inspect the
2617db6b0a61SColin Percival	# system and generate an INDEX-PRESENT file.
2618db6b0a61SColin Percival	fetch_inspect_system INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1
2619db6b0a61SColin Percival
2620db6b0a61SColin Percival	# Based on ${MERGECHANGES}, generate a file tomerge-old with the
2621db6b0a61SColin Percival	# paths and hashes of old versions of files to merge.
2622db6b0a61SColin Percival	fetch_filter_mergechanges INDEX-OLD INDEX-PRESENT tomerge-old
2623db6b0a61SColin Percival
2624db6b0a61SColin Percival	# Based on ${UPDATEIFUNMODIFIED}, remove lines from INDEX-* which
2625db6b0a61SColin Percival	# correspond to lines in INDEX-PRESENT with hashes not appearing
2626db6b0a61SColin Percival	# in INDEX-OLD or INDEX-NEW.  Also remove lines where the entry in
2627db6b0a61SColin Percival	# INDEX-PRESENT has type - and there isn't a corresponding entry in
2628db6b0a61SColin Percival	# INDEX-OLD with type -.
2629db6b0a61SColin Percival	fetch_filter_unmodified_notpresent	\
2630db6b0a61SColin Percival	    INDEX-OLD INDEX-PRESENT INDEX-NEW tomerge-old
2631db6b0a61SColin Percival
2632db6b0a61SColin Percival	# For each entry in INDEX-PRESENT of type -, remove any corresponding
2633db6b0a61SColin Percival	# entry from INDEX-NEW if ${ALLOWADD} != "yes".  Remove all entries
2634db6b0a61SColin Percival	# of type - from INDEX-PRESENT.
2635db6b0a61SColin Percival	fetch_filter_allowadd INDEX-PRESENT INDEX-NEW
2636db6b0a61SColin Percival
2637db6b0a61SColin Percival	# If ${ALLOWDELETE} != "yes", then remove any entries from
2638db6b0a61SColin Percival	# INDEX-PRESENT which don't correspond to entries in INDEX-NEW.
2639db6b0a61SColin Percival	fetch_filter_allowdelete INDEX-PRESENT INDEX-NEW
2640db6b0a61SColin Percival
2641db6b0a61SColin Percival	# If ${KEEPMODIFIEDMETADATA} == "yes", then for each entry in
2642db6b0a61SColin Percival	# INDEX-PRESENT with metadata not matching any entry in INDEX-OLD,
2643db6b0a61SColin Percival	# replace the corresponding line of INDEX-NEW with one having the
2644db6b0a61SColin Percival	# same metadata as the entry in INDEX-PRESENT.
2645db6b0a61SColin Percival	fetch_filter_modified_metadata INDEX-OLD INDEX-PRESENT INDEX-NEW
2646db6b0a61SColin Percival
2647db6b0a61SColin Percival	# Remove lines from INDEX-PRESENT and INDEX-NEW which are identical;
2648db6b0a61SColin Percival	# no need to update a file if it isn't changing.
2649db6b0a61SColin Percival	fetch_filter_uptodate INDEX-PRESENT INDEX-NEW
2650db6b0a61SColin Percival
2651db6b0a61SColin Percival	# Fetch "clean" files from the old release for merging changes.
2652db6b0a61SColin Percival	fetch_files_premerge tomerge-old
2653db6b0a61SColin Percival
2654db6b0a61SColin Percival	# Prepare to fetch files: Generate a list of the files we need,
2655db6b0a61SColin Percival	# copy the unmodified files we have into /files/, and generate
2656db6b0a61SColin Percival	# a list of patches to download.
2657db6b0a61SColin Percival	fetch_files_prepare INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1
2658db6b0a61SColin Percival
2659db6b0a61SColin Percival	# Fetch patches from to-${RELNUM}/${ARCH}/bp/
2660db6b0a61SColin Percival	PATCHDIR=to-${RELNUM}/${ARCH}/bp
2661db6b0a61SColin Percival	fetch_files || return 1
2662db6b0a61SColin Percival
2663db6b0a61SColin Percival	# Merge configuration file changes.
2664db6b0a61SColin Percival	upgrade_merge tomerge-old INDEX-PRESENT INDEX-NEW || return 1
2665db6b0a61SColin Percival
2666db6b0a61SColin Percival	# Create and populate install manifest directory; and report what
2667db6b0a61SColin Percival	# updates are available.
2668db6b0a61SColin Percival	fetch_create_manifest || return 1
2669db6b0a61SColin Percival
2670db6b0a61SColin Percival	# Leave a note behind to tell the "install" command that the kernel
2671db6b0a61SColin Percival	# needs to be installed before the world.
2672db6b0a61SColin Percival	touch ${BDHASH}-install/kernelfirst
267385451f90SColin Percival
267485451f90SColin Percival	# Remind the user that they need to run "freebsd-update install"
267585451f90SColin Percival	# to install the downloaded bits, in case they didn't RTFM.
267685451f90SColin Percival	echo "To install the downloaded upgrades, run \"$0 install\"."
2677db6b0a61SColin Percival}
2678db6b0a61SColin Percival
267948ffe56aSColin Percival# Make sure that all the file hashes mentioned in $@ have corresponding
268048ffe56aSColin Percival# gzipped files stored in /files/.
268148ffe56aSColin Percivalinstall_verify () {
268248ffe56aSColin Percival	# Generate a list of hashes
268348ffe56aSColin Percival	cat $@ |
268448ffe56aSColin Percival	    cut -f 2,7 -d '|' |
268548ffe56aSColin Percival	    grep -E '^f' |
268648ffe56aSColin Percival	    cut -f 2 -d '|' |
268748ffe56aSColin Percival	    sort -u > filelist
268848ffe56aSColin Percival
268948ffe56aSColin Percival	# Make sure all the hashes exist
269048ffe56aSColin Percival	while read HASH; do
269148ffe56aSColin Percival		if ! [ -f files/${HASH}.gz ]; then
269248ffe56aSColin Percival			echo -n "Update files missing -- "
269348ffe56aSColin Percival			echo "this should never happen."
269448ffe56aSColin Percival			echo "Re-run '$0 fetch'."
269548ffe56aSColin Percival			return 1
269648ffe56aSColin Percival		fi
269748ffe56aSColin Percival	done < filelist
269848ffe56aSColin Percival
269948ffe56aSColin Percival	# Clean up
270048ffe56aSColin Percival	rm filelist
270148ffe56aSColin Percival}
270248ffe56aSColin Percival
270348ffe56aSColin Percival# Remove the system immutable flag from files
270448ffe56aSColin Percivalinstall_unschg () {
270548ffe56aSColin Percival	# Generate file list
270648ffe56aSColin Percival	cat $@ |
270748ffe56aSColin Percival	    cut -f 1 -d '|' > filelist
270848ffe56aSColin Percival
270948ffe56aSColin Percival	# Remove flags
271048ffe56aSColin Percival	while read F; do
2711e829ed67SColin Percival		if ! [ -e ${BASEDIR}/${F} ]; then
271248ffe56aSColin Percival			continue
27135a74378cSXin LI		else
27145a74378cSXin LI			echo ${BASEDIR}/${F}
271548ffe56aSColin Percival		fi
27165a74378cSXin LI	done < filelist | xargs chflags noschg || return 1
271748ffe56aSColin Percival
271848ffe56aSColin Percival	# Clean up
271948ffe56aSColin Percival	rm filelist
272048ffe56aSColin Percival}
272148ffe56aSColin Percival
272223d827efSSimon L. B. Nielsen# Decide which directory name to use for kernel backups.
272323d827efSSimon L. B. Nielsenbackup_kernel_finddir () {
272423d827efSSimon L. B. Nielsen	CNT=0
272523d827efSSimon L. B. Nielsen	while true ; do
272623d827efSSimon L. B. Nielsen		# Pathname does not exist, so it is OK use that name
272723d827efSSimon L. B. Nielsen		# for backup directory.
2728c4a0c62cSThomas Quinot		if [ ! -e $BASEDIR/$BACKUPKERNELDIR ]; then
272923d827efSSimon L. B. Nielsen			return 0
273023d827efSSimon L. B. Nielsen		fi
273123d827efSSimon L. B. Nielsen
273223d827efSSimon L. B. Nielsen		# If directory do exist, we only use if it has our
273323d827efSSimon L. B. Nielsen		# marker file.
2734c4a0c62cSThomas Quinot		if [ -d $BASEDIR/$BACKUPKERNELDIR -a \
2735c4a0c62cSThomas Quinot			-e $BASEDIR/$BACKUPKERNELDIR/.freebsd-update ]; then
273623d827efSSimon L. B. Nielsen			return 0
273723d827efSSimon L. B. Nielsen		fi
273823d827efSSimon L. B. Nielsen
273923d827efSSimon L. B. Nielsen		# We could not use current directory name, so add counter to
274023d827efSSimon L. B. Nielsen		# the end and try again.
274123d827efSSimon L. B. Nielsen		CNT=$((CNT + 1))
274223d827efSSimon L. B. Nielsen		if [ $CNT -gt 9 ]; then
2743c4a0c62cSThomas Quinot			echo "Could not find valid backup dir ($BASEDIR/$BACKUPKERNELDIR)"
274423d827efSSimon L. B. Nielsen			exit 1
274523d827efSSimon L. B. Nielsen		fi
274623d827efSSimon L. B. Nielsen		BACKUPKERNELDIR="`echo $BACKUPKERNELDIR | sed -Ee 's/[0-9]\$//'`"
274723d827efSSimon L. B. Nielsen		BACKUPKERNELDIR="${BACKUPKERNELDIR}${CNT}"
274823d827efSSimon L. B. Nielsen	done
274923d827efSSimon L. B. Nielsen}
275023d827efSSimon L. B. Nielsen
275123d827efSSimon L. B. Nielsen# Backup the current kernel using hardlinks, if not disabled by user.
275223d827efSSimon L. B. Nielsen# Since we delete all files in the directory used for previous backups
275323d827efSSimon L. B. Nielsen# we create a marker file called ".freebsd-update" in the directory so
275423d827efSSimon L. B. Nielsen# we can determine on the next run that the directory was created by
275523d827efSSimon L. B. Nielsen# freebsd-update and we then do not accidentally remove user files in
275623d827efSSimon L. B. Nielsen# the unlikely case that the user has created a directory with a
275723d827efSSimon L. B. Nielsen# conflicting name.
275823d827efSSimon L. B. Nielsenbackup_kernel () {
275923d827efSSimon L. B. Nielsen	# Only make kernel backup is so configured.
276023d827efSSimon L. B. Nielsen	if [ $BACKUPKERNEL != yes ]; then
276123d827efSSimon L. B. Nielsen		return 0
276223d827efSSimon L. B. Nielsen	fi
276323d827efSSimon L. B. Nielsen
276423d827efSSimon L. B. Nielsen	# Decide which directory name to use for kernel backups.
276523d827efSSimon L. B. Nielsen	backup_kernel_finddir
276623d827efSSimon L. B. Nielsen
276723d827efSSimon L. B. Nielsen	# Remove old kernel backup files.  If $BACKUPKERNELDIR was
276823d827efSSimon L. B. Nielsen	# "not ours", backup_kernel_finddir would have exited, so
276923d827efSSimon L. B. Nielsen	# deleting the directory content is as safe as we can make it.
2770c4a0c62cSThomas Quinot	if [ -d $BASEDIR/$BACKUPKERNELDIR ]; then
2771c4a0c62cSThomas Quinot		rm -fr $BASEDIR/$BACKUPKERNELDIR
277223d827efSSimon L. B. Nielsen	fi
277323d827efSSimon L. B. Nielsen
2774ab7d0151SJaakko Heinonen	# Create directories for backup.
2775c4a0c62cSThomas Quinot	mkdir -p $BASEDIR/$BACKUPKERNELDIR
2776c4a0c62cSThomas Quinot	mtree -cdn -p "${BASEDIR}/${KERNELDIR}" | \
2777c4a0c62cSThomas Quinot	    mtree -Ue -p "${BASEDIR}/${BACKUPKERNELDIR}" > /dev/null
277823d827efSSimon L. B. Nielsen
277923d827efSSimon L. B. Nielsen	# Mark the directory as having been created by freebsd-update.
2780c4a0c62cSThomas Quinot	touch $BASEDIR/$BACKUPKERNELDIR/.freebsd-update
278123d827efSSimon L. B. Nielsen	if [ $? -ne 0 ]; then
278223d827efSSimon L. B. Nielsen		echo "Could not create kernel backup directory"
278323d827efSSimon L. B. Nielsen		exit 1
278423d827efSSimon L. B. Nielsen	fi
278523d827efSSimon L. B. Nielsen
278623d827efSSimon L. B. Nielsen	# Disable pathname expansion to be sure *.symbols is not
278723d827efSSimon L. B. Nielsen	# expanded.
278823d827efSSimon L. B. Nielsen	set -f
278923d827efSSimon L. B. Nielsen
279023d827efSSimon L. B. Nielsen	# Use find to ignore symbol files, unless disabled by user.
279123d827efSSimon L. B. Nielsen	if [ $BACKUPKERNELSYMBOLFILES = yes ]; then
279223d827efSSimon L. B. Nielsen		FINDFILTER=""
279323d827efSSimon L. B. Nielsen	else
27947e1ed2c7SEd Maste		FINDFILTER="-a ! -name *.debug -a ! -name *.symbols"
279523d827efSSimon L. B. Nielsen	fi
279623d827efSSimon L. B. Nielsen
279723d827efSSimon L. B. Nielsen	# Backup all the kernel files using hardlinks.
2798c4a0c62cSThomas Quinot	(cd ${BASEDIR}/${KERNELDIR} && find . -type f $FINDFILTER -exec \
2799c4a0c62cSThomas Quinot	    cp -pl '{}' ${BASEDIR}/${BACKUPKERNELDIR}/'{}' \;)
280023d827efSSimon L. B. Nielsen
280123d827efSSimon L. B. Nielsen	# Re-enable patchname expansion.
280223d827efSSimon L. B. Nielsen	set +f
280323d827efSSimon L. B. Nielsen}
280423d827efSSimon L. B. Nielsen
280548ffe56aSColin Percival# Install new files
280648ffe56aSColin Percivalinstall_from_index () {
280748ffe56aSColin Percival	# First pass: Do everything apart from setting file flags.  We
280848ffe56aSColin Percival	# can't set flags yet, because schg inhibits hard linking.
280948ffe56aSColin Percival	sort -k 1,1 -t '|' $1 |
281048ffe56aSColin Percival	    tr '|' ' ' |
281148ffe56aSColin Percival	    while read FPATH TYPE OWNER GROUP PERM FLAGS HASH LINK; do
281248ffe56aSColin Percival		case ${TYPE} in
281348ffe56aSColin Percival		d)
281448ffe56aSColin Percival			# Create a directory
281548ffe56aSColin Percival			install -d -o ${OWNER} -g ${GROUP}		\
281648ffe56aSColin Percival			    -m ${PERM} ${BASEDIR}/${FPATH}
281748ffe56aSColin Percival			;;
281848ffe56aSColin Percival		f)
281948ffe56aSColin Percival			if [ -z "${LINK}" ]; then
282048ffe56aSColin Percival				# Create a file, without setting flags.
282148ffe56aSColin Percival				gunzip < files/${HASH}.gz > ${HASH}
282248ffe56aSColin Percival				install -S -o ${OWNER} -g ${GROUP}	\
282348ffe56aSColin Percival				    -m ${PERM} ${HASH} ${BASEDIR}/${FPATH}
282448ffe56aSColin Percival				rm ${HASH}
282548ffe56aSColin Percival			else
282648ffe56aSColin Percival				# Create a hard link.
2827e829ed67SColin Percival				ln -f ${BASEDIR}/${LINK} ${BASEDIR}/${FPATH}
282848ffe56aSColin Percival			fi
282948ffe56aSColin Percival			;;
283048ffe56aSColin Percival		L)
283148ffe56aSColin Percival			# Create a symlink
283248ffe56aSColin Percival			ln -sfh ${HASH} ${BASEDIR}/${FPATH}
283348ffe56aSColin Percival			;;
283448ffe56aSColin Percival		esac
283548ffe56aSColin Percival	    done
283648ffe56aSColin Percival
283748ffe56aSColin Percival	# Perform a second pass, adding file flags.
283848ffe56aSColin Percival	tr '|' ' ' < $1 |
283948ffe56aSColin Percival	    while read FPATH TYPE OWNER GROUP PERM FLAGS HASH LINK; do
284048ffe56aSColin Percival		if [ ${TYPE} = "f" ] &&
284148ffe56aSColin Percival		    ! [ ${FLAGS} = "0" ]; then
284248ffe56aSColin Percival			chflags ${FLAGS} ${BASEDIR}/${FPATH}
284348ffe56aSColin Percival		fi
284448ffe56aSColin Percival	    done
284548ffe56aSColin Percival}
284648ffe56aSColin Percival
284748ffe56aSColin Percival# Remove files which we want to delete
284848ffe56aSColin Percivalinstall_delete () {
284948ffe56aSColin Percival	# Generate list of new files
285048ffe56aSColin Percival	cut -f 1 -d '|' < $2 |
285148ffe56aSColin Percival	    sort > newfiles
285248ffe56aSColin Percival
285348ffe56aSColin Percival	# Generate subindex of old files we want to nuke
285448ffe56aSColin Percival	sort -k 1,1 -t '|' $1 |
285548ffe56aSColin Percival	    join -t '|' -v 1 - newfiles |
2856bce02f98SColin Percival	    sort -r -k 1,1 -t '|' |
285748ffe56aSColin Percival	    cut -f 1,2 -d '|' |
285848ffe56aSColin Percival	    tr '|' ' ' > killfiles
285948ffe56aSColin Percival
286048ffe56aSColin Percival	# Remove the offending bits
286148ffe56aSColin Percival	while read FPATH TYPE; do
286248ffe56aSColin Percival		case ${TYPE} in
286348ffe56aSColin Percival		d)
286448ffe56aSColin Percival			rmdir ${BASEDIR}/${FPATH}
286548ffe56aSColin Percival			;;
286648ffe56aSColin Percival		f)
286748ffe56aSColin Percival			rm ${BASEDIR}/${FPATH}
286848ffe56aSColin Percival			;;
286948ffe56aSColin Percival		L)
287048ffe56aSColin Percival			rm ${BASEDIR}/${FPATH}
287148ffe56aSColin Percival			;;
287248ffe56aSColin Percival		esac
287348ffe56aSColin Percival	done < killfiles
287448ffe56aSColin Percival
287548ffe56aSColin Percival	# Clean up
287648ffe56aSColin Percival	rm newfiles killfiles
287748ffe56aSColin Percival}
287848ffe56aSColin Percival
2879db6b0a61SColin Percival# Install new files, delete old files, and update linker.hints
2880db6b0a61SColin Percivalinstall_files () {
2881db6b0a61SColin Percival	# If we haven't already dealt with the kernel, deal with it.
2882db6b0a61SColin Percival	if ! [ -f $1/kerneldone ]; then
2883db6b0a61SColin Percival		grep -E '^/boot/' $1/INDEX-OLD > INDEX-OLD
2884db6b0a61SColin Percival		grep -E '^/boot/' $1/INDEX-NEW > INDEX-NEW
2885db6b0a61SColin Percival
288623d827efSSimon L. B. Nielsen		# Backup current kernel before installing a new one
288723d827efSSimon L. B. Nielsen		backup_kernel || return 1
288823d827efSSimon L. B. Nielsen
2889db6b0a61SColin Percival		# Install new files
2890db6b0a61SColin Percival		install_from_index INDEX-NEW || return 1
2891db6b0a61SColin Percival
2892db6b0a61SColin Percival		# Remove files which need to be deleted
2893db6b0a61SColin Percival		install_delete INDEX-OLD INDEX-NEW || return 1
2894db6b0a61SColin Percival
2895db6b0a61SColin Percival		# Update linker.hints if necessary
2896db6b0a61SColin Percival		if [ -s INDEX-OLD -o -s INDEX-NEW ]; then
2897c4a0c62cSThomas Quinot			kldxref -R ${BASEDIR}/boot/ 2>/dev/null
289848ffe56aSColin Percival		fi
2899db6b0a61SColin Percival
2900db6b0a61SColin Percival		# We've finished updating the kernel.
2901db6b0a61SColin Percival		touch $1/kerneldone
2902db6b0a61SColin Percival
2903db6b0a61SColin Percival		# Do we need to ask for a reboot now?
2904db6b0a61SColin Percival		if [ -f $1/kernelfirst ] &&
2905db6b0a61SColin Percival		    [ -s INDEX-OLD -o -s INDEX-NEW ]; then
2906db6b0a61SColin Percival			cat <<-EOF
2907db6b0a61SColin Percival
2908db6b0a61SColin PercivalKernel updates have been installed.  Please reboot and run
2909db6b0a61SColin Percival"$0 install" again to finish installing updates.
2910db6b0a61SColin Percival			EOF
2911db6b0a61SColin Percival			exit 0
2912db6b0a61SColin Percival		fi
2913db6b0a61SColin Percival	fi
2914db6b0a61SColin Percival
2915db6b0a61SColin Percival	# If we haven't already dealt with the world, deal with it.
2916db6b0a61SColin Percival	if ! [ -f $1/worlddone ]; then
2917cd1ab228SColin Percival		# Create any necessary directories first
2918cd1ab228SColin Percival		grep -vE '^/boot/' $1/INDEX-NEW |
2919cd1ab228SColin Percival		    grep -E '^[^|]+\|d\|' > INDEX-NEW
2920cd1ab228SColin Percival		install_from_index INDEX-NEW || return 1
2921cd1ab228SColin Percival
2922722d81b5SBrooks Davis		# Install new runtime linker
2923722d81b5SBrooks Davis		grep -vE '^/boot/' $1/INDEX-NEW |
2924722d81b5SBrooks Davis		    grep -vE '^[^|]+\|d\|' |
2925722d81b5SBrooks Davis		    grep -E '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' > INDEX-NEW
2926722d81b5SBrooks Davis		install_from_index INDEX-NEW || return 1
2927722d81b5SBrooks Davis
2928db6b0a61SColin Percival		# Install new shared libraries next
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 -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-NEW
2933db6b0a61SColin Percival		install_from_index INDEX-NEW || return 1
2934db6b0a61SColin Percival
2935db6b0a61SColin Percival		# Deal with everything else
2936db6b0a61SColin Percival		grep -vE '^/boot/' $1/INDEX-OLD |
2937cd1ab228SColin Percival		    grep -vE '^[^|]+\|d\|' |
2938722d81b5SBrooks Davis		    grep -vE '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' |
29399546dbd1SColin Percival		    grep -vE '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-OLD
2940db6b0a61SColin Percival		grep -vE '^/boot/' $1/INDEX-NEW |
2941cd1ab228SColin Percival		    grep -vE '^[^|]+\|d\|' |
2942722d81b5SBrooks Davis		    grep -vE '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' |
29439546dbd1SColin Percival		    grep -vE '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-NEW
2944db6b0a61SColin Percival		install_from_index INDEX-NEW || return 1
2945db6b0a61SColin Percival		install_delete INDEX-OLD INDEX-NEW || return 1
2946db6b0a61SColin Percival
29479b659110SEd Maste		# Rebuild generated pwd files.
2948c4a0c62cSThomas Quinot		if [ ${BASEDIR}/etc/master.passwd -nt ${BASEDIR}/etc/spwd.db ] ||
29499b659110SEd Maste		    [ ${BASEDIR}/etc/master.passwd -nt ${BASEDIR}/etc/pwd.db ] ||
29509b659110SEd Maste		    [ ${BASEDIR}/etc/master.passwd -nt ${BASEDIR}/etc/passwd ]; then
29519b659110SEd Maste			pwd_mkdb -d ${BASEDIR}/etc -p ${BASEDIR}/etc/master.passwd
2952db6b0a61SColin Percival		fi
2953db6b0a61SColin Percival
2954db6b0a61SColin Percival		# Rebuild /etc/login.conf.db if necessary.
2955c4a0c62cSThomas Quinot		if [ ${BASEDIR}/etc/login.conf -nt ${BASEDIR}/etc/login.conf.db ]; then
2956c4a0c62cSThomas Quinot			cap_mkdb ${BASEDIR}/etc/login.conf
2957db6b0a61SColin Percival		fi
2958db6b0a61SColin Percival
29599c812c8dSEd Maste		# Rebuild man page databases, if necessary.
29609c812c8dSEd Maste		for D in /usr/share/man /usr/share/openssl/man; do
29619c812c8dSEd Maste			if [ ! -d ${BASEDIR}/$D ]; then
29629c812c8dSEd Maste				continue
29639c812c8dSEd Maste			fi
29649c812c8dSEd Maste			if [ -z "$(find ${BASEDIR}/$D -type f -newer ${BASEDIR}/$D/mandoc.db)" ]; then
29659c812c8dSEd Maste				continue;
29669c812c8dSEd Maste			fi
29679c812c8dSEd Maste			makewhatis ${BASEDIR}/$D
29689c812c8dSEd Maste		done
29699c812c8dSEd Maste
2970db6b0a61SColin Percival		# We've finished installing the world and deleting old files
2971db6b0a61SColin Percival		# which are not shared libraries.
2972db6b0a61SColin Percival		touch $1/worlddone
2973db6b0a61SColin Percival
2974db6b0a61SColin Percival		# Do we need to ask the user to portupgrade now?
2975db6b0a61SColin Percival		grep -vE '^/boot/' $1/INDEX-NEW |
29769546dbd1SColin Percival		    grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' |
2977db6b0a61SColin Percival		    cut -f 1 -d '|' |
2978db6b0a61SColin Percival		    sort > newfiles
2979db6b0a61SColin Percival		if grep -vE '^/boot/' $1/INDEX-OLD |
29809546dbd1SColin Percival		    grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' |
2981db6b0a61SColin Percival		    cut -f 1 -d '|' |
2982db6b0a61SColin Percival		    sort |
2983db6b0a61SColin Percival		    join -v 1 - newfiles |
2984db6b0a61SColin Percival		    grep -q .; then
2985db6b0a61SColin Percival			cat <<-EOF
2986db6b0a61SColin Percival
2987db6b0a61SColin PercivalCompleting this upgrade requires removing old shared object files.
2988db6b0a61SColin PercivalPlease rebuild all installed 3rd party software (e.g., programs
2989db6b0a61SColin Percivalinstalled from the ports tree) and then run "$0 install"
2990db6b0a61SColin Percivalagain to finish installing updates.
2991db6b0a61SColin Percival			EOF
2992db6b0a61SColin Percival			rm newfiles
2993db6b0a61SColin Percival			exit 0
2994db6b0a61SColin Percival		fi
2995db6b0a61SColin Percival		rm newfiles
2996db6b0a61SColin Percival	fi
2997db6b0a61SColin Percival
2998db6b0a61SColin Percival	# Remove old shared libraries
2999db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-NEW |
3000cd1ab228SColin Percival	    grep -vE '^[^|]+\|d\|' |
30019546dbd1SColin Percival	    grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-NEW
3002db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
3003cd1ab228SColin Percival	    grep -vE '^[^|]+\|d\|' |
30049546dbd1SColin Percival	    grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-OLD
3005db6b0a61SColin Percival	install_delete INDEX-OLD INDEX-NEW || return 1
3006db6b0a61SColin Percival
3007cd1ab228SColin Percival	# Remove old directories
3008ebc1d19cSColin Percival	grep -vE '^/boot/' $1/INDEX-NEW |
3009ebc1d19cSColin Percival	    grep -E '^[^|]+\|d\|' > INDEX-NEW
3010cd1ab228SColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
3011cd1ab228SColin Percival	    grep -E '^[^|]+\|d\|' > INDEX-OLD
3012cd1ab228SColin Percival	install_delete INDEX-OLD INDEX-NEW || return 1
3013cd1ab228SColin Percival
3014db6b0a61SColin Percival	# Remove temporary files
3015db6b0a61SColin Percival	rm INDEX-OLD INDEX-NEW
301648ffe56aSColin Percival}
301748ffe56aSColin Percival
301848ffe56aSColin Percival# Rearrange bits to allow the installed updates to be rolled back
301948ffe56aSColin Percivalinstall_setup_rollback () {
3020db6b0a61SColin Percival	# Remove the "reboot after installing kernel", "kernel updated", and
3021db6b0a61SColin Percival	# "finished installing the world" flags if present -- they are
3022db6b0a61SColin Percival	# irrelevant when rolling back updates.
3023db6b0a61SColin Percival	if [ -f ${BDHASH}-install/kernelfirst ]; then
3024db6b0a61SColin Percival		rm ${BDHASH}-install/kernelfirst
3025db6b0a61SColin Percival		rm ${BDHASH}-install/kerneldone
3026db6b0a61SColin Percival	fi
3027db6b0a61SColin Percival	if [ -f ${BDHASH}-install/worlddone ]; then
3028db6b0a61SColin Percival		rm ${BDHASH}-install/worlddone
3029db6b0a61SColin Percival	fi
3030db6b0a61SColin Percival
303148ffe56aSColin Percival	if [ -L ${BDHASH}-rollback ]; then
303248ffe56aSColin Percival		mv ${BDHASH}-rollback ${BDHASH}-install/rollback
303348ffe56aSColin Percival	fi
303448ffe56aSColin Percival
303548ffe56aSColin Percival	mv ${BDHASH}-install ${BDHASH}-rollback
303648ffe56aSColin Percival}
303748ffe56aSColin Percival
303848ffe56aSColin Percival# Actually install updates
303948ffe56aSColin Percivalinstall_run () {
304048ffe56aSColin Percival	echo -n "Installing updates..."
304148ffe56aSColin Percival
304248ffe56aSColin Percival	# Make sure we have all the files we should have
304348ffe56aSColin Percival	install_verify ${BDHASH}-install/INDEX-OLD	\
304448ffe56aSColin Percival	    ${BDHASH}-install/INDEX-NEW || return 1
304548ffe56aSColin Percival
304648ffe56aSColin Percival	# Remove system immutable flag from files
304748ffe56aSColin Percival	install_unschg ${BDHASH}-install/INDEX-OLD	\
304848ffe56aSColin Percival	    ${BDHASH}-install/INDEX-NEW || return 1
304948ffe56aSColin Percival
3050db6b0a61SColin Percival	# Install new files, delete old files, and update linker.hints
3051db6b0a61SColin Percival	install_files ${BDHASH}-install || return 1
305248ffe56aSColin Percival
305348ffe56aSColin Percival	# Rearrange bits to allow the installed updates to be rolled back
305448ffe56aSColin Percival	install_setup_rollback
305548ffe56aSColin Percival
305648ffe56aSColin Percival	echo " done."
305748ffe56aSColin Percival}
305848ffe56aSColin Percival
305948ffe56aSColin Percival# Rearrange bits to allow the previous set of updates to be rolled back next.
306048ffe56aSColin Percivalrollback_setup_rollback () {
306148ffe56aSColin Percival	if [ -L ${BDHASH}-rollback/rollback ]; then
306248ffe56aSColin Percival		mv ${BDHASH}-rollback/rollback rollback-tmp
306348ffe56aSColin Percival		rm -r ${BDHASH}-rollback/
306448ffe56aSColin Percival		rm ${BDHASH}-rollback
306548ffe56aSColin Percival		mv rollback-tmp ${BDHASH}-rollback
306648ffe56aSColin Percival	else
306748ffe56aSColin Percival		rm -r ${BDHASH}-rollback/
306848ffe56aSColin Percival		rm ${BDHASH}-rollback
306948ffe56aSColin Percival	fi
307048ffe56aSColin Percival}
307148ffe56aSColin Percival
3072db6b0a61SColin Percival# Install old files, delete new files, and update linker.hints
3073db6b0a61SColin Percivalrollback_files () {
30741ec4fb3aSColin Percival	# Install old shared library files which don't have the same path as
30751ec4fb3aSColin Percival	# a new shared library file.
30761ec4fb3aSColin Percival	grep -vE '^/boot/' $1/INDEX-NEW |
3077fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' |
30781ec4fb3aSColin Percival	    cut -f 1 -d '|' |
30791ec4fb3aSColin Percival	    sort > INDEX-NEW.libs.flist
3080db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
3081fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' |
30821ec4fb3aSColin Percival	    sort -k 1,1 -t '|' - |
30831ec4fb3aSColin Percival	    join -t '|' -v 1 - INDEX-NEW.libs.flist > INDEX-OLD
3084db6b0a61SColin Percival	install_from_index INDEX-OLD || return 1
3085db6b0a61SColin Percival
3086db6b0a61SColin Percival	# Deal with files which are neither kernel nor shared library
3087db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
3088fd0963d1SColin Percival	    grep -vE '/lib/.*\.so\.[0-9]+\|' > INDEX-OLD
3089db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-NEW |
3090fd0963d1SColin Percival	    grep -vE '/lib/.*\.so\.[0-9]+\|' > INDEX-NEW
3091db6b0a61SColin Percival	install_from_index INDEX-OLD || return 1
3092db6b0a61SColin Percival	install_delete INDEX-NEW INDEX-OLD || return 1
3093db6b0a61SColin Percival
30941ec4fb3aSColin Percival	# Install any old shared library files which we didn't install above.
30951ec4fb3aSColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
3096fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' |
30971ec4fb3aSColin Percival	    sort -k 1,1 -t '|' - |
30981ec4fb3aSColin Percival	    join -t '|' - INDEX-NEW.libs.flist > INDEX-OLD
30991ec4fb3aSColin Percival	install_from_index INDEX-OLD || return 1
31001ec4fb3aSColin Percival
3101db6b0a61SColin Percival	# Delete unneeded shared library files
3102db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
3103fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' > INDEX-OLD
3104db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-NEW |
3105fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' > INDEX-NEW
3106db6b0a61SColin Percival	install_delete INDEX-NEW INDEX-OLD || return 1
3107db6b0a61SColin Percival
3108db6b0a61SColin Percival	# Deal with kernel files
3109db6b0a61SColin Percival	grep -E '^/boot/' $1/INDEX-OLD > INDEX-OLD
3110db6b0a61SColin Percival	grep -E '^/boot/' $1/INDEX-NEW > INDEX-NEW
3111db6b0a61SColin Percival	install_from_index INDEX-OLD || return 1
3112db6b0a61SColin Percival	install_delete INDEX-NEW INDEX-OLD || return 1
3113db6b0a61SColin Percival	if [ -s INDEX-OLD -o -s INDEX-NEW ]; then
3114db6b0a61SColin Percival		kldxref -R /boot/ 2>/dev/null
3115db6b0a61SColin Percival	fi
3116db6b0a61SColin Percival
3117db6b0a61SColin Percival	# Remove temporary files
31180e0d8d5aSColin Percival	rm INDEX-OLD INDEX-NEW INDEX-NEW.libs.flist
3119db6b0a61SColin Percival}
3120db6b0a61SColin Percival
312148ffe56aSColin Percival# Actually rollback updates
312248ffe56aSColin Percivalrollback_run () {
312348ffe56aSColin Percival	echo -n "Uninstalling updates..."
312448ffe56aSColin Percival
312548ffe56aSColin Percival	# If there are updates waiting to be installed, remove them; we
312648ffe56aSColin Percival	# want the user to re-run 'fetch' after rolling back updates.
312748ffe56aSColin Percival	if [ -L ${BDHASH}-install ]; then
312848ffe56aSColin Percival		rm -r ${BDHASH}-install/
312948ffe56aSColin Percival		rm ${BDHASH}-install
313048ffe56aSColin Percival	fi
313148ffe56aSColin Percival
313248ffe56aSColin Percival	# Make sure we have all the files we should have
313348ffe56aSColin Percival	install_verify ${BDHASH}-rollback/INDEX-NEW	\
313448ffe56aSColin Percival	    ${BDHASH}-rollback/INDEX-OLD || return 1
313548ffe56aSColin Percival
313648ffe56aSColin Percival	# Remove system immutable flag from files
313748ffe56aSColin Percival	install_unschg ${BDHASH}-rollback/INDEX-NEW	\
313848ffe56aSColin Percival	    ${BDHASH}-rollback/INDEX-OLD || return 1
313948ffe56aSColin Percival
3140db6b0a61SColin Percival	# Install old files, delete new files, and update linker.hints
3141db6b0a61SColin Percival	rollback_files ${BDHASH}-rollback || return 1
314248ffe56aSColin Percival
314348ffe56aSColin Percival	# Remove the rollback directory and the symlink pointing to it; and
314448ffe56aSColin Percival	# rearrange bits to allow the previous set of updates to be rolled
314548ffe56aSColin Percival	# back next.
314648ffe56aSColin Percival	rollback_setup_rollback
314748ffe56aSColin Percival
314848ffe56aSColin Percival	echo " done."
314948ffe56aSColin Percival}
315048ffe56aSColin Percival
315108e23beeSColin Percival# Compare INDEX-ALL and INDEX-PRESENT and print warnings about differences.
315208e23beeSColin PercivalIDS_compare () {
3153bb10a826SColin Percival	# Get all the lines which mismatch in something other than file
3154bb10a826SColin Percival	# flags.  We ignore file flags because sysinstall doesn't seem to
3155bb10a826SColin Percival	# set them when it installs FreeBSD; warning about these adds a
3156bb10a826SColin Percival	# very large amount of noise.
3157bb10a826SColin Percival	cut -f 1-5,7-8 -d '|' $1 > $1.noflags
3158bb10a826SColin Percival	sort -k 1,1 -t '|' $1.noflags > $1.sorted
3159bb10a826SColin Percival	cut -f 1-5,7-8 -d '|' $2 |
3160bb10a826SColin Percival	    comm -13 $1.noflags - |
3161bb10a826SColin Percival	    fgrep -v '|-|||||' |
316208e23beeSColin Percival	    sort -k 1,1 -t '|' |
316308e23beeSColin Percival	    join -t '|' $1.sorted - > INDEX-NOTMATCHING
316408e23beeSColin Percival
316508e23beeSColin Percival	# Ignore files which match IDSIGNOREPATHS.
316608e23beeSColin Percival	for X in ${IDSIGNOREPATHS}; do
316708e23beeSColin Percival		grep -E "^${X}" INDEX-NOTMATCHING
316808e23beeSColin Percival	done |
316908e23beeSColin Percival	    sort -u |
317008e23beeSColin Percival	    comm -13 - INDEX-NOTMATCHING > INDEX-NOTMATCHING.tmp
317108e23beeSColin Percival	mv INDEX-NOTMATCHING.tmp INDEX-NOTMATCHING
317208e23beeSColin Percival
317308e23beeSColin Percival	# Go through the lines and print warnings.
3174aa60062eSColin Percival	local IFS='|'
3175aa60062eSColin Percival	while read FPATH TYPE OWNER GROUP PERM HASH LINK P_TYPE P_OWNER P_GROUP P_PERM P_HASH P_LINK; do
317608e23beeSColin Percival		# Warn about different object types.
317708e23beeSColin Percival		if ! [ "${TYPE}" = "${P_TYPE}" ]; then
317808e23beeSColin Percival			echo -n "${FPATH} is a "
317908e23beeSColin Percival			case "${P_TYPE}" in
318008e23beeSColin Percival			f)	echo -n "regular file, "
318108e23beeSColin Percival				;;
318208e23beeSColin Percival			d)	echo -n "directory, "
318308e23beeSColin Percival				;;
318408e23beeSColin Percival			L)	echo -n "symlink, "
318508e23beeSColin Percival				;;
318608e23beeSColin Percival			esac
318708e23beeSColin Percival			echo -n "but should be a "
318808e23beeSColin Percival			case "${TYPE}" in
318908e23beeSColin Percival			f)	echo -n "regular file."
319008e23beeSColin Percival				;;
319108e23beeSColin Percival			d)	echo -n "directory."
319208e23beeSColin Percival				;;
319308e23beeSColin Percival			L)	echo -n "symlink."
319408e23beeSColin Percival				;;
319508e23beeSColin Percival			esac
319608e23beeSColin Percival			echo
319708e23beeSColin Percival
319808e23beeSColin Percival			# Skip other tests, since they don't make sense if
319908e23beeSColin Percival			# we're comparing different object types.
320008e23beeSColin Percival			continue
320108e23beeSColin Percival		fi
320208e23beeSColin Percival
320308e23beeSColin Percival		# Warn about different owners.
320408e23beeSColin Percival		if ! [ "${OWNER}" = "${P_OWNER}" ]; then
320508e23beeSColin Percival			echo -n "${FPATH} is owned by user id ${P_OWNER}, "
320608e23beeSColin Percival			echo "but should be owned by user id ${OWNER}."
320708e23beeSColin Percival		fi
320808e23beeSColin Percival
320908e23beeSColin Percival		# Warn about different groups.
321008e23beeSColin Percival		if ! [ "${GROUP}" = "${P_GROUP}" ]; then
321108e23beeSColin Percival			echo -n "${FPATH} is owned by group id ${P_GROUP}, "
321208e23beeSColin Percival			echo "but should be owned by group id ${GROUP}."
321308e23beeSColin Percival		fi
321408e23beeSColin Percival
321508e23beeSColin Percival		# Warn about different permissions.  We do not warn about
321608e23beeSColin Percival		# different permissions on symlinks, since some archivers
321708e23beeSColin Percival		# don't extract symlink permissions correctly and they are
321808e23beeSColin Percival		# ignored anyway.
321908e23beeSColin Percival		if ! [ "${PERM}" = "${P_PERM}" ] &&
322008e23beeSColin Percival		    ! [ "${TYPE}" = "L" ]; then
322108e23beeSColin Percival			echo -n "${FPATH} has ${P_PERM} permissions, "
322208e23beeSColin Percival			echo "but should have ${PERM} permissions."
322308e23beeSColin Percival		fi
322408e23beeSColin Percival
322508e23beeSColin Percival		# Warn about different file hashes / symlink destinations.
322608e23beeSColin Percival		if ! [ "${HASH}" = "${P_HASH}" ]; then
322708e23beeSColin Percival			if [ "${TYPE}" = "L" ]; then
322808e23beeSColin Percival				echo -n "${FPATH} is a symlink to ${P_HASH}, "
322908e23beeSColin Percival				echo "but should be a symlink to ${HASH}."
323008e23beeSColin Percival			fi
323108e23beeSColin Percival			if [ "${TYPE}" = "f" ]; then
323208e23beeSColin Percival				echo -n "${FPATH} has SHA256 hash ${P_HASH}, "
323308e23beeSColin Percival				echo "but should have SHA256 hash ${HASH}."
323408e23beeSColin Percival			fi
323508e23beeSColin Percival		fi
323608e23beeSColin Percival
323708e23beeSColin Percival		# We don't warn about different hard links, since some
323808e23beeSColin Percival		# some archivers break hard links, and as long as the
323908e23beeSColin Percival		# underlying data is correct they really don't matter.
324008e23beeSColin Percival	done < INDEX-NOTMATCHING
324108e23beeSColin Percival
324208e23beeSColin Percival	# Clean up
3243bb10a826SColin Percival	rm $1 $1.noflags $1.sorted $2 INDEX-NOTMATCHING
324408e23beeSColin Percival}
324508e23beeSColin Percival
324608e23beeSColin Percival# Do the work involved in comparing the system to a "known good" index
324708e23beeSColin PercivalIDS_run () {
324808e23beeSColin Percival	workdir_init || return 1
324908e23beeSColin Percival
325008e23beeSColin Percival	# Prepare the mirror list.
325108e23beeSColin Percival	fetch_pick_server_init && fetch_pick_server
325208e23beeSColin Percival
325308e23beeSColin Percival	# Try to fetch the public key until we run out of servers.
325408e23beeSColin Percival	while ! fetch_key; do
325508e23beeSColin Percival		fetch_pick_server || return 1
325608e23beeSColin Percival	done
325708e23beeSColin Percival
325808e23beeSColin Percival	# Try to fetch the metadata index signature ("tag") until we run
325908e23beeSColin Percival	# out of available servers; and sanity check the downloaded tag.
326008e23beeSColin Percival	while ! fetch_tag; do
326108e23beeSColin Percival		fetch_pick_server || return 1
326208e23beeSColin Percival	done
326308e23beeSColin Percival	fetch_tagsanity || return 1
326408e23beeSColin Percival
326508e23beeSColin Percival	# Fetch INDEX-OLD and INDEX-ALL.
326608e23beeSColin Percival	fetch_metadata INDEX-OLD INDEX-ALL || return 1
326708e23beeSColin Percival
326808e23beeSColin Percival	# Generate filtered INDEX-OLD and INDEX-ALL files containing only
326908e23beeSColin Percival	# the components we want and without anything marked as "Ignore".
327008e23beeSColin Percival	fetch_filter_metadata INDEX-OLD || return 1
327108e23beeSColin Percival	fetch_filter_metadata INDEX-ALL || return 1
327208e23beeSColin Percival
327308e23beeSColin Percival	# Merge the INDEX-OLD and INDEX-ALL files into INDEX-ALL.
327408e23beeSColin Percival	sort INDEX-OLD INDEX-ALL > INDEX-ALL.tmp
327508e23beeSColin Percival	mv INDEX-ALL.tmp INDEX-ALL
327608e23beeSColin Percival	rm INDEX-OLD
327708e23beeSColin Percival
327808e23beeSColin Percival	# Translate /boot/${KERNCONF} to ${KERNELDIR}
327908e23beeSColin Percival	fetch_filter_kernel_names INDEX-ALL ${KERNCONF}
328008e23beeSColin Percival
328108e23beeSColin Percival	# Inspect the system and generate an INDEX-PRESENT file.
328208e23beeSColin Percival	fetch_inspect_system INDEX-ALL INDEX-PRESENT /dev/null || return 1
328308e23beeSColin Percival
328408e23beeSColin Percival	# Compare INDEX-ALL and INDEX-PRESENT and print warnings about any
328508e23beeSColin Percival	# differences.
328608e23beeSColin Percival	IDS_compare INDEX-ALL INDEX-PRESENT
328708e23beeSColin Percival}
328808e23beeSColin Percival
328948ffe56aSColin Percival#### Main functions -- call parameter-handling and core functions
329048ffe56aSColin Percival
329148ffe56aSColin Percival# Using the command line, configuration file, and defaults,
329248ffe56aSColin Percival# set all the parameters which are needed later.
329348ffe56aSColin Percivalget_params () {
329448ffe56aSColin Percival	init_params
329548ffe56aSColin Percival	parse_cmdline $@
329648ffe56aSColin Percival	parse_conffile
329748ffe56aSColin Percival	default_params
329812294db4SMichael Gmelin	finalize_components_config ${COMPONENTS}
329948ffe56aSColin Percival}
330048ffe56aSColin Percival
330148ffe56aSColin Percival# Fetch command.  Make sure that we're being called
330248ffe56aSColin Percival# interactively, then run fetch_check_params and fetch_run
330348ffe56aSColin Percivalcmd_fetch () {
33048bf2dcceSAllan Jude	if [ ! -t 0 -a $NOTTYOK -eq 0 ]; then
330548ffe56aSColin Percival		echo -n "`basename $0` fetch should not "
330648ffe56aSColin Percival		echo "be run non-interactively."
330748ffe56aSColin Percival		echo "Run `basename $0` cron instead."
330848ffe56aSColin Percival		exit 1
330948ffe56aSColin Percival	fi
331048ffe56aSColin Percival	fetch_check_params
331148ffe56aSColin Percival	fetch_run || exit 1
331233bd05c3SGuangyuan Yang	ISFETCHED=1
331348ffe56aSColin Percival}
331448ffe56aSColin Percival
331548ffe56aSColin Percival# Cron command.  Make sure the parameters are sensible; wait
331648ffe56aSColin Percival# rand(3600) seconds; then fetch updates.  While fetching updates,
331748ffe56aSColin Percival# send output to a temporary file; only print that file if the
331848ffe56aSColin Percival# fetching failed.
331948ffe56aSColin Percivalcmd_cron () {
332048ffe56aSColin Percival	fetch_check_params
332148ffe56aSColin Percival	sleep `jot -r 1 0 3600`
332248ffe56aSColin Percival
332348ffe56aSColin Percival	TMPFILE=`mktemp /tmp/freebsd-update.XXXXXX` || exit 1
332448ffe56aSColin Percival	if ! fetch_run >> ${TMPFILE} ||
332548ffe56aSColin Percival	    ! grep -q "No updates needed" ${TMPFILE} ||
332648ffe56aSColin Percival	    [ ${VERBOSELEVEL} = "debug" ]; then
332748ffe56aSColin Percival		mail -s "`hostname` security updates" ${MAILTO} < ${TMPFILE}
332848ffe56aSColin Percival	fi
332948ffe56aSColin Percival
333048ffe56aSColin Percival	rm ${TMPFILE}
333148ffe56aSColin Percival}
333248ffe56aSColin Percival
3333db6b0a61SColin Percival# Fetch files for upgrading to a new release.
3334db6b0a61SColin Percivalcmd_upgrade () {
3335db6b0a61SColin Percival	upgrade_check_params
3336db6b0a61SColin Percival	upgrade_run || exit 1
3337db6b0a61SColin Percival}
3338db6b0a61SColin Percival
3339*8cfda118SMichael Gmelin# Check if there are fetched updates ready to install
3340*8cfda118SMichael Gmelincmd_updatesready () {
3341*8cfda118SMichael Gmelin	# Construct a unique name from ${BASEDIR}
3342*8cfda118SMichael Gmelin	BDHASH=`echo ${BASEDIR} | sha256 -q`
3343*8cfda118SMichael Gmelin
3344*8cfda118SMichael Gmelin	# Check that we have updates ready to install
3345*8cfda118SMichael Gmelin	if ! [ -L ${BDHASH}-install ]; then
3346*8cfda118SMichael Gmelin		echo "No updates are available to install."
3347*8cfda118SMichael Gmelin		exit 2
3348*8cfda118SMichael Gmelin	fi
3349*8cfda118SMichael Gmelin
3350*8cfda118SMichael Gmelin	echo "There are updates available to install."
3351*8cfda118SMichael Gmelin	echo "Run '$0 install' to proceed."
3352*8cfda118SMichael Gmelin}
3353*8cfda118SMichael Gmelin
335448ffe56aSColin Percival# Install downloaded updates.
335548ffe56aSColin Percivalcmd_install () {
335648ffe56aSColin Percival	install_check_params
335748ffe56aSColin Percival	install_run || exit 1
335848ffe56aSColin Percival}
335948ffe56aSColin Percival
336048ffe56aSColin Percival# Rollback most recently installed updates.
336148ffe56aSColin Percivalcmd_rollback () {
336248ffe56aSColin Percival	rollback_check_params
336348ffe56aSColin Percival	rollback_run || exit 1
336448ffe56aSColin Percival}
336548ffe56aSColin Percival
336608e23beeSColin Percival# Compare system against a "known good" index.
336708e23beeSColin Percivalcmd_IDS () {
336808e23beeSColin Percival	IDS_check_params
336908e23beeSColin Percival	IDS_run || exit 1
337008e23beeSColin Percival}
337108e23beeSColin Percival
3372*8cfda118SMichael Gmelin# Output configuration.
3373*8cfda118SMichael Gmelincmd_showconfig () {
3374*8cfda118SMichael Gmelin	for X in ${CONFIGOPTIONS}; do
3375*8cfda118SMichael Gmelin		echo $X=$(eval echo \$${X})
3376*8cfda118SMichael Gmelin	done
3377*8cfda118SMichael Gmelin}
3378*8cfda118SMichael Gmelin
337948ffe56aSColin Percival#### Entry point
338048ffe56aSColin Percival
338148ffe56aSColin Percival# Make sure we find utilities from the base system
338248ffe56aSColin Percivalexport PATH=/sbin:/bin:/usr/sbin:/usr/bin:${PATH}
338348ffe56aSColin Percival
33849c990fb2SGordon Tetlow# Set a pager if the user doesn't
33859c990fb2SGordon Tetlowif [ -z "$PAGER" ]; then
338647cc9ee1SAlan Somers	PAGER=/usr/bin/less
33879c990fb2SGordon Tetlowfi
33889c990fb2SGordon Tetlow
3389f2890dbdSColin Percival# Set LC_ALL in order to avoid problems with character ranges like [A-Z].
3390f2890dbdSColin Percivalexport LC_ALL=C
3391f2890dbdSColin Percival
339248ffe56aSColin Percivalget_params $@
339348ffe56aSColin Percivalfor COMMAND in ${COMMANDS}; do
339448ffe56aSColin Percival	cmd_${COMMAND}
339548ffe56aSColin Percivaldone
3396