xref: /freebsd/usr.sbin/freebsd-update/freebsd-update.sh (revision bb10a826c16ae21ab592cccfeaf70eff3fd401fc)
148ffe56aSColin Percival#!/bin/sh
248ffe56aSColin Percival
348ffe56aSColin Percival#-
42328d598SColin Percival# Copyright 2004-2007 Colin Percival
548ffe56aSColin Percival# All rights reserved
648ffe56aSColin Percival#
748ffe56aSColin Percival# Redistribution and use in source and binary forms, with or without
848ffe56aSColin Percival# modification, are permitted providing that the following conditions
948ffe56aSColin Percival# are met:
1048ffe56aSColin Percival# 1. Redistributions of source code must retain the above copyright
1148ffe56aSColin Percival#    notice, this list of conditions and the following disclaimer.
1248ffe56aSColin Percival# 2. Redistributions in binary form must reproduce the above copyright
1348ffe56aSColin Percival#    notice, this list of conditions and the following disclaimer in the
1448ffe56aSColin Percival#    documentation and/or other materials provided with the distribution.
1548ffe56aSColin Percival#
1648ffe56aSColin Percival# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1748ffe56aSColin Percival# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1848ffe56aSColin Percival# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1948ffe56aSColin Percival# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
2048ffe56aSColin Percival# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2148ffe56aSColin Percival# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2248ffe56aSColin Percival# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2348ffe56aSColin Percival# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2448ffe56aSColin Percival# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
2548ffe56aSColin Percival# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2648ffe56aSColin Percival# POSSIBILITY OF SUCH DAMAGE.
2748ffe56aSColin Percival
2848ffe56aSColin Percival# $FreeBSD$
2948ffe56aSColin Percival
3048ffe56aSColin Percival#### Usage function -- called from command-line handling code.
3148ffe56aSColin Percival
3248ffe56aSColin Percival# Usage instructions.  Options not listed:
3348ffe56aSColin Percival# --debug	-- don't filter output from utilities
3448ffe56aSColin Percival# --no-stats	-- don't show progress statistics while fetching files
3548ffe56aSColin Percivalusage () {
3648ffe56aSColin Percival	cat <<EOF
3748ffe56aSColin Percivalusage: `basename $0` [options] command ... [path]
3848ffe56aSColin Percival
3948ffe56aSColin PercivalOptions:
4048ffe56aSColin Percival  -b basedir   -- Operate on a system mounted at basedir
4148ffe56aSColin Percival                  (default: /)
4248ffe56aSColin Percival  -d workdir   -- Store working files in workdir
4348ffe56aSColin Percival                  (default: /var/db/freebsd-update/)
4448ffe56aSColin Percival  -f conffile  -- Read configuration options from conffile
4548ffe56aSColin Percival                  (default: /etc/freebsd-update.conf)
4648ffe56aSColin Percival  -k KEY       -- Trust an RSA key with SHA256 hash of KEY
47db6b0a61SColin Percival  -r release   -- Target for upgrade (e.g., 6.2-RELEASE)
4848ffe56aSColin Percival  -s server    -- Server from which to fetch updates
4948ffe56aSColin Percival                  (default: update.FreeBSD.org)
5048ffe56aSColin Percival  -t address   -- Mail output of cron command, if any, to address
5148ffe56aSColin Percival                  (default: root)
5248ffe56aSColin PercivalCommands:
5348ffe56aSColin Percival  fetch        -- Fetch updates from server
5448ffe56aSColin Percival  cron         -- Sleep rand(3600) seconds, fetch updates, and send an
5548ffe56aSColin Percival                  email if updates were found
56db6b0a61SColin Percival  upgrade      -- Fetch upgrades to FreeBSD version specified via -r option
57db6b0a61SColin Percival  install      -- Install downloaded updates or upgrades
5848ffe56aSColin Percival  rollback     -- Uninstall most recently installed updates
5908e23beeSColin Percival  IDS          -- Compare the system against an index of "known good" files.
6048ffe56aSColin PercivalEOF
6148ffe56aSColin Percival	exit 0
6248ffe56aSColin Percival}
6348ffe56aSColin Percival
6448ffe56aSColin Percival#### Configuration processing functions
6548ffe56aSColin Percival
6648ffe56aSColin Percival#-
6748ffe56aSColin Percival# Configuration options are set in the following order of priority:
6848ffe56aSColin Percival# 1. Command line options
6948ffe56aSColin Percival# 2. Configuration file options
7048ffe56aSColin Percival# 3. Default options
7148ffe56aSColin Percival# In addition, certain options (e.g., IgnorePaths) can be specified multiple
7248ffe56aSColin Percival# times and (as long as these are all in the same place, e.g., inside the
7348ffe56aSColin Percival# configuration file) they will accumulate.  Finally, because the path to the
7448ffe56aSColin Percival# configuration file can be specified at the command line, the entire command
7548ffe56aSColin Percival# line must be processed before we start reading the configuration file.
7648ffe56aSColin Percival#
7748ffe56aSColin Percival# Sound like a mess?  It is.  Here's how we handle this:
7848ffe56aSColin Percival# 1. Initialize CONFFILE and all the options to "".
7948ffe56aSColin Percival# 2. Process the command line.  Throw an error if a non-accumulating option
8048ffe56aSColin Percival#    is specified twice.
8148ffe56aSColin Percival# 3. If CONFFILE is "", set CONFFILE to /etc/freebsd-update.conf .
8248ffe56aSColin Percival# 4. For all the configuration options X, set X_saved to X.
8348ffe56aSColin Percival# 5. Initialize all the options to "".
8448ffe56aSColin Percival# 6. Read CONFFILE line by line, parsing options.
8548ffe56aSColin Percival# 7. For each configuration option X, set X to X_saved iff X_saved is not "".
8648ffe56aSColin Percival# 8. Repeat steps 4-7, except setting options to their default values at (6).
8748ffe56aSColin Percival
8848ffe56aSColin PercivalCONFIGOPTIONS="KEYPRINT WORKDIR SERVERNAME MAILTO ALLOWADD ALLOWDELETE
8948ffe56aSColin Percival    KEEPMODIFIEDMETADATA COMPONENTS IGNOREPATHS UPDATEIFUNMODIFIED
9008e23beeSColin Percival    BASEDIR VERBOSELEVEL TARGETRELEASE STRICTCOMPONENTS MERGECHANGES
9108e23beeSColin Percival    IDSIGNOREPATHS"
9248ffe56aSColin Percival
9348ffe56aSColin Percival# Set all the configuration options to "".
9448ffe56aSColin Percivalnullconfig () {
9548ffe56aSColin Percival	for X in ${CONFIGOPTIONS}; do
9648ffe56aSColin Percival		eval ${X}=""
9748ffe56aSColin Percival	done
9848ffe56aSColin Percival}
9948ffe56aSColin Percival
10048ffe56aSColin Percival# For each configuration option X, set X_saved to X.
10148ffe56aSColin Percivalsaveconfig () {
10248ffe56aSColin Percival	for X in ${CONFIGOPTIONS}; do
10348ffe56aSColin Percival		eval ${X}_saved=\$${X}
10448ffe56aSColin Percival	done
10548ffe56aSColin Percival}
10648ffe56aSColin Percival
10748ffe56aSColin Percival# For each configuration option X, set X to X_saved if X_saved is not "".
10848ffe56aSColin Percivalmergeconfig () {
10948ffe56aSColin Percival	for X in ${CONFIGOPTIONS}; do
11048ffe56aSColin Percival		eval _=\$${X}_saved
11148ffe56aSColin Percival		if ! [ -z "${_}" ]; then
11248ffe56aSColin Percival			eval ${X}=\$${X}_saved
11348ffe56aSColin Percival		fi
11448ffe56aSColin Percival	done
11548ffe56aSColin Percival}
11648ffe56aSColin Percival
11748ffe56aSColin Percival# Set the trusted keyprint.
11848ffe56aSColin Percivalconfig_KeyPrint () {
11948ffe56aSColin Percival	if [ -z ${KEYPRINT} ]; then
12048ffe56aSColin Percival		KEYPRINT=$1
12148ffe56aSColin Percival	else
12248ffe56aSColin Percival		return 1
12348ffe56aSColin Percival	fi
12448ffe56aSColin Percival}
12548ffe56aSColin Percival
12648ffe56aSColin Percival# Set the working directory.
12748ffe56aSColin Percivalconfig_WorkDir () {
12848ffe56aSColin Percival	if [ -z ${WORKDIR} ]; then
12948ffe56aSColin Percival		WORKDIR=$1
13048ffe56aSColin Percival	else
13148ffe56aSColin Percival		return 1
13248ffe56aSColin Percival	fi
13348ffe56aSColin Percival}
13448ffe56aSColin Percival
13548ffe56aSColin Percival# Set the name of the server (pool) from which to fetch updates
13648ffe56aSColin Percivalconfig_ServerName () {
13748ffe56aSColin Percival	if [ -z ${SERVERNAME} ]; then
13848ffe56aSColin Percival		SERVERNAME=$1
13948ffe56aSColin Percival	else
14048ffe56aSColin Percival		return 1
14148ffe56aSColin Percival	fi
14248ffe56aSColin Percival}
14348ffe56aSColin Percival
14448ffe56aSColin Percival# Set the address to which 'cron' output will be mailed.
14548ffe56aSColin Percivalconfig_MailTo () {
14648ffe56aSColin Percival	if [ -z ${MAILTO} ]; then
14748ffe56aSColin Percival		MAILTO=$1
14848ffe56aSColin Percival	else
14948ffe56aSColin Percival		return 1
15048ffe56aSColin Percival	fi
15148ffe56aSColin Percival}
15248ffe56aSColin Percival
15348ffe56aSColin Percival# Set whether FreeBSD Update is allowed to add files (or directories, or
15448ffe56aSColin Percival# symlinks) which did not previously exist.
15548ffe56aSColin Percivalconfig_AllowAdd () {
15648ffe56aSColin Percival	if [ -z ${ALLOWADD} ]; then
15748ffe56aSColin Percival		case $1 in
15848ffe56aSColin Percival		[Yy][Ee][Ss])
15948ffe56aSColin Percival			ALLOWADD=yes
16048ffe56aSColin Percival			;;
16148ffe56aSColin Percival		[Nn][Oo])
16248ffe56aSColin Percival			ALLOWADD=no
16348ffe56aSColin Percival			;;
16448ffe56aSColin Percival		*)
16548ffe56aSColin Percival			return 1
16648ffe56aSColin Percival			;;
16748ffe56aSColin Percival		esac
16848ffe56aSColin Percival	else
16948ffe56aSColin Percival		return 1
17048ffe56aSColin Percival	fi
17148ffe56aSColin Percival}
17248ffe56aSColin Percival
17348ffe56aSColin Percival# Set whether FreeBSD Update is allowed to remove files/directories/symlinks.
17448ffe56aSColin Percivalconfig_AllowDelete () {
17548ffe56aSColin Percival	if [ -z ${ALLOWDELETE} ]; then
17648ffe56aSColin Percival		case $1 in
17748ffe56aSColin Percival		[Yy][Ee][Ss])
17848ffe56aSColin Percival			ALLOWDELETE=yes
17948ffe56aSColin Percival			;;
18048ffe56aSColin Percival		[Nn][Oo])
18148ffe56aSColin Percival			ALLOWDELETE=no
18248ffe56aSColin Percival			;;
18348ffe56aSColin Percival		*)
18448ffe56aSColin Percival			return 1
18548ffe56aSColin Percival			;;
18648ffe56aSColin Percival		esac
18748ffe56aSColin Percival	else
18848ffe56aSColin Percival		return 1
18948ffe56aSColin Percival	fi
19048ffe56aSColin Percival}
19148ffe56aSColin Percival
19248ffe56aSColin Percival# Set whether FreeBSD Update should keep existing inode ownership,
19348ffe56aSColin Percival# permissions, and flags, in the event that they have been modified locally
19448ffe56aSColin Percival# after the release.
19548ffe56aSColin Percivalconfig_KeepModifiedMetadata () {
19648ffe56aSColin Percival	if [ -z ${KEEPMODIFIEDMETADATA} ]; then
19748ffe56aSColin Percival		case $1 in
19848ffe56aSColin Percival		[Yy][Ee][Ss])
19948ffe56aSColin Percival			KEEPMODIFIEDMETADATA=yes
20048ffe56aSColin Percival			;;
20148ffe56aSColin Percival		[Nn][Oo])
20248ffe56aSColin Percival			KEEPMODIFIEDMETADATA=no
20348ffe56aSColin Percival			;;
20448ffe56aSColin Percival		*)
20548ffe56aSColin Percival			return 1
20648ffe56aSColin Percival			;;
20748ffe56aSColin Percival		esac
20848ffe56aSColin Percival	else
20948ffe56aSColin Percival		return 1
21048ffe56aSColin Percival	fi
21148ffe56aSColin Percival}
21248ffe56aSColin Percival
21348ffe56aSColin Percival# Add to the list of components which should be kept updated.
21448ffe56aSColin Percivalconfig_Components () {
21548ffe56aSColin Percival	for C in $@; do
21648ffe56aSColin Percival		COMPONENTS="${COMPONENTS} ${C}"
21748ffe56aSColin Percival	done
21848ffe56aSColin Percival}
21948ffe56aSColin Percival
22048ffe56aSColin Percival# Add to the list of paths under which updates will be ignored.
22148ffe56aSColin Percivalconfig_IgnorePaths () {
22248ffe56aSColin Percival	for C in $@; do
22348ffe56aSColin Percival		IGNOREPATHS="${IGNOREPATHS} ${C}"
22448ffe56aSColin Percival	done
22548ffe56aSColin Percival}
22648ffe56aSColin Percival
22708e23beeSColin Percival# Add to the list of paths which IDS should ignore.
22808e23beeSColin Percivalconfig_IDSIgnorePaths () {
22908e23beeSColin Percival	for C in $@; do
23008e23beeSColin Percival		IDSIGNOREPATHS="${IDSIGNOREPATHS} ${C}"
23108e23beeSColin Percival	done
23208e23beeSColin Percival}
23308e23beeSColin Percival
23448ffe56aSColin Percival# Add to the list of paths within which updates will be performed only if the
23548ffe56aSColin Percival# file on disk has not been modified locally.
23648ffe56aSColin Percivalconfig_UpdateIfUnmodified () {
23748ffe56aSColin Percival	for C in $@; do
23848ffe56aSColin Percival		UPDATEIFUNMODIFIED="${UPDATEIFUNMODIFIED} ${C}"
23948ffe56aSColin Percival	done
24048ffe56aSColin Percival}
24148ffe56aSColin Percival
242db6b0a61SColin Percival# Add to the list of paths within which updates to text files will be merged
243db6b0a61SColin Percival# instead of overwritten.
244db6b0a61SColin Percivalconfig_MergeChanges () {
245db6b0a61SColin Percival	for C in $@; do
246db6b0a61SColin Percival		MERGECHANGES="${MERGECHANGES} ${C}"
247db6b0a61SColin Percival	done
248db6b0a61SColin Percival}
249db6b0a61SColin Percival
25048ffe56aSColin Percival# Work on a FreeBSD installation mounted under $1
25148ffe56aSColin Percivalconfig_BaseDir () {
25248ffe56aSColin Percival	if [ -z ${BASEDIR} ]; then
25348ffe56aSColin Percival		BASEDIR=$1
25448ffe56aSColin Percival	else
25548ffe56aSColin Percival		return 1
25648ffe56aSColin Percival	fi
25748ffe56aSColin Percival}
25848ffe56aSColin Percival
259db6b0a61SColin Percival# When fetching upgrades, should we assume the user wants exactly the
260db6b0a61SColin Percival# components listed in COMPONENTS, rather than trying to guess based on
261db6b0a61SColin Percival# what's currently installed?
262db6b0a61SColin Percivalconfig_StrictComponents () {
263db6b0a61SColin Percival	if [ -z ${STRICTCOMPONENTS} ]; then
264db6b0a61SColin Percival		case $1 in
265db6b0a61SColin Percival		[Yy][Ee][Ss])
266db6b0a61SColin Percival			STRICTCOMPONENTS=yes
267db6b0a61SColin Percival			;;
268db6b0a61SColin Percival		[Nn][Oo])
269db6b0a61SColin Percival			STRICTCOMPONENTS=no
270db6b0a61SColin Percival			;;
271db6b0a61SColin Percival		*)
272db6b0a61SColin Percival			return 1
273db6b0a61SColin Percival			;;
274db6b0a61SColin Percival		esac
275db6b0a61SColin Percival	else
276db6b0a61SColin Percival		return 1
277db6b0a61SColin Percival	fi
278db6b0a61SColin Percival}
279db6b0a61SColin Percival
280db6b0a61SColin Percival# Upgrade to FreeBSD $1
281db6b0a61SColin Percivalconfig_TargetRelease () {
282db6b0a61SColin Percival	if [ -z ${TARGETRELEASE} ]; then
283db6b0a61SColin Percival		TARGETRELEASE=$1
284db6b0a61SColin Percival	else
285db6b0a61SColin Percival		return 1
286db6b0a61SColin Percival	fi
287db6b0a61SColin Percival}
288db6b0a61SColin Percival
28948ffe56aSColin Percival# Define what happens to output of utilities
29048ffe56aSColin Percivalconfig_VerboseLevel () {
29148ffe56aSColin Percival	if [ -z ${VERBOSELEVEL} ]; then
29248ffe56aSColin Percival		case $1 in
29348ffe56aSColin Percival		[Dd][Ee][Bb][Uu][Gg])
29448ffe56aSColin Percival			VERBOSELEVEL=debug
29548ffe56aSColin Percival			;;
29648ffe56aSColin Percival		[Nn][Oo][Ss][Tt][Aa][Tt][Ss])
29748ffe56aSColin Percival			VERBOSELEVEL=nostats
29848ffe56aSColin Percival			;;
29948ffe56aSColin Percival		[Ss][Tt][Aa][Tt][Ss])
30048ffe56aSColin Percival			VERBOSELEVEL=stats
30148ffe56aSColin Percival			;;
30248ffe56aSColin Percival		*)
30348ffe56aSColin Percival			return 1
30448ffe56aSColin Percival			;;
30548ffe56aSColin Percival		esac
30648ffe56aSColin Percival	else
30748ffe56aSColin Percival		return 1
30848ffe56aSColin Percival	fi
30948ffe56aSColin Percival}
31048ffe56aSColin Percival
31148ffe56aSColin Percival# Handle one line of configuration
31248ffe56aSColin Percivalconfigline () {
31348ffe56aSColin Percival	if [ $# -eq 0 ]; then
31448ffe56aSColin Percival		return
31548ffe56aSColin Percival	fi
31648ffe56aSColin Percival
31748ffe56aSColin Percival	OPT=$1
31848ffe56aSColin Percival	shift
31948ffe56aSColin Percival	config_${OPT} $@
32048ffe56aSColin Percival}
32148ffe56aSColin Percival
32248ffe56aSColin Percival#### Parameter handling functions.
32348ffe56aSColin Percival
32448ffe56aSColin Percival# Initialize parameters to null, just in case they're
32548ffe56aSColin Percival# set in the environment.
32648ffe56aSColin Percivalinit_params () {
32748ffe56aSColin Percival	# Configration settings
32848ffe56aSColin Percival	nullconfig
32948ffe56aSColin Percival
33048ffe56aSColin Percival	# No configuration file set yet
33148ffe56aSColin Percival	CONFFILE=""
33248ffe56aSColin Percival
33348ffe56aSColin Percival	# No commands specified yet
33448ffe56aSColin Percival	COMMANDS=""
33548ffe56aSColin Percival}
33648ffe56aSColin Percival
33748ffe56aSColin Percival# Parse the command line
33848ffe56aSColin Percivalparse_cmdline () {
33948ffe56aSColin Percival	while [ $# -gt 0 ]; do
34048ffe56aSColin Percival		case "$1" in
34148ffe56aSColin Percival		# Location of configuration file
34248ffe56aSColin Percival		-f)
34348ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi
34448ffe56aSColin Percival			if [ ! -z "${CONFFILE}" ]; then usage; fi
34548ffe56aSColin Percival			shift; CONFFILE="$1"
34648ffe56aSColin Percival			;;
34748ffe56aSColin Percival
34848ffe56aSColin Percival		# Configuration file equivalents
34948ffe56aSColin Percival		-b)
35048ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
35148ffe56aSColin Percival			config_BaseDir $1 || usage
35248ffe56aSColin Percival			;;
35348ffe56aSColin Percival		-d)
35448ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
35548ffe56aSColin Percival			config_WorkDir $1 || usage
35648ffe56aSColin Percival			;;
35748ffe56aSColin Percival		-k)
35848ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
35948ffe56aSColin Percival			config_KeyPrint $1 || usage
36048ffe56aSColin Percival			;;
36148ffe56aSColin Percival		-s)
36248ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
36348ffe56aSColin Percival			config_ServerName $1 || usage
36448ffe56aSColin Percival			;;
365db6b0a61SColin Percival		-r)
366db6b0a61SColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
367db6b0a61SColin Percival			config_TargetRelease $1 || usage
368db6b0a61SColin Percival			;;
36948ffe56aSColin Percival		-t)
37048ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
37148ffe56aSColin Percival			config_MailTo $1 || usage
37248ffe56aSColin Percival			;;
37348ffe56aSColin Percival		-v)
37448ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
37548ffe56aSColin Percival			config_VerboseLevel $1 || usage
37648ffe56aSColin Percival			;;
37748ffe56aSColin Percival
37848ffe56aSColin Percival		# Aliases for "-v debug" and "-v nostats"
37948ffe56aSColin Percival		--debug)
38048ffe56aSColin Percival			config_VerboseLevel debug || usage
38148ffe56aSColin Percival			;;
38248ffe56aSColin Percival		--no-stats)
38348ffe56aSColin Percival			config_VerboseLevel nostats || usage
38448ffe56aSColin Percival			;;
38548ffe56aSColin Percival
38648ffe56aSColin Percival		# Commands
38708e23beeSColin Percival		cron | fetch | upgrade | install | rollback | IDS)
38848ffe56aSColin Percival			COMMANDS="${COMMANDS} $1"
38948ffe56aSColin Percival			;;
39048ffe56aSColin Percival
39148ffe56aSColin Percival		# Anything else is an error
39248ffe56aSColin Percival		*)
39348ffe56aSColin Percival			usage
39448ffe56aSColin Percival			;;
39548ffe56aSColin Percival		esac
39648ffe56aSColin Percival		shift
39748ffe56aSColin Percival	done
39848ffe56aSColin Percival
39948ffe56aSColin Percival	# Make sure we have at least one command
40048ffe56aSColin Percival	if [ -z "${COMMANDS}" ]; then
40148ffe56aSColin Percival		usage
40248ffe56aSColin Percival	fi
40348ffe56aSColin Percival}
40448ffe56aSColin Percival
40548ffe56aSColin Percival# Parse the configuration file
40648ffe56aSColin Percivalparse_conffile () {
40748ffe56aSColin Percival	# If a configuration file was specified on the command line, check
40848ffe56aSColin Percival	# that it exists and is readable.
40948ffe56aSColin Percival	if [ ! -z "${CONFFILE}" ] && [ ! -r "${CONFFILE}" ]; then
41048ffe56aSColin Percival		echo -n "File does not exist "
41148ffe56aSColin Percival		echo -n "or is not readable: "
41248ffe56aSColin Percival		echo ${CONFFILE}
41348ffe56aSColin Percival		exit 1
41448ffe56aSColin Percival	fi
41548ffe56aSColin Percival
41648ffe56aSColin Percival	# If a configuration file was not specified on the command line,
41748ffe56aSColin Percival	# use the default configuration file path.  If that default does
41848ffe56aSColin Percival	# not exist, give up looking for any configuration.
41948ffe56aSColin Percival	if [ -z "${CONFFILE}" ]; then
42048ffe56aSColin Percival		CONFFILE="/etc/freebsd-update.conf"
42148ffe56aSColin Percival		if [ ! -r "${CONFFILE}" ]; then
42248ffe56aSColin Percival			return
42348ffe56aSColin Percival		fi
42448ffe56aSColin Percival	fi
42548ffe56aSColin Percival
42648ffe56aSColin Percival	# Save the configuration options specified on the command line, and
42748ffe56aSColin Percival	# clear all the options in preparation for reading the config file.
42848ffe56aSColin Percival	saveconfig
42948ffe56aSColin Percival	nullconfig
43048ffe56aSColin Percival
43148ffe56aSColin Percival	# Read the configuration file.  Anything after the first '#' is
43248ffe56aSColin Percival	# ignored, and any blank lines are ignored.
43348ffe56aSColin Percival	L=0
43448ffe56aSColin Percival	while read LINE; do
43548ffe56aSColin Percival		L=$(($L + 1))
43648ffe56aSColin Percival		LINEX=`echo "${LINE}" | cut -f 1 -d '#'`
43748ffe56aSColin Percival		if ! configline ${LINEX}; then
43848ffe56aSColin Percival			echo "Error processing configuration file, line $L:"
43948ffe56aSColin Percival			echo "==> ${LINE}"
44048ffe56aSColin Percival			exit 1
44148ffe56aSColin Percival		fi
44248ffe56aSColin Percival	done < ${CONFFILE}
44348ffe56aSColin Percival
44448ffe56aSColin Percival	# Merge the settings read from the configuration file with those
44548ffe56aSColin Percival	# provided at the command line.
44648ffe56aSColin Percival	mergeconfig
44748ffe56aSColin Percival}
44848ffe56aSColin Percival
44948ffe56aSColin Percival# Provide some default parameters
45048ffe56aSColin Percivaldefault_params () {
45148ffe56aSColin Percival	# Save any parameters already configured, and clear the slate
45248ffe56aSColin Percival	saveconfig
45348ffe56aSColin Percival	nullconfig
45448ffe56aSColin Percival
45548ffe56aSColin Percival	# Default configurations
45648ffe56aSColin Percival	config_WorkDir /var/db/freebsd-update
45748ffe56aSColin Percival	config_MailTo root
45848ffe56aSColin Percival	config_AllowAdd yes
45948ffe56aSColin Percival	config_AllowDelete yes
46048ffe56aSColin Percival	config_KeepModifiedMetadata yes
46148ffe56aSColin Percival	config_BaseDir /
46248ffe56aSColin Percival	config_VerboseLevel stats
463db6b0a61SColin Percival	config_StrictComponents no
46448ffe56aSColin Percival
46548ffe56aSColin Percival	# Merge these defaults into the earlier-configured settings
46648ffe56aSColin Percival	mergeconfig
46748ffe56aSColin Percival}
46848ffe56aSColin Percival
46948ffe56aSColin Percival# Set utility output filtering options, based on ${VERBOSELEVEL}
47048ffe56aSColin Percivalfetch_setup_verboselevel () {
47148ffe56aSColin Percival	case ${VERBOSELEVEL} in
47248ffe56aSColin Percival	debug)
47348ffe56aSColin Percival		QUIETREDIR="/dev/stderr"
47448ffe56aSColin Percival		QUIETFLAG=" "
47548ffe56aSColin Percival		STATSREDIR="/dev/stderr"
47648ffe56aSColin Percival		DDSTATS=".."
47748ffe56aSColin Percival		XARGST="-t"
47848ffe56aSColin Percival		NDEBUG=" "
47948ffe56aSColin Percival		;;
48048ffe56aSColin Percival	nostats)
48148ffe56aSColin Percival		QUIETREDIR=""
48248ffe56aSColin Percival		QUIETFLAG=""
48348ffe56aSColin Percival		STATSREDIR="/dev/null"
48448ffe56aSColin Percival		DDSTATS=".."
48548ffe56aSColin Percival		XARGST=""
48648ffe56aSColin Percival		NDEBUG=""
48748ffe56aSColin Percival		;;
48848ffe56aSColin Percival	stats)
48948ffe56aSColin Percival		QUIETREDIR="/dev/null"
49048ffe56aSColin Percival		QUIETFLAG="-q"
49148ffe56aSColin Percival		STATSREDIR="/dev/stdout"
49248ffe56aSColin Percival		DDSTATS=""
49348ffe56aSColin Percival		XARGST=""
49448ffe56aSColin Percival		NDEBUG="-n"
49548ffe56aSColin Percival		;;
49648ffe56aSColin Percival	esac
49748ffe56aSColin Percival}
49848ffe56aSColin Percival
49948ffe56aSColin Percival# Perform sanity checks and set some final parameters
50048ffe56aSColin Percival# in preparation for fetching files.  Figure out which
50148ffe56aSColin Percival# set of updates should be downloaded: If the user is
50248ffe56aSColin Percival# running *-p[0-9]+, strip off the last part; if the
50348ffe56aSColin Percival# user is running -SECURITY, call it -RELEASE.  Chdir
50448ffe56aSColin Percival# into the working directory.
50548ffe56aSColin Percivalfetch_check_params () {
50648ffe56aSColin Percival	export HTTP_USER_AGENT="freebsd-update (${COMMAND}, `uname -r`)"
50748ffe56aSColin Percival
50848ffe56aSColin Percival	_SERVERNAME_z=\
50948ffe56aSColin Percival"SERVERNAME must be given via command line or configuration file."
51048ffe56aSColin Percival	_KEYPRINT_z="Key must be given via -k option or configuration file."
51148ffe56aSColin Percival	_KEYPRINT_bad="Invalid key fingerprint: "
51248ffe56aSColin Percival	_WORKDIR_bad="Directory does not exist or is not writable: "
51348ffe56aSColin Percival
51448ffe56aSColin Percival	if [ -z "${SERVERNAME}" ]; then
51548ffe56aSColin Percival		echo -n "`basename $0`: "
51648ffe56aSColin Percival		echo "${_SERVERNAME_z}"
51748ffe56aSColin Percival		exit 1
51848ffe56aSColin Percival	fi
51948ffe56aSColin Percival	if [ -z "${KEYPRINT}" ]; then
52048ffe56aSColin Percival		echo -n "`basename $0`: "
52148ffe56aSColin Percival		echo "${_KEYPRINT_z}"
52248ffe56aSColin Percival		exit 1
52348ffe56aSColin Percival	fi
52448ffe56aSColin Percival	if ! echo "${KEYPRINT}" | grep -qE "^[0-9a-f]{64}$"; then
52548ffe56aSColin Percival		echo -n "`basename $0`: "
52648ffe56aSColin Percival		echo -n "${_KEYPRINT_bad}"
52748ffe56aSColin Percival		echo ${KEYPRINT}
52848ffe56aSColin Percival		exit 1
52948ffe56aSColin Percival	fi
53048ffe56aSColin Percival	if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then
53148ffe56aSColin Percival		echo -n "`basename $0`: "
53248ffe56aSColin Percival		echo -n "${_WORKDIR_bad}"
53348ffe56aSColin Percival		echo ${WORKDIR}
53448ffe56aSColin Percival		exit 1
53548ffe56aSColin Percival	fi
53648ffe56aSColin Percival	cd ${WORKDIR} || exit 1
53748ffe56aSColin Percival
53848ffe56aSColin Percival	# Generate release number.  The s/SECURITY/RELEASE/ bit exists
53948ffe56aSColin Percival	# to provide an upgrade path for FreeBSD Update 1.x users, since
54048ffe56aSColin Percival	# the kernels provided by FreeBSD Update 1.x are always labelled
54148ffe56aSColin Percival	# as X.Y-SECURITY.
54248ffe56aSColin Percival	RELNUM=`uname -r |
54348ffe56aSColin Percival	    sed -E 's,-p[0-9]+,,' |
54448ffe56aSColin Percival	    sed -E 's,-SECURITY,-RELEASE,'`
54548ffe56aSColin Percival	ARCH=`uname -m`
54648ffe56aSColin Percival	FETCHDIR=${RELNUM}/${ARCH}
547db6b0a61SColin Percival	PATCHDIR=${RELNUM}/${ARCH}/bp
54848ffe56aSColin Percival
54948ffe56aSColin Percival	# Figure out what directory contains the running kernel
55048ffe56aSColin Percival	BOOTFILE=`sysctl -n kern.bootfile`
55148ffe56aSColin Percival	KERNELDIR=${BOOTFILE%/kernel}
55248ffe56aSColin Percival	if ! [ -d ${KERNELDIR} ]; then
55348ffe56aSColin Percival		echo "Cannot identify running kernel"
55448ffe56aSColin Percival		exit 1
55548ffe56aSColin Percival	fi
55648ffe56aSColin Percival
5572c434b2cSColin Percival	# Figure out what kernel configuration is running.  We start with
5582c434b2cSColin Percival	# the output of `uname -i`, and then make the following adjustments:
5592c434b2cSColin Percival	# 1. Replace "SMP-GENERIC" with "SMP".  Why the SMP kernel config
5602c434b2cSColin Percival	# file says "ident SMP-GENERIC", I don't know...
5612c434b2cSColin Percival	# 2. If the kernel claims to be GENERIC _and_ ${ARCH} is "amd64"
5622c434b2cSColin Percival	# _and_ `sysctl kern.version` contains a line which ends "/SMP", then
5632c434b2cSColin Percival	# we're running an SMP kernel.  This mis-identification is a bug
5642c434b2cSColin Percival	# which was fixed in 6.2-STABLE.
5652c434b2cSColin Percival	KERNCONF=`uname -i`
5662c434b2cSColin Percival	if [ ${KERNCONF} = "SMP-GENERIC" ]; then
5672c434b2cSColin Percival		KERNCONF=SMP
5682c434b2cSColin Percival	fi
5692c434b2cSColin Percival	if [ ${KERNCONF} = "GENERIC" ] && [ ${ARCH} = "amd64" ]; then
5702c434b2cSColin Percival		if sysctl kern.version | grep -qE '/SMP$'; then
5712c434b2cSColin Percival			KERNCONF=SMP
5722c434b2cSColin Percival		fi
5732c434b2cSColin Percival	fi
5742c434b2cSColin Percival
57548ffe56aSColin Percival	# Define some paths
57648ffe56aSColin Percival	BSPATCH=/usr/bin/bspatch
57748ffe56aSColin Percival	SHA256=/sbin/sha256
57848ffe56aSColin Percival	PHTTPGET=/usr/libexec/phttpget
57948ffe56aSColin Percival
58048ffe56aSColin Percival	# Set up variables relating to VERBOSELEVEL
58148ffe56aSColin Percival	fetch_setup_verboselevel
58248ffe56aSColin Percival
58348ffe56aSColin Percival	# Construct a unique name from ${BASEDIR}
58448ffe56aSColin Percival	BDHASH=`echo ${BASEDIR} | sha256 -q`
58548ffe56aSColin Percival}
58648ffe56aSColin Percival
587db6b0a61SColin Percival# Perform sanity checks etc. before fetching upgrades.
588db6b0a61SColin Percivalupgrade_check_params () {
589db6b0a61SColin Percival	fetch_check_params
590db6b0a61SColin Percival
591db6b0a61SColin Percival	# Unless set otherwise, we're upgrading to the same kernel config.
592db6b0a61SColin Percival	NKERNCONF=${KERNCONF}
593db6b0a61SColin Percival
594db6b0a61SColin Percival	# We need TARGETRELEASE set
595db6b0a61SColin Percival	_TARGETRELEASE_z="Release target must be specified via -r option."
596db6b0a61SColin Percival	if [ -z "${TARGETRELEASE}" ]; then
597db6b0a61SColin Percival		echo -n "`basename $0`: "
598db6b0a61SColin Percival		echo "${_TARGETRELEASE_z}"
599db6b0a61SColin Percival		exit 1
600db6b0a61SColin Percival	fi
601db6b0a61SColin Percival
602db6b0a61SColin Percival	# The target release should be != the current release.
603db6b0a61SColin Percival	if [ "${TARGETRELEASE}" = "${RELNUM}" ]; then
604db6b0a61SColin Percival		echo -n "`basename $0`: "
605db6b0a61SColin Percival		echo "Cannot upgrade from ${RELNUM} to itself"
606db6b0a61SColin Percival		exit 1
607db6b0a61SColin Percival	fi
608db6b0a61SColin Percival
609db6b0a61SColin Percival	# Turning off AllowAdd or AllowDelete is a bad idea for upgrades.
610db6b0a61SColin Percival	if [ "${ALLOWADD}" = "no" ]; then
611db6b0a61SColin Percival		echo -n "`basename $0`: "
612db6b0a61SColin Percival		echo -n "WARNING: \"AllowAdd no\" is a bad idea "
613db6b0a61SColin Percival		echo "when upgrading between releases."
614db6b0a61SColin Percival		echo
615db6b0a61SColin Percival	fi
616db6b0a61SColin Percival	if [ "${ALLOWDELETE}" = "no" ]; then
617db6b0a61SColin Percival		echo -n "`basename $0`: "
618db6b0a61SColin Percival		echo -n "WARNING: \"AllowDelete no\" is a bad idea "
619db6b0a61SColin Percival		echo "when upgrading between releases."
620db6b0a61SColin Percival		echo
621db6b0a61SColin Percival	fi
622db6b0a61SColin Percival
623db6b0a61SColin Percival	# Set EDITOR to /usr/bin/vi if it isn't already set
624db6b0a61SColin Percival	: ${EDITOR:='/usr/bin/vi'}
625db6b0a61SColin Percival}
626db6b0a61SColin Percival
62748ffe56aSColin Percival# Perform sanity checks and set some final parameters in
62848ffe56aSColin Percival# preparation for installing updates.
62948ffe56aSColin Percivalinstall_check_params () {
63048ffe56aSColin Percival	# Check that we are root.  All sorts of things won't work otherwise.
63148ffe56aSColin Percival	if [ `id -u` != 0 ]; then
63248ffe56aSColin Percival		echo "You must be root to run this."
63348ffe56aSColin Percival		exit 1
63448ffe56aSColin Percival	fi
63548ffe56aSColin Percival
6362328d598SColin Percival	# Check that securelevel <= 0.  Otherwise we can't update schg files.
6372328d598SColin Percival	if [ `sysctl -n kern.securelevel` -gt 0 ]; then
6382328d598SColin Percival		echo "Updates cannot be installed when the system securelevel"
6392328d598SColin Percival		echo "is greater than zero."
6402328d598SColin Percival		exit 1
6412328d598SColin Percival	fi
6422328d598SColin Percival
64348ffe56aSColin Percival	# Check that we have a working directory
64448ffe56aSColin Percival	_WORKDIR_bad="Directory does not exist or is not writable: "
64548ffe56aSColin Percival	if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then
64648ffe56aSColin Percival		echo -n "`basename $0`: "
64748ffe56aSColin Percival		echo -n "${_WORKDIR_bad}"
64848ffe56aSColin Percival		echo ${WORKDIR}
64948ffe56aSColin Percival		exit 1
65048ffe56aSColin Percival	fi
65148ffe56aSColin Percival	cd ${WORKDIR} || exit 1
65248ffe56aSColin Percival
65348ffe56aSColin Percival	# Construct a unique name from ${BASEDIR}
65448ffe56aSColin Percival	BDHASH=`echo ${BASEDIR} | sha256 -q`
65548ffe56aSColin Percival
65648ffe56aSColin Percival	# Check that we have updates ready to install
65748ffe56aSColin Percival	if ! [ -L ${BDHASH}-install ]; then
65848ffe56aSColin Percival		echo "No updates are available to install."
65948ffe56aSColin Percival		echo "Run '$0 fetch' first."
66048ffe56aSColin Percival		exit 1
66148ffe56aSColin Percival	fi
66248ffe56aSColin Percival	if ! [ -f ${BDHASH}-install/INDEX-OLD ] ||
66348ffe56aSColin Percival	    ! [ -f ${BDHASH}-install/INDEX-NEW ]; then
66448ffe56aSColin Percival		echo "Update manifest is corrupt -- this should never happen."
66548ffe56aSColin Percival		echo "Re-run '$0 fetch'."
66648ffe56aSColin Percival		exit 1
66748ffe56aSColin Percival	fi
66848ffe56aSColin Percival}
66948ffe56aSColin Percival
67048ffe56aSColin Percival# Perform sanity checks and set some final parameters in
67148ffe56aSColin Percival# preparation for UNinstalling updates.
67248ffe56aSColin Percivalrollback_check_params () {
67348ffe56aSColin Percival	# Check that we are root.  All sorts of things won't work otherwise.
67448ffe56aSColin Percival	if [ `id -u` != 0 ]; then
67548ffe56aSColin Percival		echo "You must be root to run this."
67648ffe56aSColin Percival		exit 1
67748ffe56aSColin Percival	fi
67848ffe56aSColin Percival
67948ffe56aSColin Percival	# Check that we have a working directory
68048ffe56aSColin Percival	_WORKDIR_bad="Directory does not exist or is not writable: "
68148ffe56aSColin Percival	if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then
68248ffe56aSColin Percival		echo -n "`basename $0`: "
68348ffe56aSColin Percival		echo -n "${_WORKDIR_bad}"
68448ffe56aSColin Percival		echo ${WORKDIR}
68548ffe56aSColin Percival		exit 1
68648ffe56aSColin Percival	fi
68748ffe56aSColin Percival	cd ${WORKDIR} || exit 1
68848ffe56aSColin Percival
68948ffe56aSColin Percival	# Construct a unique name from ${BASEDIR}
69048ffe56aSColin Percival	BDHASH=`echo ${BASEDIR} | sha256 -q`
69148ffe56aSColin Percival
69248ffe56aSColin Percival	# Check that we have updates ready to rollback
69348ffe56aSColin Percival	if ! [ -L ${BDHASH}-rollback ]; then
69448ffe56aSColin Percival		echo "No rollback directory found."
69548ffe56aSColin Percival		exit 1
69648ffe56aSColin Percival	fi
69748ffe56aSColin Percival	if ! [ -f ${BDHASH}-rollback/INDEX-OLD ] ||
69848ffe56aSColin Percival	    ! [ -f ${BDHASH}-rollback/INDEX-NEW ]; then
69948ffe56aSColin Percival		echo "Update manifest is corrupt -- this should never happen."
70048ffe56aSColin Percival		exit 1
70148ffe56aSColin Percival	fi
70248ffe56aSColin Percival}
70348ffe56aSColin Percival
70408e23beeSColin Percival# Perform sanity checks and set some final parameters
70508e23beeSColin Percival# in preparation for comparing the system against the
70608e23beeSColin Percival# published index.  Figure out which index we should
70708e23beeSColin Percival# compare against: If the user is running *-p[0-9]+,
70808e23beeSColin Percival# strip off the last part; if the user is running
70908e23beeSColin Percival# -SECURITY, call it -RELEASE.  Chdir into the working
71008e23beeSColin Percival# directory.
71108e23beeSColin PercivalIDS_check_params () {
71208e23beeSColin Percival	export HTTP_USER_AGENT="freebsd-update (${COMMAND}, `uname -r`)"
71308e23beeSColin Percival
71408e23beeSColin Percival	_SERVERNAME_z=\
71508e23beeSColin Percival"SERVERNAME must be given via command line or configuration file."
71608e23beeSColin Percival	_KEYPRINT_z="Key must be given via -k option or configuration file."
71708e23beeSColin Percival	_KEYPRINT_bad="Invalid key fingerprint: "
71808e23beeSColin Percival	_WORKDIR_bad="Directory does not exist or is not writable: "
71908e23beeSColin Percival
72008e23beeSColin Percival	if [ -z "${SERVERNAME}" ]; then
72108e23beeSColin Percival		echo -n "`basename $0`: "
72208e23beeSColin Percival		echo "${_SERVERNAME_z}"
72308e23beeSColin Percival		exit 1
72408e23beeSColin Percival	fi
72508e23beeSColin Percival	if [ -z "${KEYPRINT}" ]; then
72608e23beeSColin Percival		echo -n "`basename $0`: "
72708e23beeSColin Percival		echo "${_KEYPRINT_z}"
72808e23beeSColin Percival		exit 1
72908e23beeSColin Percival	fi
73008e23beeSColin Percival	if ! echo "${KEYPRINT}" | grep -qE "^[0-9a-f]{64}$"; then
73108e23beeSColin Percival		echo -n "`basename $0`: "
73208e23beeSColin Percival		echo -n "${_KEYPRINT_bad}"
73308e23beeSColin Percival		echo ${KEYPRINT}
73408e23beeSColin Percival		exit 1
73508e23beeSColin Percival	fi
73608e23beeSColin Percival	if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then
73708e23beeSColin Percival		echo -n "`basename $0`: "
73808e23beeSColin Percival		echo -n "${_WORKDIR_bad}"
73908e23beeSColin Percival		echo ${WORKDIR}
74008e23beeSColin Percival		exit 1
74108e23beeSColin Percival	fi
74208e23beeSColin Percival	cd ${WORKDIR} || exit 1
74308e23beeSColin Percival
74408e23beeSColin Percival	# Generate release number.  The s/SECURITY/RELEASE/ bit exists
74508e23beeSColin Percival	# to provide an upgrade path for FreeBSD Update 1.x users, since
74608e23beeSColin Percival	# the kernels provided by FreeBSD Update 1.x are always labelled
74708e23beeSColin Percival	# as X.Y-SECURITY.
74808e23beeSColin Percival	RELNUM=`uname -r |
74908e23beeSColin Percival	    sed -E 's,-p[0-9]+,,' |
75008e23beeSColin Percival	    sed -E 's,-SECURITY,-RELEASE,'`
75108e23beeSColin Percival	ARCH=`uname -m`
75208e23beeSColin Percival	FETCHDIR=${RELNUM}/${ARCH}
75308e23beeSColin Percival	PATCHDIR=${RELNUM}/${ARCH}/bp
75408e23beeSColin Percival
75508e23beeSColin Percival	# Figure out what directory contains the running kernel
75608e23beeSColin Percival	BOOTFILE=`sysctl -n kern.bootfile`
75708e23beeSColin Percival	KERNELDIR=${BOOTFILE%/kernel}
75808e23beeSColin Percival	if ! [ -d ${KERNELDIR} ]; then
75908e23beeSColin Percival		echo "Cannot identify running kernel"
76008e23beeSColin Percival		exit 1
76108e23beeSColin Percival	fi
76208e23beeSColin Percival
76308e23beeSColin Percival	# Figure out what kernel configuration is running.  We start with
76408e23beeSColin Percival	# the output of `uname -i`, and then make the following adjustments:
76508e23beeSColin Percival	# 1. Replace "SMP-GENERIC" with "SMP".  Why the SMP kernel config
76608e23beeSColin Percival	# file says "ident SMP-GENERIC", I don't know...
76708e23beeSColin Percival	# 2. If the kernel claims to be GENERIC _and_ ${ARCH} is "amd64"
76808e23beeSColin Percival	# _and_ `sysctl kern.version` contains a line which ends "/SMP", then
76908e23beeSColin Percival	# we're running an SMP kernel.  This mis-identification is a bug
77008e23beeSColin Percival	# which was fixed in 6.2-STABLE.
77108e23beeSColin Percival	KERNCONF=`uname -i`
77208e23beeSColin Percival	if [ ${KERNCONF} = "SMP-GENERIC" ]; then
77308e23beeSColin Percival		KERNCONF=SMP
77408e23beeSColin Percival	fi
77508e23beeSColin Percival	if [ ${KERNCONF} = "GENERIC" ] && [ ${ARCH} = "amd64" ]; then
77608e23beeSColin Percival		if sysctl kern.version | grep -qE '/SMP$'; then
77708e23beeSColin Percival			KERNCONF=SMP
77808e23beeSColin Percival		fi
77908e23beeSColin Percival	fi
78008e23beeSColin Percival
78108e23beeSColin Percival	# Define some paths
78208e23beeSColin Percival	SHA256=/sbin/sha256
78308e23beeSColin Percival	PHTTPGET=/usr/libexec/phttpget
78408e23beeSColin Percival
78508e23beeSColin Percival	# Set up variables relating to VERBOSELEVEL
78608e23beeSColin Percival	fetch_setup_verboselevel
78708e23beeSColin Percival}
78808e23beeSColin Percival
78948ffe56aSColin Percival#### Core functionality -- the actual work gets done here
79048ffe56aSColin Percival
79148ffe56aSColin Percival# Use an SRV query to pick a server.  If the SRV query doesn't provide
79248ffe56aSColin Percival# a useful answer, use the server name specified by the user.
79348ffe56aSColin Percival# Put another way... look up _http._tcp.${SERVERNAME} and pick a server
79448ffe56aSColin Percival# from that; or if no servers are returned, use ${SERVERNAME}.
79548ffe56aSColin Percival# This allows a user to specify "portsnap.freebsd.org" (in which case
79648ffe56aSColin Percival# portsnap will select one of the mirrors) or "portsnap5.tld.freebsd.org"
79748ffe56aSColin Percival# (in which case portsnap will use that particular server, since there
79848ffe56aSColin Percival# won't be an SRV entry for that name).
79948ffe56aSColin Percival#
80048ffe56aSColin Percival# We ignore the Port field, since we are always going to use port 80.
80148ffe56aSColin Percival
80248ffe56aSColin Percival# Fetch the mirror list, but do not pick a mirror yet.  Returns 1 if
80348ffe56aSColin Percival# no mirrors are available for any reason.
80448ffe56aSColin Percivalfetch_pick_server_init () {
80548ffe56aSColin Percival	: > serverlist_tried
80648ffe56aSColin Percival
80748ffe56aSColin Percival# Check that host(1) exists (i.e., that the system wasn't built with the
80848ffe56aSColin Percival# WITHOUT_BIND set) and don't try to find a mirror if it doesn't exist.
80948ffe56aSColin Percival	if ! which -s host; then
81048ffe56aSColin Percival		: > serverlist_full
81148ffe56aSColin Percival		return 1
81248ffe56aSColin Percival	fi
81348ffe56aSColin Percival
81448ffe56aSColin Percival	echo -n "Looking up ${SERVERNAME} mirrors... "
81548ffe56aSColin Percival
81648ffe56aSColin Percival# Issue the SRV query and pull out the Priority, Weight, and Target fields.
81748ffe56aSColin Percival# BIND 9 prints "$name has SRV record ..." while BIND 8 prints
81848ffe56aSColin Percival# "$name server selection ..."; we allow either format.
81948ffe56aSColin Percival	MLIST="_http._tcp.${SERVERNAME}"
82048ffe56aSColin Percival	host -t srv "${MLIST}" |
82148ffe56aSColin Percival	    sed -nE "s/${MLIST} (has SRV record|server selection) //p" |
82248ffe56aSColin Percival	    cut -f 1,2,4 -d ' ' |
82348ffe56aSColin Percival	    sed -e 's/\.$//' |
82448ffe56aSColin Percival	    sort > serverlist_full
82548ffe56aSColin Percival
82648ffe56aSColin Percival# If no records, give up -- we'll just use the server name we were given.
82748ffe56aSColin Percival	if [ `wc -l < serverlist_full` -eq 0 ]; then
82848ffe56aSColin Percival		echo "none found."
82948ffe56aSColin Percival		return 1
83048ffe56aSColin Percival	fi
83148ffe56aSColin Percival
83248ffe56aSColin Percival# Report how many mirrors we found.
83348ffe56aSColin Percival	echo `wc -l < serverlist_full` "mirrors found."
83448ffe56aSColin Percival
83548ffe56aSColin Percival# Generate a random seed for use in picking mirrors.  If HTTP_PROXY
83648ffe56aSColin Percival# is set, this will be used to generate the seed; otherwise, the seed
83748ffe56aSColin Percival# will be random.
83848ffe56aSColin Percival	if [ -n "${HTTP_PROXY}${http_proxy}" ]; then
83948ffe56aSColin Percival		RANDVALUE=`sha256 -qs "${HTTP_PROXY}${http_proxy}" |
84048ffe56aSColin Percival		    tr -d 'a-f' |
84148ffe56aSColin Percival		    cut -c 1-9`
84248ffe56aSColin Percival	else
84348ffe56aSColin Percival		RANDVALUE=`jot -r 1 0 999999999`
84448ffe56aSColin Percival	fi
84548ffe56aSColin Percival}
84648ffe56aSColin Percival
84748ffe56aSColin Percival# Pick a mirror.  Returns 1 if we have run out of mirrors to try.
84848ffe56aSColin Percivalfetch_pick_server () {
84948ffe56aSColin Percival# Generate a list of not-yet-tried mirrors
85048ffe56aSColin Percival	sort serverlist_tried |
85148ffe56aSColin Percival	    comm -23 serverlist_full - > serverlist
85248ffe56aSColin Percival
85348ffe56aSColin Percival# Have we run out of mirrors?
85448ffe56aSColin Percival	if [ `wc -l < serverlist` -eq 0 ]; then
85548ffe56aSColin Percival		echo "No mirrors remaining, giving up."
85648ffe56aSColin Percival		return 1
85748ffe56aSColin Percival	fi
85848ffe56aSColin Percival
85948ffe56aSColin Percival# Find the highest priority level (lowest numeric value).
86048ffe56aSColin Percival	SRV_PRIORITY=`cut -f 1 -d ' ' serverlist | sort -n | head -1`
86148ffe56aSColin Percival
86248ffe56aSColin Percival# Add up the weights of the response lines at that priority level.
86348ffe56aSColin Percival	SRV_WSUM=0;
86448ffe56aSColin Percival	while read X; do
86548ffe56aSColin Percival		case "$X" in
86648ffe56aSColin Percival		${SRV_PRIORITY}\ *)
86748ffe56aSColin Percival			SRV_W=`echo $X | cut -f 2 -d ' '`
86848ffe56aSColin Percival			SRV_WSUM=$(($SRV_WSUM + $SRV_W))
86948ffe56aSColin Percival			;;
87048ffe56aSColin Percival		esac
87148ffe56aSColin Percival	done < serverlist
87248ffe56aSColin Percival
87348ffe56aSColin Percival# If all the weights are 0, pretend that they are all 1 instead.
87448ffe56aSColin Percival	if [ ${SRV_WSUM} -eq 0 ]; then
87548ffe56aSColin Percival		SRV_WSUM=`grep -E "^${SRV_PRIORITY} " serverlist | wc -l`
87648ffe56aSColin Percival		SRV_W_ADD=1
87748ffe56aSColin Percival	else
87848ffe56aSColin Percival		SRV_W_ADD=0
87948ffe56aSColin Percival	fi
88048ffe56aSColin Percival
88148ffe56aSColin Percival# Pick a value between 0 and the sum of the weights - 1
88248ffe56aSColin Percival	SRV_RND=`expr ${RANDVALUE} % ${SRV_WSUM}`
88348ffe56aSColin Percival
88448ffe56aSColin Percival# Read through the list of mirrors and set SERVERNAME.  Write the line
88548ffe56aSColin Percival# corresponding to the mirror we selected into serverlist_tried so that
88648ffe56aSColin Percival# we won't try it again.
88748ffe56aSColin Percival	while read X; do
88848ffe56aSColin Percival		case "$X" in
88948ffe56aSColin Percival		${SRV_PRIORITY}\ *)
89048ffe56aSColin Percival			SRV_W=`echo $X | cut -f 2 -d ' '`
89148ffe56aSColin Percival			SRV_W=$(($SRV_W + $SRV_W_ADD))
89248ffe56aSColin Percival			if [ $SRV_RND -lt $SRV_W ]; then
89348ffe56aSColin Percival				SERVERNAME=`echo $X | cut -f 3 -d ' '`
89448ffe56aSColin Percival				echo "$X" >> serverlist_tried
89548ffe56aSColin Percival				break
89648ffe56aSColin Percival			else
89748ffe56aSColin Percival				SRV_RND=$(($SRV_RND - $SRV_W))
89848ffe56aSColin Percival			fi
89948ffe56aSColin Percival			;;
90048ffe56aSColin Percival		esac
90148ffe56aSColin Percival	done < serverlist
90248ffe56aSColin Percival}
90348ffe56aSColin Percival
90448ffe56aSColin Percival# Take a list of ${oldhash}|${newhash} and output a list of needed patches,
90548ffe56aSColin Percival# i.e., those for which we have ${oldhash} and don't have ${newhash}.
90648ffe56aSColin Percivalfetch_make_patchlist () {
90748ffe56aSColin Percival	grep -vE "^([0-9a-f]{64})\|\1$" |
90848ffe56aSColin Percival	    tr '|' ' ' |
90948ffe56aSColin Percival		while read X Y; do
91048ffe56aSColin Percival			if [ -f "files/${Y}.gz" ] ||
91148ffe56aSColin Percival			    [ ! -f "files/${X}.gz" ]; then
91248ffe56aSColin Percival				continue
91348ffe56aSColin Percival			fi
91448ffe56aSColin Percival			echo "${X}|${Y}"
91548ffe56aSColin Percival		done | uniq
91648ffe56aSColin Percival}
91748ffe56aSColin Percival
91848ffe56aSColin Percival# Print user-friendly progress statistics
91948ffe56aSColin Percivalfetch_progress () {
92048ffe56aSColin Percival	LNC=0
92148ffe56aSColin Percival	while read x; do
92248ffe56aSColin Percival		LNC=$(($LNC + 1))
92348ffe56aSColin Percival		if [ $(($LNC % 10)) = 0 ]; then
92448ffe56aSColin Percival			echo -n $LNC
92548ffe56aSColin Percival		elif [ $(($LNC % 2)) = 0 ]; then
92648ffe56aSColin Percival			echo -n .
92748ffe56aSColin Percival		fi
92848ffe56aSColin Percival	done
92948ffe56aSColin Percival	echo -n " "
93048ffe56aSColin Percival}
93148ffe56aSColin Percival
932db6b0a61SColin Percival# Function for asking the user if everything is ok
933db6b0a61SColin Percivalcontinuep () {
934db6b0a61SColin Percival	while read -p "Does this look reasonable (y/n)? " CONTINUE; do
935db6b0a61SColin Percival		case "${CONTINUE}" in
936db6b0a61SColin Percival		y*)
937db6b0a61SColin Percival			return 0
938db6b0a61SColin Percival			;;
939db6b0a61SColin Percival		n*)
940db6b0a61SColin Percival			return 1
941db6b0a61SColin Percival			;;
942db6b0a61SColin Percival		esac
943db6b0a61SColin Percival	done
944db6b0a61SColin Percival}
945db6b0a61SColin Percival
94648ffe56aSColin Percival# Initialize the working directory
94748ffe56aSColin Percivalworkdir_init () {
94848ffe56aSColin Percival	mkdir -p files
94948ffe56aSColin Percival	touch tINDEX.present
95048ffe56aSColin Percival}
95148ffe56aSColin Percival
95248ffe56aSColin Percival# Check that we have a public key with an appropriate hash, or
95348ffe56aSColin Percival# fetch the key if it doesn't exist.  Returns 1 if the key has
95448ffe56aSColin Percival# not yet been fetched.
95548ffe56aSColin Percivalfetch_key () {
95648ffe56aSColin Percival	if [ -r pub.ssl ] && [ `${SHA256} -q pub.ssl` = ${KEYPRINT} ]; then
95748ffe56aSColin Percival		return 0
95848ffe56aSColin Percival	fi
95948ffe56aSColin Percival
96048ffe56aSColin Percival	echo -n "Fetching public key from ${SERVERNAME}... "
96148ffe56aSColin Percival	rm -f pub.ssl
96248ffe56aSColin Percival	fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/pub.ssl \
96348ffe56aSColin Percival	    2>${QUIETREDIR} || true
96448ffe56aSColin Percival	if ! [ -r pub.ssl ]; then
96548ffe56aSColin Percival		echo "failed."
96648ffe56aSColin Percival		return 1
96748ffe56aSColin Percival	fi
96848ffe56aSColin Percival	if ! [ `${SHA256} -q pub.ssl` = ${KEYPRINT} ]; then
96948ffe56aSColin Percival		echo "key has incorrect hash."
97048ffe56aSColin Percival		rm -f pub.ssl
97148ffe56aSColin Percival		return 1
97248ffe56aSColin Percival	fi
97348ffe56aSColin Percival	echo "done."
97448ffe56aSColin Percival}
97548ffe56aSColin Percival
97648ffe56aSColin Percival# Fetch metadata signature, aka "tag".
97748ffe56aSColin Percivalfetch_tag () {
978db6b0a61SColin Percival	echo -n "Fetching metadata signature "
979db6b0a61SColin Percival	echo ${NDEBUG} "for ${RELNUM} from ${SERVERNAME}... "
98048ffe56aSColin Percival	rm -f latest.ssl
98148ffe56aSColin Percival	fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/latest.ssl	\
98248ffe56aSColin Percival	    2>${QUIETREDIR} || true
98348ffe56aSColin Percival	if ! [ -r latest.ssl ]; then
98448ffe56aSColin Percival		echo "failed."
98548ffe56aSColin Percival		return 1
98648ffe56aSColin Percival	fi
98748ffe56aSColin Percival
98848ffe56aSColin Percival	openssl rsautl -pubin -inkey pub.ssl -verify		\
98948ffe56aSColin Percival	    < latest.ssl > tag.new 2>${QUIETREDIR} || true
99048ffe56aSColin Percival	rm latest.ssl
99148ffe56aSColin Percival
99248ffe56aSColin Percival	if ! [ `wc -l < tag.new` = 1 ] ||
99348ffe56aSColin Percival	    ! grep -qE	\
99448ffe56aSColin Percival    "^freebsd-update\|${ARCH}\|${RELNUM}\|[0-9]+\|[0-9a-f]{64}\|[0-9]{10}" \
99548ffe56aSColin Percival		tag.new; then
99648ffe56aSColin Percival		echo "invalid signature."
99748ffe56aSColin Percival		return 1
99848ffe56aSColin Percival	fi
99948ffe56aSColin Percival
100048ffe56aSColin Percival	echo "done."
100148ffe56aSColin Percival
100248ffe56aSColin Percival	RELPATCHNUM=`cut -f 4 -d '|' < tag.new`
100348ffe56aSColin Percival	TINDEXHASH=`cut -f 5 -d '|' < tag.new`
100448ffe56aSColin Percival	EOLTIME=`cut -f 6 -d '|' < tag.new`
100548ffe56aSColin Percival}
100648ffe56aSColin Percival
100748ffe56aSColin Percival# Sanity-check the patch number in a tag, to make sure that we're not
100848ffe56aSColin Percival# going to "update" backwards and to prevent replay attacks.
100948ffe56aSColin Percivalfetch_tagsanity () {
101048ffe56aSColin Percival	# Check that we're not going to move from -pX to -pY with Y < X.
101148ffe56aSColin Percival	RELPX=`uname -r | sed -E 's,.*-,,'`
101248ffe56aSColin Percival	if echo ${RELPX} | grep -qE '^p[0-9]+$'; then
101348ffe56aSColin Percival		RELPX=`echo ${RELPX} | cut -c 2-`
101448ffe56aSColin Percival	else
101548ffe56aSColin Percival		RELPX=0
101648ffe56aSColin Percival	fi
101748ffe56aSColin Percival	if [ "${RELPATCHNUM}" -lt "${RELPX}" ]; then
101848ffe56aSColin Percival		echo
101948ffe56aSColin Percival		echo -n "Files on mirror (${RELNUM}-p${RELPATCHNUM})"
102048ffe56aSColin Percival		echo " appear older than what"
102148ffe56aSColin Percival		echo "we are currently running (`uname -r`)!"
102248ffe56aSColin Percival		echo "Cowardly refusing to proceed any further."
102348ffe56aSColin Percival		return 1
102448ffe56aSColin Percival	fi
102548ffe56aSColin Percival
102648ffe56aSColin Percival	# If "tag" exists and corresponds to ${RELNUM}, make sure that
102748ffe56aSColin Percival	# it contains a patch number <= RELPATCHNUM, in order to protect
102848ffe56aSColin Percival	# against rollback (replay) attacks.
102948ffe56aSColin Percival	if [ -f tag ] &&
103048ffe56aSColin Percival	    grep -qE	\
103148ffe56aSColin Percival    "^freebsd-update\|${ARCH}\|${RELNUM}\|[0-9]+\|[0-9a-f]{64}\|[0-9]{10}" \
103248ffe56aSColin Percival		tag; then
103348ffe56aSColin Percival		LASTRELPATCHNUM=`cut -f 4 -d '|' < tag`
103448ffe56aSColin Percival
103548ffe56aSColin Percival		if [ "${RELPATCHNUM}" -lt "${LASTRELPATCHNUM}" ]; then
103648ffe56aSColin Percival			echo
103748ffe56aSColin Percival			echo -n "Files on mirror (${RELNUM}-p${RELPATCHNUM})"
103848ffe56aSColin Percival			echo " are older than the"
103948ffe56aSColin Percival			echo -n "most recently seen updates"
104048ffe56aSColin Percival			echo " (${RELNUM}-p${LASTRELPATCHNUM})."
104148ffe56aSColin Percival			echo "Cowardly refusing to proceed any further."
104248ffe56aSColin Percival			return 1
104348ffe56aSColin Percival		fi
104448ffe56aSColin Percival	fi
104548ffe56aSColin Percival}
104648ffe56aSColin Percival
104748ffe56aSColin Percival# Fetch metadata index file
104848ffe56aSColin Percivalfetch_metadata_index () {
104948ffe56aSColin Percival	echo ${NDEBUG} "Fetching metadata index... "
105048ffe56aSColin Percival	rm -f ${TINDEXHASH}
105148ffe56aSColin Percival	fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/t/${TINDEXHASH}
105248ffe56aSColin Percival	    2>${QUIETREDIR}
105348ffe56aSColin Percival	if ! [ -f ${TINDEXHASH} ]; then
105448ffe56aSColin Percival		echo "failed."
105548ffe56aSColin Percival		return 1
105648ffe56aSColin Percival	fi
105748ffe56aSColin Percival	if [ `${SHA256} -q ${TINDEXHASH}` != ${TINDEXHASH} ]; then
105848ffe56aSColin Percival		echo "update metadata index corrupt."
105948ffe56aSColin Percival		return 1
106048ffe56aSColin Percival	fi
106148ffe56aSColin Percival	echo "done."
106248ffe56aSColin Percival}
106348ffe56aSColin Percival
106448ffe56aSColin Percival# Print an error message about signed metadata being bogus.
106548ffe56aSColin Percivalfetch_metadata_bogus () {
106648ffe56aSColin Percival	echo
106748ffe56aSColin Percival	echo "The update metadata$1 is correctly signed, but"
106848ffe56aSColin Percival	echo "failed an integrity check."
106948ffe56aSColin Percival	echo "Cowardly refusing to proceed any further."
107048ffe56aSColin Percival	return 1
107148ffe56aSColin Percival}
107248ffe56aSColin Percival
107348ffe56aSColin Percival# Construct tINDEX.new by merging the lines named in $1 from ${TINDEXHASH}
107448ffe56aSColin Percival# with the lines not named in $@ from tINDEX.present (if that file exists).
107548ffe56aSColin Percivalfetch_metadata_index_merge () {
107648ffe56aSColin Percival	for METAFILE in $@; do
107748ffe56aSColin Percival		if [ `grep -E "^${METAFILE}\|" ${TINDEXHASH} | wc -l`	\
107848ffe56aSColin Percival		    -ne 1 ]; then
107948ffe56aSColin Percival			fetch_metadata_bogus " index"
108048ffe56aSColin Percival			return 1
108148ffe56aSColin Percival		fi
108248ffe56aSColin Percival
108348ffe56aSColin Percival		grep -E "${METAFILE}\|" ${TINDEXHASH}
108448ffe56aSColin Percival	done |
108548ffe56aSColin Percival	    sort > tINDEX.wanted
108648ffe56aSColin Percival
108748ffe56aSColin Percival	if [ -f tINDEX.present ]; then
108848ffe56aSColin Percival		join -t '|' -v 2 tINDEX.wanted tINDEX.present |
108948ffe56aSColin Percival		    sort -m - tINDEX.wanted > tINDEX.new
109048ffe56aSColin Percival		rm tINDEX.wanted
109148ffe56aSColin Percival	else
109248ffe56aSColin Percival		mv tINDEX.wanted tINDEX.new
109348ffe56aSColin Percival	fi
109448ffe56aSColin Percival}
109548ffe56aSColin Percival
109648ffe56aSColin Percival# Sanity check all the lines of tINDEX.new.  Even if more metadata lines
109748ffe56aSColin Percival# are added by future versions of the server, this won't cause problems,
109848ffe56aSColin Percival# since the only lines which appear in tINDEX.new are the ones which we
109948ffe56aSColin Percival# specifically grepped out of ${TINDEXHASH}.
110048ffe56aSColin Percivalfetch_metadata_index_sanity () {
110148ffe56aSColin Percival	if grep -qvE '^[0-9A-Z.-]+\|[0-9a-f]{64}$' tINDEX.new; then
110248ffe56aSColin Percival		fetch_metadata_bogus " index"
110348ffe56aSColin Percival		return 1
110448ffe56aSColin Percival	fi
110548ffe56aSColin Percival}
110648ffe56aSColin Percival
110748ffe56aSColin Percival# Sanity check the metadata file $1.
110848ffe56aSColin Percivalfetch_metadata_sanity () {
110948ffe56aSColin Percival	# Some aliases to save space later: ${P} is a character which can
111048ffe56aSColin Percival	# appear in a path; ${M} is the four numeric metadata fields; and
111148ffe56aSColin Percival	# ${H} is a sha256 hash.
111248ffe56aSColin Percival	P="[-+./:=_[[:alnum:]]"
111348ffe56aSColin Percival	M="[0-9]+\|[0-9]+\|[0-9]+\|[0-9]+"
111448ffe56aSColin Percival	H="[0-9a-f]{64}"
111548ffe56aSColin Percival
111648ffe56aSColin Percival	# Check that the first four fields make sense.
111748ffe56aSColin Percival	if gunzip -c < files/$1.gz |
111848ffe56aSColin Percival	    grep -qvE "^[a-z]+\|[0-9a-z]+\|${P}+\|[fdL-]\|"; then
111948ffe56aSColin Percival		fetch_metadata_bogus ""
112048ffe56aSColin Percival		return 1
112148ffe56aSColin Percival	fi
112248ffe56aSColin Percival
112348ffe56aSColin Percival	# Remove the first three fields.
112448ffe56aSColin Percival	gunzip -c < files/$1.gz |
112548ffe56aSColin Percival	    cut -f 4- -d '|' > sanitycheck.tmp
112648ffe56aSColin Percival
112748ffe56aSColin Percival	# Sanity check entries with type 'f'
112848ffe56aSColin Percival	if grep -E '^f' sanitycheck.tmp |
112948ffe56aSColin Percival	    grep -qvE "^f\|${M}\|${H}\|${P}*\$"; then
113048ffe56aSColin Percival		fetch_metadata_bogus ""
113148ffe56aSColin Percival		return 1
113248ffe56aSColin Percival	fi
113348ffe56aSColin Percival
113448ffe56aSColin Percival	# Sanity check entries with type 'd'
113548ffe56aSColin Percival	if grep -E '^d' sanitycheck.tmp |
113648ffe56aSColin Percival	    grep -qvE "^d\|${M}\|\|\$"; then
113748ffe56aSColin Percival		fetch_metadata_bogus ""
113848ffe56aSColin Percival		return 1
113948ffe56aSColin Percival	fi
114048ffe56aSColin Percival
114148ffe56aSColin Percival	# Sanity check entries with type 'L'
114248ffe56aSColin Percival	if grep -E '^L' sanitycheck.tmp |
114348ffe56aSColin Percival	    grep -qvE "^L\|${M}\|${P}*\|\$"; then
114448ffe56aSColin Percival		fetch_metadata_bogus ""
114548ffe56aSColin Percival		return 1
114648ffe56aSColin Percival	fi
114748ffe56aSColin Percival
114848ffe56aSColin Percival	# Sanity check entries with type '-'
114948ffe56aSColin Percival	if grep -E '^-' sanitycheck.tmp |
115048ffe56aSColin Percival	    grep -qvE "^-\|\|\|\|\|\|"; then
115148ffe56aSColin Percival		fetch_metadata_bogus ""
115248ffe56aSColin Percival		return 1
115348ffe56aSColin Percival	fi
115448ffe56aSColin Percival
115548ffe56aSColin Percival	# Clean up
115648ffe56aSColin Percival	rm sanitycheck.tmp
115748ffe56aSColin Percival}
115848ffe56aSColin Percival
115948ffe56aSColin Percival# Fetch the metadata index and metadata files listed in $@,
116048ffe56aSColin Percival# taking advantage of metadata patches where possible.
116148ffe56aSColin Percivalfetch_metadata () {
116248ffe56aSColin Percival	fetch_metadata_index || return 1
116348ffe56aSColin Percival	fetch_metadata_index_merge $@ || return 1
116448ffe56aSColin Percival	fetch_metadata_index_sanity || return 1
116548ffe56aSColin Percival
116648ffe56aSColin Percival	# Generate a list of wanted metadata patches
116748ffe56aSColin Percival	join -t '|' -o 1.2,2.2 tINDEX.present tINDEX.new |
116848ffe56aSColin Percival	    fetch_make_patchlist > patchlist
116948ffe56aSColin Percival
117048ffe56aSColin Percival	if [ -s patchlist ]; then
117148ffe56aSColin Percival		# Attempt to fetch metadata patches
117248ffe56aSColin Percival		echo -n "Fetching `wc -l < patchlist | tr -d ' '` "
117348ffe56aSColin Percival		echo ${NDEBUG} "metadata patches.${DDSTATS}"
117448ffe56aSColin Percival		tr '|' '-' < patchlist |
117548ffe56aSColin Percival		    lam -s "${FETCHDIR}/tp/" - -s ".gz" |
117648ffe56aSColin Percival		    xargs ${XARGST} ${PHTTPGET} ${SERVERNAME}	\
117748ffe56aSColin Percival			2>${STATSREDIR} | fetch_progress
117848ffe56aSColin Percival		echo "done."
117948ffe56aSColin Percival
118048ffe56aSColin Percival		# Attempt to apply metadata patches
118148ffe56aSColin Percival		echo -n "Applying metadata patches... "
118248ffe56aSColin Percival		tr '|' ' ' < patchlist |
118348ffe56aSColin Percival		    while read X Y; do
118448ffe56aSColin Percival			if [ ! -f "${X}-${Y}.gz" ]; then continue; fi
118548ffe56aSColin Percival			gunzip -c < ${X}-${Y}.gz > diff
118648ffe56aSColin Percival			gunzip -c < files/${X}.gz > diff-OLD
118748ffe56aSColin Percival
118848ffe56aSColin Percival			# Figure out which lines are being added and removed
118948ffe56aSColin Percival			grep -E '^-' diff |
119048ffe56aSColin Percival			    cut -c 2- |
119148ffe56aSColin Percival			    while read PREFIX; do
119248ffe56aSColin Percival				look "${PREFIX}" diff-OLD
119348ffe56aSColin Percival			    done |
119448ffe56aSColin Percival			    sort > diff-rm
119548ffe56aSColin Percival			grep -E '^\+' diff |
119648ffe56aSColin Percival			    cut -c 2- > diff-add
119748ffe56aSColin Percival
119848ffe56aSColin Percival			# Generate the new file
119948ffe56aSColin Percival			comm -23 diff-OLD diff-rm |
120048ffe56aSColin Percival			    sort - diff-add > diff-NEW
120148ffe56aSColin Percival
120248ffe56aSColin Percival			if [ `${SHA256} -q diff-NEW` = ${Y} ]; then
120348ffe56aSColin Percival				mv diff-NEW files/${Y}
120448ffe56aSColin Percival				gzip -n files/${Y}
120548ffe56aSColin Percival			else
120648ffe56aSColin Percival				mv diff-NEW ${Y}.bad
120748ffe56aSColin Percival			fi
120848ffe56aSColin Percival			rm -f ${X}-${Y}.gz diff
120948ffe56aSColin Percival			rm -f diff-OLD diff-NEW diff-add diff-rm
121048ffe56aSColin Percival		done 2>${QUIETREDIR}
121148ffe56aSColin Percival		echo "done."
121248ffe56aSColin Percival	fi
121348ffe56aSColin Percival
121448ffe56aSColin Percival	# Update metadata without patches
121548ffe56aSColin Percival	cut -f 2 -d '|' < tINDEX.new |
121648ffe56aSColin Percival	    while read Y; do
121748ffe56aSColin Percival		if [ ! -f "files/${Y}.gz" ]; then
121848ffe56aSColin Percival			echo ${Y};
121948ffe56aSColin Percival		fi
1220bce02f98SColin Percival	    done |
1221bce02f98SColin Percival	    sort -u > filelist
122248ffe56aSColin Percival
122348ffe56aSColin Percival	if [ -s filelist ]; then
122448ffe56aSColin Percival		echo -n "Fetching `wc -l < filelist | tr -d ' '` "
122548ffe56aSColin Percival		echo ${NDEBUG} "metadata files... "
122648ffe56aSColin Percival		lam -s "${FETCHDIR}/m/" - -s ".gz" < filelist |
122748ffe56aSColin Percival		    xargs ${XARGST} ${PHTTPGET} ${SERVERNAME}	\
122848ffe56aSColin Percival		    2>${QUIETREDIR}
122948ffe56aSColin Percival
123048ffe56aSColin Percival		while read Y; do
123148ffe56aSColin Percival			if ! [ -f ${Y}.gz ]; then
123248ffe56aSColin Percival				echo "failed."
123348ffe56aSColin Percival				return 1
123448ffe56aSColin Percival			fi
123548ffe56aSColin Percival			if [ `gunzip -c < ${Y}.gz |
123648ffe56aSColin Percival			    ${SHA256} -q` = ${Y} ]; then
123748ffe56aSColin Percival				mv ${Y}.gz files/${Y}.gz
123848ffe56aSColin Percival			else
123948ffe56aSColin Percival				echo "metadata is corrupt."
124048ffe56aSColin Percival				return 1
124148ffe56aSColin Percival			fi
124248ffe56aSColin Percival		done < filelist
124348ffe56aSColin Percival		echo "done."
124448ffe56aSColin Percival	fi
124548ffe56aSColin Percival
124648ffe56aSColin Percival# Sanity-check the metadata files.
124748ffe56aSColin Percival	cut -f 2 -d '|' tINDEX.new > filelist
124848ffe56aSColin Percival	while read X; do
124948ffe56aSColin Percival		fetch_metadata_sanity ${X} || return 1
125048ffe56aSColin Percival	done < filelist
125148ffe56aSColin Percival
125248ffe56aSColin Percival# Remove files which are no longer needed
125348ffe56aSColin Percival	cut -f 2 -d '|' tINDEX.present |
125448ffe56aSColin Percival	    sort > oldfiles
125548ffe56aSColin Percival	cut -f 2 -d '|' tINDEX.new |
125648ffe56aSColin Percival	    sort |
125748ffe56aSColin Percival	    comm -13 - oldfiles |
125848ffe56aSColin Percival	    lam -s "files/" - -s ".gz" |
125948ffe56aSColin Percival	    xargs rm -f
126048ffe56aSColin Percival	rm patchlist filelist oldfiles
126148ffe56aSColin Percival	rm ${TINDEXHASH}
126248ffe56aSColin Percival
126348ffe56aSColin Percival# We're done!
126448ffe56aSColin Percival	mv tINDEX.new tINDEX.present
126548ffe56aSColin Percival	mv tag.new tag
126648ffe56aSColin Percival
126748ffe56aSColin Percival	return 0
126848ffe56aSColin Percival}
126948ffe56aSColin Percival
1270db6b0a61SColin Percival# Extract a subset of a downloaded metadata file containing only the parts
1271db6b0a61SColin Percival# which are listed in COMPONENTS.
1272db6b0a61SColin Percivalfetch_filter_metadata_components () {
1273db6b0a61SColin Percival	METAHASH=`look "$1|" tINDEX.present | cut -f 2 -d '|'`
1274db6b0a61SColin Percival	gunzip -c < files/${METAHASH}.gz > $1.all
1275db6b0a61SColin Percival
1276db6b0a61SColin Percival	# Fish out the lines belonging to components we care about.
1277db6b0a61SColin Percival	for C in ${COMPONENTS}; do
1278db6b0a61SColin Percival		look "`echo ${C} | tr '/' '|'`|" $1.all
1279db6b0a61SColin Percival	done > $1
1280db6b0a61SColin Percival
1281db6b0a61SColin Percival	# Remove temporary file.
1282db6b0a61SColin Percival	rm $1.all
1283db6b0a61SColin Percival}
1284db6b0a61SColin Percival
1285b698a3abSColin Percival# Generate a filtered version of the metadata file $1 from the downloaded
128648ffe56aSColin Percival# file, by fishing out the lines corresponding to components we're trying
128748ffe56aSColin Percival# to keep updated, and then removing lines corresponding to paths we want
128848ffe56aSColin Percival# to ignore.
128948ffe56aSColin Percivalfetch_filter_metadata () {
129048ffe56aSColin Percival	# Fish out the lines belonging to components we care about.
1291db6b0a61SColin Percival	fetch_filter_metadata_components $1
1292db6b0a61SColin Percival
129348ffe56aSColin Percival	# Canonicalize directory names by removing any trailing / in
129448ffe56aSColin Percival	# order to avoid listing directories multiple times if they
129548ffe56aSColin Percival	# belong to multiple components.  Turning "/" into "" doesn't
129648ffe56aSColin Percival	# matter, since we add a leading "/" when we use paths later.
1297db6b0a61SColin Percival	cut -f 3- -d '|' $1 |
129848ffe56aSColin Percival	    sed -e 's,/|d|,|d|,' |
129948ffe56aSColin Percival	    sort -u > $1.tmp
130048ffe56aSColin Percival
130148ffe56aSColin Percival	# Figure out which lines to ignore and remove them.
130248ffe56aSColin Percival	for X in ${IGNOREPATHS}; do
130348ffe56aSColin Percival		grep -E "^${X}" $1.tmp
130448ffe56aSColin Percival	done |
130548ffe56aSColin Percival	    sort -u |
130648ffe56aSColin Percival	    comm -13 - $1.tmp > $1
130748ffe56aSColin Percival
130848ffe56aSColin Percival	# Remove temporary files.
1309db6b0a61SColin Percival	rm $1.tmp
131048ffe56aSColin Percival}
131148ffe56aSColin Percival
1312db6b0a61SColin Percival# Filter the metadata file $1 by adding lines with "/boot/$2"
1313bce02f98SColin Percival# replaced by ${KERNELDIR} (which is `sysctl -n kern.bootfile` minus the
1314db6b0a61SColin Percival# trailing "/kernel"); and if "/boot/$2" does not exist, remove
1315bce02f98SColin Percival# the original lines which start with that.
1316bce02f98SColin Percival# Put another way: Deal with the fact that the FOO kernel is sometimes
1317bce02f98SColin Percival# installed in /boot/FOO/ and is sometimes installed elsewhere.
131848ffe56aSColin Percivalfetch_filter_kernel_names () {
1319db6b0a61SColin Percival	grep ^/boot/$2 $1 |
1320db6b0a61SColin Percival	    sed -e "s,/boot/$2,${KERNELDIR},g" |
132148ffe56aSColin Percival	    sort - $1 > $1.tmp
132248ffe56aSColin Percival	mv $1.tmp $1
1323bce02f98SColin Percival
1324db6b0a61SColin Percival	if ! [ -d /boot/$2 ]; then
1325db6b0a61SColin Percival		grep -v ^/boot/$2 $1 > $1.tmp
1326bce02f98SColin Percival		mv $1.tmp $1
1327bce02f98SColin Percival	fi
132848ffe56aSColin Percival}
132948ffe56aSColin Percival
133048ffe56aSColin Percival# For all paths appearing in $1 or $3, inspect the system
133148ffe56aSColin Percival# and generate $2 describing what is currently installed.
133248ffe56aSColin Percivalfetch_inspect_system () {
133348ffe56aSColin Percival	# No errors yet...
133448ffe56aSColin Percival	rm -f .err
133548ffe56aSColin Percival
133648ffe56aSColin Percival	# Tell the user why his disk is suddenly making lots of noise
133748ffe56aSColin Percival	echo -n "Inspecting system... "
133848ffe56aSColin Percival
133948ffe56aSColin Percival	# Generate list of files to inspect
134048ffe56aSColin Percival	cat $1 $3 |
134148ffe56aSColin Percival	    cut -f 1 -d '|' |
134248ffe56aSColin Percival	    sort -u > filelist
134348ffe56aSColin Percival
134448ffe56aSColin Percival	# Examine each file and output lines of the form
134548ffe56aSColin Percival	# /path/to/file|type|device-inum|user|group|perm|flags|value
134648ffe56aSColin Percival	# sorted by device and inode number.
134748ffe56aSColin Percival	while read F; do
134848ffe56aSColin Percival		# If the symlink/file/directory does not exist, record this.
134948ffe56aSColin Percival		if ! [ -e ${BASEDIR}/${F} ]; then
135048ffe56aSColin Percival			echo "${F}|-||||||"
135148ffe56aSColin Percival			continue
135248ffe56aSColin Percival		fi
135348ffe56aSColin Percival		if ! [ -r ${BASEDIR}/${F} ]; then
135448ffe56aSColin Percival			echo "Cannot read file: ${BASEDIR}/${F}"	\
135548ffe56aSColin Percival			    >/dev/stderr
135648ffe56aSColin Percival			touch .err
135748ffe56aSColin Percival			return 1
135848ffe56aSColin Percival		fi
135948ffe56aSColin Percival
136048ffe56aSColin Percival		# Otherwise, output an index line.
136148ffe56aSColin Percival		if [ -L ${BASEDIR}/${F} ]; then
136248ffe56aSColin Percival			echo -n "${F}|L|"
136348ffe56aSColin Percival			stat -n -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F};
136448ffe56aSColin Percival			readlink ${BASEDIR}/${F};
136548ffe56aSColin Percival		elif [ -f ${BASEDIR}/${F} ]; then
136648ffe56aSColin Percival			echo -n "${F}|f|"
136748ffe56aSColin Percival			stat -n -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F};
136848ffe56aSColin Percival			sha256 -q ${BASEDIR}/${F};
136948ffe56aSColin Percival		elif [ -d ${BASEDIR}/${F} ]; then
137048ffe56aSColin Percival			echo -n "${F}|d|"
137148ffe56aSColin Percival			stat -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F};
137248ffe56aSColin Percival		else
137348ffe56aSColin Percival			echo "Unknown file type: ${BASEDIR}/${F}"	\
137448ffe56aSColin Percival			    >/dev/stderr
137548ffe56aSColin Percival			touch .err
137648ffe56aSColin Percival			return 1
137748ffe56aSColin Percival		fi
137848ffe56aSColin Percival	done < filelist |
137948ffe56aSColin Percival	    sort -k 3,3 -t '|' > $2.tmp
138048ffe56aSColin Percival	rm filelist
138148ffe56aSColin Percival
138248ffe56aSColin Percival	# Check if an error occured during system inspection
138348ffe56aSColin Percival	if [ -f .err ]; then
138448ffe56aSColin Percival		return 1
138548ffe56aSColin Percival	fi
138648ffe56aSColin Percival
138748ffe56aSColin Percival	# Convert to the form
138848ffe56aSColin Percival	# /path/to/file|type|user|group|perm|flags|value|hlink
138948ffe56aSColin Percival	# by resolving identical device and inode numbers into hard links.
139048ffe56aSColin Percival	cut -f 1,3 -d '|' $2.tmp |
139148ffe56aSColin Percival	    sort -k 1,1 -t '|' |
139248ffe56aSColin Percival	    sort -s -u -k 2,2 -t '|' |
139348ffe56aSColin Percival	    join -1 2 -2 3 -t '|' - $2.tmp |
139448ffe56aSColin Percival	    awk -F \| -v OFS=\|		\
139548ffe56aSColin Percival		'{
139648ffe56aSColin Percival		    if (($2 == $3) || ($4 == "-"))
139748ffe56aSColin Percival			print $3,$4,$5,$6,$7,$8,$9,""
139848ffe56aSColin Percival		    else
139948ffe56aSColin Percival			print $3,$4,$5,$6,$7,$8,$9,$2
140048ffe56aSColin Percival		}' |
140148ffe56aSColin Percival	    sort > $2
140248ffe56aSColin Percival	rm $2.tmp
140348ffe56aSColin Percival
140448ffe56aSColin Percival	# We're finished looking around
140548ffe56aSColin Percival	echo "done."
140648ffe56aSColin Percival}
140748ffe56aSColin Percival
1408db6b0a61SColin Percival# For any paths matching ${MERGECHANGES}, compare $1 and $2 and find any
1409db6b0a61SColin Percival# files which differ; generate $3 containing these paths and the old hashes.
1410db6b0a61SColin Percivalfetch_filter_mergechanges () {
1411db6b0a61SColin Percival	# Pull out the paths and hashes of the files matching ${MERGECHANGES}.
1412db6b0a61SColin Percival	for F in $1 $2; do
1413db6b0a61SColin Percival		for X in ${MERGECHANGES}; do
1414db6b0a61SColin Percival			grep -E "^${X}" ${F}
1415db6b0a61SColin Percival		done |
1416db6b0a61SColin Percival		    cut -f 1,2,7 -d '|' |
1417db6b0a61SColin Percival		    sort > ${F}-values
1418db6b0a61SColin Percival	done
1419db6b0a61SColin Percival
1420db6b0a61SColin Percival	# Any line in $2-values which doesn't appear in $1-values and is a
1421db6b0a61SColin Percival	# file means that we should list the path in $3.
1422db6b0a61SColin Percival	comm -13 $1-values $2-values |
1423db6b0a61SColin Percival	    fgrep '|f|' |
1424db6b0a61SColin Percival	    cut -f 1 -d '|' > $2-paths
1425db6b0a61SColin Percival
1426db6b0a61SColin Percival	# For each path, pull out one (and only one!) entry from $1-values.
1427db6b0a61SColin Percival	# Note that we cannot distinguish which "old" version the user made
1428db6b0a61SColin Percival	# changes to; but hopefully any changes which occur due to security
1429db6b0a61SColin Percival	# updates will exist in both the "new" version and the version which
1430db6b0a61SColin Percival	# the user has installed, so the merging will still work.
1431db6b0a61SColin Percival	while read X; do
1432db6b0a61SColin Percival		look "${X}|" $1-values |
1433db6b0a61SColin Percival		    head -1
1434db6b0a61SColin Percival	done < $2-paths > $3
1435db6b0a61SColin Percival
1436db6b0a61SColin Percival	# Clean up
1437db6b0a61SColin Percival	rm $1-values $2-values $2-paths
1438db6b0a61SColin Percival}
1439db6b0a61SColin Percival
144048ffe56aSColin Percival# For any paths matching ${UPDATEIFUNMODIFIED}, remove lines from $[123]
1441db6b0a61SColin Percival# which correspond to lines in $2 with hashes not matching $1 or $3, unless
1442db6b0a61SColin Percival# the paths are listed in $4.  For entries in $2 marked "not present"
1443db6b0a61SColin Percival# (aka. type -), remove lines from $[123] unless there is a corresponding
1444db6b0a61SColin Percival# entry in $1.
144548ffe56aSColin Percivalfetch_filter_unmodified_notpresent () {
144648ffe56aSColin Percival	# Figure out which lines of $1 and $3 correspond to bits which
144748ffe56aSColin Percival	# should only be updated if they haven't changed, and fish out
144848ffe56aSColin Percival	# the (path, type, value) tuples.
144948ffe56aSColin Percival	# NOTE: We don't consider a file to be "modified" if it matches
145048ffe56aSColin Percival	# the hash from $3.
145148ffe56aSColin Percival	for X in ${UPDATEIFUNMODIFIED}; do
145248ffe56aSColin Percival		grep -E "^${X}" $1
145348ffe56aSColin Percival		grep -E "^${X}" $3
145448ffe56aSColin Percival	done |
145548ffe56aSColin Percival	    cut -f 1,2,7 -d '|' |
145648ffe56aSColin Percival	    sort > $1-values
145748ffe56aSColin Percival
145848ffe56aSColin Percival	# Do the same for $2.
145948ffe56aSColin Percival	for X in ${UPDATEIFUNMODIFIED}; do
146048ffe56aSColin Percival		grep -E "^${X}" $2
146148ffe56aSColin Percival	done |
146248ffe56aSColin Percival	    cut -f 1,2,7 -d '|' |
146348ffe56aSColin Percival	    sort > $2-values
146448ffe56aSColin Percival
146548ffe56aSColin Percival	# Any entry in $2-values which is not in $1-values corresponds to
1466db6b0a61SColin Percival	# a path which we need to remove from $1, $2, and $3, unless it
1467db6b0a61SColin Percival	# that path appears in $4.
1468db6b0a61SColin Percival	comm -13 $1-values $2-values |
1469db6b0a61SColin Percival	    sort -t '|' -k 1,1 > mlines.tmp
1470db6b0a61SColin Percival	cut -f 1 -d '|' $4 |
1471db6b0a61SColin Percival	    sort |
1472db6b0a61SColin Percival	    join -v 2 -t '|' - mlines.tmp |
1473db6b0a61SColin Percival	    sort > mlines
1474db6b0a61SColin Percival	rm $1-values $2-values mlines.tmp
147548ffe56aSColin Percival
147648ffe56aSColin Percival	# Any lines in $2 which are not in $1 AND are "not present" lines
147748ffe56aSColin Percival	# also belong in mlines.
147848ffe56aSColin Percival	comm -13 $1 $2 |
147948ffe56aSColin Percival	    cut -f 1,2,7 -d '|' |
148048ffe56aSColin Percival	    fgrep '|-|' >> mlines
148148ffe56aSColin Percival
148248ffe56aSColin Percival	# Remove lines from $1, $2, and $3
148348ffe56aSColin Percival	for X in $1 $2 $3; do
148448ffe56aSColin Percival		sort -t '|' -k 1,1 ${X} > ${X}.tmp
148548ffe56aSColin Percival		cut -f 1 -d '|' < mlines |
148648ffe56aSColin Percival		    sort |
148748ffe56aSColin Percival		    join -v 2 -t '|' - ${X}.tmp |
148848ffe56aSColin Percival		    sort > ${X}
148948ffe56aSColin Percival		rm ${X}.tmp
149048ffe56aSColin Percival	done
149148ffe56aSColin Percival
149248ffe56aSColin Percival	# Store a list of the modified files, for future reference
149348ffe56aSColin Percival	fgrep -v '|-|' mlines |
149448ffe56aSColin Percival	    cut -f 1 -d '|' > modifiedfiles
149548ffe56aSColin Percival	rm mlines
149648ffe56aSColin Percival}
149748ffe56aSColin Percival
149848ffe56aSColin Percival# For each entry in $1 of type -, remove any corresponding
149948ffe56aSColin Percival# entry from $2 if ${ALLOWADD} != "yes".  Remove all entries
150048ffe56aSColin Percival# of type - from $1.
150148ffe56aSColin Percivalfetch_filter_allowadd () {
150248ffe56aSColin Percival	cut -f 1,2 -d '|' < $1 |
150348ffe56aSColin Percival	    fgrep '|-' |
150448ffe56aSColin Percival	    cut -f 1 -d '|' > filesnotpresent
150548ffe56aSColin Percival
150648ffe56aSColin Percival	if [ ${ALLOWADD} != "yes" ]; then
150748ffe56aSColin Percival		sort < $2 |
150848ffe56aSColin Percival		    join -v 1 -t '|' - filesnotpresent |
150948ffe56aSColin Percival		    sort > $2.tmp
151048ffe56aSColin Percival		mv $2.tmp $2
151148ffe56aSColin Percival	fi
151248ffe56aSColin Percival
151348ffe56aSColin Percival	sort < $1 |
151448ffe56aSColin Percival	    join -v 1 -t '|' - filesnotpresent |
151548ffe56aSColin Percival	    sort > $1.tmp
151648ffe56aSColin Percival	mv $1.tmp $1
151748ffe56aSColin Percival	rm filesnotpresent
151848ffe56aSColin Percival}
151948ffe56aSColin Percival
152048ffe56aSColin Percival# If ${ALLOWDELETE} != "yes", then remove any entries from $1
152148ffe56aSColin Percival# which don't correspond to entries in $2.
152248ffe56aSColin Percivalfetch_filter_allowdelete () {
152348ffe56aSColin Percival	# Produce a lists ${PATH}|${TYPE}
152448ffe56aSColin Percival	for X in $1 $2; do
152548ffe56aSColin Percival		cut -f 1-2 -d '|' < ${X} |
152648ffe56aSColin Percival		    sort -u > ${X}.nodes
152748ffe56aSColin Percival	done
152848ffe56aSColin Percival
152948ffe56aSColin Percival	# Figure out which lines need to be removed from $1.
153048ffe56aSColin Percival	if [ ${ALLOWDELETE} != "yes" ]; then
153148ffe56aSColin Percival		comm -23 $1.nodes $2.nodes > $1.badnodes
153248ffe56aSColin Percival	else
153348ffe56aSColin Percival		: > $1.badnodes
153448ffe56aSColin Percival	fi
153548ffe56aSColin Percival
153648ffe56aSColin Percival	# Remove the relevant lines from $1
153748ffe56aSColin Percival	while read X; do
153848ffe56aSColin Percival		look "${X}|" $1
153948ffe56aSColin Percival	done < $1.badnodes |
154048ffe56aSColin Percival	    comm -13 - $1 > $1.tmp
154148ffe56aSColin Percival	mv $1.tmp $1
154248ffe56aSColin Percival
154348ffe56aSColin Percival	rm $1.badnodes $1.nodes $2.nodes
154448ffe56aSColin Percival}
154548ffe56aSColin Percival
154648ffe56aSColin Percival# If ${KEEPMODIFIEDMETADATA} == "yes", then for each entry in $2
154748ffe56aSColin Percival# with metadata not matching any entry in $1, replace the corresponding
154848ffe56aSColin Percival# line of $3 with one having the same metadata as the entry in $2.
154948ffe56aSColin Percivalfetch_filter_modified_metadata () {
155048ffe56aSColin Percival	# Fish out the metadata from $1 and $2
155148ffe56aSColin Percival	for X in $1 $2; do
155248ffe56aSColin Percival		cut -f 1-6 -d '|' < ${X} > ${X}.metadata
155348ffe56aSColin Percival	done
155448ffe56aSColin Percival
155548ffe56aSColin Percival	# Find the metadata we need to keep
155648ffe56aSColin Percival	if [ ${KEEPMODIFIEDMETADATA} = "yes" ]; then
155748ffe56aSColin Percival		comm -13 $1.metadata $2.metadata > keepmeta
155848ffe56aSColin Percival	else
155948ffe56aSColin Percival		: > keepmeta
156048ffe56aSColin Percival	fi
156148ffe56aSColin Percival
156248ffe56aSColin Percival	# Extract the lines which we need to remove from $3, and
156348ffe56aSColin Percival	# construct the lines which we need to add to $3.
156448ffe56aSColin Percival	: > $3.remove
156548ffe56aSColin Percival	: > $3.add
156648ffe56aSColin Percival	while read LINE; do
156748ffe56aSColin Percival		NODE=`echo "${LINE}" | cut -f 1-2 -d '|'`
156848ffe56aSColin Percival		look "${NODE}|" $3 >> $3.remove
156948ffe56aSColin Percival		look "${NODE}|" $3 |
157048ffe56aSColin Percival		    cut -f 7- -d '|' |
157148ffe56aSColin Percival		    lam -s "${LINE}|" - >> $3.add
157248ffe56aSColin Percival	done < keepmeta
157348ffe56aSColin Percival
157448ffe56aSColin Percival	# Remove the specified lines and add the new lines.
157548ffe56aSColin Percival	sort $3.remove |
157648ffe56aSColin Percival	    comm -13 - $3 |
157748ffe56aSColin Percival	    sort -u - $3.add > $3.tmp
157848ffe56aSColin Percival	mv $3.tmp $3
157948ffe56aSColin Percival
158048ffe56aSColin Percival	rm keepmeta $1.metadata $2.metadata $3.add $3.remove
158148ffe56aSColin Percival}
158248ffe56aSColin Percival
158348ffe56aSColin Percival# Remove lines from $1 and $2 which are identical;
158448ffe56aSColin Percival# no need to update a file if it isn't changing.
158548ffe56aSColin Percivalfetch_filter_uptodate () {
158648ffe56aSColin Percival	comm -23 $1 $2 > $1.tmp
158748ffe56aSColin Percival	comm -13 $1 $2 > $2.tmp
158848ffe56aSColin Percival
158948ffe56aSColin Percival	mv $1.tmp $1
159048ffe56aSColin Percival	mv $2.tmp $2
159148ffe56aSColin Percival}
159248ffe56aSColin Percival
1593db6b0a61SColin Percival# Fetch any "clean" old versions of files we need for merging changes.
1594db6b0a61SColin Percivalfetch_files_premerge () {
1595db6b0a61SColin Percival	# We only need to do anything if $1 is non-empty.
1596db6b0a61SColin Percival	if [ -s $1 ]; then
1597db6b0a61SColin Percival		# Tell the user what we're doing
1598db6b0a61SColin Percival		echo -n "Fetching files from ${OLDRELNUM} for merging... "
1599db6b0a61SColin Percival
1600db6b0a61SColin Percival		# List of files wanted
1601db6b0a61SColin Percival		fgrep '|f|' < $1 |
1602db6b0a61SColin Percival		    cut -f 3 -d '|' |
1603db6b0a61SColin Percival		    sort -u > files.wanted
1604db6b0a61SColin Percival
1605db6b0a61SColin Percival		# Only fetch the files we don't already have
1606db6b0a61SColin Percival		while read Y; do
1607db6b0a61SColin Percival			if [ ! -f "files/${Y}.gz" ]; then
1608db6b0a61SColin Percival				echo ${Y};
1609db6b0a61SColin Percival			fi
1610db6b0a61SColin Percival		done < files.wanted > filelist
1611db6b0a61SColin Percival
1612db6b0a61SColin Percival		# Actually fetch them
1613db6b0a61SColin Percival		lam -s "${OLDFETCHDIR}/f/" - -s ".gz" < filelist |
1614db6b0a61SColin Percival		    xargs ${XARGST} ${PHTTPGET} ${SERVERNAME}	\
1615db6b0a61SColin Percival		    2>${QUIETREDIR}
1616db6b0a61SColin Percival
1617db6b0a61SColin Percival		# Make sure we got them all, and move them into /files/
1618db6b0a61SColin Percival		while read Y; do
1619db6b0a61SColin Percival			if ! [ -f ${Y}.gz ]; then
1620db6b0a61SColin Percival				echo "failed."
1621db6b0a61SColin Percival				return 1
1622db6b0a61SColin Percival			fi
1623db6b0a61SColin Percival			if [ `gunzip -c < ${Y}.gz |
1624db6b0a61SColin Percival			    ${SHA256} -q` = ${Y} ]; then
1625db6b0a61SColin Percival				mv ${Y}.gz files/${Y}.gz
1626db6b0a61SColin Percival			else
1627db6b0a61SColin Percival				echo "${Y} has incorrect hash."
1628db6b0a61SColin Percival				return 1
1629db6b0a61SColin Percival			fi
1630db6b0a61SColin Percival		done < filelist
1631db6b0a61SColin Percival		echo "done."
1632db6b0a61SColin Percival
1633db6b0a61SColin Percival		# Clean up
1634db6b0a61SColin Percival		rm filelist files.wanted
1635db6b0a61SColin Percival	fi
1636db6b0a61SColin Percival}
1637db6b0a61SColin Percival
163848ffe56aSColin Percival# Prepare to fetch files: Generate a list of the files we need,
163948ffe56aSColin Percival# copy the unmodified files we have into /files/, and generate
164048ffe56aSColin Percival# a list of patches to download.
164148ffe56aSColin Percivalfetch_files_prepare () {
164248ffe56aSColin Percival	# Tell the user why his disk is suddenly making lots of noise
164348ffe56aSColin Percival	echo -n "Preparing to download files... "
164448ffe56aSColin Percival
164548ffe56aSColin Percival	# Reduce indices to ${PATH}|${HASH} pairs
164648ffe56aSColin Percival	for X in $1 $2 $3; do
164748ffe56aSColin Percival		cut -f 1,2,7 -d '|' < ${X} |
164848ffe56aSColin Percival		    fgrep '|f|' |
164948ffe56aSColin Percival		    cut -f 1,3 -d '|' |
165048ffe56aSColin Percival		    sort > ${X}.hashes
165148ffe56aSColin Percival	done
165248ffe56aSColin Percival
165348ffe56aSColin Percival	# List of files wanted
165448ffe56aSColin Percival	cut -f 2 -d '|' < $3.hashes |
16552328d598SColin Percival	    sort -u |
16562328d598SColin Percival	    while read HASH; do
16572328d598SColin Percival		if ! [ -f files/${HASH}.gz ]; then
16582328d598SColin Percival			echo ${HASH}
16592328d598SColin Percival		fi
16602328d598SColin Percival	done > files.wanted
166148ffe56aSColin Percival
166248ffe56aSColin Percival	# Generate a list of unmodified files
166348ffe56aSColin Percival	comm -12 $1.hashes $2.hashes |
166448ffe56aSColin Percival	    sort -k 1,1 -t '|' > unmodified.files
166548ffe56aSColin Percival
166648ffe56aSColin Percival	# Copy all files into /files/.  We only need the unmodified files
166748ffe56aSColin Percival	# for use in patching; but we'll want all of them if the user asks
166848ffe56aSColin Percival	# to rollback the updates later.
1669210b8123SColin Percival	while read LINE; do
1670210b8123SColin Percival		F=`echo "${LINE}" | cut -f 1 -d '|'`
1671210b8123SColin Percival		HASH=`echo "${LINE}" | cut -f 2 -d '|'`
1672210b8123SColin Percival
1673210b8123SColin Percival		# Skip files we already have.
1674210b8123SColin Percival		if [ -f files/${HASH}.gz ]; then
1675210b8123SColin Percival			continue
1676210b8123SColin Percival		fi
1677210b8123SColin Percival
1678210b8123SColin Percival		# Make sure the file hasn't changed.
167948ffe56aSColin Percival		cp "${BASEDIR}/${F}" tmpfile
1680210b8123SColin Percival		if [ `sha256 -q tmpfile` != ${HASH} ]; then
1681210b8123SColin Percival			echo
1682210b8123SColin Percival			echo "File changed while FreeBSD Update running: ${F}"
1683210b8123SColin Percival			return 1
1684210b8123SColin Percival		fi
1685210b8123SColin Percival
1686210b8123SColin Percival		# Place the file into storage.
1687210b8123SColin Percival		gzip -c < tmpfile > files/${HASH}.gz
168848ffe56aSColin Percival		rm tmpfile
1689210b8123SColin Percival	done < $2.hashes
169048ffe56aSColin Percival
169148ffe56aSColin Percival	# Produce a list of patches to download
169248ffe56aSColin Percival	sort -k 1,1 -t '|' $3.hashes |
169348ffe56aSColin Percival	    join -t '|' -o 2.2,1.2 - unmodified.files |
169448ffe56aSColin Percival	    fetch_make_patchlist > patchlist
169548ffe56aSColin Percival
169648ffe56aSColin Percival	# Garbage collect
169748ffe56aSColin Percival	rm unmodified.files $1.hashes $2.hashes $3.hashes
169848ffe56aSColin Percival
169948ffe56aSColin Percival	# We don't need the list of possible old files any more.
170048ffe56aSColin Percival	rm $1
170148ffe56aSColin Percival
170248ffe56aSColin Percival	# We're finished making noise
170348ffe56aSColin Percival	echo "done."
170448ffe56aSColin Percival}
170548ffe56aSColin Percival
170648ffe56aSColin Percival# Fetch files.
170748ffe56aSColin Percivalfetch_files () {
170848ffe56aSColin Percival	# Attempt to fetch patches
170948ffe56aSColin Percival	if [ -s patchlist ]; then
171048ffe56aSColin Percival		echo -n "Fetching `wc -l < patchlist | tr -d ' '` "
171148ffe56aSColin Percival		echo ${NDEBUG} "patches.${DDSTATS}"
171248ffe56aSColin Percival		tr '|' '-' < patchlist |
1713db6b0a61SColin Percival		    lam -s "${PATCHDIR}/" - |
171448ffe56aSColin Percival		    xargs ${XARGST} ${PHTTPGET} ${SERVERNAME}	\
171548ffe56aSColin Percival			2>${STATSREDIR} | fetch_progress
171648ffe56aSColin Percival		echo "done."
171748ffe56aSColin Percival
171848ffe56aSColin Percival		# Attempt to apply patches
171948ffe56aSColin Percival		echo -n "Applying patches... "
172048ffe56aSColin Percival		tr '|' ' ' < patchlist |
172148ffe56aSColin Percival		    while read X Y; do
172248ffe56aSColin Percival			if [ ! -f "${X}-${Y}" ]; then continue; fi
172348ffe56aSColin Percival			gunzip -c < files/${X}.gz > OLD
172448ffe56aSColin Percival
172548ffe56aSColin Percival			bspatch OLD NEW ${X}-${Y}
172648ffe56aSColin Percival
172748ffe56aSColin Percival			if [ `${SHA256} -q NEW` = ${Y} ]; then
172848ffe56aSColin Percival				mv NEW files/${Y}
172948ffe56aSColin Percival				gzip -n files/${Y}
173048ffe56aSColin Percival			fi
173148ffe56aSColin Percival			rm -f diff OLD NEW ${X}-${Y}
173248ffe56aSColin Percival		done 2>${QUIETREDIR}
173348ffe56aSColin Percival		echo "done."
173448ffe56aSColin Percival	fi
173548ffe56aSColin Percival
173648ffe56aSColin Percival	# Download files which couldn't be generate via patching
173748ffe56aSColin Percival	while read Y; do
173848ffe56aSColin Percival		if [ ! -f "files/${Y}.gz" ]; then
173948ffe56aSColin Percival			echo ${Y};
174048ffe56aSColin Percival		fi
174148ffe56aSColin Percival	done < files.wanted > filelist
174248ffe56aSColin Percival
174348ffe56aSColin Percival	if [ -s filelist ]; then
174448ffe56aSColin Percival		echo -n "Fetching `wc -l < filelist | tr -d ' '` "
174548ffe56aSColin Percival		echo ${NDEBUG} "files... "
174648ffe56aSColin Percival		lam -s "${FETCHDIR}/f/" - -s ".gz" < filelist |
174748ffe56aSColin Percival		    xargs ${XARGST} ${PHTTPGET} ${SERVERNAME}	\
174848ffe56aSColin Percival		    2>${QUIETREDIR}
174948ffe56aSColin Percival
175048ffe56aSColin Percival		while read Y; do
175148ffe56aSColin Percival			if ! [ -f ${Y}.gz ]; then
175248ffe56aSColin Percival				echo "failed."
175348ffe56aSColin Percival				return 1
175448ffe56aSColin Percival			fi
175548ffe56aSColin Percival			if [ `gunzip -c < ${Y}.gz |
175648ffe56aSColin Percival			    ${SHA256} -q` = ${Y} ]; then
175748ffe56aSColin Percival				mv ${Y}.gz files/${Y}.gz
175848ffe56aSColin Percival			else
175948ffe56aSColin Percival				echo "${Y} has incorrect hash."
176048ffe56aSColin Percival				return 1
176148ffe56aSColin Percival			fi
176248ffe56aSColin Percival		done < filelist
176348ffe56aSColin Percival		echo "done."
176448ffe56aSColin Percival	fi
176548ffe56aSColin Percival
176648ffe56aSColin Percival	# Clean up
176748ffe56aSColin Percival	rm files.wanted filelist patchlist
176848ffe56aSColin Percival}
176948ffe56aSColin Percival
177048ffe56aSColin Percival# Create and populate install manifest directory; and report what updates
177148ffe56aSColin Percival# are available.
177248ffe56aSColin Percivalfetch_create_manifest () {
177348ffe56aSColin Percival	# If we have an existing install manifest, nuke it.
177448ffe56aSColin Percival	if [ -L "${BDHASH}-install" ]; then
177548ffe56aSColin Percival		rm -r ${BDHASH}-install/
177648ffe56aSColin Percival		rm ${BDHASH}-install
177748ffe56aSColin Percival	fi
177848ffe56aSColin Percival
177948ffe56aSColin Percival	# Report to the user if any updates were avoided due to local changes
178048ffe56aSColin Percival	if [ -s modifiedfiles ]; then
178148ffe56aSColin Percival		echo
178248ffe56aSColin Percival		echo -n "The following files are affected by updates, "
178348ffe56aSColin Percival		echo "but no changes have"
178448ffe56aSColin Percival		echo -n "been downloaded because the files have been "
178548ffe56aSColin Percival		echo "modified locally:"
178648ffe56aSColin Percival		cat modifiedfiles
1787db6b0a61SColin Percival	fi | more
178848ffe56aSColin Percival	rm modifiedfiles
178948ffe56aSColin Percival
179048ffe56aSColin Percival	# If no files will be updated, tell the user and exit
179148ffe56aSColin Percival	if ! [ -s INDEX-PRESENT ] &&
179248ffe56aSColin Percival	    ! [ -s INDEX-NEW ]; then
179348ffe56aSColin Percival		rm INDEX-PRESENT INDEX-NEW
179448ffe56aSColin Percival		echo
179548ffe56aSColin Percival		echo -n "No updates needed to update system to "
179648ffe56aSColin Percival		echo "${RELNUM}-p${RELPATCHNUM}."
179748ffe56aSColin Percival		return
179848ffe56aSColin Percival	fi
179948ffe56aSColin Percival
180048ffe56aSColin Percival	# Divide files into (a) removed files, (b) added files, and
180148ffe56aSColin Percival	# (c) updated files.
180248ffe56aSColin Percival	cut -f 1 -d '|' < INDEX-PRESENT |
180348ffe56aSColin Percival	    sort > INDEX-PRESENT.flist
180448ffe56aSColin Percival	cut -f 1 -d '|' < INDEX-NEW |
180548ffe56aSColin Percival	    sort > INDEX-NEW.flist
180648ffe56aSColin Percival	comm -23 INDEX-PRESENT.flist INDEX-NEW.flist > files.removed
180748ffe56aSColin Percival	comm -13 INDEX-PRESENT.flist INDEX-NEW.flist > files.added
180848ffe56aSColin Percival	comm -12 INDEX-PRESENT.flist INDEX-NEW.flist > files.updated
180948ffe56aSColin Percival	rm INDEX-PRESENT.flist INDEX-NEW.flist
181048ffe56aSColin Percival
181148ffe56aSColin Percival	# Report removed files, if any
181248ffe56aSColin Percival	if [ -s files.removed ]; then
181348ffe56aSColin Percival		echo
181448ffe56aSColin Percival		echo -n "The following files will be removed "
181548ffe56aSColin Percival		echo "as part of updating to ${RELNUM}-p${RELPATCHNUM}:"
181648ffe56aSColin Percival		cat files.removed
1817db6b0a61SColin Percival	fi | more
181848ffe56aSColin Percival	rm files.removed
181948ffe56aSColin Percival
182048ffe56aSColin Percival	# Report added files, if any
182148ffe56aSColin Percival	if [ -s files.added ]; then
182248ffe56aSColin Percival		echo
182348ffe56aSColin Percival		echo -n "The following files will be added "
182448ffe56aSColin Percival		echo "as part of updating to ${RELNUM}-p${RELPATCHNUM}:"
182548ffe56aSColin Percival		cat files.added
1826db6b0a61SColin Percival	fi | more
182748ffe56aSColin Percival	rm files.added
182848ffe56aSColin Percival
182948ffe56aSColin Percival	# Report updated files, if any
183048ffe56aSColin Percival	if [ -s files.updated ]; then
183148ffe56aSColin Percival		echo
183248ffe56aSColin Percival		echo -n "The following files will be updated "
183348ffe56aSColin Percival		echo "as part of updating to ${RELNUM}-p${RELPATCHNUM}:"
183448ffe56aSColin Percival
183548ffe56aSColin Percival		cat files.updated
1836db6b0a61SColin Percival	fi | more
183748ffe56aSColin Percival	rm files.updated
183848ffe56aSColin Percival
183948ffe56aSColin Percival	# Create a directory for the install manifest.
184048ffe56aSColin Percival	MDIR=`mktemp -d install.XXXXXX` || return 1
184148ffe56aSColin Percival
184248ffe56aSColin Percival	# Populate it
184348ffe56aSColin Percival	mv INDEX-PRESENT ${MDIR}/INDEX-OLD
184448ffe56aSColin Percival	mv INDEX-NEW ${MDIR}/INDEX-NEW
184548ffe56aSColin Percival
184648ffe56aSColin Percival	# Link it into place
184748ffe56aSColin Percival	ln -s ${MDIR} ${BDHASH}-install
184848ffe56aSColin Percival}
184948ffe56aSColin Percival
185048ffe56aSColin Percival# Warn about any upcoming EoL
185148ffe56aSColin Percivalfetch_warn_eol () {
185248ffe56aSColin Percival	# What's the current time?
185348ffe56aSColin Percival	NOWTIME=`date "+%s"`
185448ffe56aSColin Percival
185548ffe56aSColin Percival	# When did we last warn about the EoL date?
185648ffe56aSColin Percival	if [ -f lasteolwarn ]; then
185748ffe56aSColin Percival		LASTWARN=`cat lasteolwarn`
185848ffe56aSColin Percival	else
185948ffe56aSColin Percival		LASTWARN=`expr ${NOWTIME} - 63072000`
186048ffe56aSColin Percival	fi
186148ffe56aSColin Percival
186248ffe56aSColin Percival	# If the EoL time is past, warn.
186348ffe56aSColin Percival	if [ ${EOLTIME} -lt ${NOWTIME} ]; then
186448ffe56aSColin Percival		echo
186548ffe56aSColin Percival		cat <<-EOF
1866b698a3abSColin Percival		WARNING: `uname -sr` HAS PASSED ITS END-OF-LIFE DATE.
186748ffe56aSColin Percival		Any security issues discovered after `date -r ${EOLTIME}`
186848ffe56aSColin Percival		will not have been corrected.
186948ffe56aSColin Percival		EOF
187048ffe56aSColin Percival		return 1
187148ffe56aSColin Percival	fi
187248ffe56aSColin Percival
187348ffe56aSColin Percival	# Figure out how long it has been since we last warned about the
187448ffe56aSColin Percival	# upcoming EoL, and how much longer we have left.
187548ffe56aSColin Percival	SINCEWARN=`expr ${NOWTIME} - ${LASTWARN}`
187648ffe56aSColin Percival	TIMELEFT=`expr ${EOLTIME} - ${NOWTIME}`
187748ffe56aSColin Percival
187889b14566SColin Percival	# Don't warn if the EoL is more than 3 months away
187989b14566SColin Percival	if [ ${TIMELEFT} -gt 7884000 ]; then
188048ffe56aSColin Percival		return 0
188148ffe56aSColin Percival	fi
188248ffe56aSColin Percival
188348ffe56aSColin Percival	# Don't warn if the time remaining is more than 3 times the time
188448ffe56aSColin Percival	# since the last warning.
188548ffe56aSColin Percival	if [ ${TIMELEFT} -gt `expr ${SINCEWARN} \* 3` ]; then
188648ffe56aSColin Percival		return 0
188748ffe56aSColin Percival	fi
188848ffe56aSColin Percival
188948ffe56aSColin Percival	# Figure out what time units to use.
189048ffe56aSColin Percival	if [ ${TIMELEFT} -lt 604800 ]; then
189148ffe56aSColin Percival		UNIT="day"
189248ffe56aSColin Percival		SIZE=86400
189348ffe56aSColin Percival	elif [ ${TIMELEFT} -lt 2678400 ]; then
189448ffe56aSColin Percival		UNIT="week"
189548ffe56aSColin Percival		SIZE=604800
189648ffe56aSColin Percival	else
189748ffe56aSColin Percival		UNIT="month"
189848ffe56aSColin Percival		SIZE=2678400
189948ffe56aSColin Percival	fi
190048ffe56aSColin Percival
190148ffe56aSColin Percival	# Compute the right number of units
190248ffe56aSColin Percival	NUM=`expr ${TIMELEFT} / ${SIZE}`
190348ffe56aSColin Percival	if [ ${NUM} != 1 ]; then
190448ffe56aSColin Percival		UNIT="${UNIT}s"
190548ffe56aSColin Percival	fi
190648ffe56aSColin Percival
190748ffe56aSColin Percival	# Print the warning
190848ffe56aSColin Percival	echo
190948ffe56aSColin Percival	cat <<-EOF
191048ffe56aSColin Percival		WARNING: `uname -sr` is approaching its End-of-Life date.
191148ffe56aSColin Percival		It is strongly recommended that you upgrade to a newer
191248ffe56aSColin Percival		release within the next ${NUM} ${UNIT}.
191348ffe56aSColin Percival	EOF
191448ffe56aSColin Percival
191548ffe56aSColin Percival	# Update the stored time of last warning
191648ffe56aSColin Percival	echo ${NOWTIME} > lasteolwarn
191748ffe56aSColin Percival}
191848ffe56aSColin Percival
191948ffe56aSColin Percival# Do the actual work involved in "fetch" / "cron".
192048ffe56aSColin Percivalfetch_run () {
192148ffe56aSColin Percival	workdir_init || return 1
192248ffe56aSColin Percival
192348ffe56aSColin Percival	# Prepare the mirror list.
192448ffe56aSColin Percival	fetch_pick_server_init && fetch_pick_server
192548ffe56aSColin Percival
192648ffe56aSColin Percival	# Try to fetch the public key until we run out of servers.
192748ffe56aSColin Percival	while ! fetch_key; do
192848ffe56aSColin Percival		fetch_pick_server || return 1
192948ffe56aSColin Percival	done
193048ffe56aSColin Percival
193148ffe56aSColin Percival	# Try to fetch the metadata index signature ("tag") until we run
193248ffe56aSColin Percival	# out of available servers; and sanity check the downloaded tag.
193348ffe56aSColin Percival	while ! fetch_tag; do
193448ffe56aSColin Percival		fetch_pick_server || return 1
193548ffe56aSColin Percival	done
193648ffe56aSColin Percival	fetch_tagsanity || return 1
193748ffe56aSColin Percival
193848ffe56aSColin Percival	# Fetch the latest INDEX-NEW and INDEX-OLD files.
193948ffe56aSColin Percival	fetch_metadata INDEX-NEW INDEX-OLD || return 1
194048ffe56aSColin Percival
194148ffe56aSColin Percival	# Generate filtered INDEX-NEW and INDEX-OLD files containing only
194248ffe56aSColin Percival	# the lines which (a) belong to components we care about, and (b)
194348ffe56aSColin Percival	# don't correspond to paths we're explicitly ignoring.
194448ffe56aSColin Percival	fetch_filter_metadata INDEX-NEW || return 1
194548ffe56aSColin Percival	fetch_filter_metadata INDEX-OLD || return 1
194648ffe56aSColin Percival
1947db6b0a61SColin Percival	# Translate /boot/${KERNCONF} into ${KERNELDIR}
1948db6b0a61SColin Percival	fetch_filter_kernel_names INDEX-NEW ${KERNCONF}
1949db6b0a61SColin Percival	fetch_filter_kernel_names INDEX-OLD ${KERNCONF}
195048ffe56aSColin Percival
195148ffe56aSColin Percival	# For all paths appearing in INDEX-OLD or INDEX-NEW, inspect the
195248ffe56aSColin Percival	# system and generate an INDEX-PRESENT file.
195348ffe56aSColin Percival	fetch_inspect_system INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1
195448ffe56aSColin Percival
195548ffe56aSColin Percival	# Based on ${UPDATEIFUNMODIFIED}, remove lines from INDEX-* which
195648ffe56aSColin Percival	# correspond to lines in INDEX-PRESENT with hashes not appearing
195748ffe56aSColin Percival	# in INDEX-OLD or INDEX-NEW.  Also remove lines where the entry in
195848ffe56aSColin Percival	# INDEX-PRESENT has type - and there isn't a corresponding entry in
195948ffe56aSColin Percival	# INDEX-OLD with type -.
1960db6b0a61SColin Percival	fetch_filter_unmodified_notpresent	\
1961db6b0a61SColin Percival	    INDEX-OLD INDEX-PRESENT INDEX-NEW /dev/null
196248ffe56aSColin Percival
196348ffe56aSColin Percival	# For each entry in INDEX-PRESENT of type -, remove any corresponding
196448ffe56aSColin Percival	# entry from INDEX-NEW if ${ALLOWADD} != "yes".  Remove all entries
196548ffe56aSColin Percival	# of type - from INDEX-PRESENT.
196648ffe56aSColin Percival	fetch_filter_allowadd INDEX-PRESENT INDEX-NEW
196748ffe56aSColin Percival
196848ffe56aSColin Percival	# If ${ALLOWDELETE} != "yes", then remove any entries from
196948ffe56aSColin Percival	# INDEX-PRESENT which don't correspond to entries in INDEX-NEW.
197048ffe56aSColin Percival	fetch_filter_allowdelete INDEX-PRESENT INDEX-NEW
197148ffe56aSColin Percival
197248ffe56aSColin Percival	# If ${KEEPMODIFIEDMETADATA} == "yes", then for each entry in
197348ffe56aSColin Percival	# INDEX-PRESENT with metadata not matching any entry in INDEX-OLD,
197448ffe56aSColin Percival	# replace the corresponding line of INDEX-NEW with one having the
197548ffe56aSColin Percival	# same metadata as the entry in INDEX-PRESENT.
197648ffe56aSColin Percival	fetch_filter_modified_metadata INDEX-OLD INDEX-PRESENT INDEX-NEW
197748ffe56aSColin Percival
197848ffe56aSColin Percival	# Remove lines from INDEX-PRESENT and INDEX-NEW which are identical;
197948ffe56aSColin Percival	# no need to update a file if it isn't changing.
198048ffe56aSColin Percival	fetch_filter_uptodate INDEX-PRESENT INDEX-NEW
198148ffe56aSColin Percival
198248ffe56aSColin Percival	# Prepare to fetch files: Generate a list of the files we need,
198348ffe56aSColin Percival	# copy the unmodified files we have into /files/, and generate
198448ffe56aSColin Percival	# a list of patches to download.
1985210b8123SColin Percival	fetch_files_prepare INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1
198648ffe56aSColin Percival
198748ffe56aSColin Percival	# Fetch files.
198848ffe56aSColin Percival	fetch_files || return 1
198948ffe56aSColin Percival
199048ffe56aSColin Percival	# Create and populate install manifest directory; and report what
199148ffe56aSColin Percival	# updates are available.
199248ffe56aSColin Percival	fetch_create_manifest || return 1
199348ffe56aSColin Percival
199448ffe56aSColin Percival	# Warn about any upcoming EoL
199548ffe56aSColin Percival	fetch_warn_eol || return 1
199648ffe56aSColin Percival}
199748ffe56aSColin Percival
1998db6b0a61SColin Percival# If StrictComponents is not "yes", generate a new components list
1999db6b0a61SColin Percival# with only the components which appear to be installed.
2000db6b0a61SColin Percivalupgrade_guess_components () {
2001db6b0a61SColin Percival	if [ "${STRICTCOMPONENTS}" = "no" ]; then
2002db6b0a61SColin Percival		# Generate filtered INDEX-ALL with only the components listed
2003db6b0a61SColin Percival		# in COMPONENTS.
2004db6b0a61SColin Percival		fetch_filter_metadata_components $1 || return 1
2005db6b0a61SColin Percival
2006db6b0a61SColin Percival		# Tell the user why his disk is suddenly making lots of noise
2007db6b0a61SColin Percival		echo -n "Inspecting system... "
2008db6b0a61SColin Percival
2009db6b0a61SColin Percival		# Look at the files on disk, and assume that a component is
2010db6b0a61SColin Percival		# supposed to be present if it is more than half-present.
2011db6b0a61SColin Percival		cut -f 1-3 -d '|' < INDEX-ALL |
2012db6b0a61SColin Percival		    tr '|' ' ' |
2013db6b0a61SColin Percival		    while read C S F; do
2014db6b0a61SColin Percival			if [ -e ${BASEDIR}/${F} ]; then
2015db6b0a61SColin Percival				echo "+ ${C}|${S}"
2016db6b0a61SColin Percival			fi
2017db6b0a61SColin Percival			echo "= ${C}|${S}"
2018db6b0a61SColin Percival		    done |
2019db6b0a61SColin Percival		    sort |
2020db6b0a61SColin Percival		    uniq -c |
2021db6b0a61SColin Percival		    sed -E 's,^ +,,' > compfreq
2022db6b0a61SColin Percival		grep ' = ' compfreq |
2023db6b0a61SColin Percival		    cut -f 1,3 -d ' ' |
2024db6b0a61SColin Percival		    sort -k 2,2 -t ' ' > compfreq.total
2025db6b0a61SColin Percival		grep ' + ' compfreq |
2026db6b0a61SColin Percival		    cut -f 1,3 -d ' ' |
2027db6b0a61SColin Percival		    sort -k 2,2 -t ' ' > compfreq.present
2028db6b0a61SColin Percival		join -t ' ' -1 2 -2 2 compfreq.present compfreq.total |
2029db6b0a61SColin Percival		    while read S P T; do
2030db6b0a61SColin Percival			if [ ${P} -gt `expr ${T} / 2` ]; then
2031db6b0a61SColin Percival				echo ${S}
2032db6b0a61SColin Percival			fi
2033db6b0a61SColin Percival		    done > comp.present
2034db6b0a61SColin Percival		cut -f 2 -d ' ' < compfreq.total > comp.total
2035db6b0a61SColin Percival		rm INDEX-ALL compfreq compfreq.total compfreq.present
2036db6b0a61SColin Percival
2037db6b0a61SColin Percival		# We're done making noise.
2038db6b0a61SColin Percival		echo "done."
2039db6b0a61SColin Percival
2040db6b0a61SColin Percival		# Sometimes the kernel isn't installed where INDEX-ALL
2041db6b0a61SColin Percival		# thinks that it should be: In particular, it is often in
2042db6b0a61SColin Percival		# /boot/kernel instead of /boot/GENERIC or /boot/SMP.  To
2043db6b0a61SColin Percival		# deal with this, if "kernel|X" is listed in comp.total
2044db6b0a61SColin Percival		# (i.e., is a component which would be upgraded if it is
2045db6b0a61SColin Percival		# found to be present) we will add it to comp.present.
2046db6b0a61SColin Percival		# If "kernel|<anything>" is in comp.total but "kernel|X" is
2047db6b0a61SColin Percival		# not, we print a warning -- the user is running a kernel
2048db6b0a61SColin Percival		# which isn't part of the release.
2049db6b0a61SColin Percival		KCOMP=`echo ${KERNCONF} | tr 'A-Z' 'a-z'`
2050db6b0a61SColin Percival		grep -E "^kernel\|${KCOMP}\$" comp.total >> comp.present
2051db6b0a61SColin Percival
2052db6b0a61SColin Percival		if grep -qE "^kernel\|" comp.total &&
2053db6b0a61SColin Percival		    ! grep -qE "^kernel\|${KCOMP}\$" comp.total; then
2054db6b0a61SColin Percival			cat <<-EOF
2055db6b0a61SColin Percival
2056db6b0a61SColin PercivalWARNING: This system is running a "${KCOMP}" kernel, which is not a
2057db6b0a61SColin Percivalkernel configuration distributed as part of FreeBSD ${RELNUM}.
2058db6b0a61SColin PercivalThis kernel will not be updated: you MUST update the kernel manually
2059db6b0a61SColin Percivalbefore running "$0 install".
2060db6b0a61SColin Percival			EOF
2061db6b0a61SColin Percival		fi
2062db6b0a61SColin Percival
2063db6b0a61SColin Percival		# Re-sort the list of installed components and generate
2064db6b0a61SColin Percival		# the list of non-installed components.
2065db6b0a61SColin Percival		sort -u < comp.present > comp.present.tmp
2066db6b0a61SColin Percival		mv comp.present.tmp comp.present
2067db6b0a61SColin Percival		comm -13 comp.present comp.total > comp.absent
2068db6b0a61SColin Percival
2069db6b0a61SColin Percival		# Ask the user to confirm that what we have is correct.  To
2070db6b0a61SColin Percival		# reduce user confusion, translate "X|Y" back to "X/Y" (as
2071db6b0a61SColin Percival		# subcomponents must be listed in the configuration file).
2072db6b0a61SColin Percival		echo
2073db6b0a61SColin Percival		echo -n "The following components of FreeBSD "
2074db6b0a61SColin Percival		echo "seem to be installed:"
2075db6b0a61SColin Percival		tr '|' '/' < comp.present |
2076db6b0a61SColin Percival		    fmt -72
2077db6b0a61SColin Percival		echo
2078db6b0a61SColin Percival		echo -n "The following components of FreeBSD "
2079db6b0a61SColin Percival		echo "do not seem to be installed:"
2080db6b0a61SColin Percival		tr '|' '/' < comp.absent |
2081db6b0a61SColin Percival		    fmt -72
2082db6b0a61SColin Percival		echo
2083db6b0a61SColin Percival		continuep || return 1
2084db6b0a61SColin Percival		echo
2085db6b0a61SColin Percival
2086db6b0a61SColin Percival		# Suck the generated list of components into ${COMPONENTS}.
2087db6b0a61SColin Percival		# Note that comp.present.tmp is used due to issues with
2088db6b0a61SColin Percival		# pipelines and setting variables.
2089db6b0a61SColin Percival		COMPONENTS=""
2090db6b0a61SColin Percival		tr '|' '/' < comp.present > comp.present.tmp
2091db6b0a61SColin Percival		while read C; do
2092db6b0a61SColin Percival			COMPONENTS="${COMPONENTS} ${C}"
2093db6b0a61SColin Percival		done < comp.present.tmp
2094db6b0a61SColin Percival
2095db6b0a61SColin Percival		# Delete temporary files
2096db6b0a61SColin Percival		rm comp.present comp.present.tmp comp.absent comp.total
2097db6b0a61SColin Percival	fi
2098db6b0a61SColin Percival}
2099db6b0a61SColin Percival
2100db6b0a61SColin Percival# If StrictComponents is not "yes", COMPONENTS contains an entry
2101db6b0a61SColin Percival# corresponding to the currently running kernel, and said kernel
2102db6b0a61SColin Percival# does not exist in the new release, add "kernel/generic" to the
2103db6b0a61SColin Percival# list of components.
2104db6b0a61SColin Percivalupgrade_guess_new_kernel () {
2105db6b0a61SColin Percival	if [ "${STRICTCOMPONENTS}" = "no" ]; then
2106db6b0a61SColin Percival		# Grab the unfiltered metadata file.
2107db6b0a61SColin Percival		METAHASH=`look "$1|" tINDEX.present | cut -f 2 -d '|'`
2108db6b0a61SColin Percival		gunzip -c < files/${METAHASH}.gz > $1.all
2109db6b0a61SColin Percival
2110db6b0a61SColin Percival		# If "kernel/${KCOMP}" is in ${COMPONENTS} and that component
2111db6b0a61SColin Percival		# isn't in $1.all, we need to add kernel/generic.
2112db6b0a61SColin Percival		for C in ${COMPONENTS}; do
2113db6b0a61SColin Percival			if [ ${C} = "kernel/${KCOMP}" ] &&
2114db6b0a61SColin Percival			    ! grep -qE "^kernel\|${KCOMP}\|" $1.all; then
2115db6b0a61SColin Percival				COMPONENTS="${COMPONENTS} kernel/generic"
2116db6b0a61SColin Percival				NKERNCONF="GENERIC"
2117db6b0a61SColin Percival				cat <<-EOF
2118db6b0a61SColin Percival
2119db6b0a61SColin PercivalWARNING: This system is running a "${KCOMP}" kernel, which is not a
2120db6b0a61SColin Percivalkernel configuration distributed as part of FreeBSD ${RELNUM}.
2121db6b0a61SColin PercivalAs part of upgrading to FreeBSD ${RELNUM}, this kernel will be
2122db6b0a61SColin Percivalreplaced with a "generic" kernel.
2123db6b0a61SColin Percival				EOF
2124db6b0a61SColin Percival				continuep || return 1
2125db6b0a61SColin Percival			fi
2126db6b0a61SColin Percival		done
2127db6b0a61SColin Percival
2128db6b0a61SColin Percival		# Don't need this any more...
2129db6b0a61SColin Percival		rm $1.all
2130db6b0a61SColin Percival	fi
2131db6b0a61SColin Percival}
2132db6b0a61SColin Percival
2133db6b0a61SColin Percival# Convert INDEX-OLD (last release) and INDEX-ALL (new release) into
2134db6b0a61SColin Percival# INDEX-OLD and INDEX-NEW files (in the sense of normal upgrades).
2135db6b0a61SColin Percivalupgrade_oldall_to_oldnew () {
2136db6b0a61SColin Percival	# For each ${F}|... which appears in INDEX-ALL but does not appear
2137db6b0a61SColin Percival	# in INDEX-OLD, add ${F}|-|||||| to INDEX-OLD.
2138db6b0a61SColin Percival	cut -f 1 -d '|' < $1 |
2139db6b0a61SColin Percival	    sort -u > $1.paths
2140db6b0a61SColin Percival	cut -f 1 -d '|' < $2 |
2141db6b0a61SColin Percival	    sort -u |
2142db6b0a61SColin Percival	    comm -13 $1.paths - |
2143db6b0a61SColin Percival	    lam - -s "|-||||||" |
2144db6b0a61SColin Percival	    sort - $1 > $1.tmp
2145db6b0a61SColin Percival	mv $1.tmp $1
2146db6b0a61SColin Percival
2147db6b0a61SColin Percival	# Remove lines from INDEX-OLD which also appear in INDEX-ALL
2148db6b0a61SColin Percival	comm -23 $1 $2 > $1.tmp
2149db6b0a61SColin Percival	mv $1.tmp $1
2150db6b0a61SColin Percival
2151db6b0a61SColin Percival	# Remove lines from INDEX-ALL which have a file name not appearing
2152db6b0a61SColin Percival	# anywhere in INDEX-OLD (since these must be files which haven't
2153db6b0a61SColin Percival	# changed -- if they were new, there would be an entry of type "-").
2154db6b0a61SColin Percival	cut -f 1 -d '|' < $1 |
2155db6b0a61SColin Percival	    sort -u > $1.paths
2156db6b0a61SColin Percival	sort -k 1,1 -t '|' < $2 |
2157db6b0a61SColin Percival	    join -t '|' - $1.paths |
2158db6b0a61SColin Percival	    sort > $2.tmp
2159db6b0a61SColin Percival	rm $1.paths
2160db6b0a61SColin Percival	mv $2.tmp $2
2161db6b0a61SColin Percival
2162db6b0a61SColin Percival	# Rename INDEX-ALL to INDEX-NEW.
2163db6b0a61SColin Percival	mv $2 $3
2164db6b0a61SColin Percival}
2165db6b0a61SColin Percival
2166db6b0a61SColin Percival# From the list of "old" files in $1, merge changes in $2 with those in $3,
2167db6b0a61SColin Percival# and update $3 to reflect the hashes of merged files.
2168db6b0a61SColin Percivalupgrade_merge () {
2169db6b0a61SColin Percival	# We only need to do anything if $1 is non-empty.
2170db6b0a61SColin Percival	if [ -s $1 ]; then
2171db6b0a61SColin Percival		cut -f 1 -d '|' $1 |
2172db6b0a61SColin Percival		    sort > $1-paths
2173db6b0a61SColin Percival
2174db6b0a61SColin Percival		# Create staging area for merging files
2175db6b0a61SColin Percival		rm -rf merge/
2176db6b0a61SColin Percival		while read F; do
2177db6b0a61SColin Percival			D=`dirname ${F}`
2178db6b0a61SColin Percival			mkdir -p merge/old/${D}
2179db6b0a61SColin Percival			mkdir -p merge/${OLDRELNUM}/${D}
2180db6b0a61SColin Percival			mkdir -p merge/${RELNUM}/${D}
2181db6b0a61SColin Percival			mkdir -p merge/new/${D}
2182db6b0a61SColin Percival		done < $1-paths
2183db6b0a61SColin Percival
2184db6b0a61SColin Percival		# Copy in files
2185db6b0a61SColin Percival		while read F; do
2186db6b0a61SColin Percival			# Currently installed file
2187db6b0a61SColin Percival			V=`look "${F}|" $2 | cut -f 7 -d '|'`
2188db6b0a61SColin Percival			gunzip < files/${V}.gz > merge/old/${F}
2189db6b0a61SColin Percival
2190db6b0a61SColin Percival			# Old release
2191db6b0a61SColin Percival			if look "${F}|" $1 | fgrep -q "|f|"; then
2192db6b0a61SColin Percival				V=`look "${F}|" $1 | cut -f 3 -d '|'`
2193db6b0a61SColin Percival				gunzip < files/${V}.gz		\
2194db6b0a61SColin Percival				    > merge/${OLDRELNUM}/${F}
2195db6b0a61SColin Percival			fi
2196db6b0a61SColin Percival
2197db6b0a61SColin Percival			# New release
2198db6b0a61SColin Percival			if look "${F}|" $3 | cut -f 1,2,7 -d '|' |
2199db6b0a61SColin Percival			    fgrep -q "|f|"; then
2200db6b0a61SColin Percival				V=`look "${F}|" $3 | cut -f 7 -d '|'`
2201db6b0a61SColin Percival				gunzip < files/${V}.gz		\
2202db6b0a61SColin Percival				    > merge/${RELNUM}/${F}
2203db6b0a61SColin Percival			fi
2204db6b0a61SColin Percival		done < $1-paths
2205db6b0a61SColin Percival
2206db6b0a61SColin Percival		# Attempt to automatically merge changes
2207db6b0a61SColin Percival		echo -n "Attempting to automatically merge "
2208db6b0a61SColin Percival		echo -n "changes in files..."
2209db6b0a61SColin Percival		: > failed.merges
2210db6b0a61SColin Percival		while read F; do
2211db6b0a61SColin Percival			# If the file doesn't exist in the new release,
2212db6b0a61SColin Percival			# the result of "merging changes" is having the file
2213db6b0a61SColin Percival			# not exist.
2214db6b0a61SColin Percival			if ! [ -f merge/${RELNUM}/${F} ]; then
2215db6b0a61SColin Percival				continue
2216db6b0a61SColin Percival			fi
2217db6b0a61SColin Percival
2218db6b0a61SColin Percival			# If the file didn't exist in the old release, we're
2219db6b0a61SColin Percival			# going to throw away the existing file and hope that
2220db6b0a61SColin Percival			# the version from the new release is what we want.
2221db6b0a61SColin Percival			if ! [ -f merge/${OLDRELNUM}/${F} ]; then
2222db6b0a61SColin Percival				cp merge/${RELNUM}/${F} merge/new/${F}
2223db6b0a61SColin Percival				continue
2224db6b0a61SColin Percival			fi
2225db6b0a61SColin Percival
2226db6b0a61SColin Percival			# Some files need special treatment.
2227db6b0a61SColin Percival			case ${F} in
2228db6b0a61SColin Percival			/etc/spwd.db | /etc/pwd.db | /etc/login.conf.db)
2229db6b0a61SColin Percival				# Don't merge these -- we're rebuild them
2230db6b0a61SColin Percival				# after updates are installed.
2231db6b0a61SColin Percival				cp merge/old/${F} merge/new/${F}
2232db6b0a61SColin Percival				;;
2233db6b0a61SColin Percival			*)
2234db6b0a61SColin Percival				if ! merge -p -L "current version"	\
2235db6b0a61SColin Percival				    -L "${OLDRELNUM}" -L "${RELNUM}"	\
2236db6b0a61SColin Percival				    merge/old/${F}			\
2237db6b0a61SColin Percival				    merge/${OLDRELNUM}/${F}		\
2238db6b0a61SColin Percival				    merge/${RELNUM}/${F}		\
2239db6b0a61SColin Percival				    > merge/new/${F} 2>/dev/null; then
2240db6b0a61SColin Percival					echo ${F} >> failed.merges
2241db6b0a61SColin Percival				fi
2242db6b0a61SColin Percival				;;
2243db6b0a61SColin Percival			esac
2244db6b0a61SColin Percival		done < $1-paths
2245db6b0a61SColin Percival		echo " done."
2246db6b0a61SColin Percival
2247db6b0a61SColin Percival		# Ask the user to handle any files which didn't merge.
2248db6b0a61SColin Percival		while read F; do
2249db6b0a61SColin Percival			cat <<-EOF
2250db6b0a61SColin Percival
2251db6b0a61SColin PercivalThe following file could not be merged automatically: ${F}
2252db6b0a61SColin PercivalPress Enter to edit this file in ${EDITOR} and resolve the conflicts
2253db6b0a61SColin Percivalmanually...
2254db6b0a61SColin Percival			EOF
2255db6b0a61SColin Percival			read dummy </dev/tty
2256db6b0a61SColin Percival			${EDITOR} `pwd`/merge/new/${F} < /dev/tty
2257db6b0a61SColin Percival		done < failed.merges
2258db6b0a61SColin Percival		rm failed.merges
2259db6b0a61SColin Percival
2260db6b0a61SColin Percival		# Ask the user to confirm that he likes how the result
2261db6b0a61SColin Percival		# of merging files.
2262db6b0a61SColin Percival		while read F; do
2263db6b0a61SColin Percival			# Skip files which haven't changed.
2264db6b0a61SColin Percival			if [ -f merge/new/${F} ] &&
2265db6b0a61SColin Percival			    cmp -s merge/old/${F} merge/new/${F}; then
2266db6b0a61SColin Percival				continue
2267db6b0a61SColin Percival			fi
2268db6b0a61SColin Percival
2269db6b0a61SColin Percival			# Warn about files which are ceasing to exist.
2270db6b0a61SColin Percival			if ! [ -f merge/new/${F} ]; then
2271db6b0a61SColin Percival				cat <<-EOF
2272db6b0a61SColin Percival
2273db6b0a61SColin PercivalThe following file will be removed, as it no longer exists in
2274db6b0a61SColin PercivalFreeBSD ${RELNUM}: ${F}
2275db6b0a61SColin Percival				EOF
2276db6b0a61SColin Percival				continuep < /dev/tty || return 1
2277db6b0a61SColin Percival				continue
2278db6b0a61SColin Percival			fi
2279db6b0a61SColin Percival
2280db6b0a61SColin Percival			# Print changes for the user's approval.
2281db6b0a61SColin Percival			cat <<-EOF
2282db6b0a61SColin Percival
2283db6b0a61SColin PercivalThe following changes, which occurred between FreeBSD ${OLDRELNUM} and
2284db6b0a61SColin PercivalFreeBSD ${RELNUM} have been merged into ${F}:
2285db6b0a61SColin PercivalEOF
2286db6b0a61SColin Percival			diff -U 5 -L "current version" -L "new version"	\
2287db6b0a61SColin Percival			    merge/old/${F} merge/new/${F} || true
2288db6b0a61SColin Percival			continuep < /dev/tty || return 1
2289db6b0a61SColin Percival		done < $1-paths
2290db6b0a61SColin Percival
2291db6b0a61SColin Percival		# Store merged files.
2292db6b0a61SColin Percival		while read F; do
2293c58b62efSColin Percival			if [ -f merge/new/${F} ]; then
2294db6b0a61SColin Percival				V=`${SHA256} -q merge/new/${F}`
2295db6b0a61SColin Percival
2296db6b0a61SColin Percival				gzip -c < merge/new/${F} > files/${V}.gz
2297db6b0a61SColin Percival				echo "${F}|${V}"
2298db6b0a61SColin Percival			fi
2299db6b0a61SColin Percival		done < $1-paths > newhashes
2300db6b0a61SColin Percival
2301db6b0a61SColin Percival		# Pull lines out from $3 which need to be updated to
2302db6b0a61SColin Percival		# reflect merged files.
2303db6b0a61SColin Percival		while read F; do
2304db6b0a61SColin Percival			look "${F}|" $3
2305db6b0a61SColin Percival		done < $1-paths > $3-oldlines
2306db6b0a61SColin Percival
2307db6b0a61SColin Percival		# Update lines to reflect merged files
2308db6b0a61SColin Percival		join -t '|' -o 1.1,1.2,1.3,1.4,1.5,1.6,2.2,1.8		\
2309db6b0a61SColin Percival		    $3-oldlines newhashes > $3-newlines
2310db6b0a61SColin Percival
2311db6b0a61SColin Percival		# Remove old lines from $3 and add new lines.
2312db6b0a61SColin Percival		sort $3-oldlines |
2313db6b0a61SColin Percival		    comm -13 - $3 |
2314db6b0a61SColin Percival		    sort - $3-newlines > $3.tmp
2315db6b0a61SColin Percival		mv $3.tmp $3
2316db6b0a61SColin Percival
2317db6b0a61SColin Percival		# Clean up
2318db6b0a61SColin Percival		rm $1-paths newhashes $3-oldlines $3-newlines
2319db6b0a61SColin Percival		rm -rf merge/
2320db6b0a61SColin Percival	fi
2321db6b0a61SColin Percival
2322db6b0a61SColin Percival	# We're done with merging files.
2323db6b0a61SColin Percival	rm $1
2324db6b0a61SColin Percival}
2325db6b0a61SColin Percival
2326db6b0a61SColin Percival# Do the work involved in fetching upgrades to a new release
2327db6b0a61SColin Percivalupgrade_run () {
2328db6b0a61SColin Percival	workdir_init || return 1
2329db6b0a61SColin Percival
2330db6b0a61SColin Percival	# Prepare the mirror list.
2331db6b0a61SColin Percival	fetch_pick_server_init && fetch_pick_server
2332db6b0a61SColin Percival
2333db6b0a61SColin Percival	# Try to fetch the public key until we run out of servers.
2334db6b0a61SColin Percival	while ! fetch_key; do
2335db6b0a61SColin Percival		fetch_pick_server || return 1
2336db6b0a61SColin Percival	done
2337db6b0a61SColin Percival
2338db6b0a61SColin Percival	# Try to fetch the metadata index signature ("tag") until we run
2339db6b0a61SColin Percival	# out of available servers; and sanity check the downloaded tag.
2340db6b0a61SColin Percival	while ! fetch_tag; do
2341db6b0a61SColin Percival		fetch_pick_server || return 1
2342db6b0a61SColin Percival	done
2343db6b0a61SColin Percival	fetch_tagsanity || return 1
2344db6b0a61SColin Percival
2345db6b0a61SColin Percival	# Fetch the INDEX-OLD and INDEX-ALL.
2346db6b0a61SColin Percival	fetch_metadata INDEX-OLD INDEX-ALL || return 1
2347db6b0a61SColin Percival
2348db6b0a61SColin Percival	# If StrictComponents is not "yes", generate a new components list
2349db6b0a61SColin Percival	# with only the components which appear to be installed.
2350db6b0a61SColin Percival	upgrade_guess_components INDEX-ALL || return 1
2351db6b0a61SColin Percival
2352db6b0a61SColin Percival	# Generate filtered INDEX-OLD and INDEX-ALL files containing only
2353db6b0a61SColin Percival	# the components we want and without anything marked as "Ignore".
2354db6b0a61SColin Percival	fetch_filter_metadata INDEX-OLD || return 1
2355db6b0a61SColin Percival	fetch_filter_metadata INDEX-ALL || return 1
2356db6b0a61SColin Percival
2357db6b0a61SColin Percival	# Merge the INDEX-OLD and INDEX-ALL files into INDEX-OLD.
2358db6b0a61SColin Percival	sort INDEX-OLD INDEX-ALL > INDEX-OLD.tmp
2359db6b0a61SColin Percival	mv INDEX-OLD.tmp INDEX-OLD
2360db6b0a61SColin Percival	rm INDEX-ALL
2361db6b0a61SColin Percival
2362db6b0a61SColin Percival	# Adjust variables for fetching files from the new release.
2363db6b0a61SColin Percival	OLDRELNUM=${RELNUM}
2364db6b0a61SColin Percival	RELNUM=${TARGETRELEASE}
2365db6b0a61SColin Percival	OLDFETCHDIR=${FETCHDIR}
2366db6b0a61SColin Percival	FETCHDIR=${RELNUM}/${ARCH}
2367db6b0a61SColin Percival
2368db6b0a61SColin Percival	# Try to fetch the NEW metadata index signature ("tag") until we run
2369db6b0a61SColin Percival	# out of available servers; and sanity check the downloaded tag.
2370db6b0a61SColin Percival	while ! fetch_tag; do
2371db6b0a61SColin Percival		fetch_pick_server || return 1
2372db6b0a61SColin Percival	done
2373db6b0a61SColin Percival
2374db6b0a61SColin Percival	# Fetch the new INDEX-ALL.
2375db6b0a61SColin Percival	fetch_metadata INDEX-ALL || return 1
2376db6b0a61SColin Percival
2377db6b0a61SColin Percival	# If StrictComponents is not "yes", COMPONENTS contains an entry
2378db6b0a61SColin Percival	# corresponding to the currently running kernel, and said kernel
2379db6b0a61SColin Percival	# does not exist in the new release, add "kernel/generic" to the
2380db6b0a61SColin Percival	# list of components.
2381db6b0a61SColin Percival	upgrade_guess_new_kernel INDEX-ALL || return 1
2382db6b0a61SColin Percival
2383db6b0a61SColin Percival	# Filter INDEX-ALL to contain only the components we want and without
2384db6b0a61SColin Percival	# anything marked as "Ignore".
2385db6b0a61SColin Percival	fetch_filter_metadata INDEX-ALL || return 1
2386db6b0a61SColin Percival
2387db6b0a61SColin Percival	# Convert INDEX-OLD (last release) and INDEX-ALL (new release) into
2388db6b0a61SColin Percival	# INDEX-OLD and INDEX-NEW files (in the sense of normal upgrades).
2389db6b0a61SColin Percival	upgrade_oldall_to_oldnew INDEX-OLD INDEX-ALL INDEX-NEW
2390db6b0a61SColin Percival
2391db6b0a61SColin Percival	# Translate /boot/${KERNCONF} or /boot/${NKERNCONF} into ${KERNELDIR}
2392db6b0a61SColin Percival	fetch_filter_kernel_names INDEX-NEW ${NKERNCONF}
2393db6b0a61SColin Percival	fetch_filter_kernel_names INDEX-OLD ${KERNCONF}
2394db6b0a61SColin Percival
2395db6b0a61SColin Percival	# For all paths appearing in INDEX-OLD or INDEX-NEW, inspect the
2396db6b0a61SColin Percival	# system and generate an INDEX-PRESENT file.
2397db6b0a61SColin Percival	fetch_inspect_system INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1
2398db6b0a61SColin Percival
2399db6b0a61SColin Percival	# Based on ${MERGECHANGES}, generate a file tomerge-old with the
2400db6b0a61SColin Percival	# paths and hashes of old versions of files to merge.
2401db6b0a61SColin Percival	fetch_filter_mergechanges INDEX-OLD INDEX-PRESENT tomerge-old
2402db6b0a61SColin Percival
2403db6b0a61SColin Percival	# Based on ${UPDATEIFUNMODIFIED}, remove lines from INDEX-* which
2404db6b0a61SColin Percival	# correspond to lines in INDEX-PRESENT with hashes not appearing
2405db6b0a61SColin Percival	# in INDEX-OLD or INDEX-NEW.  Also remove lines where the entry in
2406db6b0a61SColin Percival	# INDEX-PRESENT has type - and there isn't a corresponding entry in
2407db6b0a61SColin Percival	# INDEX-OLD with type -.
2408db6b0a61SColin Percival	fetch_filter_unmodified_notpresent	\
2409db6b0a61SColin Percival	    INDEX-OLD INDEX-PRESENT INDEX-NEW tomerge-old
2410db6b0a61SColin Percival
2411db6b0a61SColin Percival	# For each entry in INDEX-PRESENT of type -, remove any corresponding
2412db6b0a61SColin Percival	# entry from INDEX-NEW if ${ALLOWADD} != "yes".  Remove all entries
2413db6b0a61SColin Percival	# of type - from INDEX-PRESENT.
2414db6b0a61SColin Percival	fetch_filter_allowadd INDEX-PRESENT INDEX-NEW
2415db6b0a61SColin Percival
2416db6b0a61SColin Percival	# If ${ALLOWDELETE} != "yes", then remove any entries from
2417db6b0a61SColin Percival	# INDEX-PRESENT which don't correspond to entries in INDEX-NEW.
2418db6b0a61SColin Percival	fetch_filter_allowdelete INDEX-PRESENT INDEX-NEW
2419db6b0a61SColin Percival
2420db6b0a61SColin Percival	# If ${KEEPMODIFIEDMETADATA} == "yes", then for each entry in
2421db6b0a61SColin Percival	# INDEX-PRESENT with metadata not matching any entry in INDEX-OLD,
2422db6b0a61SColin Percival	# replace the corresponding line of INDEX-NEW with one having the
2423db6b0a61SColin Percival	# same metadata as the entry in INDEX-PRESENT.
2424db6b0a61SColin Percival	fetch_filter_modified_metadata INDEX-OLD INDEX-PRESENT INDEX-NEW
2425db6b0a61SColin Percival
2426db6b0a61SColin Percival	# Remove lines from INDEX-PRESENT and INDEX-NEW which are identical;
2427db6b0a61SColin Percival	# no need to update a file if it isn't changing.
2428db6b0a61SColin Percival	fetch_filter_uptodate INDEX-PRESENT INDEX-NEW
2429db6b0a61SColin Percival
2430db6b0a61SColin Percival	# Fetch "clean" files from the old release for merging changes.
2431db6b0a61SColin Percival	fetch_files_premerge tomerge-old
2432db6b0a61SColin Percival
2433db6b0a61SColin Percival	# Prepare to fetch files: Generate a list of the files we need,
2434db6b0a61SColin Percival	# copy the unmodified files we have into /files/, and generate
2435db6b0a61SColin Percival	# a list of patches to download.
2436db6b0a61SColin Percival	fetch_files_prepare INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1
2437db6b0a61SColin Percival
2438db6b0a61SColin Percival	# Fetch patches from to-${RELNUM}/${ARCH}/bp/
2439db6b0a61SColin Percival	PATCHDIR=to-${RELNUM}/${ARCH}/bp
2440db6b0a61SColin Percival	fetch_files || return 1
2441db6b0a61SColin Percival
2442db6b0a61SColin Percival	# Merge configuration file changes.
2443db6b0a61SColin Percival	upgrade_merge tomerge-old INDEX-PRESENT INDEX-NEW || return 1
2444db6b0a61SColin Percival
2445db6b0a61SColin Percival	# Create and populate install manifest directory; and report what
2446db6b0a61SColin Percival	# updates are available.
2447db6b0a61SColin Percival	fetch_create_manifest || return 1
2448db6b0a61SColin Percival
2449db6b0a61SColin Percival	# Leave a note behind to tell the "install" command that the kernel
2450db6b0a61SColin Percival	# needs to be installed before the world.
2451db6b0a61SColin Percival	touch ${BDHASH}-install/kernelfirst
2452db6b0a61SColin Percival}
2453db6b0a61SColin Percival
245448ffe56aSColin Percival# Make sure that all the file hashes mentioned in $@ have corresponding
245548ffe56aSColin Percival# gzipped files stored in /files/.
245648ffe56aSColin Percivalinstall_verify () {
245748ffe56aSColin Percival	# Generate a list of hashes
245848ffe56aSColin Percival	cat $@ |
245948ffe56aSColin Percival	    cut -f 2,7 -d '|' |
246048ffe56aSColin Percival	    grep -E '^f' |
246148ffe56aSColin Percival	    cut -f 2 -d '|' |
246248ffe56aSColin Percival	    sort -u > filelist
246348ffe56aSColin Percival
246448ffe56aSColin Percival	# Make sure all the hashes exist
246548ffe56aSColin Percival	while read HASH; do
246648ffe56aSColin Percival		if ! [ -f files/${HASH}.gz ]; then
246748ffe56aSColin Percival			echo -n "Update files missing -- "
246848ffe56aSColin Percival			echo "this should never happen."
246948ffe56aSColin Percival			echo "Re-run '$0 fetch'."
247048ffe56aSColin Percival			return 1
247148ffe56aSColin Percival		fi
247248ffe56aSColin Percival	done < filelist
247348ffe56aSColin Percival
247448ffe56aSColin Percival	# Clean up
247548ffe56aSColin Percival	rm filelist
247648ffe56aSColin Percival}
247748ffe56aSColin Percival
247848ffe56aSColin Percival# Remove the system immutable flag from files
247948ffe56aSColin Percivalinstall_unschg () {
248048ffe56aSColin Percival	# Generate file list
248148ffe56aSColin Percival	cat $@ |
248248ffe56aSColin Percival	    cut -f 1 -d '|' > filelist
248348ffe56aSColin Percival
248448ffe56aSColin Percival	# Remove flags
248548ffe56aSColin Percival	while read F; do
2486e829ed67SColin Percival		if ! [ -e ${BASEDIR}/${F} ]; then
248748ffe56aSColin Percival			continue
248848ffe56aSColin Percival		fi
248948ffe56aSColin Percival
2490e829ed67SColin Percival		chflags noschg ${BASEDIR}/${F} || return 1
249148ffe56aSColin Percival	done < filelist
249248ffe56aSColin Percival
249348ffe56aSColin Percival	# Clean up
249448ffe56aSColin Percival	rm filelist
249548ffe56aSColin Percival}
249648ffe56aSColin Percival
249748ffe56aSColin Percival# Install new files
249848ffe56aSColin Percivalinstall_from_index () {
249948ffe56aSColin Percival	# First pass: Do everything apart from setting file flags.  We
250048ffe56aSColin Percival	# can't set flags yet, because schg inhibits hard linking.
250148ffe56aSColin Percival	sort -k 1,1 -t '|' $1 |
250248ffe56aSColin Percival	    tr '|' ' ' |
250348ffe56aSColin Percival	    while read FPATH TYPE OWNER GROUP PERM FLAGS HASH LINK; do
250448ffe56aSColin Percival		case ${TYPE} in
250548ffe56aSColin Percival		d)
250648ffe56aSColin Percival			# Create a directory
250748ffe56aSColin Percival			install -d -o ${OWNER} -g ${GROUP}		\
250848ffe56aSColin Percival			    -m ${PERM} ${BASEDIR}/${FPATH}
250948ffe56aSColin Percival			;;
251048ffe56aSColin Percival		f)
251148ffe56aSColin Percival			if [ -z "${LINK}" ]; then
251248ffe56aSColin Percival				# Create a file, without setting flags.
251348ffe56aSColin Percival				gunzip < files/${HASH}.gz > ${HASH}
251448ffe56aSColin Percival				install -S -o ${OWNER} -g ${GROUP}	\
251548ffe56aSColin Percival				    -m ${PERM} ${HASH} ${BASEDIR}/${FPATH}
251648ffe56aSColin Percival				rm ${HASH}
251748ffe56aSColin Percival			else
251848ffe56aSColin Percival				# Create a hard link.
2519e829ed67SColin Percival				ln -f ${BASEDIR}/${LINK} ${BASEDIR}/${FPATH}
252048ffe56aSColin Percival			fi
252148ffe56aSColin Percival			;;
252248ffe56aSColin Percival		L)
252348ffe56aSColin Percival			# Create a symlink
252448ffe56aSColin Percival			ln -sfh ${HASH} ${BASEDIR}/${FPATH}
252548ffe56aSColin Percival			;;
252648ffe56aSColin Percival		esac
252748ffe56aSColin Percival	    done
252848ffe56aSColin Percival
252948ffe56aSColin Percival	# Perform a second pass, adding file flags.
253048ffe56aSColin Percival	tr '|' ' ' < $1 |
253148ffe56aSColin Percival	    while read FPATH TYPE OWNER GROUP PERM FLAGS HASH LINK; do
253248ffe56aSColin Percival		if [ ${TYPE} = "f" ] &&
253348ffe56aSColin Percival		    ! [ ${FLAGS} = "0" ]; then
253448ffe56aSColin Percival			chflags ${FLAGS} ${BASEDIR}/${FPATH}
253548ffe56aSColin Percival		fi
253648ffe56aSColin Percival	    done
253748ffe56aSColin Percival}
253848ffe56aSColin Percival
253948ffe56aSColin Percival# Remove files which we want to delete
254048ffe56aSColin Percivalinstall_delete () {
254148ffe56aSColin Percival	# Generate list of new files
254248ffe56aSColin Percival	cut -f 1 -d '|' < $2 |
254348ffe56aSColin Percival	    sort > newfiles
254448ffe56aSColin Percival
254548ffe56aSColin Percival	# Generate subindex of old files we want to nuke
254648ffe56aSColin Percival	sort -k 1,1 -t '|' $1 |
254748ffe56aSColin Percival	    join -t '|' -v 1 - newfiles |
2548bce02f98SColin Percival	    sort -r -k 1,1 -t '|' |
254948ffe56aSColin Percival	    cut -f 1,2 -d '|' |
255048ffe56aSColin Percival	    tr '|' ' ' > killfiles
255148ffe56aSColin Percival
255248ffe56aSColin Percival	# Remove the offending bits
255348ffe56aSColin Percival	while read FPATH TYPE; do
255448ffe56aSColin Percival		case ${TYPE} in
255548ffe56aSColin Percival		d)
255648ffe56aSColin Percival			rmdir ${BASEDIR}/${FPATH}
255748ffe56aSColin Percival			;;
255848ffe56aSColin Percival		f)
255948ffe56aSColin Percival			rm ${BASEDIR}/${FPATH}
256048ffe56aSColin Percival			;;
256148ffe56aSColin Percival		L)
256248ffe56aSColin Percival			rm ${BASEDIR}/${FPATH}
256348ffe56aSColin Percival			;;
256448ffe56aSColin Percival		esac
256548ffe56aSColin Percival	done < killfiles
256648ffe56aSColin Percival
256748ffe56aSColin Percival	# Clean up
256848ffe56aSColin Percival	rm newfiles killfiles
256948ffe56aSColin Percival}
257048ffe56aSColin Percival
2571db6b0a61SColin Percival# Install new files, delete old files, and update linker.hints
2572db6b0a61SColin Percivalinstall_files () {
2573db6b0a61SColin Percival	# If we haven't already dealt with the kernel, deal with it.
2574db6b0a61SColin Percival	if ! [ -f $1/kerneldone ]; then
2575db6b0a61SColin Percival		grep -E '^/boot/' $1/INDEX-OLD > INDEX-OLD
2576db6b0a61SColin Percival		grep -E '^/boot/' $1/INDEX-NEW > INDEX-NEW
2577db6b0a61SColin Percival
2578db6b0a61SColin Percival		# Install new files
2579db6b0a61SColin Percival		install_from_index INDEX-NEW || return 1
2580db6b0a61SColin Percival
2581db6b0a61SColin Percival		# Remove files which need to be deleted
2582db6b0a61SColin Percival		install_delete INDEX-OLD INDEX-NEW || return 1
2583db6b0a61SColin Percival
2584db6b0a61SColin Percival		# Update linker.hints if necessary
2585db6b0a61SColin Percival		if [ -s INDEX-OLD -o -s INDEX-NEW ]; then
2586db6b0a61SColin Percival			kldxref -R /boot/ 2>/dev/null
258748ffe56aSColin Percival		fi
2588db6b0a61SColin Percival
2589db6b0a61SColin Percival		# We've finished updating the kernel.
2590db6b0a61SColin Percival		touch $1/kerneldone
2591db6b0a61SColin Percival
2592db6b0a61SColin Percival		# Do we need to ask for a reboot now?
2593db6b0a61SColin Percival		if [ -f $1/kernelfirst ] &&
2594db6b0a61SColin Percival		    [ -s INDEX-OLD -o -s INDEX-NEW ]; then
2595db6b0a61SColin Percival			cat <<-EOF
2596db6b0a61SColin Percival
2597db6b0a61SColin PercivalKernel updates have been installed.  Please reboot and run
2598db6b0a61SColin Percival"$0 install" again to finish installing updates.
2599db6b0a61SColin Percival			EOF
2600db6b0a61SColin Percival			exit 0
2601db6b0a61SColin Percival		fi
2602db6b0a61SColin Percival	fi
2603db6b0a61SColin Percival
2604db6b0a61SColin Percival	# If we haven't already dealt with the world, deal with it.
2605db6b0a61SColin Percival	if ! [ -f $1/worlddone ]; then
2606db6b0a61SColin Percival		# Install new shared libraries next
2607db6b0a61SColin Percival		grep -vE '^/boot/' $1/INDEX-NEW |
2608fd0963d1SColin Percival		    grep -E '/lib/.*\.so\.[0-9]+\|' > INDEX-NEW
2609db6b0a61SColin Percival		install_from_index INDEX-NEW || return 1
2610db6b0a61SColin Percival
2611db6b0a61SColin Percival		# Deal with everything else
2612db6b0a61SColin Percival		grep -vE '^/boot/' $1/INDEX-OLD |
2613fd0963d1SColin Percival		    grep -vE '/lib/.*\.so\.[0-9]+\|' > INDEX-OLD
2614db6b0a61SColin Percival		grep -vE '^/boot/' $1/INDEX-NEW |
2615fd0963d1SColin Percival		    grep -vE '/lib/.*\.so\.[0-9]+\|' > INDEX-NEW
2616db6b0a61SColin Percival		install_from_index INDEX-NEW || return 1
2617db6b0a61SColin Percival		install_delete INDEX-OLD INDEX-NEW || return 1
2618db6b0a61SColin Percival
2619db6b0a61SColin Percival		# Rebuild /etc/spwd.db and /etc/pwd.db if necessary.
2620db6b0a61SColin Percival		if [ /etc/master.passwd -nt /etc/spwd.db ] ||
2621db6b0a61SColin Percival		    [ /etc/master.passwd -nt /etc/pwd.db ]; then
2622db6b0a61SColin Percival			pwd_mkdb /etc/master.passwd
2623db6b0a61SColin Percival		fi
2624db6b0a61SColin Percival
2625db6b0a61SColin Percival		# Rebuild /etc/login.conf.db if necessary.
2626db6b0a61SColin Percival		if [ /etc/login.conf -nt /etc/login.conf.db ]; then
2627db6b0a61SColin Percival			cap_mkdb /etc/login.conf
2628db6b0a61SColin Percival		fi
2629db6b0a61SColin Percival
2630db6b0a61SColin Percival		# We've finished installing the world and deleting old files
2631db6b0a61SColin Percival		# which are not shared libraries.
2632db6b0a61SColin Percival		touch $1/worlddone
2633db6b0a61SColin Percival
2634db6b0a61SColin Percival		# Do we need to ask the user to portupgrade now?
2635db6b0a61SColin Percival		grep -vE '^/boot/' $1/INDEX-NEW |
2636fd0963d1SColin Percival		    grep -E '/lib/.*\.so\.[0-9]+\|' |
2637db6b0a61SColin Percival		    cut -f 1 -d '|' |
2638db6b0a61SColin Percival		    sort > newfiles
2639db6b0a61SColin Percival		if grep -vE '^/boot/' $1/INDEX-OLD |
2640fd0963d1SColin Percival		    grep -E '/lib/.*\.so\.[0-9]+\|' |
2641db6b0a61SColin Percival		    cut -f 1 -d '|' |
2642db6b0a61SColin Percival		    sort |
2643db6b0a61SColin Percival		    join -v 1 - newfiles |
2644db6b0a61SColin Percival		    grep -q .; then
2645db6b0a61SColin Percival			cat <<-EOF
2646db6b0a61SColin Percival
2647db6b0a61SColin PercivalCompleting this upgrade requires removing old shared object files.
2648db6b0a61SColin PercivalPlease rebuild all installed 3rd party software (e.g., programs
2649db6b0a61SColin Percivalinstalled from the ports tree) and then run "$0 install"
2650db6b0a61SColin Percivalagain to finish installing updates.
2651db6b0a61SColin Percival			EOF
2652db6b0a61SColin Percival			rm newfiles
2653db6b0a61SColin Percival			exit 0
2654db6b0a61SColin Percival		fi
2655db6b0a61SColin Percival		rm newfiles
2656db6b0a61SColin Percival	fi
2657db6b0a61SColin Percival
2658db6b0a61SColin Percival	# Remove old shared libraries
2659db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-NEW |
2660fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' > INDEX-NEW
2661db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
2662fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' > INDEX-OLD
2663db6b0a61SColin Percival	install_delete INDEX-OLD INDEX-NEW || return 1
2664db6b0a61SColin Percival
2665db6b0a61SColin Percival	# Remove temporary files
2666db6b0a61SColin Percival	rm INDEX-OLD INDEX-NEW
266748ffe56aSColin Percival}
266848ffe56aSColin Percival
266948ffe56aSColin Percival# Rearrange bits to allow the installed updates to be rolled back
267048ffe56aSColin Percivalinstall_setup_rollback () {
2671db6b0a61SColin Percival	# Remove the "reboot after installing kernel", "kernel updated", and
2672db6b0a61SColin Percival	# "finished installing the world" flags if present -- they are
2673db6b0a61SColin Percival	# irrelevant when rolling back updates.
2674db6b0a61SColin Percival	if [ -f ${BDHASH}-install/kernelfirst ]; then
2675db6b0a61SColin Percival		rm ${BDHASH}-install/kernelfirst
2676db6b0a61SColin Percival		rm ${BDHASH}-install/kerneldone
2677db6b0a61SColin Percival	fi
2678db6b0a61SColin Percival	if [ -f ${BDHASH}-install/worlddone ]; then
2679db6b0a61SColin Percival		rm ${BDHASH}-install/worlddone
2680db6b0a61SColin Percival	fi
2681db6b0a61SColin Percival
268248ffe56aSColin Percival	if [ -L ${BDHASH}-rollback ]; then
268348ffe56aSColin Percival		mv ${BDHASH}-rollback ${BDHASH}-install/rollback
268448ffe56aSColin Percival	fi
268548ffe56aSColin Percival
268648ffe56aSColin Percival	mv ${BDHASH}-install ${BDHASH}-rollback
268748ffe56aSColin Percival}
268848ffe56aSColin Percival
268948ffe56aSColin Percival# Actually install updates
269048ffe56aSColin Percivalinstall_run () {
269148ffe56aSColin Percival	echo -n "Installing updates..."
269248ffe56aSColin Percival
269348ffe56aSColin Percival	# Make sure we have all the files we should have
269448ffe56aSColin Percival	install_verify ${BDHASH}-install/INDEX-OLD	\
269548ffe56aSColin Percival	    ${BDHASH}-install/INDEX-NEW || return 1
269648ffe56aSColin Percival
269748ffe56aSColin Percival	# Remove system immutable flag from files
269848ffe56aSColin Percival	install_unschg ${BDHASH}-install/INDEX-OLD	\
269948ffe56aSColin Percival	    ${BDHASH}-install/INDEX-NEW || return 1
270048ffe56aSColin Percival
2701db6b0a61SColin Percival	# Install new files, delete old files, and update linker.hints
2702db6b0a61SColin Percival	install_files ${BDHASH}-install || return 1
270348ffe56aSColin Percival
270448ffe56aSColin Percival	# Rearrange bits to allow the installed updates to be rolled back
270548ffe56aSColin Percival	install_setup_rollback
270648ffe56aSColin Percival
270748ffe56aSColin Percival	echo " done."
270848ffe56aSColin Percival}
270948ffe56aSColin Percival
271048ffe56aSColin Percival# Rearrange bits to allow the previous set of updates to be rolled back next.
271148ffe56aSColin Percivalrollback_setup_rollback () {
271248ffe56aSColin Percival	if [ -L ${BDHASH}-rollback/rollback ]; then
271348ffe56aSColin Percival		mv ${BDHASH}-rollback/rollback rollback-tmp
271448ffe56aSColin Percival		rm -r ${BDHASH}-rollback/
271548ffe56aSColin Percival		rm ${BDHASH}-rollback
271648ffe56aSColin Percival		mv rollback-tmp ${BDHASH}-rollback
271748ffe56aSColin Percival	else
271848ffe56aSColin Percival		rm -r ${BDHASH}-rollback/
271948ffe56aSColin Percival		rm ${BDHASH}-rollback
272048ffe56aSColin Percival	fi
272148ffe56aSColin Percival}
272248ffe56aSColin Percival
2723db6b0a61SColin Percival# Install old files, delete new files, and update linker.hints
2724db6b0a61SColin Percivalrollback_files () {
27251ec4fb3aSColin Percival	# Install old shared library files which don't have the same path as
27261ec4fb3aSColin Percival	# a new shared library file.
27271ec4fb3aSColin Percival	grep -vE '^/boot/' $1/INDEX-NEW |
2728fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' |
27291ec4fb3aSColin Percival	    cut -f 1 -d '|' |
27301ec4fb3aSColin Percival	    sort > INDEX-NEW.libs.flist
2731db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
2732fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' |
27331ec4fb3aSColin Percival	    sort -k 1,1 -t '|' - |
27341ec4fb3aSColin Percival	    join -t '|' -v 1 - INDEX-NEW.libs.flist > INDEX-OLD
2735db6b0a61SColin Percival	install_from_index INDEX-OLD || return 1
2736db6b0a61SColin Percival
2737db6b0a61SColin Percival	# Deal with files which are neither kernel nor shared library
2738db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
2739fd0963d1SColin Percival	    grep -vE '/lib/.*\.so\.[0-9]+\|' > INDEX-OLD
2740db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-NEW |
2741fd0963d1SColin Percival	    grep -vE '/lib/.*\.so\.[0-9]+\|' > INDEX-NEW
2742db6b0a61SColin Percival	install_from_index INDEX-OLD || return 1
2743db6b0a61SColin Percival	install_delete INDEX-NEW INDEX-OLD || return 1
2744db6b0a61SColin Percival
27451ec4fb3aSColin Percival	# Install any old shared library files which we didn't install above.
27461ec4fb3aSColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
2747fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' |
27481ec4fb3aSColin Percival	    sort -k 1,1 -t '|' - |
27491ec4fb3aSColin Percival	    join -t '|' - INDEX-NEW.libs.flist > INDEX-OLD
27501ec4fb3aSColin Percival	install_from_index INDEX-OLD || return 1
27511ec4fb3aSColin Percival
2752db6b0a61SColin Percival	# Delete unneeded shared library files
2753db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
2754fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' > INDEX-OLD
2755db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-NEW |
2756fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' > INDEX-NEW
2757db6b0a61SColin Percival	install_delete INDEX-NEW INDEX-OLD || return 1
2758db6b0a61SColin Percival
2759db6b0a61SColin Percival	# Deal with kernel files
2760db6b0a61SColin Percival	grep -E '^/boot/' $1/INDEX-OLD > INDEX-OLD
2761db6b0a61SColin Percival	grep -E '^/boot/' $1/INDEX-NEW > INDEX-NEW
2762db6b0a61SColin Percival	install_from_index INDEX-OLD || return 1
2763db6b0a61SColin Percival	install_delete INDEX-NEW INDEX-OLD || return 1
2764db6b0a61SColin Percival	if [ -s INDEX-OLD -o -s INDEX-NEW ]; then
2765db6b0a61SColin Percival		kldxref -R /boot/ 2>/dev/null
2766db6b0a61SColin Percival	fi
2767db6b0a61SColin Percival
2768db6b0a61SColin Percival	# Remove temporary files
27690e0d8d5aSColin Percival	rm INDEX-OLD INDEX-NEW INDEX-NEW.libs.flist
2770db6b0a61SColin Percival}
2771db6b0a61SColin Percival
277248ffe56aSColin Percival# Actually rollback updates
277348ffe56aSColin Percivalrollback_run () {
277448ffe56aSColin Percival	echo -n "Uninstalling updates..."
277548ffe56aSColin Percival
277648ffe56aSColin Percival	# If there are updates waiting to be installed, remove them; we
277748ffe56aSColin Percival	# want the user to re-run 'fetch' after rolling back updates.
277848ffe56aSColin Percival	if [ -L ${BDHASH}-install ]; then
277948ffe56aSColin Percival		rm -r ${BDHASH}-install/
278048ffe56aSColin Percival		rm ${BDHASH}-install
278148ffe56aSColin Percival	fi
278248ffe56aSColin Percival
278348ffe56aSColin Percival	# Make sure we have all the files we should have
278448ffe56aSColin Percival	install_verify ${BDHASH}-rollback/INDEX-NEW	\
278548ffe56aSColin Percival	    ${BDHASH}-rollback/INDEX-OLD || return 1
278648ffe56aSColin Percival
278748ffe56aSColin Percival	# Remove system immutable flag from files
278848ffe56aSColin Percival	install_unschg ${BDHASH}-rollback/INDEX-NEW	\
278948ffe56aSColin Percival	    ${BDHASH}-rollback/INDEX-OLD || return 1
279048ffe56aSColin Percival
2791db6b0a61SColin Percival	# Install old files, delete new files, and update linker.hints
2792db6b0a61SColin Percival	rollback_files ${BDHASH}-rollback || return 1
279348ffe56aSColin Percival
279448ffe56aSColin Percival	# Remove the rollback directory and the symlink pointing to it; and
279548ffe56aSColin Percival	# rearrange bits to allow the previous set of updates to be rolled
279648ffe56aSColin Percival	# back next.
279748ffe56aSColin Percival	rollback_setup_rollback
279848ffe56aSColin Percival
279948ffe56aSColin Percival	echo " done."
280048ffe56aSColin Percival}
280148ffe56aSColin Percival
280208e23beeSColin Percival# Compare INDEX-ALL and INDEX-PRESENT and print warnings about differences.
280308e23beeSColin PercivalIDS_compare () {
2804bb10a826SColin Percival	# Get all the lines which mismatch in something other than file
2805bb10a826SColin Percival	# flags.  We ignore file flags because sysinstall doesn't seem to
2806bb10a826SColin Percival	# set them when it installs FreeBSD; warning about these adds a
2807bb10a826SColin Percival	# very large amount of noise.
2808bb10a826SColin Percival	cut -f 1-5,7-8 -d '|' $1 > $1.noflags
2809bb10a826SColin Percival	sort -k 1,1 -t '|' $1.noflags > $1.sorted
2810bb10a826SColin Percival	cut -f 1-5,7-8 -d '|' $2 |
2811bb10a826SColin Percival	    comm -13 $1.noflags - |
2812bb10a826SColin Percival	    fgrep -v '|-|||||' |
281308e23beeSColin Percival	    sort -k 1,1 -t '|' |
281408e23beeSColin Percival	    join -t '|' $1.sorted - > INDEX-NOTMATCHING
281508e23beeSColin Percival
281608e23beeSColin Percival	# Ignore files which match IDSIGNOREPATHS.
281708e23beeSColin Percival	for X in ${IDSIGNOREPATHS}; do
281808e23beeSColin Percival		grep -E "^${X}" INDEX-NOTMATCHING
281908e23beeSColin Percival	done |
282008e23beeSColin Percival	    sort -u |
282108e23beeSColin Percival	    comm -13 - INDEX-NOTMATCHING > INDEX-NOTMATCHING.tmp
282208e23beeSColin Percival	mv INDEX-NOTMATCHING.tmp INDEX-NOTMATCHING
282308e23beeSColin Percival
282408e23beeSColin Percival	# Go through the lines and print warnings.
282508e23beeSColin Percival	while read LINE; do
282608e23beeSColin Percival		FPATH=`echo "${LINE}" | cut -f 1 -d '|'`
282708e23beeSColin Percival		TYPE=`echo "${LINE}" | cut -f 2 -d '|'`
282808e23beeSColin Percival		OWNER=`echo "${LINE}" | cut -f 3 -d '|'`
282908e23beeSColin Percival		GROUP=`echo "${LINE}" | cut -f 4 -d '|'`
283008e23beeSColin Percival		PERM=`echo "${LINE}" | cut -f 5 -d '|'`
2831bb10a826SColin Percival		HASH=`echo "${LINE}" | cut -f 6 -d '|'`
2832bb10a826SColin Percival		LINK=`echo "${LINE}" | cut -f 7 -d '|'`
2833bb10a826SColin Percival		P_TYPE=`echo "${LINE}" | cut -f 8 -d '|'`
2834bb10a826SColin Percival		P_OWNER=`echo "${LINE}" | cut -f 9 -d '|'`
2835bb10a826SColin Percival		P_GROUP=`echo "${LINE}" | cut -f 10 -d '|'`
2836bb10a826SColin Percival		P_PERM=`echo "${LINE}" | cut -f 11 -d '|'`
2837bb10a826SColin Percival		P_HASH=`echo "${LINE}" | cut -f 12 -d '|'`
2838bb10a826SColin Percival		P_LINK=`echo "${LINE}" | cut -f 13 -d '|'`
283908e23beeSColin Percival
284008e23beeSColin Percival		# Warn about different object types.
284108e23beeSColin Percival		if ! [ "${TYPE}" = "${P_TYPE}" ]; then
284208e23beeSColin Percival			echo -n "${FPATH} is a "
284308e23beeSColin Percival			case "${P_TYPE}" in
284408e23beeSColin Percival			f)	echo -n "regular file, "
284508e23beeSColin Percival				;;
284608e23beeSColin Percival			d)	echo -n "directory, "
284708e23beeSColin Percival				;;
284808e23beeSColin Percival			L)	echo -n "symlink, "
284908e23beeSColin Percival				;;
285008e23beeSColin Percival			esac
285108e23beeSColin Percival			echo -n "but should be a "
285208e23beeSColin Percival			case "${TYPE}" in
285308e23beeSColin Percival			f)	echo -n "regular file."
285408e23beeSColin Percival				;;
285508e23beeSColin Percival			d)	echo -n "directory."
285608e23beeSColin Percival				;;
285708e23beeSColin Percival			L)	echo -n "symlink."
285808e23beeSColin Percival				;;
285908e23beeSColin Percival			esac
286008e23beeSColin Percival			echo
286108e23beeSColin Percival
286208e23beeSColin Percival			# Skip other tests, since they don't make sense if
286308e23beeSColin Percival			# we're comparing different object types.
286408e23beeSColin Percival			continue
286508e23beeSColin Percival		fi
286608e23beeSColin Percival
286708e23beeSColin Percival		# Warn about different owners.
286808e23beeSColin Percival		if ! [ "${OWNER}" = "${P_OWNER}" ]; then
286908e23beeSColin Percival			echo -n "${FPATH} is owned by user id ${P_OWNER}, "
287008e23beeSColin Percival			echo "but should be owned by user id ${OWNER}."
287108e23beeSColin Percival		fi
287208e23beeSColin Percival
287308e23beeSColin Percival		# Warn about different groups.
287408e23beeSColin Percival		if ! [ "${GROUP}" = "${P_GROUP}" ]; then
287508e23beeSColin Percival			echo -n "${FPATH} is owned by group id ${P_GROUP}, "
287608e23beeSColin Percival			echo "but should be owned by group id ${GROUP}."
287708e23beeSColin Percival		fi
287808e23beeSColin Percival
287908e23beeSColin Percival		# Warn about different permissions.  We do not warn about
288008e23beeSColin Percival		# different permissions on symlinks, since some archivers
288108e23beeSColin Percival		# don't extract symlink permissions correctly and they are
288208e23beeSColin Percival		# ignored anyway.
288308e23beeSColin Percival		if ! [ "${PERM}" = "${P_PERM}" ] &&
288408e23beeSColin Percival		    ! [ "${TYPE}" = "L" ]; then
288508e23beeSColin Percival			echo -n "${FPATH} has ${P_PERM} permissions, "
288608e23beeSColin Percival			echo "but should have ${PERM} permissions."
288708e23beeSColin Percival		fi
288808e23beeSColin Percival
288908e23beeSColin Percival		# Warn about different file hashes / symlink destinations.
289008e23beeSColin Percival		if ! [ "${HASH}" = "${P_HASH}" ]; then
289108e23beeSColin Percival			if [ "${TYPE}" = "L" ]; then
289208e23beeSColin Percival				echo -n "${FPATH} is a symlink to ${P_HASH}, "
289308e23beeSColin Percival				echo "but should be a symlink to ${HASH}."
289408e23beeSColin Percival			fi
289508e23beeSColin Percival			if [ "${TYPE}" = "f" ]; then
289608e23beeSColin Percival				echo -n "${FPATH} has SHA256 hash ${P_HASH}, "
289708e23beeSColin Percival				echo "but should have SHA256 hash ${HASH}."
289808e23beeSColin Percival			fi
289908e23beeSColin Percival		fi
290008e23beeSColin Percival
290108e23beeSColin Percival		# We don't warn about different hard links, since some
290208e23beeSColin Percival		# some archivers break hard links, and as long as the
290308e23beeSColin Percival		# underlying data is correct they really don't matter.
290408e23beeSColin Percival	done < INDEX-NOTMATCHING
290508e23beeSColin Percival
290608e23beeSColin Percival	# Clean up
2907bb10a826SColin Percival	rm $1 $1.noflags $1.sorted $2 INDEX-NOTMATCHING
290808e23beeSColin Percival}
290908e23beeSColin Percival
291008e23beeSColin Percival# Do the work involved in comparing the system to a "known good" index
291108e23beeSColin PercivalIDS_run () {
291208e23beeSColin Percival	workdir_init || return 1
291308e23beeSColin Percival
291408e23beeSColin Percival	# Prepare the mirror list.
291508e23beeSColin Percival	fetch_pick_server_init && fetch_pick_server
291608e23beeSColin Percival
291708e23beeSColin Percival	# Try to fetch the public key until we run out of servers.
291808e23beeSColin Percival	while ! fetch_key; do
291908e23beeSColin Percival		fetch_pick_server || return 1
292008e23beeSColin Percival	done
292108e23beeSColin Percival
292208e23beeSColin Percival	# Try to fetch the metadata index signature ("tag") until we run
292308e23beeSColin Percival	# out of available servers; and sanity check the downloaded tag.
292408e23beeSColin Percival	while ! fetch_tag; do
292508e23beeSColin Percival		fetch_pick_server || return 1
292608e23beeSColin Percival	done
292708e23beeSColin Percival	fetch_tagsanity || return 1
292808e23beeSColin Percival
292908e23beeSColin Percival	# Fetch INDEX-OLD and INDEX-ALL.
293008e23beeSColin Percival	fetch_metadata INDEX-OLD INDEX-ALL || return 1
293108e23beeSColin Percival
293208e23beeSColin Percival	# Generate filtered INDEX-OLD and INDEX-ALL files containing only
293308e23beeSColin Percival	# the components we want and without anything marked as "Ignore".
293408e23beeSColin Percival	fetch_filter_metadata INDEX-OLD || return 1
293508e23beeSColin Percival	fetch_filter_metadata INDEX-ALL || return 1
293608e23beeSColin Percival
293708e23beeSColin Percival	# Merge the INDEX-OLD and INDEX-ALL files into INDEX-ALL.
293808e23beeSColin Percival	sort INDEX-OLD INDEX-ALL > INDEX-ALL.tmp
293908e23beeSColin Percival	mv INDEX-ALL.tmp INDEX-ALL
294008e23beeSColin Percival	rm INDEX-OLD
294108e23beeSColin Percival
294208e23beeSColin Percival	# Translate /boot/${KERNCONF} to ${KERNELDIR}
294308e23beeSColin Percival	fetch_filter_kernel_names INDEX-ALL ${KERNCONF}
294408e23beeSColin Percival
294508e23beeSColin Percival	# Inspect the system and generate an INDEX-PRESENT file.
294608e23beeSColin Percival	fetch_inspect_system INDEX-ALL INDEX-PRESENT /dev/null || return 1
294708e23beeSColin Percival
294808e23beeSColin Percival	# Compare INDEX-ALL and INDEX-PRESENT and print warnings about any
294908e23beeSColin Percival	# differences.
295008e23beeSColin Percival	IDS_compare INDEX-ALL INDEX-PRESENT
295108e23beeSColin Percival}
295208e23beeSColin Percival
295348ffe56aSColin Percival#### Main functions -- call parameter-handling and core functions
295448ffe56aSColin Percival
295548ffe56aSColin Percival# Using the command line, configuration file, and defaults,
295648ffe56aSColin Percival# set all the parameters which are needed later.
295748ffe56aSColin Percivalget_params () {
295848ffe56aSColin Percival	init_params
295948ffe56aSColin Percival	parse_cmdline $@
296048ffe56aSColin Percival	parse_conffile
296148ffe56aSColin Percival	default_params
296248ffe56aSColin Percival}
296348ffe56aSColin Percival
296448ffe56aSColin Percival# Fetch command.  Make sure that we're being called
296548ffe56aSColin Percival# interactively, then run fetch_check_params and fetch_run
296648ffe56aSColin Percivalcmd_fetch () {
296748ffe56aSColin Percival	if [ ! -t 0 ]; then
296848ffe56aSColin Percival		echo -n "`basename $0` fetch should not "
296948ffe56aSColin Percival		echo "be run non-interactively."
297048ffe56aSColin Percival		echo "Run `basename $0` cron instead."
297148ffe56aSColin Percival		exit 1
297248ffe56aSColin Percival	fi
297348ffe56aSColin Percival	fetch_check_params
297448ffe56aSColin Percival	fetch_run || exit 1
297548ffe56aSColin Percival}
297648ffe56aSColin Percival
297748ffe56aSColin Percival# Cron command.  Make sure the parameters are sensible; wait
297848ffe56aSColin Percival# rand(3600) seconds; then fetch updates.  While fetching updates,
297948ffe56aSColin Percival# send output to a temporary file; only print that file if the
298048ffe56aSColin Percival# fetching failed.
298148ffe56aSColin Percivalcmd_cron () {
298248ffe56aSColin Percival	fetch_check_params
298348ffe56aSColin Percival	sleep `jot -r 1 0 3600`
298448ffe56aSColin Percival
298548ffe56aSColin Percival	TMPFILE=`mktemp /tmp/freebsd-update.XXXXXX` || exit 1
298648ffe56aSColin Percival	if ! fetch_run >> ${TMPFILE} ||
298748ffe56aSColin Percival	    ! grep -q "No updates needed" ${TMPFILE} ||
298848ffe56aSColin Percival	    [ ${VERBOSELEVEL} = "debug" ]; then
298948ffe56aSColin Percival		mail -s "`hostname` security updates" ${MAILTO} < ${TMPFILE}
299048ffe56aSColin Percival	fi
299148ffe56aSColin Percival
299248ffe56aSColin Percival	rm ${TMPFILE}
299348ffe56aSColin Percival}
299448ffe56aSColin Percival
2995db6b0a61SColin Percival# Fetch files for upgrading to a new release.
2996db6b0a61SColin Percivalcmd_upgrade () {
2997db6b0a61SColin Percival	upgrade_check_params
2998db6b0a61SColin Percival	upgrade_run || exit 1
2999db6b0a61SColin Percival}
3000db6b0a61SColin Percival
300148ffe56aSColin Percival# Install downloaded updates.
300248ffe56aSColin Percivalcmd_install () {
300348ffe56aSColin Percival	install_check_params
300448ffe56aSColin Percival	install_run || exit 1
300548ffe56aSColin Percival}
300648ffe56aSColin Percival
300748ffe56aSColin Percival# Rollback most recently installed updates.
300848ffe56aSColin Percivalcmd_rollback () {
300948ffe56aSColin Percival	rollback_check_params
301048ffe56aSColin Percival	rollback_run || exit 1
301148ffe56aSColin Percival}
301248ffe56aSColin Percival
301308e23beeSColin Percival# Compare system against a "known good" index.
301408e23beeSColin Percivalcmd_IDS () {
301508e23beeSColin Percival	IDS_check_params
301608e23beeSColin Percival	IDS_run || exit 1
301708e23beeSColin Percival}
301808e23beeSColin Percival
301948ffe56aSColin Percival#### Entry point
302048ffe56aSColin Percival
302148ffe56aSColin Percival# Make sure we find utilities from the base system
302248ffe56aSColin Percivalexport PATH=/sbin:/bin:/usr/sbin:/usr/bin:${PATH}
302348ffe56aSColin Percival
3024f2890dbdSColin Percival# Set LC_ALL in order to avoid problems with character ranges like [A-Z].
3025f2890dbdSColin Percivalexport LC_ALL=C
3026f2890dbdSColin Percival
302748ffe56aSColin Percivalget_params $@
302848ffe56aSColin Percivalfor COMMAND in ${COMMANDS}; do
302948ffe56aSColin Percival	cmd_${COMMAND}
303048ffe56aSColin Percivaldone
3031