xref: /freebsd/usr.sbin/freebsd-update/freebsd-update.sh (revision c0f52443166ae7ecd512ab0350469d9c3648788c)
148ffe56aSColin Percival#!/bin/sh
248ffe56aSColin Percival
348ffe56aSColin Percival#-
44d846d26SWarner Losh# SPDX-License-Identifier: BSD-2-Clause
51de7b4b8SPedro F. Giffuni#
62328d598SColin Percival# Copyright 2004-2007 Colin Percival
748ffe56aSColin Percival# All rights reserved
848ffe56aSColin Percival#
948ffe56aSColin Percival# Redistribution and use in source and binary forms, with or without
1048ffe56aSColin Percival# modification, are permitted providing that the following conditions
1148ffe56aSColin Percival# are met:
1248ffe56aSColin Percival# 1. Redistributions of source code must retain the above copyright
1348ffe56aSColin Percival#    notice, this list of conditions and the following disclaimer.
1448ffe56aSColin Percival# 2. Redistributions in binary form must reproduce the above copyright
1548ffe56aSColin Percival#    notice, this list of conditions and the following disclaimer in the
1648ffe56aSColin Percival#    documentation and/or other materials provided with the distribution.
1748ffe56aSColin Percival#
1848ffe56aSColin Percival# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1948ffe56aSColin Percival# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2048ffe56aSColin Percival# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2148ffe56aSColin Percival# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
2248ffe56aSColin Percival# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2348ffe56aSColin Percival# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2448ffe56aSColin Percival# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2548ffe56aSColin Percival# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2648ffe56aSColin Percival# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
2748ffe56aSColin Percival# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2848ffe56aSColin Percival# POSSIBILITY OF SUCH DAMAGE.
2948ffe56aSColin Percival
3048ffe56aSColin Percival#### 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
37c76da1f0SFaraz Vahediusage: `basename $0` [options] command ...
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)
46df7e2e0dSEd Maste  -F           -- Force a fetch operation to proceed in the
47df7e2e0dSEd Maste                  case of an unfinished upgrade
48c76da1f0SFaraz Vahedi  -j jail      -- Operate on the given jail specified by jid or name
4948ffe56aSColin Percival  -k KEY       -- Trust an RSA key with SHA256 hash of KEY
50e0e5bf4dSPoul-Henning Kamp  -r release   -- Target for upgrade (e.g., 13.2-RELEASE)
5148ffe56aSColin Percival  -s server    -- Server from which to fetch updates
5248ffe56aSColin Percival                  (default: update.FreeBSD.org)
5348ffe56aSColin Percival  -t address   -- Mail output of cron command, if any, to address
5448ffe56aSColin Percival                  (default: root)
558935f242SAllan Jude  --not-running-from-cron
568935f242SAllan Jude               -- Run without a tty, for use by automated tools
57b39ce43eSColin Percival  --currently-running release
58b39ce43eSColin Percival               -- Update as if currently running this release
5948ffe56aSColin PercivalCommands:
6048ffe56aSColin Percival  fetch        -- Fetch updates from server
6148ffe56aSColin Percival  cron         -- Sleep rand(3600) seconds, fetch updates, and send an
6248ffe56aSColin Percival                  email if updates were found
63db6b0a61SColin Percival  upgrade      -- Fetch upgrades to FreeBSD version specified via -r option
648cfda118SMichael Gmelin  updatesready -- Check if there are fetched updates ready to install
65db6b0a61SColin Percival  install      -- Install downloaded updates or upgrades
6648ffe56aSColin Percival  rollback     -- Uninstall most recently installed updates
6775cb6429SEd Maste  IDS          -- Compare the system against an index of "known good" files
688cfda118SMichael Gmelin  showconfig   -- Show configuration
6948ffe56aSColin PercivalEOF
7048ffe56aSColin Percival	exit 0
7148ffe56aSColin Percival}
7248ffe56aSColin Percival
7348ffe56aSColin Percival#### Configuration processing functions
7448ffe56aSColin Percival
7548ffe56aSColin Percival#-
7648ffe56aSColin Percival# Configuration options are set in the following order of priority:
7748ffe56aSColin Percival# 1. Command line options
7848ffe56aSColin Percival# 2. Configuration file options
7948ffe56aSColin Percival# 3. Default options
8048ffe56aSColin Percival# In addition, certain options (e.g., IgnorePaths) can be specified multiple
8148ffe56aSColin Percival# times and (as long as these are all in the same place, e.g., inside the
8248ffe56aSColin Percival# configuration file) they will accumulate.  Finally, because the path to the
8348ffe56aSColin Percival# configuration file can be specified at the command line, the entire command
8448ffe56aSColin Percival# line must be processed before we start reading the configuration file.
8548ffe56aSColin Percival#
8648ffe56aSColin Percival# Sound like a mess?  It is.  Here's how we handle this:
8748ffe56aSColin Percival# 1. Initialize CONFFILE and all the options to "".
8848ffe56aSColin Percival# 2. Process the command line.  Throw an error if a non-accumulating option
8948ffe56aSColin Percival#    is specified twice.
9048ffe56aSColin Percival# 3. If CONFFILE is "", set CONFFILE to /etc/freebsd-update.conf .
9148ffe56aSColin Percival# 4. For all the configuration options X, set X_saved to X.
9248ffe56aSColin Percival# 5. Initialize all the options to "".
9348ffe56aSColin Percival# 6. Read CONFFILE line by line, parsing options.
9448ffe56aSColin Percival# 7. For each configuration option X, set X to X_saved iff X_saved is not "".
9548ffe56aSColin Percival# 8. Repeat steps 4-7, except setting options to their default values at (6).
9648ffe56aSColin Percival
9748ffe56aSColin PercivalCONFIGOPTIONS="KEYPRINT WORKDIR SERVERNAME MAILTO ALLOWADD ALLOWDELETE
9848ffe56aSColin Percival    KEEPMODIFIEDMETADATA COMPONENTS IGNOREPATHS UPDATEIFUNMODIFIED
9908e23beeSColin Percival    BASEDIR VERBOSELEVEL TARGETRELEASE STRICTCOMPONENTS MERGECHANGES
10023d827efSSimon L. B. Nielsen    IDSIGNOREPATHS BACKUPKERNEL BACKUPKERNELDIR BACKUPKERNELSYMBOLFILES"
10148ffe56aSColin Percival
10248ffe56aSColin Percival# Set all the configuration options to "".
10348ffe56aSColin Percivalnullconfig () {
10448ffe56aSColin Percival	for X in ${CONFIGOPTIONS}; do
10548ffe56aSColin Percival		eval ${X}=""
10648ffe56aSColin Percival	done
10748ffe56aSColin Percival}
10848ffe56aSColin Percival
10948ffe56aSColin Percival# For each configuration option X, set X_saved to X.
11048ffe56aSColin Percivalsaveconfig () {
11148ffe56aSColin Percival	for X in ${CONFIGOPTIONS}; do
11248ffe56aSColin Percival		eval ${X}_saved=\$${X}
11348ffe56aSColin Percival	done
11448ffe56aSColin Percival}
11548ffe56aSColin Percival
11648ffe56aSColin Percival# For each configuration option X, set X to X_saved if X_saved is not "".
11748ffe56aSColin Percivalmergeconfig () {
11848ffe56aSColin Percival	for X in ${CONFIGOPTIONS}; do
11948ffe56aSColin Percival		eval _=\$${X}_saved
12048ffe56aSColin Percival		if ! [ -z "${_}" ]; then
12148ffe56aSColin Percival			eval ${X}=\$${X}_saved
12248ffe56aSColin Percival		fi
12348ffe56aSColin Percival	done
12448ffe56aSColin Percival}
12548ffe56aSColin Percival
12648ffe56aSColin Percival# Set the trusted keyprint.
12748ffe56aSColin Percivalconfig_KeyPrint () {
12848ffe56aSColin Percival	if [ -z ${KEYPRINT} ]; then
12948ffe56aSColin Percival		KEYPRINT=$1
13048ffe56aSColin Percival	else
13148ffe56aSColin Percival		return 1
13248ffe56aSColin Percival	fi
13348ffe56aSColin Percival}
13448ffe56aSColin Percival
13548ffe56aSColin Percival# Set the working directory.
13648ffe56aSColin Percivalconfig_WorkDir () {
13748ffe56aSColin Percival	if [ -z ${WORKDIR} ]; then
13848ffe56aSColin Percival		WORKDIR=$1
13948ffe56aSColin Percival	else
14048ffe56aSColin Percival		return 1
14148ffe56aSColin Percival	fi
14248ffe56aSColin Percival}
14348ffe56aSColin Percival
14448ffe56aSColin Percival# Set the name of the server (pool) from which to fetch updates
14548ffe56aSColin Percivalconfig_ServerName () {
14648ffe56aSColin Percival	if [ -z ${SERVERNAME} ]; then
14748ffe56aSColin Percival		SERVERNAME=$1
14848ffe56aSColin Percival	else
14948ffe56aSColin Percival		return 1
15048ffe56aSColin Percival	fi
15148ffe56aSColin Percival}
15248ffe56aSColin Percival
15348ffe56aSColin Percival# Set the address to which 'cron' output will be mailed.
15448ffe56aSColin Percivalconfig_MailTo () {
15548ffe56aSColin Percival	if [ -z ${MAILTO} ]; then
15648ffe56aSColin Percival		MAILTO=$1
15748ffe56aSColin Percival	else
15848ffe56aSColin Percival		return 1
15948ffe56aSColin Percival	fi
16048ffe56aSColin Percival}
16148ffe56aSColin Percival
16248ffe56aSColin Percival# Set whether FreeBSD Update is allowed to add files (or directories, or
16348ffe56aSColin Percival# symlinks) which did not previously exist.
16448ffe56aSColin Percivalconfig_AllowAdd () {
16548ffe56aSColin Percival	if [ -z ${ALLOWADD} ]; then
16648ffe56aSColin Percival		case $1 in
16748ffe56aSColin Percival		[Yy][Ee][Ss])
16848ffe56aSColin Percival			ALLOWADD=yes
16948ffe56aSColin Percival			;;
17048ffe56aSColin Percival		[Nn][Oo])
17148ffe56aSColin Percival			ALLOWADD=no
17248ffe56aSColin Percival			;;
17348ffe56aSColin Percival		*)
17448ffe56aSColin Percival			return 1
17548ffe56aSColin Percival			;;
17648ffe56aSColin Percival		esac
17748ffe56aSColin Percival	else
17848ffe56aSColin Percival		return 1
17948ffe56aSColin Percival	fi
18048ffe56aSColin Percival}
18148ffe56aSColin Percival
18248ffe56aSColin Percival# Set whether FreeBSD Update is allowed to remove files/directories/symlinks.
18348ffe56aSColin Percivalconfig_AllowDelete () {
18448ffe56aSColin Percival	if [ -z ${ALLOWDELETE} ]; then
18548ffe56aSColin Percival		case $1 in
18648ffe56aSColin Percival		[Yy][Ee][Ss])
18748ffe56aSColin Percival			ALLOWDELETE=yes
18848ffe56aSColin Percival			;;
18948ffe56aSColin Percival		[Nn][Oo])
19048ffe56aSColin Percival			ALLOWDELETE=no
19148ffe56aSColin Percival			;;
19248ffe56aSColin Percival		*)
19348ffe56aSColin Percival			return 1
19448ffe56aSColin Percival			;;
19548ffe56aSColin Percival		esac
19648ffe56aSColin Percival	else
19748ffe56aSColin Percival		return 1
19848ffe56aSColin Percival	fi
19948ffe56aSColin Percival}
20048ffe56aSColin Percival
20148ffe56aSColin Percival# Set whether FreeBSD Update should keep existing inode ownership,
20248ffe56aSColin Percival# permissions, and flags, in the event that they have been modified locally
20348ffe56aSColin Percival# after the release.
20448ffe56aSColin Percivalconfig_KeepModifiedMetadata () {
20548ffe56aSColin Percival	if [ -z ${KEEPMODIFIEDMETADATA} ]; then
20648ffe56aSColin Percival		case $1 in
20748ffe56aSColin Percival		[Yy][Ee][Ss])
20848ffe56aSColin Percival			KEEPMODIFIEDMETADATA=yes
20948ffe56aSColin Percival			;;
21048ffe56aSColin Percival		[Nn][Oo])
21148ffe56aSColin Percival			KEEPMODIFIEDMETADATA=no
21248ffe56aSColin Percival			;;
21348ffe56aSColin Percival		*)
21448ffe56aSColin Percival			return 1
21548ffe56aSColin Percival			;;
21648ffe56aSColin Percival		esac
21748ffe56aSColin Percival	else
21848ffe56aSColin Percival		return 1
21948ffe56aSColin Percival	fi
22048ffe56aSColin Percival}
22148ffe56aSColin Percival
22248ffe56aSColin Percival# Add to the list of components which should be kept updated.
22348ffe56aSColin Percivalconfig_Components () {
22448ffe56aSColin Percival	for C in $@; do
22512294db4SMichael Gmelin		COMPONENTS="${COMPONENTS} ${C}"
22612294db4SMichael Gmelin	done
22712294db4SMichael Gmelin}
22812294db4SMichael Gmelin
22912294db4SMichael Gmelin# Remove src component from list if it isn't installed
23012294db4SMichael Gmelinfinalize_components_config () {
23112294db4SMichael Gmelin	COMPONENTS=""
23212294db4SMichael Gmelin	for C in $@; do
2335a74378cSXin LI		if [ "$C" = "src" ]; then
234cfd9be9cSEd Maste			if [ -e "${BASEDIR}/usr/src/COPYRIGHT" ]; then
23548ffe56aSColin Percival				COMPONENTS="${COMPONENTS} ${C}"
2365a74378cSXin LI			else
2375a74378cSXin LI				echo "src component not installed, skipped"
2385a74378cSXin LI			fi
2395a74378cSXin LI		else
2405a74378cSXin LI			COMPONENTS="${COMPONENTS} ${C}"
2415a74378cSXin LI		fi
24248ffe56aSColin Percival	done
24348ffe56aSColin Percival}
24448ffe56aSColin Percival
24548ffe56aSColin Percival# Add to the list of paths under which updates will be ignored.
24648ffe56aSColin Percivalconfig_IgnorePaths () {
24748ffe56aSColin Percival	for C in $@; do
24848ffe56aSColin Percival		IGNOREPATHS="${IGNOREPATHS} ${C}"
24948ffe56aSColin Percival	done
25048ffe56aSColin Percival}
25148ffe56aSColin Percival
25208e23beeSColin Percival# Add to the list of paths which IDS should ignore.
25308e23beeSColin Percivalconfig_IDSIgnorePaths () {
25408e23beeSColin Percival	for C in $@; do
25508e23beeSColin Percival		IDSIGNOREPATHS="${IDSIGNOREPATHS} ${C}"
25608e23beeSColin Percival	done
25708e23beeSColin Percival}
25808e23beeSColin Percival
25948ffe56aSColin Percival# Add to the list of paths within which updates will be performed only if the
26048ffe56aSColin Percival# file on disk has not been modified locally.
26148ffe56aSColin Percivalconfig_UpdateIfUnmodified () {
26248ffe56aSColin Percival	for C in $@; do
26348ffe56aSColin Percival		UPDATEIFUNMODIFIED="${UPDATEIFUNMODIFIED} ${C}"
26448ffe56aSColin Percival	done
26548ffe56aSColin Percival}
26648ffe56aSColin Percival
267db6b0a61SColin Percival# Add to the list of paths within which updates to text files will be merged
268db6b0a61SColin Percival# instead of overwritten.
269db6b0a61SColin Percivalconfig_MergeChanges () {
270db6b0a61SColin Percival	for C in $@; do
271db6b0a61SColin Percival		MERGECHANGES="${MERGECHANGES} ${C}"
272db6b0a61SColin Percival	done
273db6b0a61SColin Percival}
274db6b0a61SColin Percival
27548ffe56aSColin Percival# Work on a FreeBSD installation mounted under $1
27648ffe56aSColin Percivalconfig_BaseDir () {
27748ffe56aSColin Percival	if [ -z ${BASEDIR} ]; then
27848ffe56aSColin Percival		BASEDIR=$1
27948ffe56aSColin Percival	else
28048ffe56aSColin Percival		return 1
28148ffe56aSColin Percival	fi
28248ffe56aSColin Percival}
28348ffe56aSColin Percival
284db6b0a61SColin Percival# When fetching upgrades, should we assume the user wants exactly the
285db6b0a61SColin Percival# components listed in COMPONENTS, rather than trying to guess based on
286db6b0a61SColin Percival# what's currently installed?
287db6b0a61SColin Percivalconfig_StrictComponents () {
288db6b0a61SColin Percival	if [ -z ${STRICTCOMPONENTS} ]; then
289db6b0a61SColin Percival		case $1 in
290db6b0a61SColin Percival		[Yy][Ee][Ss])
291db6b0a61SColin Percival			STRICTCOMPONENTS=yes
292db6b0a61SColin Percival			;;
293db6b0a61SColin Percival		[Nn][Oo])
294db6b0a61SColin Percival			STRICTCOMPONENTS=no
295db6b0a61SColin Percival			;;
296db6b0a61SColin Percival		*)
297db6b0a61SColin Percival			return 1
298db6b0a61SColin Percival			;;
299db6b0a61SColin Percival		esac
300db6b0a61SColin Percival	else
301db6b0a61SColin Percival		return 1
302db6b0a61SColin Percival	fi
303db6b0a61SColin Percival}
304db6b0a61SColin Percival
305db6b0a61SColin Percival# Upgrade to FreeBSD $1
306db6b0a61SColin Percivalconfig_TargetRelease () {
307db6b0a61SColin Percival	if [ -z ${TARGETRELEASE} ]; then
308db6b0a61SColin Percival		TARGETRELEASE=$1
309db6b0a61SColin Percival	else
310db6b0a61SColin Percival		return 1
311db6b0a61SColin Percival	fi
312d23dc1eeSColin Percival	if echo ${TARGETRELEASE} | grep -qE '^[0-9.]+$'; then
313d23dc1eeSColin Percival		TARGETRELEASE="${TARGETRELEASE}-RELEASE"
314d23dc1eeSColin Percival	fi
315db6b0a61SColin Percival}
316db6b0a61SColin Percival
3170d5c5243SEd Maste# Pretend current release is FreeBSD $1
3180d5c5243SEd Masteconfig_SourceRelease () {
3190d5c5243SEd Maste	UNAME_r=$1
3200d5c5243SEd Maste	if echo ${UNAME_r} | grep -qE '^[0-9.]+$'; then
3210d5c5243SEd Maste		UNAME_r="${UNAME_r}-RELEASE"
3220d5c5243SEd Maste	fi
323b958d4b2SEd Maste	export UNAME_r
3240d5c5243SEd Maste}
3250d5c5243SEd Maste
326c76da1f0SFaraz Vahedi# Get the Jail's path and the version of its installed userland
327c76da1f0SFaraz Vahediconfig_TargetJail () {
328c76da1f0SFaraz Vahedi	JAIL=$1
329c76da1f0SFaraz Vahedi	UNAME_r=$(freebsd-version -j ${JAIL})
330c76da1f0SFaraz Vahedi	BASEDIR=$(jls -j ${JAIL} -h path | awk 'NR == 2 {print}')
331c76da1f0SFaraz Vahedi	if [ -z ${BASEDIR} ] || [ -z ${UNAME_r} ]; then
332c76da1f0SFaraz Vahedi		echo "The specified jail either doesn't exist or" \
333c76da1f0SFaraz Vahedi		      "does not have freebsd-version."
334c76da1f0SFaraz Vahedi		exit 1
335c76da1f0SFaraz Vahedi	fi
336c76da1f0SFaraz Vahedi	export UNAME_r
337c76da1f0SFaraz Vahedi}
338c76da1f0SFaraz Vahedi
33948ffe56aSColin Percival# Define what happens to output of utilities
34048ffe56aSColin Percivalconfig_VerboseLevel () {
34148ffe56aSColin Percival	if [ -z ${VERBOSELEVEL} ]; then
34248ffe56aSColin Percival		case $1 in
34348ffe56aSColin Percival		[Dd][Ee][Bb][Uu][Gg])
34448ffe56aSColin Percival			VERBOSELEVEL=debug
34548ffe56aSColin Percival			;;
34648ffe56aSColin Percival		[Nn][Oo][Ss][Tt][Aa][Tt][Ss])
34748ffe56aSColin Percival			VERBOSELEVEL=nostats
34848ffe56aSColin Percival			;;
34948ffe56aSColin Percival		[Ss][Tt][Aa][Tt][Ss])
35048ffe56aSColin Percival			VERBOSELEVEL=stats
35148ffe56aSColin Percival			;;
35248ffe56aSColin Percival		*)
35348ffe56aSColin Percival			return 1
35448ffe56aSColin Percival			;;
35548ffe56aSColin Percival		esac
35648ffe56aSColin Percival	else
35748ffe56aSColin Percival		return 1
35848ffe56aSColin Percival	fi
35948ffe56aSColin Percival}
36048ffe56aSColin Percival
36123d827efSSimon L. B. Nielsenconfig_BackupKernel () {
36223d827efSSimon L. B. Nielsen	if [ -z ${BACKUPKERNEL} ]; then
36323d827efSSimon L. B. Nielsen		case $1 in
36423d827efSSimon L. B. Nielsen		[Yy][Ee][Ss])
36523d827efSSimon L. B. Nielsen			BACKUPKERNEL=yes
36623d827efSSimon L. B. Nielsen			;;
36723d827efSSimon L. B. Nielsen		[Nn][Oo])
36823d827efSSimon L. B. Nielsen			BACKUPKERNEL=no
36923d827efSSimon L. B. Nielsen			;;
37023d827efSSimon L. B. Nielsen		*)
37123d827efSSimon L. B. Nielsen			return 1
37223d827efSSimon L. B. Nielsen			;;
37323d827efSSimon L. B. Nielsen		esac
37423d827efSSimon L. B. Nielsen	else
37523d827efSSimon L. B. Nielsen		return 1
37623d827efSSimon L. B. Nielsen	fi
37723d827efSSimon L. B. Nielsen}
37823d827efSSimon L. B. Nielsen
37923d827efSSimon L. B. Nielsenconfig_BackupKernelDir () {
38023d827efSSimon L. B. Nielsen	if [ -z ${BACKUPKERNELDIR} ]; then
38123d827efSSimon L. B. Nielsen		if [ -z "$1" ]; then
38223d827efSSimon L. B. Nielsen			echo "BackupKernelDir set to empty dir"
38323d827efSSimon L. B. Nielsen			return 1
38423d827efSSimon L. B. Nielsen		fi
38523d827efSSimon L. B. Nielsen
38623d827efSSimon L. B. Nielsen		# We check for some paths which would be extremely odd
38723d827efSSimon L. B. Nielsen		# to use, but which could cause a lot of problems if
38823d827efSSimon L. B. Nielsen		# used.
38923d827efSSimon L. B. Nielsen		case $1 in
39023d827efSSimon L. B. Nielsen		/|/bin|/boot|/etc|/lib|/libexec|/sbin|/usr|/var)
39123d827efSSimon L. B. Nielsen			echo "BackupKernelDir set to invalid path $1"
39223d827efSSimon L. B. Nielsen			return 1
39323d827efSSimon L. B. Nielsen			;;
39423d827efSSimon L. B. Nielsen		/*)
39523d827efSSimon L. B. Nielsen			BACKUPKERNELDIR=$1
39623d827efSSimon L. B. Nielsen			;;
39723d827efSSimon L. B. Nielsen		*)
39823d827efSSimon L. B. Nielsen			echo "BackupKernelDir ($1) is not an absolute path"
39923d827efSSimon L. B. Nielsen			return 1
40023d827efSSimon L. B. Nielsen			;;
40123d827efSSimon L. B. Nielsen		esac
40223d827efSSimon L. B. Nielsen	else
40323d827efSSimon L. B. Nielsen		return 1
40423d827efSSimon L. B. Nielsen	fi
40523d827efSSimon L. B. Nielsen}
40623d827efSSimon L. B. Nielsen
40723d827efSSimon L. B. Nielsenconfig_BackupKernelSymbolFiles () {
40823d827efSSimon L. B. Nielsen	if [ -z ${BACKUPKERNELSYMBOLFILES} ]; then
40923d827efSSimon L. B. Nielsen		case $1 in
41023d827efSSimon L. B. Nielsen		[Yy][Ee][Ss])
41123d827efSSimon L. B. Nielsen			BACKUPKERNELSYMBOLFILES=yes
41223d827efSSimon L. B. Nielsen			;;
41323d827efSSimon L. B. Nielsen		[Nn][Oo])
41423d827efSSimon L. B. Nielsen			BACKUPKERNELSYMBOLFILES=no
41523d827efSSimon L. B. Nielsen			;;
41623d827efSSimon L. B. Nielsen		*)
41723d827efSSimon L. B. Nielsen			return 1
41823d827efSSimon L. B. Nielsen			;;
41923d827efSSimon L. B. Nielsen		esac
42023d827efSSimon L. B. Nielsen	else
42123d827efSSimon L. B. Nielsen		return 1
42223d827efSSimon L. B. Nielsen	fi
42323d827efSSimon L. B. Nielsen}
42423d827efSSimon L. B. Nielsen
425f28f1389SDave Fullardconfig_CreateBootEnv () {
426f28f1389SDave Fullard	if [ -z ${BOOTENV} ]; then
427f28f1389SDave Fullard		case $1 in
428f28f1389SDave Fullard		[Yy][Ee][Ss])
429f28f1389SDave Fullard			BOOTENV=yes
430f28f1389SDave Fullard			;;
431f28f1389SDave Fullard		[Nn][Oo])
432f28f1389SDave Fullard			BOOTENV=no
433f28f1389SDave Fullard			;;
434f28f1389SDave Fullard		*)
435f28f1389SDave Fullard			return 1
436f28f1389SDave Fullard			;;
437f28f1389SDave Fullard		esac
438f28f1389SDave Fullard	else
439f28f1389SDave Fullard		return 1
440f28f1389SDave Fullard	fi
441f28f1389SDave Fullard}
44248ffe56aSColin Percival# Handle one line of configuration
44348ffe56aSColin Percivalconfigline () {
44448ffe56aSColin Percival	if [ $# -eq 0 ]; then
44548ffe56aSColin Percival		return
44648ffe56aSColin Percival	fi
44748ffe56aSColin Percival
44848ffe56aSColin Percival	OPT=$1
44948ffe56aSColin Percival	shift
45048ffe56aSColin Percival	config_${OPT} $@
45148ffe56aSColin Percival}
45248ffe56aSColin Percival
45348ffe56aSColin Percival#### Parameter handling functions.
45448ffe56aSColin Percival
45548ffe56aSColin Percival# Initialize parameters to null, just in case they're
45648ffe56aSColin Percival# set in the environment.
45748ffe56aSColin Percivalinit_params () {
45848ffe56aSColin Percival	# Configration settings
45948ffe56aSColin Percival	nullconfig
46048ffe56aSColin Percival
46148ffe56aSColin Percival	# No configuration file set yet
46248ffe56aSColin Percival	CONFFILE=""
46348ffe56aSColin Percival
46448ffe56aSColin Percival	# No commands specified yet
46548ffe56aSColin Percival	COMMANDS=""
4668935f242SAllan Jude
4678935f242SAllan Jude	# Force fetch to proceed
4688935f242SAllan Jude	FORCEFETCH=0
4698935f242SAllan Jude
4708935f242SAllan Jude	# Run without a TTY
4718935f242SAllan Jude	NOTTYOK=0
47233bd05c3SGuangyuan Yang
47333bd05c3SGuangyuan Yang	# Fetched first in a chain of commands
47433bd05c3SGuangyuan Yang	ISFETCHED=0
47548ffe56aSColin Percival}
47648ffe56aSColin Percival
47748ffe56aSColin Percival# Parse the command line
47848ffe56aSColin Percivalparse_cmdline () {
47948ffe56aSColin Percival	while [ $# -gt 0 ]; do
48048ffe56aSColin Percival		case "$1" in
48148ffe56aSColin Percival		# Location of configuration file
48248ffe56aSColin Percival		-f)
48348ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi
48448ffe56aSColin Percival			if [ ! -z "${CONFFILE}" ]; then usage; fi
48548ffe56aSColin Percival			shift; CONFFILE="$1"
48648ffe56aSColin Percival			;;
4878935f242SAllan Jude		-F)
4888935f242SAllan Jude			FORCEFETCH=1
4898935f242SAllan Jude			;;
4908935f242SAllan Jude		--not-running-from-cron)
4918935f242SAllan Jude			NOTTYOK=1
4928935f242SAllan Jude			;;
493b39ce43eSColin Percival		--currently-running)
4940d5c5243SEd Maste			shift
4950d5c5243SEd Maste			config_SourceRelease $1 || usage
496b39ce43eSColin Percival			;;
49748ffe56aSColin Percival
49848ffe56aSColin Percival		# Configuration file equivalents
49948ffe56aSColin Percival		-b)
50048ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
50148ffe56aSColin Percival			config_BaseDir $1 || usage
50248ffe56aSColin Percival			;;
50348ffe56aSColin Percival		-d)
50448ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
50548ffe56aSColin Percival			config_WorkDir $1 || usage
50648ffe56aSColin Percival			;;
507c76da1f0SFaraz Vahedi		-j)
508c76da1f0SFaraz Vahedi			if [ $# -eq 1 ]; then usage; fi; shift
509c76da1f0SFaraz Vahedi			config_TargetJail $1 || usage
510c76da1f0SFaraz Vahedi			;;
51148ffe56aSColin Percival		-k)
51248ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
51348ffe56aSColin Percival			config_KeyPrint $1 || usage
51448ffe56aSColin Percival			;;
51548ffe56aSColin Percival		-s)
51648ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
51748ffe56aSColin Percival			config_ServerName $1 || usage
51848ffe56aSColin Percival			;;
519db6b0a61SColin Percival		-r)
520db6b0a61SColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
521db6b0a61SColin Percival			config_TargetRelease $1 || usage
522db6b0a61SColin Percival			;;
52348ffe56aSColin Percival		-t)
52448ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
52548ffe56aSColin Percival			config_MailTo $1 || usage
52648ffe56aSColin Percival			;;
52748ffe56aSColin Percival		-v)
52848ffe56aSColin Percival			if [ $# -eq 1 ]; then usage; fi; shift
52948ffe56aSColin Percival			config_VerboseLevel $1 || usage
53048ffe56aSColin Percival			;;
53148ffe56aSColin Percival
53248ffe56aSColin Percival		# Aliases for "-v debug" and "-v nostats"
53348ffe56aSColin Percival		--debug)
53448ffe56aSColin Percival			config_VerboseLevel debug || usage
53548ffe56aSColin Percival			;;
53648ffe56aSColin Percival		--no-stats)
53748ffe56aSColin Percival			config_VerboseLevel nostats || usage
53848ffe56aSColin Percival			;;
53948ffe56aSColin Percival
54048ffe56aSColin Percival		# Commands
5418cfda118SMichael Gmelin		cron | fetch | upgrade | updatesready | install | rollback |\
5428cfda118SMichael Gmelin		IDS | showconfig)
54348ffe56aSColin Percival			COMMANDS="${COMMANDS} $1"
54448ffe56aSColin Percival			;;
54548ffe56aSColin Percival
54648ffe56aSColin Percival		# Anything else is an error
54748ffe56aSColin Percival		*)
54848ffe56aSColin Percival			usage
54948ffe56aSColin Percival			;;
55048ffe56aSColin Percival		esac
55148ffe56aSColin Percival		shift
55248ffe56aSColin Percival	done
55348ffe56aSColin Percival
55448ffe56aSColin Percival	# Make sure we have at least one command
55548ffe56aSColin Percival	if [ -z "${COMMANDS}" ]; then
55648ffe56aSColin Percival		usage
55748ffe56aSColin Percival	fi
55848ffe56aSColin Percival}
55948ffe56aSColin Percival
56048ffe56aSColin Percival# Parse the configuration file
56148ffe56aSColin Percivalparse_conffile () {
56248ffe56aSColin Percival	# If a configuration file was specified on the command line, check
56348ffe56aSColin Percival	# that it exists and is readable.
56448ffe56aSColin Percival	if [ ! -z "${CONFFILE}" ] && [ ! -r "${CONFFILE}" ]; then
56548ffe56aSColin Percival		echo -n "File does not exist "
56648ffe56aSColin Percival		echo -n "or is not readable: "
56748ffe56aSColin Percival		echo ${CONFFILE}
56848ffe56aSColin Percival		exit 1
56948ffe56aSColin Percival	fi
57048ffe56aSColin Percival
57148ffe56aSColin Percival	# If a configuration file was not specified on the command line,
57248ffe56aSColin Percival	# use the default configuration file path.  If that default does
57348ffe56aSColin Percival	# not exist, give up looking for any configuration.
57448ffe56aSColin Percival	if [ -z "${CONFFILE}" ]; then
57548ffe56aSColin Percival		CONFFILE="/etc/freebsd-update.conf"
57648ffe56aSColin Percival		if [ ! -r "${CONFFILE}" ]; then
57748ffe56aSColin Percival			return
57848ffe56aSColin Percival		fi
57948ffe56aSColin Percival	fi
58048ffe56aSColin Percival
58148ffe56aSColin Percival	# Save the configuration options specified on the command line, and
58248ffe56aSColin Percival	# clear all the options in preparation for reading the config file.
58348ffe56aSColin Percival	saveconfig
58448ffe56aSColin Percival	nullconfig
58548ffe56aSColin Percival
58648ffe56aSColin Percival	# Read the configuration file.  Anything after the first '#' is
58748ffe56aSColin Percival	# ignored, and any blank lines are ignored.
58848ffe56aSColin Percival	L=0
58948ffe56aSColin Percival	while read LINE; do
59048ffe56aSColin Percival		L=$(($L + 1))
59148ffe56aSColin Percival		LINEX=`echo "${LINE}" | cut -f 1 -d '#'`
59248ffe56aSColin Percival		if ! configline ${LINEX}; then
59348ffe56aSColin Percival			echo "Error processing configuration file, line $L:"
59448ffe56aSColin Percival			echo "==> ${LINE}"
59548ffe56aSColin Percival			exit 1
59648ffe56aSColin Percival		fi
59748ffe56aSColin Percival	done < ${CONFFILE}
59848ffe56aSColin Percival
59948ffe56aSColin Percival	# Merge the settings read from the configuration file with those
60048ffe56aSColin Percival	# provided at the command line.
60148ffe56aSColin Percival	mergeconfig
60248ffe56aSColin Percival}
60348ffe56aSColin Percival
60448ffe56aSColin Percival# Provide some default parameters
60548ffe56aSColin Percivaldefault_params () {
60648ffe56aSColin Percival	# Save any parameters already configured, and clear the slate
60748ffe56aSColin Percival	saveconfig
60848ffe56aSColin Percival	nullconfig
60948ffe56aSColin Percival
61048ffe56aSColin Percival	# Default configurations
61148ffe56aSColin Percival	config_WorkDir /var/db/freebsd-update
61248ffe56aSColin Percival	config_MailTo root
61348ffe56aSColin Percival	config_AllowAdd yes
61448ffe56aSColin Percival	config_AllowDelete yes
61548ffe56aSColin Percival	config_KeepModifiedMetadata yes
61648ffe56aSColin Percival	config_BaseDir /
61748ffe56aSColin Percival	config_VerboseLevel stats
618db6b0a61SColin Percival	config_StrictComponents no
61923d827efSSimon L. B. Nielsen	config_BackupKernel yes
62023d827efSSimon L. B. Nielsen	config_BackupKernelDir /boot/kernel.old
62123d827efSSimon L. B. Nielsen	config_BackupKernelSymbolFiles no
622f28f1389SDave Fullard	config_CreateBootEnv yes
62348ffe56aSColin Percival
62448ffe56aSColin Percival	# Merge these defaults into the earlier-configured settings
62548ffe56aSColin Percival	mergeconfig
62648ffe56aSColin Percival}
62748ffe56aSColin Percival
62848ffe56aSColin Percival# Set utility output filtering options, based on ${VERBOSELEVEL}
62948ffe56aSColin Percivalfetch_setup_verboselevel () {
63048ffe56aSColin Percival	case ${VERBOSELEVEL} in
63148ffe56aSColin Percival	debug)
63248ffe56aSColin Percival		QUIETREDIR="/dev/stderr"
63348ffe56aSColin Percival		QUIETFLAG=" "
63448ffe56aSColin Percival		STATSREDIR="/dev/stderr"
63548ffe56aSColin Percival		DDSTATS=".."
63648ffe56aSColin Percival		XARGST="-t"
63748ffe56aSColin Percival		NDEBUG=" "
63848ffe56aSColin Percival		;;
63948ffe56aSColin Percival	nostats)
64048ffe56aSColin Percival		QUIETREDIR=""
64148ffe56aSColin Percival		QUIETFLAG=""
64248ffe56aSColin Percival		STATSREDIR="/dev/null"
64348ffe56aSColin Percival		DDSTATS=".."
64448ffe56aSColin Percival		XARGST=""
64548ffe56aSColin Percival		NDEBUG=""
64648ffe56aSColin Percival		;;
64748ffe56aSColin Percival	stats)
64848ffe56aSColin Percival		QUIETREDIR="/dev/null"
64948ffe56aSColin Percival		QUIETFLAG="-q"
65048ffe56aSColin Percival		STATSREDIR="/dev/stdout"
65148ffe56aSColin Percival		DDSTATS=""
65248ffe56aSColin Percival		XARGST=""
65348ffe56aSColin Percival		NDEBUG="-n"
65448ffe56aSColin Percival		;;
65548ffe56aSColin Percival	esac
65648ffe56aSColin Percival}
65748ffe56aSColin Percival
65848ffe56aSColin Percival# Perform sanity checks and set some final parameters
65948ffe56aSColin Percival# in preparation for fetching files.  Figure out which
66048ffe56aSColin Percival# set of updates should be downloaded: If the user is
66148ffe56aSColin Percival# running *-p[0-9]+, strip off the last part; if the
66248ffe56aSColin Percival# user is running -SECURITY, call it -RELEASE.  Chdir
66348ffe56aSColin Percival# into the working directory.
664211f2ba0SColin Percivalfetchupgrade_check_params () {
66548ffe56aSColin Percival	export HTTP_USER_AGENT="freebsd-update (${COMMAND}, `uname -r`)"
66648ffe56aSColin Percival
66748ffe56aSColin Percival	_SERVERNAME_z=\
66848ffe56aSColin Percival"SERVERNAME must be given via command line or configuration file."
66948ffe56aSColin Percival	_KEYPRINT_z="Key must be given via -k option or configuration file."
67048ffe56aSColin Percival	_KEYPRINT_bad="Invalid key fingerprint: "
67148ffe56aSColin Percival	_WORKDIR_bad="Directory does not exist or is not writable: "
672f88076f0SMark Felder	_WORKDIR_bad2="Directory is not on a persistent filesystem: "
67348ffe56aSColin Percival
67448ffe56aSColin Percival	if [ -z "${SERVERNAME}" ]; then
67548ffe56aSColin Percival		echo -n "`basename $0`: "
67648ffe56aSColin Percival		echo "${_SERVERNAME_z}"
67748ffe56aSColin Percival		exit 1
67848ffe56aSColin Percival	fi
67948ffe56aSColin Percival	if [ -z "${KEYPRINT}" ]; then
68048ffe56aSColin Percival		echo -n "`basename $0`: "
68148ffe56aSColin Percival		echo "${_KEYPRINT_z}"
68248ffe56aSColin Percival		exit 1
68348ffe56aSColin Percival	fi
68448ffe56aSColin Percival	if ! echo "${KEYPRINT}" | grep -qE "^[0-9a-f]{64}$"; then
68548ffe56aSColin Percival		echo -n "`basename $0`: "
68648ffe56aSColin Percival		echo -n "${_KEYPRINT_bad}"
68748ffe56aSColin Percival		echo ${KEYPRINT}
68848ffe56aSColin Percival		exit 1
68948ffe56aSColin Percival	fi
69048ffe56aSColin Percival	if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then
69148ffe56aSColin Percival		echo -n "`basename $0`: "
69248ffe56aSColin Percival		echo -n "${_WORKDIR_bad}"
69348ffe56aSColin Percival		echo ${WORKDIR}
69448ffe56aSColin Percival		exit 1
69548ffe56aSColin Percival	fi
696dfe9215bSMark Felder	case `df -T ${WORKDIR}` in */dev/md[0-9]* | *tmpfs*)
697f88076f0SMark Felder		echo -n "`basename $0`: "
698f88076f0SMark Felder		echo -n "${_WORKDIR_bad2}"
699f88076f0SMark Felder		echo ${WORKDIR}
700f88076f0SMark Felder		exit 1
701dfe9215bSMark Felder		;;
702dfe9215bSMark Felder	esac
703a2356430SColin Percival	chmod 700 ${WORKDIR}
70448ffe56aSColin Percival	cd ${WORKDIR} || exit 1
70548ffe56aSColin Percival
70648ffe56aSColin Percival	# Generate release number.  The s/SECURITY/RELEASE/ bit exists
70748ffe56aSColin Percival	# to provide an upgrade path for FreeBSD Update 1.x users, since
70848ffe56aSColin Percival	# the kernels provided by FreeBSD Update 1.x are always labelled
70948ffe56aSColin Percival	# as X.Y-SECURITY.
71048ffe56aSColin Percival	RELNUM=`uname -r |
71148ffe56aSColin Percival	    sed -E 's,-p[0-9]+,,' |
71248ffe56aSColin Percival	    sed -E 's,-SECURITY,-RELEASE,'`
71348ffe56aSColin Percival	ARCH=`uname -m`
71448ffe56aSColin Percival	FETCHDIR=${RELNUM}/${ARCH}
715db6b0a61SColin Percival	PATCHDIR=${RELNUM}/${ARCH}/bp
71648ffe56aSColin Percival
717d308a8bfSEd Maste	# Disallow upgrade from a version that is not a release
718d308a8bfSEd Maste	case ${RELNUM} in
719d308a8bfSEd Maste	*-RELEASE | *-ALPHA*  | *-BETA* | *-RC*)
720d308a8bfSEd Maste		;;
721d308a8bfSEd Maste	*)
7220d5c5243SEd Maste		echo -n "`basename $0`: "
7230d5c5243SEd Maste		cat <<- EOF
724d308a8bfSEd Maste			Cannot upgrade from a version that is not a release
725d308a8bfSEd Maste			(including alpha, beta and release candidates)
726d308a8bfSEd Maste			using `basename $0`. Instead, FreeBSD can be directly
727d308a8bfSEd Maste			upgraded by source or upgraded to a RELEASE/RELENG version
728d308a8bfSEd Maste			prior to running `basename $0`.
729d308a8bfSEd Maste			Currently running: ${RELNUM}
7300d5c5243SEd Maste		EOF
7310d5c5243SEd Maste		exit 1
732d308a8bfSEd Maste		;;
733d308a8bfSEd Maste	esac
7340d5c5243SEd Maste
73548ffe56aSColin Percival	# Figure out what directory contains the running kernel
73648ffe56aSColin Percival	BOOTFILE=`sysctl -n kern.bootfile`
73748ffe56aSColin Percival	KERNELDIR=${BOOTFILE%/kernel}
73848ffe56aSColin Percival	if ! [ -d ${KERNELDIR} ]; then
73948ffe56aSColin Percival		echo "Cannot identify running kernel"
74048ffe56aSColin Percival		exit 1
74148ffe56aSColin Percival	fi
74248ffe56aSColin Percival
7432c434b2cSColin Percival	# Figure out what kernel configuration is running.  We start with
7442c434b2cSColin Percival	# the output of `uname -i`, and then make the following adjustments:
7452c434b2cSColin Percival	# 1. Replace "SMP-GENERIC" with "SMP".  Why the SMP kernel config
7462c434b2cSColin Percival	# file says "ident SMP-GENERIC", I don't know...
7472c434b2cSColin Percival	# 2. If the kernel claims to be GENERIC _and_ ${ARCH} is "amd64"
7482c434b2cSColin Percival	# _and_ `sysctl kern.version` contains a line which ends "/SMP", then
7492c434b2cSColin Percival	# we're running an SMP kernel.  This mis-identification is a bug
7502c434b2cSColin Percival	# which was fixed in 6.2-STABLE.
7512c434b2cSColin Percival	KERNCONF=`uname -i`
7522c434b2cSColin Percival	if [ ${KERNCONF} = "SMP-GENERIC" ]; then
7532c434b2cSColin Percival		KERNCONF=SMP
7542c434b2cSColin Percival	fi
7552c434b2cSColin Percival	if [ ${KERNCONF} = "GENERIC" ] && [ ${ARCH} = "amd64" ]; then
7562c434b2cSColin Percival		if sysctl kern.version | grep -qE '/SMP$'; then
7572c434b2cSColin Percival			KERNCONF=SMP
7582c434b2cSColin Percival		fi
7592c434b2cSColin Percival	fi
7602c434b2cSColin Percival
76148ffe56aSColin Percival	# Define some paths
76248ffe56aSColin Percival	BSPATCH=/usr/bin/bspatch
76348ffe56aSColin Percival	SHA256=/sbin/sha256
76448ffe56aSColin Percival	PHTTPGET=/usr/libexec/phttpget
76548ffe56aSColin Percival
76648ffe56aSColin Percival	# Set up variables relating to VERBOSELEVEL
76748ffe56aSColin Percival	fetch_setup_verboselevel
76848ffe56aSColin Percival
76948ffe56aSColin Percival	# Construct a unique name from ${BASEDIR}
77048ffe56aSColin Percival	BDHASH=`echo ${BASEDIR} | sha256 -q`
77148ffe56aSColin Percival}
77248ffe56aSColin Percival
773211f2ba0SColin Percival# Perform sanity checks etc. before fetching updates.
774211f2ba0SColin Percivalfetch_check_params () {
775211f2ba0SColin Percival	fetchupgrade_check_params
776211f2ba0SColin Percival
777211f2ba0SColin Percival	if ! [ -z "${TARGETRELEASE}" ]; then
778211f2ba0SColin Percival		echo -n "`basename $0`: "
779211f2ba0SColin Percival		echo -n "-r option is meaningless with 'fetch' command.  "
780211f2ba0SColin Percival		echo "(Did you mean 'upgrade' instead?)"
781211f2ba0SColin Percival		exit 1
782211f2ba0SColin Percival	fi
7838935f242SAllan Jude
7848935f242SAllan Jude	# Check that we have updates ready to install
7858bf2dcceSAllan Jude	if [ -f ${BDHASH}-install/kerneldone -a $FORCEFETCH -eq 0 ]; then
7868935f242SAllan Jude		echo "You have a partially completed upgrade pending"
7878935f242SAllan Jude		echo "Run '$0 install' first."
7888935f242SAllan Jude		echo "Run '$0 fetch -F' to proceed anyway."
7898935f242SAllan Jude		exit 1
7908935f242SAllan Jude	fi
791211f2ba0SColin Percival}
792211f2ba0SColin Percival
793db6b0a61SColin Percival# Perform sanity checks etc. before fetching upgrades.
794db6b0a61SColin Percivalupgrade_check_params () {
795211f2ba0SColin Percival	fetchupgrade_check_params
796db6b0a61SColin Percival
797db6b0a61SColin Percival	# Unless set otherwise, we're upgrading to the same kernel config.
798db6b0a61SColin Percival	NKERNCONF=${KERNCONF}
799db6b0a61SColin Percival
800db6b0a61SColin Percival	# We need TARGETRELEASE set
801db6b0a61SColin Percival	_TARGETRELEASE_z="Release target must be specified via -r option."
802db6b0a61SColin Percival	if [ -z "${TARGETRELEASE}" ]; then
803db6b0a61SColin Percival		echo -n "`basename $0`: "
804db6b0a61SColin Percival		echo "${_TARGETRELEASE_z}"
805db6b0a61SColin Percival		exit 1
806db6b0a61SColin Percival	fi
807db6b0a61SColin Percival
808db6b0a61SColin Percival	# The target release should be != the current release.
809db6b0a61SColin Percival	if [ "${TARGETRELEASE}" = "${RELNUM}" ]; then
810db6b0a61SColin Percival		echo -n "`basename $0`: "
811db6b0a61SColin Percival		echo "Cannot upgrade from ${RELNUM} to itself"
812db6b0a61SColin Percival		exit 1
813db6b0a61SColin Percival	fi
814db6b0a61SColin Percival
815db6b0a61SColin Percival	# Turning off AllowAdd or AllowDelete is a bad idea for upgrades.
816db6b0a61SColin Percival	if [ "${ALLOWADD}" = "no" ]; then
817db6b0a61SColin Percival		echo -n "`basename $0`: "
818db6b0a61SColin Percival		echo -n "WARNING: \"AllowAdd no\" is a bad idea "
819db6b0a61SColin Percival		echo "when upgrading between releases."
820db6b0a61SColin Percival		echo
821db6b0a61SColin Percival	fi
822db6b0a61SColin Percival	if [ "${ALLOWDELETE}" = "no" ]; then
823db6b0a61SColin Percival		echo -n "`basename $0`: "
824db6b0a61SColin Percival		echo -n "WARNING: \"AllowDelete no\" is a bad idea "
825db6b0a61SColin Percival		echo "when upgrading between releases."
826db6b0a61SColin Percival		echo
827db6b0a61SColin Percival	fi
828db6b0a61SColin Percival
829db6b0a61SColin Percival	# Set EDITOR to /usr/bin/vi if it isn't already set
830db6b0a61SColin Percival	: ${EDITOR:='/usr/bin/vi'}
831db6b0a61SColin Percival}
832db6b0a61SColin Percival
83348ffe56aSColin Percival# Perform sanity checks and set some final parameters in
83448ffe56aSColin Percival# preparation for installing updates.
83548ffe56aSColin Percivalinstall_check_params () {
83648ffe56aSColin Percival	# Check that we are root.  All sorts of things won't work otherwise.
83748ffe56aSColin Percival	if [ `id -u` != 0 ]; then
83848ffe56aSColin Percival		echo "You must be root to run this."
83948ffe56aSColin Percival		exit 1
84048ffe56aSColin Percival	fi
84148ffe56aSColin Percival
8422328d598SColin Percival	# Check that securelevel <= 0.  Otherwise we can't update schg files.
8432328d598SColin Percival	if [ `sysctl -n kern.securelevel` -gt 0 ]; then
8442328d598SColin Percival		echo "Updates cannot be installed when the system securelevel"
8452328d598SColin Percival		echo "is greater than zero."
8462328d598SColin Percival		exit 1
8472328d598SColin Percival	fi
8482328d598SColin Percival
84948ffe56aSColin Percival	# Check that we have a working directory
85048ffe56aSColin Percival	_WORKDIR_bad="Directory does not exist or is not writable: "
85148ffe56aSColin Percival	if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then
85248ffe56aSColin Percival		echo -n "`basename $0`: "
85348ffe56aSColin Percival		echo -n "${_WORKDIR_bad}"
85448ffe56aSColin Percival		echo ${WORKDIR}
85548ffe56aSColin Percival		exit 1
85648ffe56aSColin Percival	fi
85748ffe56aSColin Percival	cd ${WORKDIR} || exit 1
85848ffe56aSColin Percival
85948ffe56aSColin Percival	# Construct a unique name from ${BASEDIR}
86048ffe56aSColin Percival	BDHASH=`echo ${BASEDIR} | sha256 -q`
86148ffe56aSColin Percival
86248ffe56aSColin Percival	# Check that we have updates ready to install
86348ffe56aSColin Percival	if ! [ -L ${BDHASH}-install ]; then
86448ffe56aSColin Percival		echo "No updates are available to install."
86533bd05c3SGuangyuan Yang		if [ $ISFETCHED -eq 0 ]; then
86648ffe56aSColin Percival			echo "Run '$0 fetch' first."
8678cfda118SMichael Gmelin			exit 2
86833bd05c3SGuangyuan Yang		fi
86933bd05c3SGuangyuan Yang		exit 0
87048ffe56aSColin Percival	fi
87148ffe56aSColin Percival	if ! [ -f ${BDHASH}-install/INDEX-OLD ] ||
87248ffe56aSColin Percival	    ! [ -f ${BDHASH}-install/INDEX-NEW ]; then
87348ffe56aSColin Percival		echo "Update manifest is corrupt -- this should never happen."
87448ffe56aSColin Percival		echo "Re-run '$0 fetch'."
87548ffe56aSColin Percival		exit 1
87648ffe56aSColin Percival	fi
87723d827efSSimon L. B. Nielsen
87823d827efSSimon L. B. Nielsen	# Figure out what directory contains the running kernel
87923d827efSSimon L. B. Nielsen	BOOTFILE=`sysctl -n kern.bootfile`
88023d827efSSimon L. B. Nielsen	KERNELDIR=${BOOTFILE%/kernel}
88123d827efSSimon L. B. Nielsen	if ! [ -d ${KERNELDIR} ]; then
88223d827efSSimon L. B. Nielsen		echo "Cannot identify running kernel"
88323d827efSSimon L. B. Nielsen		exit 1
88423d827efSSimon L. B. Nielsen	fi
88548ffe56aSColin Percival}
88648ffe56aSColin Percival
887f28f1389SDave Fullard# Creates a new boot environment
888f28f1389SDave Fullardinstall_create_be () {
889f28f1389SDave Fullard	# Figure out if we're running in a jail and return if we are
890f28f1389SDave Fullard	if [ `sysctl -n security.jail.jailed` = 1 ]; then
891f28f1389SDave Fullard		return 1
892f28f1389SDave Fullard	fi
893e01e8f91SKyle Evans	# Operating on roots that aren't located at / will, more often than not,
894e01e8f91SKyle Evans	# not touch the boot environment.
895e01e8f91SKyle Evans	if [ "$BASEDIR" != "/" ]; then
896e01e8f91SKyle Evans		return 1
897e01e8f91SKyle Evans	fi
898f28f1389SDave Fullard	# Create a boot environment if enabled
899f28f1389SDave Fullard	if [ ${BOOTENV} = yes ]; then
900f28f1389SDave Fullard		bectl check 2>/dev/null
901f28f1389SDave Fullard		case $? in
902f28f1389SDave Fullard			0)
903f28f1389SDave Fullard				# Boot environment are supported
904f28f1389SDave Fullard				CREATEBE=yes
905f28f1389SDave Fullard				;;
906f28f1389SDave Fullard			255)
907f28f1389SDave Fullard				# Boot environments are not supported
908f28f1389SDave Fullard				CREATEBE=no
909f28f1389SDave Fullard				;;
910f28f1389SDave Fullard			*)
911f28f1389SDave Fullard				# If bectl returns an unexpected exit code, don't create a BE
912f28f1389SDave Fullard				CREATEBE=no
913f28f1389SDave Fullard				;;
914f28f1389SDave Fullard		esac
915f28f1389SDave Fullard		if [ ${CREATEBE} = yes ]; then
916f28f1389SDave Fullard			echo -n "Creating snapshot of existing boot environment... "
917e01e8f91SKyle Evans			VERSION=`freebsd-version -ku | sort -V | tail -n 1`
918f28f1389SDave Fullard			TIMESTAMP=`date +"%Y-%m-%d_%H%M%S"`
919989c5f6dSKyle Evans			bectl create -r ${VERSION}_${TIMESTAMP}
920f28f1389SDave Fullard			if [ $? -eq 0 ]; then
921f28f1389SDave Fullard				echo "done.";
922f28f1389SDave Fullard			else
923f28f1389SDave Fullard				echo "failed."
924f28f1389SDave Fullard				exit 1
925f28f1389SDave Fullard			fi
926f28f1389SDave Fullard		fi
927f28f1389SDave Fullard	fi
928f28f1389SDave Fullard}
929f28f1389SDave Fullard
93048ffe56aSColin Percival# Perform sanity checks and set some final parameters in
93148ffe56aSColin Percival# preparation for UNinstalling updates.
93248ffe56aSColin Percivalrollback_check_params () {
93348ffe56aSColin Percival	# Check that we are root.  All sorts of things won't work otherwise.
93448ffe56aSColin Percival	if [ `id -u` != 0 ]; then
93548ffe56aSColin Percival		echo "You must be root to run this."
93648ffe56aSColin Percival		exit 1
93748ffe56aSColin Percival	fi
93848ffe56aSColin Percival
93948ffe56aSColin Percival	# Check that we have a working directory
94048ffe56aSColin Percival	_WORKDIR_bad="Directory does not exist or is not writable: "
94148ffe56aSColin Percival	if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then
94248ffe56aSColin Percival		echo -n "`basename $0`: "
94348ffe56aSColin Percival		echo -n "${_WORKDIR_bad}"
94448ffe56aSColin Percival		echo ${WORKDIR}
94548ffe56aSColin Percival		exit 1
94648ffe56aSColin Percival	fi
94748ffe56aSColin Percival	cd ${WORKDIR} || exit 1
94848ffe56aSColin Percival
94948ffe56aSColin Percival	# Construct a unique name from ${BASEDIR}
95048ffe56aSColin Percival	BDHASH=`echo ${BASEDIR} | sha256 -q`
95148ffe56aSColin Percival
95248ffe56aSColin Percival	# Check that we have updates ready to rollback
95348ffe56aSColin Percival	if ! [ -L ${BDHASH}-rollback ]; then
95448ffe56aSColin Percival		echo "No rollback directory found."
95548ffe56aSColin Percival		exit 1
95648ffe56aSColin Percival	fi
95748ffe56aSColin Percival	if ! [ -f ${BDHASH}-rollback/INDEX-OLD ] ||
95848ffe56aSColin Percival	    ! [ -f ${BDHASH}-rollback/INDEX-NEW ]; then
95948ffe56aSColin Percival		echo "Update manifest is corrupt -- this should never happen."
96048ffe56aSColin Percival		exit 1
96148ffe56aSColin Percival	fi
96248ffe56aSColin Percival}
96348ffe56aSColin Percival
96408e23beeSColin Percival# Perform sanity checks and set some final parameters
96508e23beeSColin Percival# in preparation for comparing the system against the
96608e23beeSColin Percival# published index.  Figure out which index we should
96708e23beeSColin Percival# compare against: If the user is running *-p[0-9]+,
96808e23beeSColin Percival# strip off the last part; if the user is running
96908e23beeSColin Percival# -SECURITY, call it -RELEASE.  Chdir into the working
97008e23beeSColin Percival# directory.
97108e23beeSColin PercivalIDS_check_params () {
97208e23beeSColin Percival	export HTTP_USER_AGENT="freebsd-update (${COMMAND}, `uname -r`)"
97308e23beeSColin Percival
97408e23beeSColin Percival	_SERVERNAME_z=\
97508e23beeSColin Percival"SERVERNAME must be given via command line or configuration file."
97608e23beeSColin Percival	_KEYPRINT_z="Key must be given via -k option or configuration file."
97708e23beeSColin Percival	_KEYPRINT_bad="Invalid key fingerprint: "
97808e23beeSColin Percival	_WORKDIR_bad="Directory does not exist or is not writable: "
97908e23beeSColin Percival
98008e23beeSColin Percival	if [ -z "${SERVERNAME}" ]; then
98108e23beeSColin Percival		echo -n "`basename $0`: "
98208e23beeSColin Percival		echo "${_SERVERNAME_z}"
98308e23beeSColin Percival		exit 1
98408e23beeSColin Percival	fi
98508e23beeSColin Percival	if [ -z "${KEYPRINT}" ]; then
98608e23beeSColin Percival		echo -n "`basename $0`: "
98708e23beeSColin Percival		echo "${_KEYPRINT_z}"
98808e23beeSColin Percival		exit 1
98908e23beeSColin Percival	fi
99008e23beeSColin Percival	if ! echo "${KEYPRINT}" | grep -qE "^[0-9a-f]{64}$"; then
99108e23beeSColin Percival		echo -n "`basename $0`: "
99208e23beeSColin Percival		echo -n "${_KEYPRINT_bad}"
99308e23beeSColin Percival		echo ${KEYPRINT}
99408e23beeSColin Percival		exit 1
99508e23beeSColin Percival	fi
99608e23beeSColin Percival	if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then
99708e23beeSColin Percival		echo -n "`basename $0`: "
99808e23beeSColin Percival		echo -n "${_WORKDIR_bad}"
99908e23beeSColin Percival		echo ${WORKDIR}
100008e23beeSColin Percival		exit 1
100108e23beeSColin Percival	fi
100208e23beeSColin Percival	cd ${WORKDIR} || exit 1
100308e23beeSColin Percival
100408e23beeSColin Percival	# Generate release number.  The s/SECURITY/RELEASE/ bit exists
100508e23beeSColin Percival	# to provide an upgrade path for FreeBSD Update 1.x users, since
100608e23beeSColin Percival	# the kernels provided by FreeBSD Update 1.x are always labelled
100708e23beeSColin Percival	# as X.Y-SECURITY.
100808e23beeSColin Percival	RELNUM=`uname -r |
100908e23beeSColin Percival	    sed -E 's,-p[0-9]+,,' |
101008e23beeSColin Percival	    sed -E 's,-SECURITY,-RELEASE,'`
101108e23beeSColin Percival	ARCH=`uname -m`
101208e23beeSColin Percival	FETCHDIR=${RELNUM}/${ARCH}
101308e23beeSColin Percival	PATCHDIR=${RELNUM}/${ARCH}/bp
101408e23beeSColin Percival
101508e23beeSColin Percival	# Figure out what directory contains the running kernel
101608e23beeSColin Percival	BOOTFILE=`sysctl -n kern.bootfile`
101708e23beeSColin Percival	KERNELDIR=${BOOTFILE%/kernel}
101808e23beeSColin Percival	if ! [ -d ${KERNELDIR} ]; then
101908e23beeSColin Percival		echo "Cannot identify running kernel"
102008e23beeSColin Percival		exit 1
102108e23beeSColin Percival	fi
102208e23beeSColin Percival
102308e23beeSColin Percival	# Figure out what kernel configuration is running.  We start with
102408e23beeSColin Percival	# the output of `uname -i`, and then make the following adjustments:
102508e23beeSColin Percival	# 1. Replace "SMP-GENERIC" with "SMP".  Why the SMP kernel config
102608e23beeSColin Percival	# file says "ident SMP-GENERIC", I don't know...
102708e23beeSColin Percival	# 2. If the kernel claims to be GENERIC _and_ ${ARCH} is "amd64"
102808e23beeSColin Percival	# _and_ `sysctl kern.version` contains a line which ends "/SMP", then
102908e23beeSColin Percival	# we're running an SMP kernel.  This mis-identification is a bug
103008e23beeSColin Percival	# which was fixed in 6.2-STABLE.
103108e23beeSColin Percival	KERNCONF=`uname -i`
103208e23beeSColin Percival	if [ ${KERNCONF} = "SMP-GENERIC" ]; then
103308e23beeSColin Percival		KERNCONF=SMP
103408e23beeSColin Percival	fi
103508e23beeSColin Percival	if [ ${KERNCONF} = "GENERIC" ] && [ ${ARCH} = "amd64" ]; then
103608e23beeSColin Percival		if sysctl kern.version | grep -qE '/SMP$'; then
103708e23beeSColin Percival			KERNCONF=SMP
103808e23beeSColin Percival		fi
103908e23beeSColin Percival	fi
104008e23beeSColin Percival
104108e23beeSColin Percival	# Define some paths
104208e23beeSColin Percival	SHA256=/sbin/sha256
104308e23beeSColin Percival	PHTTPGET=/usr/libexec/phttpget
104408e23beeSColin Percival
104508e23beeSColin Percival	# Set up variables relating to VERBOSELEVEL
104608e23beeSColin Percival	fetch_setup_verboselevel
104708e23beeSColin Percival}
104808e23beeSColin Percival
104948ffe56aSColin Percival#### Core functionality -- the actual work gets done here
105048ffe56aSColin Percival
105148ffe56aSColin Percival# Use an SRV query to pick a server.  If the SRV query doesn't provide
105248ffe56aSColin Percival# a useful answer, use the server name specified by the user.
105348ffe56aSColin Percival# Put another way... look up _http._tcp.${SERVERNAME} and pick a server
105448ffe56aSColin Percival# from that; or if no servers are returned, use ${SERVERNAME}.
105548ffe56aSColin Percival# This allows a user to specify "portsnap.freebsd.org" (in which case
105648ffe56aSColin Percival# portsnap will select one of the mirrors) or "portsnap5.tld.freebsd.org"
105748ffe56aSColin Percival# (in which case portsnap will use that particular server, since there
105848ffe56aSColin Percival# won't be an SRV entry for that name).
105948ffe56aSColin Percival#
106048ffe56aSColin Percival# We ignore the Port field, since we are always going to use port 80.
106148ffe56aSColin Percival
106248ffe56aSColin Percival# Fetch the mirror list, but do not pick a mirror yet.  Returns 1 if
106348ffe56aSColin Percival# no mirrors are available for any reason.
106448ffe56aSColin Percivalfetch_pick_server_init () {
106548ffe56aSColin Percival	: > serverlist_tried
106648ffe56aSColin Percival
106748ffe56aSColin Percival# Check that host(1) exists (i.e., that the system wasn't built with the
106848ffe56aSColin Percival# WITHOUT_BIND set) and don't try to find a mirror if it doesn't exist.
106948ffe56aSColin Percival	if ! which -s host; then
107048ffe56aSColin Percival		: > serverlist_full
107148ffe56aSColin Percival		return 1
107248ffe56aSColin Percival	fi
107348ffe56aSColin Percival
107448ffe56aSColin Percival	echo -n "Looking up ${SERVERNAME} mirrors... "
107548ffe56aSColin Percival
107648ffe56aSColin Percival# Issue the SRV query and pull out the Priority, Weight, and Target fields.
107748ffe56aSColin Percival# BIND 9 prints "$name has SRV record ..." while BIND 8 prints
107848ffe56aSColin Percival# "$name server selection ..."; we allow either format.
107948ffe56aSColin Percival	MLIST="_http._tcp.${SERVERNAME}"
108048ffe56aSColin Percival	host -t srv "${MLIST}" |
1081e7fd266eSColin Percival	    sed -nE "s/${MLIST} (has SRV record|server selection) //Ip" |
108248ffe56aSColin Percival	    cut -f 1,2,4 -d ' ' |
108348ffe56aSColin Percival	    sed -e 's/\.$//' |
108448ffe56aSColin Percival	    sort > serverlist_full
108548ffe56aSColin Percival
108648ffe56aSColin Percival# If no records, give up -- we'll just use the server name we were given.
108748ffe56aSColin Percival	if [ `wc -l < serverlist_full` -eq 0 ]; then
108848ffe56aSColin Percival		echo "none found."
108948ffe56aSColin Percival		return 1
109048ffe56aSColin Percival	fi
109148ffe56aSColin Percival
109248ffe56aSColin Percival# Report how many mirrors we found.
109348ffe56aSColin Percival	echo `wc -l < serverlist_full` "mirrors found."
109448ffe56aSColin Percival
109548ffe56aSColin Percival# Generate a random seed for use in picking mirrors.  If HTTP_PROXY
109648ffe56aSColin Percival# is set, this will be used to generate the seed; otherwise, the seed
109748ffe56aSColin Percival# will be random.
109848ffe56aSColin Percival	if [ -n "${HTTP_PROXY}${http_proxy}" ]; then
109948ffe56aSColin Percival		RANDVALUE=`sha256 -qs "${HTTP_PROXY}${http_proxy}" |
110048ffe56aSColin Percival		    tr -d 'a-f' |
110148ffe56aSColin Percival		    cut -c 1-9`
110248ffe56aSColin Percival	else
110348ffe56aSColin Percival		RANDVALUE=`jot -r 1 0 999999999`
110448ffe56aSColin Percival	fi
110548ffe56aSColin Percival}
110648ffe56aSColin Percival
110748ffe56aSColin Percival# Pick a mirror.  Returns 1 if we have run out of mirrors to try.
110848ffe56aSColin Percivalfetch_pick_server () {
110948ffe56aSColin Percival# Generate a list of not-yet-tried mirrors
111048ffe56aSColin Percival	sort serverlist_tried |
111148ffe56aSColin Percival	    comm -23 serverlist_full - > serverlist
111248ffe56aSColin Percival
111348ffe56aSColin Percival# Have we run out of mirrors?
111448ffe56aSColin Percival	if [ `wc -l < serverlist` -eq 0 ]; then
11159e8c28fcSEd Maste		cat <<- EOF
11169e8c28fcSEd Maste			No mirrors remaining, giving up.
11179e8c28fcSEd Maste
11189e8c28fcSEd Maste			This may be because upgrading from this platform (${ARCH})
11199e8c28fcSEd Maste			or release (${RELNUM}) is unsupported by `basename $0`. Only
11209e8c28fcSEd Maste			platforms with Tier 1 support can be upgraded by `basename $0`.
112186d0d3aaSLi-Wen Hsu			See https://www.freebsd.org/platforms/ for more info.
11229e8c28fcSEd Maste
11239e8c28fcSEd Maste			If unsupported, FreeBSD must be upgraded by source.
11249e8c28fcSEd Maste		EOF
112548ffe56aSColin Percival		return 1
112648ffe56aSColin Percival	fi
112748ffe56aSColin Percival
112848ffe56aSColin Percival# Find the highest priority level (lowest numeric value).
112948ffe56aSColin Percival	SRV_PRIORITY=`cut -f 1 -d ' ' serverlist | sort -n | head -1`
113048ffe56aSColin Percival
113148ffe56aSColin Percival# Add up the weights of the response lines at that priority level.
113248ffe56aSColin Percival	SRV_WSUM=0;
113348ffe56aSColin Percival	while read X; do
113448ffe56aSColin Percival		case "$X" in
113548ffe56aSColin Percival		${SRV_PRIORITY}\ *)
113648ffe56aSColin Percival			SRV_W=`echo $X | cut -f 2 -d ' '`
113748ffe56aSColin Percival			SRV_WSUM=$(($SRV_WSUM + $SRV_W))
113848ffe56aSColin Percival			;;
113948ffe56aSColin Percival		esac
114048ffe56aSColin Percival	done < serverlist
114148ffe56aSColin Percival
114248ffe56aSColin Percival# If all the weights are 0, pretend that they are all 1 instead.
114348ffe56aSColin Percival	if [ ${SRV_WSUM} -eq 0 ]; then
114448ffe56aSColin Percival		SRV_WSUM=`grep -E "^${SRV_PRIORITY} " serverlist | wc -l`
114548ffe56aSColin Percival		SRV_W_ADD=1
114648ffe56aSColin Percival	else
114748ffe56aSColin Percival		SRV_W_ADD=0
114848ffe56aSColin Percival	fi
114948ffe56aSColin Percival
115048ffe56aSColin Percival# Pick a value between 0 and the sum of the weights - 1
115148ffe56aSColin Percival	SRV_RND=`expr ${RANDVALUE} % ${SRV_WSUM}`
115248ffe56aSColin Percival
115348ffe56aSColin Percival# Read through the list of mirrors and set SERVERNAME.  Write the line
115448ffe56aSColin Percival# corresponding to the mirror we selected into serverlist_tried so that
115548ffe56aSColin Percival# we won't try it again.
115648ffe56aSColin Percival	while read X; do
115748ffe56aSColin Percival		case "$X" in
115848ffe56aSColin Percival		${SRV_PRIORITY}\ *)
115948ffe56aSColin Percival			SRV_W=`echo $X | cut -f 2 -d ' '`
116048ffe56aSColin Percival			SRV_W=$(($SRV_W + $SRV_W_ADD))
116148ffe56aSColin Percival			if [ $SRV_RND -lt $SRV_W ]; then
116248ffe56aSColin Percival				SERVERNAME=`echo $X | cut -f 3 -d ' '`
116348ffe56aSColin Percival				echo "$X" >> serverlist_tried
116448ffe56aSColin Percival				break
116548ffe56aSColin Percival			else
116648ffe56aSColin Percival				SRV_RND=$(($SRV_RND - $SRV_W))
116748ffe56aSColin Percival			fi
116848ffe56aSColin Percival			;;
116948ffe56aSColin Percival		esac
117048ffe56aSColin Percival	done < serverlist
117148ffe56aSColin Percival}
117248ffe56aSColin Percival
117348ffe56aSColin Percival# Take a list of ${oldhash}|${newhash} and output a list of needed patches,
117448ffe56aSColin Percival# i.e., those for which we have ${oldhash} and don't have ${newhash}.
117548ffe56aSColin Percivalfetch_make_patchlist () {
117648ffe56aSColin Percival	grep -vE "^([0-9a-f]{64})\|\1$" |
117748ffe56aSColin Percival	    tr '|' ' ' |
117848ffe56aSColin Percival		while read X Y; do
117948ffe56aSColin Percival			if [ -f "files/${Y}.gz" ] ||
118048ffe56aSColin Percival			    [ ! -f "files/${X}.gz" ]; then
118148ffe56aSColin Percival				continue
118248ffe56aSColin Percival			fi
118348ffe56aSColin Percival			echo "${X}|${Y}"
1184f6e21461SEd Maste		done | sort -u
118548ffe56aSColin Percival}
118648ffe56aSColin Percival
118748ffe56aSColin Percival# Print user-friendly progress statistics
118848ffe56aSColin Percivalfetch_progress () {
118948ffe56aSColin Percival	LNC=0
119048ffe56aSColin Percival	while read x; do
119148ffe56aSColin Percival		LNC=$(($LNC + 1))
119248ffe56aSColin Percival		if [ $(($LNC % 10)) = 0 ]; then
119348ffe56aSColin Percival			echo -n $LNC
119448ffe56aSColin Percival		elif [ $(($LNC % 2)) = 0 ]; then
119548ffe56aSColin Percival			echo -n .
119648ffe56aSColin Percival		fi
119748ffe56aSColin Percival	done
119848ffe56aSColin Percival	echo -n " "
119948ffe56aSColin Percival}
120048ffe56aSColin Percival
1201db6b0a61SColin Percival# Function for asking the user if everything is ok
1202db6b0a61SColin Percivalcontinuep () {
1203db6b0a61SColin Percival	while read -p "Does this look reasonable (y/n)? " CONTINUE; do
1204db6b0a61SColin Percival		case "${CONTINUE}" in
120539f4633bSJuraj Lutter		[yY]*)
1206db6b0a61SColin Percival			return 0
1207db6b0a61SColin Percival			;;
120839f4633bSJuraj Lutter		[nN]*)
1209db6b0a61SColin Percival			return 1
1210db6b0a61SColin Percival			;;
1211db6b0a61SColin Percival		esac
1212db6b0a61SColin Percival	done
1213db6b0a61SColin Percival}
1214db6b0a61SColin Percival
121548ffe56aSColin Percival# Initialize the working directory
121648ffe56aSColin Percivalworkdir_init () {
121748ffe56aSColin Percival	mkdir -p files
121848ffe56aSColin Percival	touch tINDEX.present
121948ffe56aSColin Percival}
122048ffe56aSColin Percival
122148ffe56aSColin Percival# Check that we have a public key with an appropriate hash, or
122248ffe56aSColin Percival# fetch the key if it doesn't exist.  Returns 1 if the key has
122348ffe56aSColin Percival# not yet been fetched.
122448ffe56aSColin Percivalfetch_key () {
122548ffe56aSColin Percival	if [ -r pub.ssl ] && [ `${SHA256} -q pub.ssl` = ${KEYPRINT} ]; then
122648ffe56aSColin Percival		return 0
122748ffe56aSColin Percival	fi
122848ffe56aSColin Percival
122948ffe56aSColin Percival	echo -n "Fetching public key from ${SERVERNAME}... "
123048ffe56aSColin Percival	rm -f pub.ssl
123148ffe56aSColin Percival	fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/pub.ssl \
123248ffe56aSColin Percival	    2>${QUIETREDIR} || true
123348ffe56aSColin Percival	if ! [ -r pub.ssl ]; then
123448ffe56aSColin Percival		echo "failed."
123548ffe56aSColin Percival		return 1
123648ffe56aSColin Percival	fi
123748ffe56aSColin Percival	if ! [ `${SHA256} -q pub.ssl` = ${KEYPRINT} ]; then
123848ffe56aSColin Percival		echo "key has incorrect hash."
123948ffe56aSColin Percival		rm -f pub.ssl
124048ffe56aSColin Percival		return 1
124148ffe56aSColin Percival	fi
124248ffe56aSColin Percival	echo "done."
124348ffe56aSColin Percival}
124448ffe56aSColin Percival
124548ffe56aSColin Percival# Fetch metadata signature, aka "tag".
124648ffe56aSColin Percivalfetch_tag () {
1247db6b0a61SColin Percival	echo -n "Fetching metadata signature "
1248db6b0a61SColin Percival	echo ${NDEBUG} "for ${RELNUM} from ${SERVERNAME}... "
124948ffe56aSColin Percival	rm -f latest.ssl
125048ffe56aSColin Percival	fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/latest.ssl	\
125148ffe56aSColin Percival	    2>${QUIETREDIR} || true
125248ffe56aSColin Percival	if ! [ -r latest.ssl ]; then
125348ffe56aSColin Percival		echo "failed."
125448ffe56aSColin Percival		return 1
125548ffe56aSColin Percival	fi
125648ffe56aSColin Percival
125748ffe56aSColin Percival	openssl rsautl -pubin -inkey pub.ssl -verify		\
125848ffe56aSColin Percival	    < latest.ssl > tag.new 2>${QUIETREDIR} || true
125948ffe56aSColin Percival	rm latest.ssl
126048ffe56aSColin Percival
126148ffe56aSColin Percival	if ! [ `wc -l < tag.new` = 1 ] ||
126248ffe56aSColin Percival	    ! grep -qE	\
126348ffe56aSColin Percival    "^freebsd-update\|${ARCH}\|${RELNUM}\|[0-9]+\|[0-9a-f]{64}\|[0-9]{10}" \
126448ffe56aSColin Percival		tag.new; then
126548ffe56aSColin Percival		echo "invalid signature."
126648ffe56aSColin Percival		return 1
126748ffe56aSColin Percival	fi
126848ffe56aSColin Percival
126948ffe56aSColin Percival	echo "done."
127048ffe56aSColin Percival
127148ffe56aSColin Percival	RELPATCHNUM=`cut -f 4 -d '|' < tag.new`
127248ffe56aSColin Percival	TINDEXHASH=`cut -f 5 -d '|' < tag.new`
127348ffe56aSColin Percival	EOLTIME=`cut -f 6 -d '|' < tag.new`
127448ffe56aSColin Percival}
127548ffe56aSColin Percival
127648ffe56aSColin Percival# Sanity-check the patch number in a tag, to make sure that we're not
127748ffe56aSColin Percival# going to "update" backwards and to prevent replay attacks.
127848ffe56aSColin Percivalfetch_tagsanity () {
127948ffe56aSColin Percival	# Check that we're not going to move from -pX to -pY with Y < X.
128048ffe56aSColin Percival	RELPX=`uname -r | sed -E 's,.*-,,'`
128148ffe56aSColin Percival	if echo ${RELPX} | grep -qE '^p[0-9]+$'; then
128248ffe56aSColin Percival		RELPX=`echo ${RELPX} | cut -c 2-`
128348ffe56aSColin Percival	else
128448ffe56aSColin Percival		RELPX=0
128548ffe56aSColin Percival	fi
128648ffe56aSColin Percival	if [ "${RELPATCHNUM}" -lt "${RELPX}" ]; then
128748ffe56aSColin Percival		echo
128848ffe56aSColin Percival		echo -n "Files on mirror (${RELNUM}-p${RELPATCHNUM})"
128948ffe56aSColin Percival		echo " appear older than what"
129048ffe56aSColin Percival		echo "we are currently running (`uname -r`)!"
129148ffe56aSColin Percival		echo "Cowardly refusing to proceed any further."
129248ffe56aSColin Percival		return 1
129348ffe56aSColin Percival	fi
129448ffe56aSColin Percival
129548ffe56aSColin Percival	# If "tag" exists and corresponds to ${RELNUM}, make sure that
129648ffe56aSColin Percival	# it contains a patch number <= RELPATCHNUM, in order to protect
129748ffe56aSColin Percival	# against rollback (replay) attacks.
129848ffe56aSColin Percival	if [ -f tag ] &&
129948ffe56aSColin Percival	    grep -qE	\
130048ffe56aSColin Percival    "^freebsd-update\|${ARCH}\|${RELNUM}\|[0-9]+\|[0-9a-f]{64}\|[0-9]{10}" \
130148ffe56aSColin Percival		tag; then
130248ffe56aSColin Percival		LASTRELPATCHNUM=`cut -f 4 -d '|' < tag`
130348ffe56aSColin Percival
130448ffe56aSColin Percival		if [ "${RELPATCHNUM}" -lt "${LASTRELPATCHNUM}" ]; then
130548ffe56aSColin Percival			echo
130648ffe56aSColin Percival			echo -n "Files on mirror (${RELNUM}-p${RELPATCHNUM})"
130748ffe56aSColin Percival			echo " are older than the"
130848ffe56aSColin Percival			echo -n "most recently seen updates"
130948ffe56aSColin Percival			echo " (${RELNUM}-p${LASTRELPATCHNUM})."
131048ffe56aSColin Percival			echo "Cowardly refusing to proceed any further."
131148ffe56aSColin Percival			return 1
131248ffe56aSColin Percival		fi
131348ffe56aSColin Percival	fi
131448ffe56aSColin Percival}
131548ffe56aSColin Percival
131648ffe56aSColin Percival# Fetch metadata index file
131748ffe56aSColin Percivalfetch_metadata_index () {
131848ffe56aSColin Percival	echo ${NDEBUG} "Fetching metadata index... "
131948ffe56aSColin Percival	rm -f ${TINDEXHASH}
132048ffe56aSColin Percival	fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/t/${TINDEXHASH}
132148ffe56aSColin Percival	    2>${QUIETREDIR}
132248ffe56aSColin Percival	if ! [ -f ${TINDEXHASH} ]; then
132348ffe56aSColin Percival		echo "failed."
132448ffe56aSColin Percival		return 1
132548ffe56aSColin Percival	fi
132648ffe56aSColin Percival	if [ `${SHA256} -q ${TINDEXHASH}` != ${TINDEXHASH} ]; then
132748ffe56aSColin Percival		echo "update metadata index corrupt."
132848ffe56aSColin Percival		return 1
132948ffe56aSColin Percival	fi
133048ffe56aSColin Percival	echo "done."
133148ffe56aSColin Percival}
133248ffe56aSColin Percival
133348ffe56aSColin Percival# Print an error message about signed metadata being bogus.
133448ffe56aSColin Percivalfetch_metadata_bogus () {
133548ffe56aSColin Percival	echo
133648ffe56aSColin Percival	echo "The update metadata$1 is correctly signed, but"
133748ffe56aSColin Percival	echo "failed an integrity check."
133848ffe56aSColin Percival	echo "Cowardly refusing to proceed any further."
133948ffe56aSColin Percival	return 1
134048ffe56aSColin Percival}
134148ffe56aSColin Percival
134248ffe56aSColin Percival# Construct tINDEX.new by merging the lines named in $1 from ${TINDEXHASH}
134348ffe56aSColin Percival# with the lines not named in $@ from tINDEX.present (if that file exists).
134448ffe56aSColin Percivalfetch_metadata_index_merge () {
134548ffe56aSColin Percival	for METAFILE in $@; do
134648ffe56aSColin Percival		if [ `grep -E "^${METAFILE}\|" ${TINDEXHASH} | wc -l`	\
134748ffe56aSColin Percival		    -ne 1 ]; then
134848ffe56aSColin Percival			fetch_metadata_bogus " index"
134948ffe56aSColin Percival			return 1
135048ffe56aSColin Percival		fi
135148ffe56aSColin Percival
135248ffe56aSColin Percival		grep -E "${METAFILE}\|" ${TINDEXHASH}
135348ffe56aSColin Percival	done |
135448ffe56aSColin Percival	    sort > tINDEX.wanted
135548ffe56aSColin Percival
135648ffe56aSColin Percival	if [ -f tINDEX.present ]; then
135748ffe56aSColin Percival		join -t '|' -v 2 tINDEX.wanted tINDEX.present |
135848ffe56aSColin Percival		    sort -m - tINDEX.wanted > tINDEX.new
135948ffe56aSColin Percival		rm tINDEX.wanted
136048ffe56aSColin Percival	else
136148ffe56aSColin Percival		mv tINDEX.wanted tINDEX.new
136248ffe56aSColin Percival	fi
136348ffe56aSColin Percival}
136448ffe56aSColin Percival
136548ffe56aSColin Percival# Sanity check all the lines of tINDEX.new.  Even if more metadata lines
136648ffe56aSColin Percival# are added by future versions of the server, this won't cause problems,
136748ffe56aSColin Percival# since the only lines which appear in tINDEX.new are the ones which we
136848ffe56aSColin Percival# specifically grepped out of ${TINDEXHASH}.
136948ffe56aSColin Percivalfetch_metadata_index_sanity () {
137048ffe56aSColin Percival	if grep -qvE '^[0-9A-Z.-]+\|[0-9a-f]{64}$' tINDEX.new; then
137148ffe56aSColin Percival		fetch_metadata_bogus " index"
137248ffe56aSColin Percival		return 1
137348ffe56aSColin Percival	fi
137448ffe56aSColin Percival}
137548ffe56aSColin Percival
137648ffe56aSColin Percival# Sanity check the metadata file $1.
137748ffe56aSColin Percivalfetch_metadata_sanity () {
137848ffe56aSColin Percival	# Some aliases to save space later: ${P} is a character which can
137948ffe56aSColin Percival	# appear in a path; ${M} is the four numeric metadata fields; and
138048ffe56aSColin Percival	# ${H} is a sha256 hash.
13817c06c7c5SKris Moore	P="[-+./:=,%@_[~[:alnum:]]"
138248ffe56aSColin Percival	M="[0-9]+\|[0-9]+\|[0-9]+\|[0-9]+"
138348ffe56aSColin Percival	H="[0-9a-f]{64}"
138448ffe56aSColin Percival
138548ffe56aSColin Percival	# Check that the first four fields make sense.
138648ffe56aSColin Percival	if gunzip -c < files/$1.gz |
1387823c0d5fSXin LI	    grep -qvE "^[a-z]+\|[0-9a-z-]+\|${P}+\|[fdL-]\|"; then
138848ffe56aSColin Percival		fetch_metadata_bogus ""
138948ffe56aSColin Percival		return 1
139048ffe56aSColin Percival	fi
139148ffe56aSColin Percival
139248ffe56aSColin Percival	# Remove the first three fields.
139348ffe56aSColin Percival	gunzip -c < files/$1.gz |
139448ffe56aSColin Percival	    cut -f 4- -d '|' > sanitycheck.tmp
139548ffe56aSColin Percival
139648ffe56aSColin Percival	# Sanity check entries with type 'f'
139748ffe56aSColin Percival	if grep -E '^f' sanitycheck.tmp |
139848ffe56aSColin Percival	    grep -qvE "^f\|${M}\|${H}\|${P}*\$"; then
139948ffe56aSColin Percival		fetch_metadata_bogus ""
140048ffe56aSColin Percival		return 1
140148ffe56aSColin Percival	fi
140248ffe56aSColin Percival
140348ffe56aSColin Percival	# Sanity check entries with type 'd'
140448ffe56aSColin Percival	if grep -E '^d' sanitycheck.tmp |
140548ffe56aSColin Percival	    grep -qvE "^d\|${M}\|\|\$"; then
140648ffe56aSColin Percival		fetch_metadata_bogus ""
140748ffe56aSColin Percival		return 1
140848ffe56aSColin Percival	fi
140948ffe56aSColin Percival
141048ffe56aSColin Percival	# Sanity check entries with type 'L'
141148ffe56aSColin Percival	if grep -E '^L' sanitycheck.tmp |
141248ffe56aSColin Percival	    grep -qvE "^L\|${M}\|${P}*\|\$"; then
141348ffe56aSColin Percival		fetch_metadata_bogus ""
141448ffe56aSColin Percival		return 1
141548ffe56aSColin Percival	fi
141648ffe56aSColin Percival
141748ffe56aSColin Percival	# Sanity check entries with type '-'
141848ffe56aSColin Percival	if grep -E '^-' sanitycheck.tmp |
141948ffe56aSColin Percival	    grep -qvE "^-\|\|\|\|\|\|"; then
142048ffe56aSColin Percival		fetch_metadata_bogus ""
142148ffe56aSColin Percival		return 1
142248ffe56aSColin Percival	fi
142348ffe56aSColin Percival
142448ffe56aSColin Percival	# Clean up
142548ffe56aSColin Percival	rm sanitycheck.tmp
142648ffe56aSColin Percival}
142748ffe56aSColin Percival
142848ffe56aSColin Percival# Fetch the metadata index and metadata files listed in $@,
142948ffe56aSColin Percival# taking advantage of metadata patches where possible.
143048ffe56aSColin Percivalfetch_metadata () {
143148ffe56aSColin Percival	fetch_metadata_index || return 1
143248ffe56aSColin Percival	fetch_metadata_index_merge $@ || return 1
143348ffe56aSColin Percival	fetch_metadata_index_sanity || return 1
143448ffe56aSColin Percival
143548ffe56aSColin Percival	# Generate a list of wanted metadata patches
143648ffe56aSColin Percival	join -t '|' -o 1.2,2.2 tINDEX.present tINDEX.new |
143748ffe56aSColin Percival	    fetch_make_patchlist > patchlist
143848ffe56aSColin Percival
143948ffe56aSColin Percival	if [ -s patchlist ]; then
144048ffe56aSColin Percival		# Attempt to fetch metadata patches
144148ffe56aSColin Percival		echo -n "Fetching `wc -l < patchlist | tr -d ' '` "
144248ffe56aSColin Percival		echo ${NDEBUG} "metadata patches.${DDSTATS}"
144348ffe56aSColin Percival		tr '|' '-' < patchlist |
144448ffe56aSColin Percival		    lam -s "${FETCHDIR}/tp/" - -s ".gz" |
144548ffe56aSColin Percival		    xargs ${XARGST} ${PHTTPGET} ${SERVERNAME}	\
144648ffe56aSColin Percival			2>${STATSREDIR} | fetch_progress
144748ffe56aSColin Percival		echo "done."
144848ffe56aSColin Percival
144948ffe56aSColin Percival		# Attempt to apply metadata patches
145048ffe56aSColin Percival		echo -n "Applying metadata patches... "
145148ffe56aSColin Percival		tr '|' ' ' < patchlist |
145248ffe56aSColin Percival		    while read X Y; do
145348ffe56aSColin Percival			if [ ! -f "${X}-${Y}.gz" ]; then continue; fi
145448ffe56aSColin Percival			gunzip -c < ${X}-${Y}.gz > diff
145548ffe56aSColin Percival			gunzip -c < files/${X}.gz > diff-OLD
145648ffe56aSColin Percival
145748ffe56aSColin Percival			# Figure out which lines are being added and removed
145848ffe56aSColin Percival			grep -E '^-' diff |
145948ffe56aSColin Percival			    cut -c 2- |
146048ffe56aSColin Percival			    while read PREFIX; do
146148ffe56aSColin Percival				look "${PREFIX}" diff-OLD
146248ffe56aSColin Percival			    done |
146348ffe56aSColin Percival			    sort > diff-rm
146448ffe56aSColin Percival			grep -E '^\+' diff |
146548ffe56aSColin Percival			    cut -c 2- > diff-add
146648ffe56aSColin Percival
146748ffe56aSColin Percival			# Generate the new file
146848ffe56aSColin Percival			comm -23 diff-OLD diff-rm |
146948ffe56aSColin Percival			    sort - diff-add > diff-NEW
147048ffe56aSColin Percival
147148ffe56aSColin Percival			if [ `${SHA256} -q diff-NEW` = ${Y} ]; then
147248ffe56aSColin Percival				mv diff-NEW files/${Y}
147348ffe56aSColin Percival				gzip -n files/${Y}
147448ffe56aSColin Percival			else
147548ffe56aSColin Percival				mv diff-NEW ${Y}.bad
147648ffe56aSColin Percival			fi
147748ffe56aSColin Percival			rm -f ${X}-${Y}.gz diff
147848ffe56aSColin Percival			rm -f diff-OLD diff-NEW diff-add diff-rm
147948ffe56aSColin Percival		done 2>${QUIETREDIR}
148048ffe56aSColin Percival		echo "done."
148148ffe56aSColin Percival	fi
148248ffe56aSColin Percival
148348ffe56aSColin Percival	# Update metadata without patches
148448ffe56aSColin Percival	cut -f 2 -d '|' < tINDEX.new |
148548ffe56aSColin Percival	    while read Y; do
148648ffe56aSColin Percival		if [ ! -f "files/${Y}.gz" ]; then
148748ffe56aSColin Percival			echo ${Y};
148848ffe56aSColin Percival		fi
1489bce02f98SColin Percival	    done |
1490bce02f98SColin Percival	    sort -u > filelist
149148ffe56aSColin Percival
149248ffe56aSColin Percival	if [ -s filelist ]; then
149348ffe56aSColin Percival		echo -n "Fetching `wc -l < filelist | tr -d ' '` "
149448ffe56aSColin Percival		echo ${NDEBUG} "metadata files... "
149548ffe56aSColin Percival		lam -s "${FETCHDIR}/m/" - -s ".gz" < filelist |
149648ffe56aSColin Percival		    xargs ${XARGST} ${PHTTPGET} ${SERVERNAME}	\
149748ffe56aSColin Percival		    2>${QUIETREDIR}
149848ffe56aSColin Percival
149948ffe56aSColin Percival		while read Y; do
150048ffe56aSColin Percival			if ! [ -f ${Y}.gz ]; then
150148ffe56aSColin Percival				echo "failed."
150248ffe56aSColin Percival				return 1
150348ffe56aSColin Percival			fi
150448ffe56aSColin Percival			if [ `gunzip -c < ${Y}.gz |
150548ffe56aSColin Percival			    ${SHA256} -q` = ${Y} ]; then
150648ffe56aSColin Percival				mv ${Y}.gz files/${Y}.gz
150748ffe56aSColin Percival			else
150848ffe56aSColin Percival				echo "metadata is corrupt."
150948ffe56aSColin Percival				return 1
151048ffe56aSColin Percival			fi
151148ffe56aSColin Percival		done < filelist
151248ffe56aSColin Percival		echo "done."
151348ffe56aSColin Percival	fi
151448ffe56aSColin Percival
151548ffe56aSColin Percival# Sanity-check the metadata files.
151648ffe56aSColin Percival	cut -f 2 -d '|' tINDEX.new > filelist
151748ffe56aSColin Percival	while read X; do
151848ffe56aSColin Percival		fetch_metadata_sanity ${X} || return 1
151948ffe56aSColin Percival	done < filelist
152048ffe56aSColin Percival
152148ffe56aSColin Percival# Remove files which are no longer needed
152248ffe56aSColin Percival	cut -f 2 -d '|' tINDEX.present |
152348ffe56aSColin Percival	    sort > oldfiles
152448ffe56aSColin Percival	cut -f 2 -d '|' tINDEX.new |
152548ffe56aSColin Percival	    sort |
152648ffe56aSColin Percival	    comm -13 - oldfiles |
152748ffe56aSColin Percival	    lam -s "files/" - -s ".gz" |
152848ffe56aSColin Percival	    xargs rm -f
152948ffe56aSColin Percival	rm patchlist filelist oldfiles
153048ffe56aSColin Percival	rm ${TINDEXHASH}
153148ffe56aSColin Percival
153248ffe56aSColin Percival# We're done!
153348ffe56aSColin Percival	mv tINDEX.new tINDEX.present
153448ffe56aSColin Percival	mv tag.new tag
153548ffe56aSColin Percival
153648ffe56aSColin Percival	return 0
153748ffe56aSColin Percival}
153848ffe56aSColin Percival
1539db6b0a61SColin Percival# Extract a subset of a downloaded metadata file containing only the parts
1540db6b0a61SColin Percival# which are listed in COMPONENTS.
1541db6b0a61SColin Percivalfetch_filter_metadata_components () {
1542db6b0a61SColin Percival	METAHASH=`look "$1|" tINDEX.present | cut -f 2 -d '|'`
1543db6b0a61SColin Percival	gunzip -c < files/${METAHASH}.gz > $1.all
1544db6b0a61SColin Percival
1545db6b0a61SColin Percival	# Fish out the lines belonging to components we care about.
1546db6b0a61SColin Percival	for C in ${COMPONENTS}; do
1547db6b0a61SColin Percival		look "`echo ${C} | tr '/' '|'`|" $1.all
1548db6b0a61SColin Percival	done > $1
1549db6b0a61SColin Percival
1550db6b0a61SColin Percival	# Remove temporary file.
1551db6b0a61SColin Percival	rm $1.all
1552db6b0a61SColin Percival}
1553db6b0a61SColin Percival
1554b698a3abSColin Percival# Generate a filtered version of the metadata file $1 from the downloaded
155548ffe56aSColin Percival# file, by fishing out the lines corresponding to components we're trying
155648ffe56aSColin Percival# to keep updated, and then removing lines corresponding to paths we want
155748ffe56aSColin Percival# to ignore.
155848ffe56aSColin Percivalfetch_filter_metadata () {
155948ffe56aSColin Percival	# Fish out the lines belonging to components we care about.
1560db6b0a61SColin Percival	fetch_filter_metadata_components $1
1561db6b0a61SColin Percival
156248ffe56aSColin Percival	# Canonicalize directory names by removing any trailing / in
156348ffe56aSColin Percival	# order to avoid listing directories multiple times if they
156448ffe56aSColin Percival	# belong to multiple components.  Turning "/" into "" doesn't
156548ffe56aSColin Percival	# matter, since we add a leading "/" when we use paths later.
1566db6b0a61SColin Percival	cut -f 3- -d '|' $1 |
156748ffe56aSColin Percival	    sed -e 's,/|d|,|d|,' |
15687e654612SColin Percival	    sed -e 's,/|-|,|-|,' |
156948ffe56aSColin Percival	    sort -u > $1.tmp
157048ffe56aSColin Percival
157148ffe56aSColin Percival	# Figure out which lines to ignore and remove them.
157248ffe56aSColin Percival	for X in ${IGNOREPATHS}; do
157348ffe56aSColin Percival		grep -E "^${X}" $1.tmp
157448ffe56aSColin Percival	done |
157548ffe56aSColin Percival	    sort -u |
157648ffe56aSColin Percival	    comm -13 - $1.tmp > $1
157748ffe56aSColin Percival
157848ffe56aSColin Percival	# Remove temporary files.
1579db6b0a61SColin Percival	rm $1.tmp
158048ffe56aSColin Percival}
158148ffe56aSColin Percival
1582db6b0a61SColin Percival# Filter the metadata file $1 by adding lines with "/boot/$2"
1583bce02f98SColin Percival# replaced by ${KERNELDIR} (which is `sysctl -n kern.bootfile` minus the
1584db6b0a61SColin Percival# trailing "/kernel"); and if "/boot/$2" does not exist, remove
1585bce02f98SColin Percival# the original lines which start with that.
1586bce02f98SColin Percival# Put another way: Deal with the fact that the FOO kernel is sometimes
1587bce02f98SColin Percival# installed in /boot/FOO/ and is sometimes installed elsewhere.
158848ffe56aSColin Percivalfetch_filter_kernel_names () {
1589db6b0a61SColin Percival	grep ^/boot/$2 $1 |
1590db6b0a61SColin Percival	    sed -e "s,/boot/$2,${KERNELDIR},g" |
159148ffe56aSColin Percival	    sort - $1 > $1.tmp
159248ffe56aSColin Percival	mv $1.tmp $1
1593bce02f98SColin Percival
1594db6b0a61SColin Percival	if ! [ -d /boot/$2 ]; then
1595db6b0a61SColin Percival		grep -v ^/boot/$2 $1 > $1.tmp
1596bce02f98SColin Percival		mv $1.tmp $1
1597bce02f98SColin Percival	fi
159848ffe56aSColin Percival}
159948ffe56aSColin Percival
160048ffe56aSColin Percival# For all paths appearing in $1 or $3, inspect the system
160148ffe56aSColin Percival# and generate $2 describing what is currently installed.
160248ffe56aSColin Percivalfetch_inspect_system () {
160348ffe56aSColin Percival	# No errors yet...
160448ffe56aSColin Percival	rm -f .err
160548ffe56aSColin Percival
160648ffe56aSColin Percival	# Tell the user why his disk is suddenly making lots of noise
160748ffe56aSColin Percival	echo -n "Inspecting system... "
160848ffe56aSColin Percival
160948ffe56aSColin Percival	# Generate list of files to inspect
161048ffe56aSColin Percival	cat $1 $3 |
161148ffe56aSColin Percival	    cut -f 1 -d '|' |
161248ffe56aSColin Percival	    sort -u > filelist
161348ffe56aSColin Percival
161448ffe56aSColin Percival	# Examine each file and output lines of the form
161548ffe56aSColin Percival	# /path/to/file|type|device-inum|user|group|perm|flags|value
161648ffe56aSColin Percival	# sorted by device and inode number.
161748ffe56aSColin Percival	while read F; do
161848ffe56aSColin Percival		# If the symlink/file/directory does not exist, record this.
161948ffe56aSColin Percival		if ! [ -e ${BASEDIR}/${F} ]; then
162048ffe56aSColin Percival			echo "${F}|-||||||"
162148ffe56aSColin Percival			continue
162248ffe56aSColin Percival		fi
162348ffe56aSColin Percival		if ! [ -r ${BASEDIR}/${F} ]; then
162448ffe56aSColin Percival			echo "Cannot read file: ${BASEDIR}/${F}"	\
162548ffe56aSColin Percival			    >/dev/stderr
162648ffe56aSColin Percival			touch .err
162748ffe56aSColin Percival			return 1
162848ffe56aSColin Percival		fi
162948ffe56aSColin Percival
163048ffe56aSColin Percival		# Otherwise, output an index line.
163148ffe56aSColin Percival		if [ -L ${BASEDIR}/${F} ]; then
163248ffe56aSColin Percival			echo -n "${F}|L|"
163348ffe56aSColin Percival			stat -n -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F};
163448ffe56aSColin Percival			readlink ${BASEDIR}/${F};
163548ffe56aSColin Percival		elif [ -f ${BASEDIR}/${F} ]; then
163648ffe56aSColin Percival			echo -n "${F}|f|"
163748ffe56aSColin Percival			stat -n -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F};
163848ffe56aSColin Percival			sha256 -q ${BASEDIR}/${F};
163948ffe56aSColin Percival		elif [ -d ${BASEDIR}/${F} ]; then
164048ffe56aSColin Percival			echo -n "${F}|d|"
164148ffe56aSColin Percival			stat -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F};
164248ffe56aSColin Percival		else
164348ffe56aSColin Percival			echo "Unknown file type: ${BASEDIR}/${F}"	\
164448ffe56aSColin Percival			    >/dev/stderr
164548ffe56aSColin Percival			touch .err
164648ffe56aSColin Percival			return 1
164748ffe56aSColin Percival		fi
164848ffe56aSColin Percival	done < filelist |
164948ffe56aSColin Percival	    sort -k 3,3 -t '|' > $2.tmp
165048ffe56aSColin Percival	rm filelist
165148ffe56aSColin Percival
16526dcc68c8SBenedict Reuschling	# Check if an error occurred during system inspection
165348ffe56aSColin Percival	if [ -f .err ]; then
165448ffe56aSColin Percival		return 1
165548ffe56aSColin Percival	fi
165648ffe56aSColin Percival
165748ffe56aSColin Percival	# Convert to the form
165848ffe56aSColin Percival	# /path/to/file|type|user|group|perm|flags|value|hlink
165948ffe56aSColin Percival	# by resolving identical device and inode numbers into hard links.
166048ffe56aSColin Percival	cut -f 1,3 -d '|' $2.tmp |
166148ffe56aSColin Percival	    sort -k 1,1 -t '|' |
166248ffe56aSColin Percival	    sort -s -u -k 2,2 -t '|' |
166348ffe56aSColin Percival	    join -1 2 -2 3 -t '|' - $2.tmp |
166448ffe56aSColin Percival	    awk -F \| -v OFS=\|		\
166548ffe56aSColin Percival		'{
166648ffe56aSColin Percival		    if (($2 == $3) || ($4 == "-"))
166748ffe56aSColin Percival			print $3,$4,$5,$6,$7,$8,$9,""
166848ffe56aSColin Percival		    else
166948ffe56aSColin Percival			print $3,$4,$5,$6,$7,$8,$9,$2
167048ffe56aSColin Percival		}' |
167148ffe56aSColin Percival	    sort > $2
167248ffe56aSColin Percival	rm $2.tmp
167348ffe56aSColin Percival
167448ffe56aSColin Percival	# We're finished looking around
167548ffe56aSColin Percival	echo "done."
167648ffe56aSColin Percival}
167748ffe56aSColin Percival
1678c55b7e52SColin Percival# For any paths matching ${MERGECHANGES}, compare $2 against $1 and $3 and
1679c55b7e52SColin Percival# find any files with values unique to $2; generate $4 containing these paths
1680c55b7e52SColin Percival# and their corresponding hashes from $1.
1681db6b0a61SColin Percivalfetch_filter_mergechanges () {
1682db6b0a61SColin Percival	# Pull out the paths and hashes of the files matching ${MERGECHANGES}.
1683c55b7e52SColin Percival	for F in $1 $2 $3; do
1684db6b0a61SColin Percival		for X in ${MERGECHANGES}; do
1685db6b0a61SColin Percival			grep -E "^${X}" ${F}
1686db6b0a61SColin Percival		done |
1687db6b0a61SColin Percival		    cut -f 1,2,7 -d '|' |
1688db6b0a61SColin Percival		    sort > ${F}-values
1689db6b0a61SColin Percival	done
1690db6b0a61SColin Percival
1691c55b7e52SColin Percival	# Any line in $2-values which doesn't appear in $1-values or $3-values
1692c55b7e52SColin Percival	# and is a file means that we should list the path in $3.
1693c55b7e52SColin Percival	sort $1-values $3-values |
1694c55b7e52SColin Percival	    comm -13 - $2-values |
1695db6b0a61SColin Percival	    fgrep '|f|' |
1696db6b0a61SColin Percival	    cut -f 1 -d '|' > $2-paths
1697db6b0a61SColin Percival
1698db6b0a61SColin Percival	# For each path, pull out one (and only one!) entry from $1-values.
1699db6b0a61SColin Percival	# Note that we cannot distinguish which "old" version the user made
1700db6b0a61SColin Percival	# changes to; but hopefully any changes which occur due to security
1701db6b0a61SColin Percival	# updates will exist in both the "new" version and the version which
1702db6b0a61SColin Percival	# the user has installed, so the merging will still work.
1703db6b0a61SColin Percival	while read X; do
1704db6b0a61SColin Percival		look "${X}|" $1-values |
1705db6b0a61SColin Percival		    head -1
1706c55b7e52SColin Percival	done < $2-paths > $4
1707db6b0a61SColin Percival
1708db6b0a61SColin Percival	# Clean up
1709c55b7e52SColin Percival	rm $1-values $2-values $3-values $2-paths
1710db6b0a61SColin Percival}
1711db6b0a61SColin Percival
171248ffe56aSColin Percival# For any paths matching ${UPDATEIFUNMODIFIED}, remove lines from $[123]
1713db6b0a61SColin Percival# which correspond to lines in $2 with hashes not matching $1 or $3, unless
1714db6b0a61SColin Percival# the paths are listed in $4.  For entries in $2 marked "not present"
1715db6b0a61SColin Percival# (aka. type -), remove lines from $[123] unless there is a corresponding
1716db6b0a61SColin Percival# entry in $1.
171748ffe56aSColin Percivalfetch_filter_unmodified_notpresent () {
171848ffe56aSColin Percival	# Figure out which lines of $1 and $3 correspond to bits which
171948ffe56aSColin Percival	# should only be updated if they haven't changed, and fish out
172048ffe56aSColin Percival	# the (path, type, value) tuples.
172148ffe56aSColin Percival	# NOTE: We don't consider a file to be "modified" if it matches
172248ffe56aSColin Percival	# the hash from $3.
172348ffe56aSColin Percival	for X in ${UPDATEIFUNMODIFIED}; do
172448ffe56aSColin Percival		grep -E "^${X}" $1
172548ffe56aSColin Percival		grep -E "^${X}" $3
172648ffe56aSColin Percival	done |
172748ffe56aSColin Percival	    cut -f 1,2,7 -d '|' |
172848ffe56aSColin Percival	    sort > $1-values
172948ffe56aSColin Percival
173048ffe56aSColin Percival	# Do the same for $2.
173148ffe56aSColin Percival	for X in ${UPDATEIFUNMODIFIED}; do
173248ffe56aSColin Percival		grep -E "^${X}" $2
173348ffe56aSColin Percival	done |
173448ffe56aSColin Percival	    cut -f 1,2,7 -d '|' |
173548ffe56aSColin Percival	    sort > $2-values
173648ffe56aSColin Percival
173748ffe56aSColin Percival	# Any entry in $2-values which is not in $1-values corresponds to
1738db6b0a61SColin Percival	# a path which we need to remove from $1, $2, and $3, unless it
1739db6b0a61SColin Percival	# that path appears in $4.
1740db6b0a61SColin Percival	comm -13 $1-values $2-values |
1741db6b0a61SColin Percival	    sort -t '|' -k 1,1 > mlines.tmp
1742db6b0a61SColin Percival	cut -f 1 -d '|' $4 |
1743db6b0a61SColin Percival	    sort |
1744db6b0a61SColin Percival	    join -v 2 -t '|' - mlines.tmp |
1745db6b0a61SColin Percival	    sort > mlines
1746db6b0a61SColin Percival	rm $1-values $2-values mlines.tmp
174748ffe56aSColin Percival
174848ffe56aSColin Percival	# Any lines in $2 which are not in $1 AND are "not present" lines
174948ffe56aSColin Percival	# also belong in mlines.
175048ffe56aSColin Percival	comm -13 $1 $2 |
175148ffe56aSColin Percival	    cut -f 1,2,7 -d '|' |
175248ffe56aSColin Percival	    fgrep '|-|' >> mlines
175348ffe56aSColin Percival
175448ffe56aSColin Percival	# Remove lines from $1, $2, and $3
175548ffe56aSColin Percival	for X in $1 $2 $3; do
175648ffe56aSColin Percival		sort -t '|' -k 1,1 ${X} > ${X}.tmp
175748ffe56aSColin Percival		cut -f 1 -d '|' < mlines |
175848ffe56aSColin Percival		    sort |
175948ffe56aSColin Percival		    join -v 2 -t '|' - ${X}.tmp |
176048ffe56aSColin Percival		    sort > ${X}
176148ffe56aSColin Percival		rm ${X}.tmp
176248ffe56aSColin Percival	done
176348ffe56aSColin Percival
176448ffe56aSColin Percival	# Store a list of the modified files, for future reference
176548ffe56aSColin Percival	fgrep -v '|-|' mlines |
176648ffe56aSColin Percival	    cut -f 1 -d '|' > modifiedfiles
176748ffe56aSColin Percival	rm mlines
176848ffe56aSColin Percival}
176948ffe56aSColin Percival
177048ffe56aSColin Percival# For each entry in $1 of type -, remove any corresponding
177148ffe56aSColin Percival# entry from $2 if ${ALLOWADD} != "yes".  Remove all entries
177248ffe56aSColin Percival# of type - from $1.
177348ffe56aSColin Percivalfetch_filter_allowadd () {
177448ffe56aSColin Percival	cut -f 1,2 -d '|' < $1 |
177548ffe56aSColin Percival	    fgrep '|-' |
177648ffe56aSColin Percival	    cut -f 1 -d '|' > filesnotpresent
177748ffe56aSColin Percival
177848ffe56aSColin Percival	if [ ${ALLOWADD} != "yes" ]; then
177948ffe56aSColin Percival		sort < $2 |
178048ffe56aSColin Percival		    join -v 1 -t '|' - filesnotpresent |
178148ffe56aSColin Percival		    sort > $2.tmp
178248ffe56aSColin Percival		mv $2.tmp $2
178348ffe56aSColin Percival	fi
178448ffe56aSColin Percival
178548ffe56aSColin Percival	sort < $1 |
178648ffe56aSColin Percival	    join -v 1 -t '|' - filesnotpresent |
178748ffe56aSColin Percival	    sort > $1.tmp
178848ffe56aSColin Percival	mv $1.tmp $1
178948ffe56aSColin Percival	rm filesnotpresent
179048ffe56aSColin Percival}
179148ffe56aSColin Percival
179248ffe56aSColin Percival# If ${ALLOWDELETE} != "yes", then remove any entries from $1
179348ffe56aSColin Percival# which don't correspond to entries in $2.
179448ffe56aSColin Percivalfetch_filter_allowdelete () {
179548ffe56aSColin Percival	# Produce a lists ${PATH}|${TYPE}
179648ffe56aSColin Percival	for X in $1 $2; do
179748ffe56aSColin Percival		cut -f 1-2 -d '|' < ${X} |
179848ffe56aSColin Percival		    sort -u > ${X}.nodes
179948ffe56aSColin Percival	done
180048ffe56aSColin Percival
180148ffe56aSColin Percival	# Figure out which lines need to be removed from $1.
180248ffe56aSColin Percival	if [ ${ALLOWDELETE} != "yes" ]; then
180348ffe56aSColin Percival		comm -23 $1.nodes $2.nodes > $1.badnodes
180448ffe56aSColin Percival	else
180548ffe56aSColin Percival		: > $1.badnodes
180648ffe56aSColin Percival	fi
180748ffe56aSColin Percival
180848ffe56aSColin Percival	# Remove the relevant lines from $1
180948ffe56aSColin Percival	while read X; do
181048ffe56aSColin Percival		look "${X}|" $1
181148ffe56aSColin Percival	done < $1.badnodes |
181248ffe56aSColin Percival	    comm -13 - $1 > $1.tmp
181348ffe56aSColin Percival	mv $1.tmp $1
181448ffe56aSColin Percival
181548ffe56aSColin Percival	rm $1.badnodes $1.nodes $2.nodes
181648ffe56aSColin Percival}
181748ffe56aSColin Percival
181848ffe56aSColin Percival# If ${KEEPMODIFIEDMETADATA} == "yes", then for each entry in $2
181948ffe56aSColin Percival# with metadata not matching any entry in $1, replace the corresponding
182048ffe56aSColin Percival# line of $3 with one having the same metadata as the entry in $2.
182148ffe56aSColin Percivalfetch_filter_modified_metadata () {
182248ffe56aSColin Percival	# Fish out the metadata from $1 and $2
182348ffe56aSColin Percival	for X in $1 $2; do
182448ffe56aSColin Percival		cut -f 1-6 -d '|' < ${X} > ${X}.metadata
182548ffe56aSColin Percival	done
182648ffe56aSColin Percival
182748ffe56aSColin Percival	# Find the metadata we need to keep
182848ffe56aSColin Percival	if [ ${KEEPMODIFIEDMETADATA} = "yes" ]; then
182948ffe56aSColin Percival		comm -13 $1.metadata $2.metadata > keepmeta
183048ffe56aSColin Percival	else
183148ffe56aSColin Percival		: > keepmeta
183248ffe56aSColin Percival	fi
183348ffe56aSColin Percival
183448ffe56aSColin Percival	# Extract the lines which we need to remove from $3, and
183548ffe56aSColin Percival	# construct the lines which we need to add to $3.
183648ffe56aSColin Percival	: > $3.remove
183748ffe56aSColin Percival	: > $3.add
183848ffe56aSColin Percival	while read LINE; do
183948ffe56aSColin Percival		NODE=`echo "${LINE}" | cut -f 1-2 -d '|'`
184048ffe56aSColin Percival		look "${NODE}|" $3 >> $3.remove
184148ffe56aSColin Percival		look "${NODE}|" $3 |
184248ffe56aSColin Percival		    cut -f 7- -d '|' |
184348ffe56aSColin Percival		    lam -s "${LINE}|" - >> $3.add
184448ffe56aSColin Percival	done < keepmeta
184548ffe56aSColin Percival
184648ffe56aSColin Percival	# Remove the specified lines and add the new lines.
184748ffe56aSColin Percival	sort $3.remove |
184848ffe56aSColin Percival	    comm -13 - $3 |
184948ffe56aSColin Percival	    sort -u - $3.add > $3.tmp
185048ffe56aSColin Percival	mv $3.tmp $3
185148ffe56aSColin Percival
185248ffe56aSColin Percival	rm keepmeta $1.metadata $2.metadata $3.add $3.remove
185348ffe56aSColin Percival}
185448ffe56aSColin Percival
185548ffe56aSColin Percival# Remove lines from $1 and $2 which are identical;
185648ffe56aSColin Percival# no need to update a file if it isn't changing.
185748ffe56aSColin Percivalfetch_filter_uptodate () {
185848ffe56aSColin Percival	comm -23 $1 $2 > $1.tmp
185948ffe56aSColin Percival	comm -13 $1 $2 > $2.tmp
186048ffe56aSColin Percival
186148ffe56aSColin Percival	mv $1.tmp $1
186248ffe56aSColin Percival	mv $2.tmp $2
186348ffe56aSColin Percival}
186448ffe56aSColin Percival
1865db6b0a61SColin Percival# Fetch any "clean" old versions of files we need for merging changes.
1866db6b0a61SColin Percivalfetch_files_premerge () {
1867db6b0a61SColin Percival	# We only need to do anything if $1 is non-empty.
1868db6b0a61SColin Percival	if [ -s $1 ]; then
1869db6b0a61SColin Percival		# Tell the user what we're doing
1870db6b0a61SColin Percival		echo -n "Fetching files from ${OLDRELNUM} for merging... "
1871db6b0a61SColin Percival
1872db6b0a61SColin Percival		# List of files wanted
1873db6b0a61SColin Percival		fgrep '|f|' < $1 |
1874db6b0a61SColin Percival		    cut -f 3 -d '|' |
1875db6b0a61SColin Percival		    sort -u > files.wanted
1876db6b0a61SColin Percival
1877db6b0a61SColin Percival		# Only fetch the files we don't already have
1878db6b0a61SColin Percival		while read Y; do
1879db6b0a61SColin Percival			if [ ! -f "files/${Y}.gz" ]; then
1880db6b0a61SColin Percival				echo ${Y};
1881db6b0a61SColin Percival			fi
1882db6b0a61SColin Percival		done < files.wanted > filelist
1883db6b0a61SColin Percival
1884db6b0a61SColin Percival		# Actually fetch them
1885db6b0a61SColin Percival		lam -s "${OLDFETCHDIR}/f/" - -s ".gz" < filelist |
1886db6b0a61SColin Percival		    xargs ${XARGST} ${PHTTPGET} ${SERVERNAME}	\
1887db6b0a61SColin Percival		    2>${QUIETREDIR}
1888db6b0a61SColin Percival
1889db6b0a61SColin Percival		# Make sure we got them all, and move them into /files/
1890db6b0a61SColin Percival		while read Y; do
1891db6b0a61SColin Percival			if ! [ -f ${Y}.gz ]; then
1892db6b0a61SColin Percival				echo "failed."
1893db6b0a61SColin Percival				return 1
1894db6b0a61SColin Percival			fi
1895db6b0a61SColin Percival			if [ `gunzip -c < ${Y}.gz |
1896db6b0a61SColin Percival			    ${SHA256} -q` = ${Y} ]; then
1897db6b0a61SColin Percival				mv ${Y}.gz files/${Y}.gz
1898db6b0a61SColin Percival			else
1899db6b0a61SColin Percival				echo "${Y} has incorrect hash."
1900db6b0a61SColin Percival				return 1
1901db6b0a61SColin Percival			fi
1902db6b0a61SColin Percival		done < filelist
1903db6b0a61SColin Percival		echo "done."
1904db6b0a61SColin Percival
1905db6b0a61SColin Percival		# Clean up
1906db6b0a61SColin Percival		rm filelist files.wanted
1907db6b0a61SColin Percival	fi
1908db6b0a61SColin Percival}
1909db6b0a61SColin Percival
191048ffe56aSColin Percival# Prepare to fetch files: Generate a list of the files we need,
191148ffe56aSColin Percival# copy the unmodified files we have into /files/, and generate
191248ffe56aSColin Percival# a list of patches to download.
191348ffe56aSColin Percivalfetch_files_prepare () {
191448ffe56aSColin Percival	# Tell the user why his disk is suddenly making lots of noise
191548ffe56aSColin Percival	echo -n "Preparing to download files... "
191648ffe56aSColin Percival
191748ffe56aSColin Percival	# Reduce indices to ${PATH}|${HASH} pairs
191848ffe56aSColin Percival	for X in $1 $2 $3; do
191948ffe56aSColin Percival		cut -f 1,2,7 -d '|' < ${X} |
192048ffe56aSColin Percival		    fgrep '|f|' |
192148ffe56aSColin Percival		    cut -f 1,3 -d '|' |
192248ffe56aSColin Percival		    sort > ${X}.hashes
192348ffe56aSColin Percival	done
192448ffe56aSColin Percival
192548ffe56aSColin Percival	# List of files wanted
192648ffe56aSColin Percival	cut -f 2 -d '|' < $3.hashes |
19272328d598SColin Percival	    sort -u |
19282328d598SColin Percival	    while read HASH; do
19292328d598SColin Percival		if ! [ -f files/${HASH}.gz ]; then
19302328d598SColin Percival			echo ${HASH}
19312328d598SColin Percival		fi
19322328d598SColin Percival	done > files.wanted
193348ffe56aSColin Percival
193448ffe56aSColin Percival	# Generate a list of unmodified files
193548ffe56aSColin Percival	comm -12 $1.hashes $2.hashes |
193648ffe56aSColin Percival	    sort -k 1,1 -t '|' > unmodified.files
193748ffe56aSColin Percival
193848ffe56aSColin Percival	# Copy all files into /files/.  We only need the unmodified files
193948ffe56aSColin Percival	# for use in patching; but we'll want all of them if the user asks
194048ffe56aSColin Percival	# to rollback the updates later.
1941210b8123SColin Percival	while read LINE; do
1942210b8123SColin Percival		F=`echo "${LINE}" | cut -f 1 -d '|'`
1943210b8123SColin Percival		HASH=`echo "${LINE}" | cut -f 2 -d '|'`
1944210b8123SColin Percival
1945210b8123SColin Percival		# Skip files we already have.
1946210b8123SColin Percival		if [ -f files/${HASH}.gz ]; then
1947210b8123SColin Percival			continue
1948210b8123SColin Percival		fi
1949210b8123SColin Percival
1950210b8123SColin Percival		# Make sure the file hasn't changed.
195148ffe56aSColin Percival		cp "${BASEDIR}/${F}" tmpfile
1952210b8123SColin Percival		if [ `sha256 -q tmpfile` != ${HASH} ]; then
1953210b8123SColin Percival			echo
1954210b8123SColin Percival			echo "File changed while FreeBSD Update running: ${F}"
1955210b8123SColin Percival			return 1
1956210b8123SColin Percival		fi
1957210b8123SColin Percival
1958210b8123SColin Percival		# Place the file into storage.
1959210b8123SColin Percival		gzip -c < tmpfile > files/${HASH}.gz
196048ffe56aSColin Percival		rm tmpfile
1961210b8123SColin Percival	done < $2.hashes
196248ffe56aSColin Percival
196348ffe56aSColin Percival	# Produce a list of patches to download
196448ffe56aSColin Percival	sort -k 1,1 -t '|' $3.hashes |
196548ffe56aSColin Percival	    join -t '|' -o 2.2,1.2 - unmodified.files |
196648ffe56aSColin Percival	    fetch_make_patchlist > patchlist
196748ffe56aSColin Percival
196848ffe56aSColin Percival	# Garbage collect
196948ffe56aSColin Percival	rm unmodified.files $1.hashes $2.hashes $3.hashes
197048ffe56aSColin Percival
197148ffe56aSColin Percival	# We don't need the list of possible old files any more.
197248ffe56aSColin Percival	rm $1
197348ffe56aSColin Percival
197448ffe56aSColin Percival	# We're finished making noise
197548ffe56aSColin Percival	echo "done."
197648ffe56aSColin Percival}
197748ffe56aSColin Percival
197848ffe56aSColin Percival# Fetch files.
197948ffe56aSColin Percivalfetch_files () {
198048ffe56aSColin Percival	# Attempt to fetch patches
198148ffe56aSColin Percival	if [ -s patchlist ]; then
198248ffe56aSColin Percival		echo -n "Fetching `wc -l < patchlist | tr -d ' '` "
198348ffe56aSColin Percival		echo ${NDEBUG} "patches.${DDSTATS}"
198448ffe56aSColin Percival		tr '|' '-' < patchlist |
1985db6b0a61SColin Percival		    lam -s "${PATCHDIR}/" - |
198648ffe56aSColin Percival		    xargs ${XARGST} ${PHTTPGET} ${SERVERNAME}	\
198748ffe56aSColin Percival			2>${STATSREDIR} | fetch_progress
198848ffe56aSColin Percival		echo "done."
198948ffe56aSColin Percival
199048ffe56aSColin Percival		# Attempt to apply patches
199148ffe56aSColin Percival		echo -n "Applying patches... "
199248ffe56aSColin Percival		tr '|' ' ' < patchlist |
199348ffe56aSColin Percival		    while read X Y; do
199448ffe56aSColin Percival			if [ ! -f "${X}-${Y}" ]; then continue; fi
199548ffe56aSColin Percival			gunzip -c < files/${X}.gz > OLD
199648ffe56aSColin Percival
199748ffe56aSColin Percival			bspatch OLD NEW ${X}-${Y}
199848ffe56aSColin Percival
199948ffe56aSColin Percival			if [ `${SHA256} -q NEW` = ${Y} ]; then
200048ffe56aSColin Percival				mv NEW files/${Y}
200148ffe56aSColin Percival				gzip -n files/${Y}
200248ffe56aSColin Percival			fi
200348ffe56aSColin Percival			rm -f diff OLD NEW ${X}-${Y}
200448ffe56aSColin Percival		done 2>${QUIETREDIR}
200548ffe56aSColin Percival		echo "done."
200648ffe56aSColin Percival	fi
200748ffe56aSColin Percival
200848ffe56aSColin Percival	# Download files which couldn't be generate via patching
200948ffe56aSColin Percival	while read Y; do
201048ffe56aSColin Percival		if [ ! -f "files/${Y}.gz" ]; then
201148ffe56aSColin Percival			echo ${Y};
201248ffe56aSColin Percival		fi
201348ffe56aSColin Percival	done < files.wanted > filelist
201448ffe56aSColin Percival
201548ffe56aSColin Percival	if [ -s filelist ]; then
201648ffe56aSColin Percival		echo -n "Fetching `wc -l < filelist | tr -d ' '` "
201748ffe56aSColin Percival		echo ${NDEBUG} "files... "
201848ffe56aSColin Percival		lam -s "${FETCHDIR}/f/" - -s ".gz" < filelist |
201948ffe56aSColin Percival		    xargs ${XARGST} ${PHTTPGET} ${SERVERNAME}	\
2020d6e1e31aSConrad Meyer			2>${STATSREDIR} | fetch_progress
202148ffe56aSColin Percival
202248ffe56aSColin Percival		while read Y; do
202348ffe56aSColin Percival			if ! [ -f ${Y}.gz ]; then
202448ffe56aSColin Percival				echo "failed."
202548ffe56aSColin Percival				return 1
202648ffe56aSColin Percival			fi
202748ffe56aSColin Percival			if [ `gunzip -c < ${Y}.gz |
202848ffe56aSColin Percival			    ${SHA256} -q` = ${Y} ]; then
202948ffe56aSColin Percival				mv ${Y}.gz files/${Y}.gz
203048ffe56aSColin Percival			else
203148ffe56aSColin Percival				echo "${Y} has incorrect hash."
203248ffe56aSColin Percival				return 1
203348ffe56aSColin Percival			fi
203448ffe56aSColin Percival		done < filelist
203548ffe56aSColin Percival		echo "done."
203648ffe56aSColin Percival	fi
203748ffe56aSColin Percival
203848ffe56aSColin Percival	# Clean up
203948ffe56aSColin Percival	rm files.wanted filelist patchlist
204048ffe56aSColin Percival}
204148ffe56aSColin Percival
204248ffe56aSColin Percival# Create and populate install manifest directory; and report what updates
204348ffe56aSColin Percival# are available.
204448ffe56aSColin Percivalfetch_create_manifest () {
204548ffe56aSColin Percival	# If we have an existing install manifest, nuke it.
204648ffe56aSColin Percival	if [ -L "${BDHASH}-install" ]; then
204748ffe56aSColin Percival		rm -r ${BDHASH}-install/
204848ffe56aSColin Percival		rm ${BDHASH}-install
204948ffe56aSColin Percival	fi
205048ffe56aSColin Percival
205148ffe56aSColin Percival	# Report to the user if any updates were avoided due to local changes
205248ffe56aSColin Percival	if [ -s modifiedfiles ]; then
2053fc24ba59SEd Maste		cat - modifiedfiles <<- EOF | ${PAGER}
2054b882e02bSEnji Cooper			The following files are affected by updates. No changes have
2055b882e02bSEnji Cooper			been downloaded, however, because the files have been modified
2056b882e02bSEnji Cooper			locally:
2057fc24ba59SEd Maste		EOF
2058fc24ba59SEd Maste	fi
205948ffe56aSColin Percival	rm modifiedfiles
206048ffe56aSColin Percival
206148ffe56aSColin Percival	# If no files will be updated, tell the user and exit
206248ffe56aSColin Percival	if ! [ -s INDEX-PRESENT ] &&
206348ffe56aSColin Percival	    ! [ -s INDEX-NEW ]; then
206448ffe56aSColin Percival		rm INDEX-PRESENT INDEX-NEW
206548ffe56aSColin Percival		echo
206648ffe56aSColin Percival		echo -n "No updates needed to update system to "
206748ffe56aSColin Percival		echo "${RELNUM}-p${RELPATCHNUM}."
206848ffe56aSColin Percival		return
206948ffe56aSColin Percival	fi
207048ffe56aSColin Percival
207148ffe56aSColin Percival	# Divide files into (a) removed files, (b) added files, and
207248ffe56aSColin Percival	# (c) updated files.
207348ffe56aSColin Percival	cut -f 1 -d '|' < INDEX-PRESENT |
207448ffe56aSColin Percival	    sort > INDEX-PRESENT.flist
207548ffe56aSColin Percival	cut -f 1 -d '|' < INDEX-NEW |
207648ffe56aSColin Percival	    sort > INDEX-NEW.flist
207748ffe56aSColin Percival	comm -23 INDEX-PRESENT.flist INDEX-NEW.flist > files.removed
207848ffe56aSColin Percival	comm -13 INDEX-PRESENT.flist INDEX-NEW.flist > files.added
207948ffe56aSColin Percival	comm -12 INDEX-PRESENT.flist INDEX-NEW.flist > files.updated
208048ffe56aSColin Percival	rm INDEX-PRESENT.flist INDEX-NEW.flist
208148ffe56aSColin Percival
208248ffe56aSColin Percival	# Report removed files, if any
208348ffe56aSColin Percival	if [ -s files.removed ]; then
2084fc24ba59SEd Maste		cat - files.removed <<- EOF | ${PAGER}
2085fc24ba59SEd Maste			The following files will be removed as part of updating to
2086fc24ba59SEd Maste			${RELNUM}-p${RELPATCHNUM}:
2087fc24ba59SEd Maste		EOF
2088fc24ba59SEd Maste	fi
208948ffe56aSColin Percival	rm files.removed
209048ffe56aSColin Percival
209148ffe56aSColin Percival	# Report added files, if any
209248ffe56aSColin Percival	if [ -s files.added ]; then
2093fc24ba59SEd Maste		cat - files.added <<- EOF | ${PAGER}
2094fc24ba59SEd Maste			The following files will be added as part of updating to
2095fc24ba59SEd Maste			${RELNUM}-p${RELPATCHNUM}:
2096fc24ba59SEd Maste		EOF
2097fc24ba59SEd Maste	fi
209848ffe56aSColin Percival	rm files.added
209948ffe56aSColin Percival
210048ffe56aSColin Percival	# Report updated files, if any
210148ffe56aSColin Percival	if [ -s files.updated ]; then
2102fc24ba59SEd Maste		cat - files.updated <<- EOF | ${PAGER}
2103fc24ba59SEd Maste			The following files will be updated as part of updating to
2104fc24ba59SEd Maste			${RELNUM}-p${RELPATCHNUM}:
2105fc24ba59SEd Maste		EOF
2106fc24ba59SEd Maste	fi
210748ffe56aSColin Percival	rm files.updated
210848ffe56aSColin Percival
210948ffe56aSColin Percival	# Create a directory for the install manifest.
211048ffe56aSColin Percival	MDIR=`mktemp -d install.XXXXXX` || return 1
211148ffe56aSColin Percival
211248ffe56aSColin Percival	# Populate it
211348ffe56aSColin Percival	mv INDEX-PRESENT ${MDIR}/INDEX-OLD
211448ffe56aSColin Percival	mv INDEX-NEW ${MDIR}/INDEX-NEW
211548ffe56aSColin Percival
211648ffe56aSColin Percival	# Link it into place
211748ffe56aSColin Percival	ln -s ${MDIR} ${BDHASH}-install
211848ffe56aSColin Percival}
211948ffe56aSColin Percival
212048ffe56aSColin Percival# Warn about any upcoming EoL
212148ffe56aSColin Percivalfetch_warn_eol () {
212248ffe56aSColin Percival	# What's the current time?
212348ffe56aSColin Percival	NOWTIME=`date "+%s"`
212448ffe56aSColin Percival
212548ffe56aSColin Percival	# When did we last warn about the EoL date?
212648ffe56aSColin Percival	if [ -f lasteolwarn ]; then
212748ffe56aSColin Percival		LASTWARN=`cat lasteolwarn`
212848ffe56aSColin Percival	else
212948ffe56aSColin Percival		LASTWARN=`expr ${NOWTIME} - 63072000`
213048ffe56aSColin Percival	fi
213148ffe56aSColin Percival
213248ffe56aSColin Percival	# If the EoL time is past, warn.
213348ffe56aSColin Percival	if [ ${EOLTIME} -lt ${NOWTIME} ]; then
213448ffe56aSColin Percival		echo
213548ffe56aSColin Percival		cat <<-EOF
2136b698a3abSColin Percival		WARNING: `uname -sr` HAS PASSED ITS END-OF-LIFE DATE.
213748ffe56aSColin Percival		Any security issues discovered after `date -r ${EOLTIME}`
213848ffe56aSColin Percival		will not have been corrected.
213948ffe56aSColin Percival		EOF
214048ffe56aSColin Percival		return 1
214148ffe56aSColin Percival	fi
214248ffe56aSColin Percival
214348ffe56aSColin Percival	# Figure out how long it has been since we last warned about the
214448ffe56aSColin Percival	# upcoming EoL, and how much longer we have left.
214548ffe56aSColin Percival	SINCEWARN=`expr ${NOWTIME} - ${LASTWARN}`
214648ffe56aSColin Percival	TIMELEFT=`expr ${EOLTIME} - ${NOWTIME}`
214748ffe56aSColin Percival
214889b14566SColin Percival	# Don't warn if the EoL is more than 3 months away
214989b14566SColin Percival	if [ ${TIMELEFT} -gt 7884000 ]; then
215048ffe56aSColin Percival		return 0
215148ffe56aSColin Percival	fi
215248ffe56aSColin Percival
215348ffe56aSColin Percival	# Don't warn if the time remaining is more than 3 times the time
215448ffe56aSColin Percival	# since the last warning.
215548ffe56aSColin Percival	if [ ${TIMELEFT} -gt `expr ${SINCEWARN} \* 3` ]; then
215648ffe56aSColin Percival		return 0
215748ffe56aSColin Percival	fi
215848ffe56aSColin Percival
215948ffe56aSColin Percival	# Figure out what time units to use.
216048ffe56aSColin Percival	if [ ${TIMELEFT} -lt 604800 ]; then
216148ffe56aSColin Percival		UNIT="day"
216248ffe56aSColin Percival		SIZE=86400
216348ffe56aSColin Percival	elif [ ${TIMELEFT} -lt 2678400 ]; then
216448ffe56aSColin Percival		UNIT="week"
216548ffe56aSColin Percival		SIZE=604800
216648ffe56aSColin Percival	else
216748ffe56aSColin Percival		UNIT="month"
216848ffe56aSColin Percival		SIZE=2678400
216948ffe56aSColin Percival	fi
217048ffe56aSColin Percival
217148ffe56aSColin Percival	# Compute the right number of units
217248ffe56aSColin Percival	NUM=`expr ${TIMELEFT} / ${SIZE}`
217348ffe56aSColin Percival	if [ ${NUM} != 1 ]; then
217448ffe56aSColin Percival		UNIT="${UNIT}s"
217548ffe56aSColin Percival	fi
217648ffe56aSColin Percival
217748ffe56aSColin Percival	# Print the warning
217848ffe56aSColin Percival	echo
217948ffe56aSColin Percival	cat <<-EOF
218048ffe56aSColin Percival		WARNING: `uname -sr` is approaching its End-of-Life date.
218148ffe56aSColin Percival		It is strongly recommended that you upgrade to a newer
218248ffe56aSColin Percival		release within the next ${NUM} ${UNIT}.
218348ffe56aSColin Percival	EOF
218448ffe56aSColin Percival
218548ffe56aSColin Percival	# Update the stored time of last warning
218648ffe56aSColin Percival	echo ${NOWTIME} > lasteolwarn
218748ffe56aSColin Percival}
218848ffe56aSColin Percival
218948ffe56aSColin Percival# Do the actual work involved in "fetch" / "cron".
219048ffe56aSColin Percivalfetch_run () {
219148ffe56aSColin Percival	workdir_init || return 1
219248ffe56aSColin Percival
219348ffe56aSColin Percival	# Prepare the mirror list.
219448ffe56aSColin Percival	fetch_pick_server_init && fetch_pick_server
219548ffe56aSColin Percival
219648ffe56aSColin Percival	# Try to fetch the public key until we run out of servers.
219748ffe56aSColin Percival	while ! fetch_key; do
219848ffe56aSColin Percival		fetch_pick_server || return 1
219948ffe56aSColin Percival	done
220048ffe56aSColin Percival
220148ffe56aSColin Percival	# Try to fetch the metadata index signature ("tag") until we run
220248ffe56aSColin Percival	# out of available servers; and sanity check the downloaded tag.
220348ffe56aSColin Percival	while ! fetch_tag; do
220448ffe56aSColin Percival		fetch_pick_server || return 1
220548ffe56aSColin Percival	done
220648ffe56aSColin Percival	fetch_tagsanity || return 1
220748ffe56aSColin Percival
220848ffe56aSColin Percival	# Fetch the latest INDEX-NEW and INDEX-OLD files.
220948ffe56aSColin Percival	fetch_metadata INDEX-NEW INDEX-OLD || return 1
221048ffe56aSColin Percival
221148ffe56aSColin Percival	# Generate filtered INDEX-NEW and INDEX-OLD files containing only
221248ffe56aSColin Percival	# the lines which (a) belong to components we care about, and (b)
221348ffe56aSColin Percival	# don't correspond to paths we're explicitly ignoring.
221448ffe56aSColin Percival	fetch_filter_metadata INDEX-NEW || return 1
221548ffe56aSColin Percival	fetch_filter_metadata INDEX-OLD || return 1
221648ffe56aSColin Percival
2217db6b0a61SColin Percival	# Translate /boot/${KERNCONF} into ${KERNELDIR}
2218db6b0a61SColin Percival	fetch_filter_kernel_names INDEX-NEW ${KERNCONF}
2219db6b0a61SColin Percival	fetch_filter_kernel_names INDEX-OLD ${KERNCONF}
222048ffe56aSColin Percival
222148ffe56aSColin Percival	# For all paths appearing in INDEX-OLD or INDEX-NEW, inspect the
222248ffe56aSColin Percival	# system and generate an INDEX-PRESENT file.
222348ffe56aSColin Percival	fetch_inspect_system INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1
222448ffe56aSColin Percival
222548ffe56aSColin Percival	# Based on ${UPDATEIFUNMODIFIED}, remove lines from INDEX-* which
222648ffe56aSColin Percival	# correspond to lines in INDEX-PRESENT with hashes not appearing
222748ffe56aSColin Percival	# in INDEX-OLD or INDEX-NEW.  Also remove lines where the entry in
222848ffe56aSColin Percival	# INDEX-PRESENT has type - and there isn't a corresponding entry in
222948ffe56aSColin Percival	# INDEX-OLD with type -.
2230db6b0a61SColin Percival	fetch_filter_unmodified_notpresent	\
2231db6b0a61SColin Percival	    INDEX-OLD INDEX-PRESENT INDEX-NEW /dev/null
223248ffe56aSColin Percival
223348ffe56aSColin Percival	# For each entry in INDEX-PRESENT of type -, remove any corresponding
223448ffe56aSColin Percival	# entry from INDEX-NEW if ${ALLOWADD} != "yes".  Remove all entries
223548ffe56aSColin Percival	# of type - from INDEX-PRESENT.
223648ffe56aSColin Percival	fetch_filter_allowadd INDEX-PRESENT INDEX-NEW
223748ffe56aSColin Percival
223848ffe56aSColin Percival	# If ${ALLOWDELETE} != "yes", then remove any entries from
223948ffe56aSColin Percival	# INDEX-PRESENT which don't correspond to entries in INDEX-NEW.
224048ffe56aSColin Percival	fetch_filter_allowdelete INDEX-PRESENT INDEX-NEW
224148ffe56aSColin Percival
224248ffe56aSColin Percival	# If ${KEEPMODIFIEDMETADATA} == "yes", then for each entry in
224348ffe56aSColin Percival	# INDEX-PRESENT with metadata not matching any entry in INDEX-OLD,
224448ffe56aSColin Percival	# replace the corresponding line of INDEX-NEW with one having the
224548ffe56aSColin Percival	# same metadata as the entry in INDEX-PRESENT.
224648ffe56aSColin Percival	fetch_filter_modified_metadata INDEX-OLD INDEX-PRESENT INDEX-NEW
224748ffe56aSColin Percival
224848ffe56aSColin Percival	# Remove lines from INDEX-PRESENT and INDEX-NEW which are identical;
224948ffe56aSColin Percival	# no need to update a file if it isn't changing.
225048ffe56aSColin Percival	fetch_filter_uptodate INDEX-PRESENT INDEX-NEW
225148ffe56aSColin Percival
225248ffe56aSColin Percival	# Prepare to fetch files: Generate a list of the files we need,
225348ffe56aSColin Percival	# copy the unmodified files we have into /files/, and generate
225448ffe56aSColin Percival	# a list of patches to download.
2255210b8123SColin Percival	fetch_files_prepare INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1
225648ffe56aSColin Percival
225748ffe56aSColin Percival	# Fetch files.
225848ffe56aSColin Percival	fetch_files || return 1
225948ffe56aSColin Percival
226048ffe56aSColin Percival	# Create and populate install manifest directory; and report what
226148ffe56aSColin Percival	# updates are available.
226248ffe56aSColin Percival	fetch_create_manifest || return 1
226348ffe56aSColin Percival
226448ffe56aSColin Percival	# Warn about any upcoming EoL
226548ffe56aSColin Percival	fetch_warn_eol || return 1
226648ffe56aSColin Percival}
226748ffe56aSColin Percival
2268db6b0a61SColin Percival# If StrictComponents is not "yes", generate a new components list
2269db6b0a61SColin Percival# with only the components which appear to be installed.
2270db6b0a61SColin Percivalupgrade_guess_components () {
2271db6b0a61SColin Percival	if [ "${STRICTCOMPONENTS}" = "no" ]; then
2272db6b0a61SColin Percival		# Generate filtered INDEX-ALL with only the components listed
2273db6b0a61SColin Percival		# in COMPONENTS.
2274db6b0a61SColin Percival		fetch_filter_metadata_components $1 || return 1
2275db6b0a61SColin Percival
2276db6b0a61SColin Percival		# Tell the user why his disk is suddenly making lots of noise
2277db6b0a61SColin Percival		echo -n "Inspecting system... "
2278db6b0a61SColin Percival
2279db6b0a61SColin Percival		# Look at the files on disk, and assume that a component is
2280db6b0a61SColin Percival		# supposed to be present if it is more than half-present.
2281db6b0a61SColin Percival		cut -f 1-3 -d '|' < INDEX-ALL |
2282db6b0a61SColin Percival		    tr '|' ' ' |
2283db6b0a61SColin Percival		    while read C S F; do
2284db6b0a61SColin Percival			if [ -e ${BASEDIR}/${F} ]; then
2285db6b0a61SColin Percival				echo "+ ${C}|${S}"
2286db6b0a61SColin Percival			fi
2287db6b0a61SColin Percival			echo "= ${C}|${S}"
2288db6b0a61SColin Percival		    done |
2289db6b0a61SColin Percival		    sort |
2290db6b0a61SColin Percival		    uniq -c |
2291db6b0a61SColin Percival		    sed -E 's,^ +,,' > compfreq
2292db6b0a61SColin Percival		grep ' = ' compfreq |
2293db6b0a61SColin Percival		    cut -f 1,3 -d ' ' |
2294db6b0a61SColin Percival		    sort -k 2,2 -t ' ' > compfreq.total
2295db6b0a61SColin Percival		grep ' + ' compfreq |
2296db6b0a61SColin Percival		    cut -f 1,3 -d ' ' |
2297db6b0a61SColin Percival		    sort -k 2,2 -t ' ' > compfreq.present
2298db6b0a61SColin Percival		join -t ' ' -1 2 -2 2 compfreq.present compfreq.total |
2299db6b0a61SColin Percival		    while read S P T; do
2300ae97aa98SEd Maste			if [ ${T} -ne 0 -a ${P} -gt `expr ${T} / 2` ]; then
2301db6b0a61SColin Percival				echo ${S}
2302db6b0a61SColin Percival			fi
2303db6b0a61SColin Percival		    done > comp.present
2304db6b0a61SColin Percival		cut -f 2 -d ' ' < compfreq.total > comp.total
2305db6b0a61SColin Percival		rm INDEX-ALL compfreq compfreq.total compfreq.present
2306db6b0a61SColin Percival
2307db6b0a61SColin Percival		# We're done making noise.
2308db6b0a61SColin Percival		echo "done."
2309db6b0a61SColin Percival
2310db6b0a61SColin Percival		# Sometimes the kernel isn't installed where INDEX-ALL
2311db6b0a61SColin Percival		# thinks that it should be: In particular, it is often in
2312db6b0a61SColin Percival		# /boot/kernel instead of /boot/GENERIC or /boot/SMP.  To
2313db6b0a61SColin Percival		# deal with this, if "kernel|X" is listed in comp.total
2314db6b0a61SColin Percival		# (i.e., is a component which would be upgraded if it is
2315db6b0a61SColin Percival		# found to be present) we will add it to comp.present.
2316db6b0a61SColin Percival		# If "kernel|<anything>" is in comp.total but "kernel|X" is
2317db6b0a61SColin Percival		# not, we print a warning -- the user is running a kernel
2318db6b0a61SColin Percival		# which isn't part of the release.
2319db6b0a61SColin Percival		KCOMP=`echo ${KERNCONF} | tr 'A-Z' 'a-z'`
2320db6b0a61SColin Percival		grep -E "^kernel\|${KCOMP}\$" comp.total >> comp.present
2321db6b0a61SColin Percival
2322db6b0a61SColin Percival		if grep -qE "^kernel\|" comp.total &&
2323db6b0a61SColin Percival		    ! grep -qE "^kernel\|${KCOMP}\$" comp.total; then
2324db6b0a61SColin Percival			cat <<-EOF
2325db6b0a61SColin Percival
2326db6b0a61SColin PercivalWARNING: This system is running a "${KCOMP}" kernel, which is not a
2327db6b0a61SColin Percivalkernel configuration distributed as part of FreeBSD ${RELNUM}.
2328db6b0a61SColin PercivalThis kernel will not be updated: you MUST update the kernel manually
2329db6b0a61SColin Percivalbefore running "$0 install".
2330db6b0a61SColin Percival			EOF
2331db6b0a61SColin Percival		fi
2332db6b0a61SColin Percival
2333db6b0a61SColin Percival		# Re-sort the list of installed components and generate
2334db6b0a61SColin Percival		# the list of non-installed components.
2335db6b0a61SColin Percival		sort -u < comp.present > comp.present.tmp
2336db6b0a61SColin Percival		mv comp.present.tmp comp.present
2337db6b0a61SColin Percival		comm -13 comp.present comp.total > comp.absent
2338db6b0a61SColin Percival
2339db6b0a61SColin Percival		# Ask the user to confirm that what we have is correct.  To
2340db6b0a61SColin Percival		# reduce user confusion, translate "X|Y" back to "X/Y" (as
2341db6b0a61SColin Percival		# subcomponents must be listed in the configuration file).
2342db6b0a61SColin Percival		echo
2343db6b0a61SColin Percival		echo -n "The following components of FreeBSD "
2344db6b0a61SColin Percival		echo "seem to be installed:"
2345db6b0a61SColin Percival		tr '|' '/' < comp.present |
2346db6b0a61SColin Percival		    fmt -72
2347db6b0a61SColin Percival		echo
2348db6b0a61SColin Percival		echo -n "The following components of FreeBSD "
2349db6b0a61SColin Percival		echo "do not seem to be installed:"
2350db6b0a61SColin Percival		tr '|' '/' < comp.absent |
2351db6b0a61SColin Percival		    fmt -72
2352db6b0a61SColin Percival		echo
2353db6b0a61SColin Percival		continuep || return 1
2354db6b0a61SColin Percival		echo
2355db6b0a61SColin Percival
2356db6b0a61SColin Percival		# Suck the generated list of components into ${COMPONENTS}.
2357db6b0a61SColin Percival		# Note that comp.present.tmp is used due to issues with
2358db6b0a61SColin Percival		# pipelines and setting variables.
2359db6b0a61SColin Percival		COMPONENTS=""
2360db6b0a61SColin Percival		tr '|' '/' < comp.present > comp.present.tmp
2361db6b0a61SColin Percival		while read C; do
2362db6b0a61SColin Percival			COMPONENTS="${COMPONENTS} ${C}"
2363db6b0a61SColin Percival		done < comp.present.tmp
2364db6b0a61SColin Percival
2365db6b0a61SColin Percival		# Delete temporary files
2366db6b0a61SColin Percival		rm comp.present comp.present.tmp comp.absent comp.total
2367db6b0a61SColin Percival	fi
2368db6b0a61SColin Percival}
2369db6b0a61SColin Percival
2370db6b0a61SColin Percival# If StrictComponents is not "yes", COMPONENTS contains an entry
2371db6b0a61SColin Percival# corresponding to the currently running kernel, and said kernel
2372db6b0a61SColin Percival# does not exist in the new release, add "kernel/generic" to the
2373db6b0a61SColin Percival# list of components.
2374db6b0a61SColin Percivalupgrade_guess_new_kernel () {
2375db6b0a61SColin Percival	if [ "${STRICTCOMPONENTS}" = "no" ]; then
2376db6b0a61SColin Percival		# Grab the unfiltered metadata file.
2377db6b0a61SColin Percival		METAHASH=`look "$1|" tINDEX.present | cut -f 2 -d '|'`
2378db6b0a61SColin Percival		gunzip -c < files/${METAHASH}.gz > $1.all
2379db6b0a61SColin Percival
2380db6b0a61SColin Percival		# If "kernel/${KCOMP}" is in ${COMPONENTS} and that component
2381db6b0a61SColin Percival		# isn't in $1.all, we need to add kernel/generic.
2382db6b0a61SColin Percival		for C in ${COMPONENTS}; do
2383db6b0a61SColin Percival			if [ ${C} = "kernel/${KCOMP}" ] &&
2384db6b0a61SColin Percival			    ! grep -qE "^kernel\|${KCOMP}\|" $1.all; then
2385db6b0a61SColin Percival				COMPONENTS="${COMPONENTS} kernel/generic"
2386db6b0a61SColin Percival				NKERNCONF="GENERIC"
2387db6b0a61SColin Percival				cat <<-EOF
2388db6b0a61SColin Percival
2389db6b0a61SColin PercivalWARNING: This system is running a "${KCOMP}" kernel, which is not a
2390db6b0a61SColin Percivalkernel configuration distributed as part of FreeBSD ${RELNUM}.
2391db6b0a61SColin PercivalAs part of upgrading to FreeBSD ${RELNUM}, this kernel will be
2392db6b0a61SColin Percivalreplaced with a "generic" kernel.
2393db6b0a61SColin Percival				EOF
2394db6b0a61SColin Percival				continuep || return 1
2395db6b0a61SColin Percival			fi
2396db6b0a61SColin Percival		done
2397db6b0a61SColin Percival
2398db6b0a61SColin Percival		# Don't need this any more...
2399db6b0a61SColin Percival		rm $1.all
2400db6b0a61SColin Percival	fi
2401db6b0a61SColin Percival}
2402db6b0a61SColin Percival
2403db6b0a61SColin Percival# Convert INDEX-OLD (last release) and INDEX-ALL (new release) into
2404db6b0a61SColin Percival# INDEX-OLD and INDEX-NEW files (in the sense of normal upgrades).
2405db6b0a61SColin Percivalupgrade_oldall_to_oldnew () {
2406db6b0a61SColin Percival	# For each ${F}|... which appears in INDEX-ALL but does not appear
2407db6b0a61SColin Percival	# in INDEX-OLD, add ${F}|-|||||| to INDEX-OLD.
2408db6b0a61SColin Percival	cut -f 1 -d '|' < $1 |
2409db6b0a61SColin Percival	    sort -u > $1.paths
2410db6b0a61SColin Percival	cut -f 1 -d '|' < $2 |
2411db6b0a61SColin Percival	    sort -u |
2412db6b0a61SColin Percival	    comm -13 $1.paths - |
2413db6b0a61SColin Percival	    lam - -s "|-||||||" |
2414db6b0a61SColin Percival	    sort - $1 > $1.tmp
2415db6b0a61SColin Percival	mv $1.tmp $1
2416db6b0a61SColin Percival
2417db6b0a61SColin Percival	# Remove lines from INDEX-OLD which also appear in INDEX-ALL
2418db6b0a61SColin Percival	comm -23 $1 $2 > $1.tmp
2419db6b0a61SColin Percival	mv $1.tmp $1
2420db6b0a61SColin Percival
2421db6b0a61SColin Percival	# Remove lines from INDEX-ALL which have a file name not appearing
2422db6b0a61SColin Percival	# anywhere in INDEX-OLD (since these must be files which haven't
2423db6b0a61SColin Percival	# changed -- if they were new, there would be an entry of type "-").
2424db6b0a61SColin Percival	cut -f 1 -d '|' < $1 |
2425db6b0a61SColin Percival	    sort -u > $1.paths
2426db6b0a61SColin Percival	sort -k 1,1 -t '|' < $2 |
2427db6b0a61SColin Percival	    join -t '|' - $1.paths |
2428db6b0a61SColin Percival	    sort > $2.tmp
2429db6b0a61SColin Percival	rm $1.paths
2430db6b0a61SColin Percival	mv $2.tmp $2
2431db6b0a61SColin Percival
2432db6b0a61SColin Percival	# Rename INDEX-ALL to INDEX-NEW.
2433db6b0a61SColin Percival	mv $2 $3
2434db6b0a61SColin Percival}
2435db6b0a61SColin Percival
24367449d2f5SColin Percival# Helper for upgrade_merge: Return zero true iff the two files differ only
24376d514f10SDag-Erling Smørgrav# in the contents of their RCS tags.
24387449d2f5SColin Percivalsamef () {
24397449d2f5SColin Percival	X=`sed -E 's/\\$FreeBSD.*\\$/\$FreeBSD\$/' < $1 | ${SHA256}`
24407449d2f5SColin Percival	Y=`sed -E 's/\\$FreeBSD.*\\$/\$FreeBSD\$/' < $2 | ${SHA256}`
24417449d2f5SColin Percival
24427449d2f5SColin Percival	if [ $X = $Y ]; then
24437449d2f5SColin Percival		return 0;
24447449d2f5SColin Percival	else
24457449d2f5SColin Percival		return 1;
24467449d2f5SColin Percival	fi
24477449d2f5SColin Percival}
24487449d2f5SColin Percival
2449db6b0a61SColin Percival# From the list of "old" files in $1, merge changes in $2 with those in $3,
2450db6b0a61SColin Percival# and update $3 to reflect the hashes of merged files.
2451db6b0a61SColin Percivalupgrade_merge () {
2452db6b0a61SColin Percival	# We only need to do anything if $1 is non-empty.
2453db6b0a61SColin Percival	if [ -s $1 ]; then
2454db6b0a61SColin Percival		cut -f 1 -d '|' $1 |
2455db6b0a61SColin Percival		    sort > $1-paths
2456db6b0a61SColin Percival
2457db6b0a61SColin Percival		# Create staging area for merging files
2458db6b0a61SColin Percival		rm -rf merge/
2459db6b0a61SColin Percival		while read F; do
2460db6b0a61SColin Percival			D=`dirname ${F}`
2461db6b0a61SColin Percival			mkdir -p merge/old/${D}
2462db6b0a61SColin Percival			mkdir -p merge/${OLDRELNUM}/${D}
2463db6b0a61SColin Percival			mkdir -p merge/${RELNUM}/${D}
2464db6b0a61SColin Percival			mkdir -p merge/new/${D}
2465db6b0a61SColin Percival		done < $1-paths
2466db6b0a61SColin Percival
2467db6b0a61SColin Percival		# Copy in files
2468db6b0a61SColin Percival		while read F; do
2469db6b0a61SColin Percival			# Currently installed file
2470db6b0a61SColin Percival			V=`look "${F}|" $2 | cut -f 7 -d '|'`
2471db6b0a61SColin Percival			gunzip < files/${V}.gz > merge/old/${F}
2472db6b0a61SColin Percival
2473db6b0a61SColin Percival			# Old release
2474db6b0a61SColin Percival			if look "${F}|" $1 | fgrep -q "|f|"; then
2475db6b0a61SColin Percival				V=`look "${F}|" $1 | cut -f 3 -d '|'`
2476db6b0a61SColin Percival				gunzip < files/${V}.gz		\
2477db6b0a61SColin Percival				    > merge/${OLDRELNUM}/${F}
2478db6b0a61SColin Percival			fi
2479db6b0a61SColin Percival
2480db6b0a61SColin Percival			# New release
2481db6b0a61SColin Percival			if look "${F}|" $3 | cut -f 1,2,7 -d '|' |
2482db6b0a61SColin Percival			    fgrep -q "|f|"; then
2483db6b0a61SColin Percival				V=`look "${F}|" $3 | cut -f 7 -d '|'`
2484db6b0a61SColin Percival				gunzip < files/${V}.gz		\
2485db6b0a61SColin Percival				    > merge/${RELNUM}/${F}
2486db6b0a61SColin Percival			fi
2487db6b0a61SColin Percival		done < $1-paths
2488db6b0a61SColin Percival
2489db6b0a61SColin Percival		# Attempt to automatically merge changes
2490db6b0a61SColin Percival		echo -n "Attempting to automatically merge "
2491db6b0a61SColin Percival		echo -n "changes in files..."
2492db6b0a61SColin Percival		: > failed.merges
2493db6b0a61SColin Percival		while read F; do
2494db6b0a61SColin Percival			# If the file doesn't exist in the new release,
2495db6b0a61SColin Percival			# the result of "merging changes" is having the file
2496db6b0a61SColin Percival			# not exist.
2497db6b0a61SColin Percival			if ! [ -f merge/${RELNUM}/${F} ]; then
2498db6b0a61SColin Percival				continue
2499db6b0a61SColin Percival			fi
2500db6b0a61SColin Percival
2501db6b0a61SColin Percival			# If the file didn't exist in the old release, we're
2502db6b0a61SColin Percival			# going to throw away the existing file and hope that
2503db6b0a61SColin Percival			# the version from the new release is what we want.
2504db6b0a61SColin Percival			if ! [ -f merge/${OLDRELNUM}/${F} ]; then
2505db6b0a61SColin Percival				cp merge/${RELNUM}/${F} merge/new/${F}
2506db6b0a61SColin Percival				continue
2507db6b0a61SColin Percival			fi
2508db6b0a61SColin Percival
2509db6b0a61SColin Percival			# Some files need special treatment.
2510db6b0a61SColin Percival			case ${F} in
2511db6b0a61SColin Percival			/etc/spwd.db | /etc/pwd.db | /etc/login.conf.db)
2512db6b0a61SColin Percival				# Don't merge these -- we're rebuild them
2513db6b0a61SColin Percival				# after updates are installed.
2514db6b0a61SColin Percival				cp merge/old/${F} merge/new/${F}
2515db6b0a61SColin Percival				;;
2516db6b0a61SColin Percival			*)
2517073dd712SBaptiste Daroussin				if ! diff3 -E -m -L "current version"	\
2518db6b0a61SColin Percival				    -L "${OLDRELNUM}" -L "${RELNUM}"	\
2519db6b0a61SColin Percival				    merge/old/${F}			\
2520db6b0a61SColin Percival				    merge/${OLDRELNUM}/${F}		\
2521db6b0a61SColin Percival				    merge/${RELNUM}/${F}		\
2522db6b0a61SColin Percival				    > merge/new/${F} 2>/dev/null; then
2523db6b0a61SColin Percival					echo ${F} >> failed.merges
2524db6b0a61SColin Percival				fi
2525db6b0a61SColin Percival				;;
2526db6b0a61SColin Percival			esac
2527db6b0a61SColin Percival		done < $1-paths
2528db6b0a61SColin Percival		echo " done."
2529db6b0a61SColin Percival
2530db6b0a61SColin Percival		# Ask the user to handle any files which didn't merge.
2531db6b0a61SColin Percival		while read F; do
25327449d2f5SColin Percival			# If the installed file differs from the version in
25336d514f10SDag-Erling Smørgrav			# the old release only due to RCS tag expansion
25347449d2f5SColin Percival			# then just use the version in the new release.
25357449d2f5SColin Percival			if samef merge/old/${F} merge/${OLDRELNUM}/${F}; then
25367449d2f5SColin Percival				cp merge/${RELNUM}/${F} merge/new/${F}
25377449d2f5SColin Percival				continue
25387449d2f5SColin Percival			fi
25397449d2f5SColin Percival
2540db6b0a61SColin Percival			cat <<-EOF
2541db6b0a61SColin Percival
2542db6b0a61SColin PercivalThe following file could not be merged automatically: ${F}
2543db6b0a61SColin PercivalPress Enter to edit this file in ${EDITOR} and resolve the conflicts
2544db6b0a61SColin Percivalmanually...
2545db6b0a61SColin Percival			EOF
2546ceb5f28bSEd Maste			while true; do
2547db6b0a61SColin Percival				read dummy </dev/tty
2548db6b0a61SColin Percival				${EDITOR} `pwd`/merge/new/${F} < /dev/tty
2549ceb5f28bSEd Maste
2550e27ded83SEd Maste				if ! grep -qE '^(<<<<<<<|=======|>>>>>>>)([[:space:]].*)?$' $(pwd)/merge/new/${F} ; then
2551ceb5f28bSEd Maste					break
2552ceb5f28bSEd Maste				fi
2553ceb5f28bSEd Maste				cat <<-EOF
2554ceb5f28bSEd Maste
2555ceb5f28bSEd MasteMerge conflict markers remain in: ${F}
2556ceb5f28bSEd MasteThese must be resolved for the system to be functional.
2557ceb5f28bSEd Maste
2558ceb5f28bSEd MastePress Enter to return to editing this file.
2559ceb5f28bSEd Maste				EOF
2560ceb5f28bSEd Maste			done
2561db6b0a61SColin Percival		done < failed.merges
2562db6b0a61SColin Percival		rm failed.merges
2563db6b0a61SColin Percival
2564db6b0a61SColin Percival		# Ask the user to confirm that he likes how the result
2565db6b0a61SColin Percival		# of merging files.
2566db6b0a61SColin Percival		while read F; do
25677449d2f5SColin Percival			# Skip files which haven't changed except possibly
25686d514f10SDag-Erling Smørgrav			# in their RCS tags.
25697449d2f5SColin Percival			if [ -f merge/old/${F} ] && [ -f merge/new/${F} ] &&
25707449d2f5SColin Percival			    samef merge/old/${F} merge/new/${F}; then
25717449d2f5SColin Percival				continue
25727449d2f5SColin Percival			fi
25737449d2f5SColin Percival
25747449d2f5SColin Percival			# Skip files where the installed file differs from
25756d514f10SDag-Erling Smørgrav			# the old file only due to RCS tags.
25767449d2f5SColin Percival			if [ -f merge/old/${F} ] &&
25777449d2f5SColin Percival			    [ -f merge/${OLDRELNUM}/${F} ] &&
25787449d2f5SColin Percival			    samef merge/old/${F} merge/${OLDRELNUM}/${F}; then
2579db6b0a61SColin Percival				continue
2580db6b0a61SColin Percival			fi
2581db6b0a61SColin Percival
2582db6b0a61SColin Percival			# Warn about files which are ceasing to exist.
2583db6b0a61SColin Percival			if ! [ -f merge/new/${F} ]; then
2584db6b0a61SColin Percival				cat <<-EOF
2585db6b0a61SColin Percival
2586db6b0a61SColin PercivalThe following file will be removed, as it no longer exists in
2587db6b0a61SColin PercivalFreeBSD ${RELNUM}: ${F}
2588db6b0a61SColin Percival				EOF
2589db6b0a61SColin Percival				continuep < /dev/tty || return 1
2590db6b0a61SColin Percival				continue
2591db6b0a61SColin Percival			fi
2592db6b0a61SColin Percival
2593db6b0a61SColin Percival			# Print changes for the user's approval.
2594db6b0a61SColin Percival			cat <<-EOF
2595db6b0a61SColin Percival
2596db6b0a61SColin PercivalThe following changes, which occurred between FreeBSD ${OLDRELNUM} and
2597db6b0a61SColin PercivalFreeBSD ${RELNUM} have been merged into ${F}:
2598db6b0a61SColin PercivalEOF
2599db6b0a61SColin Percival			diff -U 5 -L "current version" -L "new version"	\
2600db6b0a61SColin Percival			    merge/old/${F} merge/new/${F} || true
2601db6b0a61SColin Percival			continuep < /dev/tty || return 1
2602db6b0a61SColin Percival		done < $1-paths
2603db6b0a61SColin Percival
2604db6b0a61SColin Percival		# Store merged files.
2605db6b0a61SColin Percival		while read F; do
2606c58b62efSColin Percival			if [ -f merge/new/${F} ]; then
2607db6b0a61SColin Percival				V=`${SHA256} -q merge/new/${F}`
2608db6b0a61SColin Percival
2609db6b0a61SColin Percival				gzip -c < merge/new/${F} > files/${V}.gz
2610db6b0a61SColin Percival				echo "${F}|${V}"
2611db6b0a61SColin Percival			fi
2612db6b0a61SColin Percival		done < $1-paths > newhashes
2613db6b0a61SColin Percival
2614db6b0a61SColin Percival		# Pull lines out from $3 which need to be updated to
2615db6b0a61SColin Percival		# reflect merged files.
2616db6b0a61SColin Percival		while read F; do
2617db6b0a61SColin Percival			look "${F}|" $3
2618db6b0a61SColin Percival		done < $1-paths > $3-oldlines
2619db6b0a61SColin Percival
2620db6b0a61SColin Percival		# Update lines to reflect merged files
2621db6b0a61SColin Percival		join -t '|' -o 1.1,1.2,1.3,1.4,1.5,1.6,2.2,1.8		\
2622db6b0a61SColin Percival		    $3-oldlines newhashes > $3-newlines
2623db6b0a61SColin Percival
2624db6b0a61SColin Percival		# Remove old lines from $3 and add new lines.
2625db6b0a61SColin Percival		sort $3-oldlines |
2626db6b0a61SColin Percival		    comm -13 - $3 |
2627db6b0a61SColin Percival		    sort - $3-newlines > $3.tmp
2628db6b0a61SColin Percival		mv $3.tmp $3
2629db6b0a61SColin Percival
2630db6b0a61SColin Percival		# Clean up
2631db6b0a61SColin Percival		rm $1-paths newhashes $3-oldlines $3-newlines
2632db6b0a61SColin Percival		rm -rf merge/
2633db6b0a61SColin Percival	fi
2634db6b0a61SColin Percival
2635db6b0a61SColin Percival	# We're done with merging files.
2636db6b0a61SColin Percival	rm $1
2637db6b0a61SColin Percival}
2638db6b0a61SColin Percival
2639db6b0a61SColin Percival# Do the work involved in fetching upgrades to a new release
2640db6b0a61SColin Percivalupgrade_run () {
2641db6b0a61SColin Percival	workdir_init || return 1
2642db6b0a61SColin Percival
2643db6b0a61SColin Percival	# Prepare the mirror list.
2644db6b0a61SColin Percival	fetch_pick_server_init && fetch_pick_server
2645db6b0a61SColin Percival
2646db6b0a61SColin Percival	# Try to fetch the public key until we run out of servers.
2647db6b0a61SColin Percival	while ! fetch_key; do
2648db6b0a61SColin Percival		fetch_pick_server || return 1
2649db6b0a61SColin Percival	done
2650db6b0a61SColin Percival
2651db6b0a61SColin Percival	# Try to fetch the metadata index signature ("tag") until we run
2652db6b0a61SColin Percival	# out of available servers; and sanity check the downloaded tag.
2653db6b0a61SColin Percival	while ! fetch_tag; do
2654db6b0a61SColin Percival		fetch_pick_server || return 1
2655db6b0a61SColin Percival	done
2656db6b0a61SColin Percival	fetch_tagsanity || return 1
2657db6b0a61SColin Percival
2658db6b0a61SColin Percival	# Fetch the INDEX-OLD and INDEX-ALL.
2659db6b0a61SColin Percival	fetch_metadata INDEX-OLD INDEX-ALL || return 1
2660db6b0a61SColin Percival
2661db6b0a61SColin Percival	# If StrictComponents is not "yes", generate a new components list
2662db6b0a61SColin Percival	# with only the components which appear to be installed.
2663db6b0a61SColin Percival	upgrade_guess_components INDEX-ALL || return 1
2664db6b0a61SColin Percival
2665db6b0a61SColin Percival	# Generate filtered INDEX-OLD and INDEX-ALL files containing only
2666db6b0a61SColin Percival	# the components we want and without anything marked as "Ignore".
2667db6b0a61SColin Percival	fetch_filter_metadata INDEX-OLD || return 1
2668db6b0a61SColin Percival	fetch_filter_metadata INDEX-ALL || return 1
2669db6b0a61SColin Percival
2670db6b0a61SColin Percival	# Merge the INDEX-OLD and INDEX-ALL files into INDEX-OLD.
2671db6b0a61SColin Percival	sort INDEX-OLD INDEX-ALL > INDEX-OLD.tmp
2672db6b0a61SColin Percival	mv INDEX-OLD.tmp INDEX-OLD
2673db6b0a61SColin Percival	rm INDEX-ALL
2674db6b0a61SColin Percival
2675db6b0a61SColin Percival	# Adjust variables for fetching files from the new release.
2676db6b0a61SColin Percival	OLDRELNUM=${RELNUM}
2677db6b0a61SColin Percival	RELNUM=${TARGETRELEASE}
2678db6b0a61SColin Percival	OLDFETCHDIR=${FETCHDIR}
2679db6b0a61SColin Percival	FETCHDIR=${RELNUM}/${ARCH}
2680db6b0a61SColin Percival
2681db6b0a61SColin Percival	# Try to fetch the NEW metadata index signature ("tag") until we run
2682db6b0a61SColin Percival	# out of available servers; and sanity check the downloaded tag.
2683db6b0a61SColin Percival	while ! fetch_tag; do
2684db6b0a61SColin Percival		fetch_pick_server || return 1
2685db6b0a61SColin Percival	done
2686db6b0a61SColin Percival
2687db6b0a61SColin Percival	# Fetch the new INDEX-ALL.
2688db6b0a61SColin Percival	fetch_metadata INDEX-ALL || return 1
2689db6b0a61SColin Percival
2690db6b0a61SColin Percival	# If StrictComponents is not "yes", COMPONENTS contains an entry
2691db6b0a61SColin Percival	# corresponding to the currently running kernel, and said kernel
2692db6b0a61SColin Percival	# does not exist in the new release, add "kernel/generic" to the
2693db6b0a61SColin Percival	# list of components.
2694db6b0a61SColin Percival	upgrade_guess_new_kernel INDEX-ALL || return 1
2695db6b0a61SColin Percival
2696db6b0a61SColin Percival	# Filter INDEX-ALL to contain only the components we want and without
2697db6b0a61SColin Percival	# anything marked as "Ignore".
2698db6b0a61SColin Percival	fetch_filter_metadata INDEX-ALL || return 1
2699db6b0a61SColin Percival
2700db6b0a61SColin Percival	# Convert INDEX-OLD (last release) and INDEX-ALL (new release) into
2701db6b0a61SColin Percival	# INDEX-OLD and INDEX-NEW files (in the sense of normal upgrades).
2702db6b0a61SColin Percival	upgrade_oldall_to_oldnew INDEX-OLD INDEX-ALL INDEX-NEW
2703db6b0a61SColin Percival
2704db6b0a61SColin Percival	# Translate /boot/${KERNCONF} or /boot/${NKERNCONF} into ${KERNELDIR}
2705db6b0a61SColin Percival	fetch_filter_kernel_names INDEX-NEW ${NKERNCONF}
2706db6b0a61SColin Percival	fetch_filter_kernel_names INDEX-OLD ${KERNCONF}
2707db6b0a61SColin Percival
2708db6b0a61SColin Percival	# For all paths appearing in INDEX-OLD or INDEX-NEW, inspect the
2709db6b0a61SColin Percival	# system and generate an INDEX-PRESENT file.
2710db6b0a61SColin Percival	fetch_inspect_system INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1
2711db6b0a61SColin Percival
2712db6b0a61SColin Percival	# Based on ${MERGECHANGES}, generate a file tomerge-old with the
2713db6b0a61SColin Percival	# paths and hashes of old versions of files to merge.
2714c55b7e52SColin Percival	fetch_filter_mergechanges INDEX-OLD INDEX-PRESENT INDEX-NEW tomerge-old
2715db6b0a61SColin Percival
2716db6b0a61SColin Percival	# Based on ${UPDATEIFUNMODIFIED}, remove lines from INDEX-* which
2717db6b0a61SColin Percival	# correspond to lines in INDEX-PRESENT with hashes not appearing
2718db6b0a61SColin Percival	# in INDEX-OLD or INDEX-NEW.  Also remove lines where the entry in
2719db6b0a61SColin Percival	# INDEX-PRESENT has type - and there isn't a corresponding entry in
2720db6b0a61SColin Percival	# INDEX-OLD with type -.
2721db6b0a61SColin Percival	fetch_filter_unmodified_notpresent	\
2722db6b0a61SColin Percival	    INDEX-OLD INDEX-PRESENT INDEX-NEW tomerge-old
2723db6b0a61SColin Percival
2724db6b0a61SColin Percival	# For each entry in INDEX-PRESENT of type -, remove any corresponding
2725db6b0a61SColin Percival	# entry from INDEX-NEW if ${ALLOWADD} != "yes".  Remove all entries
2726db6b0a61SColin Percival	# of type - from INDEX-PRESENT.
2727db6b0a61SColin Percival	fetch_filter_allowadd INDEX-PRESENT INDEX-NEW
2728db6b0a61SColin Percival
2729db6b0a61SColin Percival	# If ${ALLOWDELETE} != "yes", then remove any entries from
2730db6b0a61SColin Percival	# INDEX-PRESENT which don't correspond to entries in INDEX-NEW.
2731db6b0a61SColin Percival	fetch_filter_allowdelete INDEX-PRESENT INDEX-NEW
2732db6b0a61SColin Percival
2733db6b0a61SColin Percival	# If ${KEEPMODIFIEDMETADATA} == "yes", then for each entry in
2734db6b0a61SColin Percival	# INDEX-PRESENT with metadata not matching any entry in INDEX-OLD,
2735db6b0a61SColin Percival	# replace the corresponding line of INDEX-NEW with one having the
2736db6b0a61SColin Percival	# same metadata as the entry in INDEX-PRESENT.
2737db6b0a61SColin Percival	fetch_filter_modified_metadata INDEX-OLD INDEX-PRESENT INDEX-NEW
2738db6b0a61SColin Percival
2739db6b0a61SColin Percival	# Remove lines from INDEX-PRESENT and INDEX-NEW which are identical;
2740db6b0a61SColin Percival	# no need to update a file if it isn't changing.
2741db6b0a61SColin Percival	fetch_filter_uptodate INDEX-PRESENT INDEX-NEW
2742db6b0a61SColin Percival
2743db6b0a61SColin Percival	# Fetch "clean" files from the old release for merging changes.
2744db6b0a61SColin Percival	fetch_files_premerge tomerge-old
2745db6b0a61SColin Percival
2746db6b0a61SColin Percival	# Prepare to fetch files: Generate a list of the files we need,
2747db6b0a61SColin Percival	# copy the unmodified files we have into /files/, and generate
2748db6b0a61SColin Percival	# a list of patches to download.
2749db6b0a61SColin Percival	fetch_files_prepare INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1
2750db6b0a61SColin Percival
2751db6b0a61SColin Percival	# Fetch patches from to-${RELNUM}/${ARCH}/bp/
2752db6b0a61SColin Percival	PATCHDIR=to-${RELNUM}/${ARCH}/bp
2753db6b0a61SColin Percival	fetch_files || return 1
2754db6b0a61SColin Percival
2755db6b0a61SColin Percival	# Merge configuration file changes.
2756db6b0a61SColin Percival	upgrade_merge tomerge-old INDEX-PRESENT INDEX-NEW || return 1
2757db6b0a61SColin Percival
2758db6b0a61SColin Percival	# Create and populate install manifest directory; and report what
2759db6b0a61SColin Percival	# updates are available.
2760db6b0a61SColin Percival	fetch_create_manifest || return 1
2761db6b0a61SColin Percival
2762db6b0a61SColin Percival	# Leave a note behind to tell the "install" command that the kernel
2763db6b0a61SColin Percival	# needs to be installed before the world.
2764db6b0a61SColin Percival	touch ${BDHASH}-install/kernelfirst
276585451f90SColin Percival
276685451f90SColin Percival	# Remind the user that they need to run "freebsd-update install"
276785451f90SColin Percival	# to install the downloaded bits, in case they didn't RTFM.
276885451f90SColin Percival	echo "To install the downloaded upgrades, run \"$0 install\"."
2769db6b0a61SColin Percival}
2770db6b0a61SColin Percival
277148ffe56aSColin Percival# Make sure that all the file hashes mentioned in $@ have corresponding
277248ffe56aSColin Percival# gzipped files stored in /files/.
277348ffe56aSColin Percivalinstall_verify () {
277448ffe56aSColin Percival	# Generate a list of hashes
277548ffe56aSColin Percival	cat $@ |
277648ffe56aSColin Percival	    cut -f 2,7 -d '|' |
277748ffe56aSColin Percival	    grep -E '^f' |
277848ffe56aSColin Percival	    cut -f 2 -d '|' |
277948ffe56aSColin Percival	    sort -u > filelist
278048ffe56aSColin Percival
278148ffe56aSColin Percival	# Make sure all the hashes exist
278248ffe56aSColin Percival	while read HASH; do
278348ffe56aSColin Percival		if ! [ -f files/${HASH}.gz ]; then
278448ffe56aSColin Percival			echo -n "Update files missing -- "
278548ffe56aSColin Percival			echo "this should never happen."
278648ffe56aSColin Percival			echo "Re-run '$0 fetch'."
278748ffe56aSColin Percival			return 1
278848ffe56aSColin Percival		fi
278948ffe56aSColin Percival	done < filelist
279048ffe56aSColin Percival
279148ffe56aSColin Percival	# Clean up
279248ffe56aSColin Percival	rm filelist
279348ffe56aSColin Percival}
279448ffe56aSColin Percival
279548ffe56aSColin Percival# Remove the system immutable flag from files
279648ffe56aSColin Percivalinstall_unschg () {
279748ffe56aSColin Percival	# Generate file list
279848ffe56aSColin Percival	cat $@ |
279948ffe56aSColin Percival	    cut -f 1 -d '|' > filelist
280048ffe56aSColin Percival
280148ffe56aSColin Percival	# Remove flags
280248ffe56aSColin Percival	while read F; do
2803e829ed67SColin Percival		if ! [ -e ${BASEDIR}/${F} ]; then
280448ffe56aSColin Percival			continue
28055a74378cSXin LI		else
28065a74378cSXin LI			echo ${BASEDIR}/${F}
280748ffe56aSColin Percival		fi
28085a74378cSXin LI	done < filelist | xargs chflags noschg || return 1
280948ffe56aSColin Percival
281048ffe56aSColin Percival	# Clean up
281148ffe56aSColin Percival	rm filelist
281248ffe56aSColin Percival}
281348ffe56aSColin Percival
281423d827efSSimon L. B. Nielsen# Decide which directory name to use for kernel backups.
281523d827efSSimon L. B. Nielsenbackup_kernel_finddir () {
281623d827efSSimon L. B. Nielsen	CNT=0
281723d827efSSimon L. B. Nielsen	while true ; do
281823d827efSSimon L. B. Nielsen		# Pathname does not exist, so it is OK use that name
281923d827efSSimon L. B. Nielsen		# for backup directory.
2820c4a0c62cSThomas Quinot		if [ ! -e $BASEDIR/$BACKUPKERNELDIR ]; then
282123d827efSSimon L. B. Nielsen			return 0
282223d827efSSimon L. B. Nielsen		fi
282323d827efSSimon L. B. Nielsen
282423d827efSSimon L. B. Nielsen		# If directory do exist, we only use if it has our
282523d827efSSimon L. B. Nielsen		# marker file.
2826c4a0c62cSThomas Quinot		if [ -d $BASEDIR/$BACKUPKERNELDIR -a \
2827c4a0c62cSThomas Quinot			-e $BASEDIR/$BACKUPKERNELDIR/.freebsd-update ]; then
282823d827efSSimon L. B. Nielsen			return 0
282923d827efSSimon L. B. Nielsen		fi
283023d827efSSimon L. B. Nielsen
283123d827efSSimon L. B. Nielsen		# We could not use current directory name, so add counter to
283223d827efSSimon L. B. Nielsen		# the end and try again.
283323d827efSSimon L. B. Nielsen		CNT=$((CNT + 1))
283423d827efSSimon L. B. Nielsen		if [ $CNT -gt 9 ]; then
2835c4a0c62cSThomas Quinot			echo "Could not find valid backup dir ($BASEDIR/$BACKUPKERNELDIR)"
283623d827efSSimon L. B. Nielsen			exit 1
283723d827efSSimon L. B. Nielsen		fi
283823d827efSSimon L. B. Nielsen		BACKUPKERNELDIR="`echo $BACKUPKERNELDIR | sed -Ee 's/[0-9]\$//'`"
283923d827efSSimon L. B. Nielsen		BACKUPKERNELDIR="${BACKUPKERNELDIR}${CNT}"
284023d827efSSimon L. B. Nielsen	done
284123d827efSSimon L. B. Nielsen}
284223d827efSSimon L. B. Nielsen
284323d827efSSimon L. B. Nielsen# Backup the current kernel using hardlinks, if not disabled by user.
284423d827efSSimon L. B. Nielsen# Since we delete all files in the directory used for previous backups
284523d827efSSimon L. B. Nielsen# we create a marker file called ".freebsd-update" in the directory so
284623d827efSSimon L. B. Nielsen# we can determine on the next run that the directory was created by
284723d827efSSimon L. B. Nielsen# freebsd-update and we then do not accidentally remove user files in
284823d827efSSimon L. B. Nielsen# the unlikely case that the user has created a directory with a
284923d827efSSimon L. B. Nielsen# conflicting name.
285023d827efSSimon L. B. Nielsenbackup_kernel () {
285123d827efSSimon L. B. Nielsen	# Only make kernel backup is so configured.
285223d827efSSimon L. B. Nielsen	if [ $BACKUPKERNEL != yes ]; then
285323d827efSSimon L. B. Nielsen		return 0
285423d827efSSimon L. B. Nielsen	fi
285523d827efSSimon L. B. Nielsen
285623d827efSSimon L. B. Nielsen	# Decide which directory name to use for kernel backups.
285723d827efSSimon L. B. Nielsen	backup_kernel_finddir
285823d827efSSimon L. B. Nielsen
285923d827efSSimon L. B. Nielsen	# Remove old kernel backup files.  If $BACKUPKERNELDIR was
286023d827efSSimon L. B. Nielsen	# "not ours", backup_kernel_finddir would have exited, so
286123d827efSSimon L. B. Nielsen	# deleting the directory content is as safe as we can make it.
2862c4a0c62cSThomas Quinot	if [ -d $BASEDIR/$BACKUPKERNELDIR ]; then
2863c4a0c62cSThomas Quinot		rm -fr $BASEDIR/$BACKUPKERNELDIR
286423d827efSSimon L. B. Nielsen	fi
286523d827efSSimon L. B. Nielsen
2866ab7d0151SJaakko Heinonen	# Create directories for backup.
2867c4a0c62cSThomas Quinot	mkdir -p $BASEDIR/$BACKUPKERNELDIR
2868c4a0c62cSThomas Quinot	mtree -cdn -p "${BASEDIR}/${KERNELDIR}" | \
2869c4a0c62cSThomas Quinot	    mtree -Ue -p "${BASEDIR}/${BACKUPKERNELDIR}" > /dev/null
287023d827efSSimon L. B. Nielsen
287123d827efSSimon L. B. Nielsen	# Mark the directory as having been created by freebsd-update.
2872c4a0c62cSThomas Quinot	touch $BASEDIR/$BACKUPKERNELDIR/.freebsd-update
287323d827efSSimon L. B. Nielsen	if [ $? -ne 0 ]; then
287423d827efSSimon L. B. Nielsen		echo "Could not create kernel backup directory"
287523d827efSSimon L. B. Nielsen		exit 1
287623d827efSSimon L. B. Nielsen	fi
287723d827efSSimon L. B. Nielsen
287823d827efSSimon L. B. Nielsen	# Disable pathname expansion to be sure *.symbols is not
287923d827efSSimon L. B. Nielsen	# expanded.
288023d827efSSimon L. B. Nielsen	set -f
288123d827efSSimon L. B. Nielsen
288223d827efSSimon L. B. Nielsen	# Use find to ignore symbol files, unless disabled by user.
288323d827efSSimon L. B. Nielsen	if [ $BACKUPKERNELSYMBOLFILES = yes ]; then
288423d827efSSimon L. B. Nielsen		FINDFILTER=""
288523d827efSSimon L. B. Nielsen	else
28867e1ed2c7SEd Maste		FINDFILTER="-a ! -name *.debug -a ! -name *.symbols"
288723d827efSSimon L. B. Nielsen	fi
288823d827efSSimon L. B. Nielsen
288923d827efSSimon L. B. Nielsen	# Backup all the kernel files using hardlinks.
2890c4a0c62cSThomas Quinot	(cd ${BASEDIR}/${KERNELDIR} && find . -type f $FINDFILTER -exec \
2891c4a0c62cSThomas Quinot	    cp -pl '{}' ${BASEDIR}/${BACKUPKERNELDIR}/'{}' \;)
289223d827efSSimon L. B. Nielsen
289323d827efSSimon L. B. Nielsen	# Re-enable patchname expansion.
289423d827efSSimon L. B. Nielsen	set +f
289523d827efSSimon L. B. Nielsen}
289623d827efSSimon L. B. Nielsen
2897*c0f52443SEd Maste# Check for and remove an existing directory that conflicts with the file or
2898*c0f52443SEd Maste# symlink that we are going to install.
2899*c0f52443SEd Mastedir_conflict () {
2900*c0f52443SEd Maste	if [ -d "$1" ]; then
2901*c0f52443SEd Maste		echo "Removing conflicting directory $1"
2902*c0f52443SEd Maste		rm -rf -- "$1"
2903*c0f52443SEd Maste	fi
2904*c0f52443SEd Maste}
2905*c0f52443SEd Maste
290648ffe56aSColin Percival# Install new files
290748ffe56aSColin Percivalinstall_from_index () {
290848ffe56aSColin Percival	# First pass: Do everything apart from setting file flags.  We
290948ffe56aSColin Percival	# can't set flags yet, because schg inhibits hard linking.
291048ffe56aSColin Percival	sort -k 1,1 -t '|' $1 |
291148ffe56aSColin Percival	    tr '|' ' ' |
291248ffe56aSColin Percival	    while read FPATH TYPE OWNER GROUP PERM FLAGS HASH LINK; do
291348ffe56aSColin Percival		case ${TYPE} in
291448ffe56aSColin Percival		d)
2915f6d37c9cSEd Maste			# Create a directory.  A file may change to a directory
2916f6d37c9cSEd Maste			# on upgrade (PR273661).  If that happens, remove the
2917f6d37c9cSEd Maste			# file first.
2918f6d37c9cSEd Maste			if [ -e "${BASEDIR}/${FPATH}" ] && \
2919f6d37c9cSEd Maste			    ! [ -d "${BASEDIR}/${FPATH}" ]; then
2920f6d37c9cSEd Maste				rm -f -- "${BASEDIR}/${FPATH}"
2921f6d37c9cSEd Maste			fi
292248ffe56aSColin Percival			install -d -o ${OWNER} -g ${GROUP}		\
292348ffe56aSColin Percival			    -m ${PERM} ${BASEDIR}/${FPATH}
292448ffe56aSColin Percival			;;
292548ffe56aSColin Percival		f)
2926*c0f52443SEd Maste			dir_conflict "${BASEDIR}/${FPATH}"
292748ffe56aSColin Percival			if [ -z "${LINK}" ]; then
292848ffe56aSColin Percival				# Create a file, without setting flags.
292948ffe56aSColin Percival				gunzip < files/${HASH}.gz > ${HASH}
293048ffe56aSColin Percival				install -S -o ${OWNER} -g ${GROUP}	\
293148ffe56aSColin Percival				    -m ${PERM} ${HASH} ${BASEDIR}/${FPATH}
293248ffe56aSColin Percival				rm ${HASH}
293348ffe56aSColin Percival			else
293448ffe56aSColin Percival				# Create a hard link.
2935e829ed67SColin Percival				ln -f ${BASEDIR}/${LINK} ${BASEDIR}/${FPATH}
293648ffe56aSColin Percival			fi
293748ffe56aSColin Percival			;;
293848ffe56aSColin Percival		L)
2939*c0f52443SEd Maste			dir_conflict "${BASEDIR}/${FPATH}"
294048ffe56aSColin Percival			# Create a symlink
294148ffe56aSColin Percival			ln -sfh ${HASH} ${BASEDIR}/${FPATH}
294248ffe56aSColin Percival			;;
294348ffe56aSColin Percival		esac
294448ffe56aSColin Percival	    done
294548ffe56aSColin Percival
294648ffe56aSColin Percival	# Perform a second pass, adding file flags.
294748ffe56aSColin Percival	tr '|' ' ' < $1 |
294848ffe56aSColin Percival	    while read FPATH TYPE OWNER GROUP PERM FLAGS HASH LINK; do
294948ffe56aSColin Percival		if [ ${TYPE} = "f" ] &&
295048ffe56aSColin Percival		    ! [ ${FLAGS} = "0" ]; then
295148ffe56aSColin Percival			chflags ${FLAGS} ${BASEDIR}/${FPATH}
295248ffe56aSColin Percival		fi
295348ffe56aSColin Percival	    done
295448ffe56aSColin Percival}
295548ffe56aSColin Percival
295648ffe56aSColin Percival# Remove files which we want to delete
295748ffe56aSColin Percivalinstall_delete () {
295848ffe56aSColin Percival	# Generate list of new files
295948ffe56aSColin Percival	cut -f 1 -d '|' < $2 |
296048ffe56aSColin Percival	    sort > newfiles
296148ffe56aSColin Percival
296248ffe56aSColin Percival	# Generate subindex of old files we want to nuke
296348ffe56aSColin Percival	sort -k 1,1 -t '|' $1 |
296448ffe56aSColin Percival	    join -t '|' -v 1 - newfiles |
2965bce02f98SColin Percival	    sort -r -k 1,1 -t '|' |
296648ffe56aSColin Percival	    cut -f 1,2 -d '|' |
296748ffe56aSColin Percival	    tr '|' ' ' > killfiles
296848ffe56aSColin Percival
296948ffe56aSColin Percival	# Remove the offending bits
297048ffe56aSColin Percival	while read FPATH TYPE; do
297148ffe56aSColin Percival		case ${TYPE} in
297248ffe56aSColin Percival		d)
297348ffe56aSColin Percival			rmdir ${BASEDIR}/${FPATH}
297448ffe56aSColin Percival			;;
297548ffe56aSColin Percival		f)
2976*c0f52443SEd Maste			if [ -f "${BASEDIR}/${FPATH}" ]; then
2977*c0f52443SEd Maste				rm "${BASEDIR}/${FPATH}"
2978*c0f52443SEd Maste			fi
297948ffe56aSColin Percival			;;
298048ffe56aSColin Percival		L)
2981*c0f52443SEd Maste			if [ -L "${BASEDIR}/${FPATH}" ]; then
2982*c0f52443SEd Maste				rm "${BASEDIR}/${FPATH}"
2983*c0f52443SEd Maste			fi
298448ffe56aSColin Percival			;;
298548ffe56aSColin Percival		esac
298648ffe56aSColin Percival	done < killfiles
298748ffe56aSColin Percival
298848ffe56aSColin Percival	# Clean up
298948ffe56aSColin Percival	rm newfiles killfiles
299048ffe56aSColin Percival}
299148ffe56aSColin Percival
29922b17527cSKyle Evans# Install new files, delete old files, and update generated files
2993db6b0a61SColin Percivalinstall_files () {
2994db6b0a61SColin Percival	# If we haven't already dealt with the kernel, deal with it.
2995db6b0a61SColin Percival	if ! [ -f $1/kerneldone ]; then
2996db6b0a61SColin Percival		grep -E '^/boot/' $1/INDEX-OLD > INDEX-OLD
2997db6b0a61SColin Percival		grep -E '^/boot/' $1/INDEX-NEW > INDEX-NEW
2998db6b0a61SColin Percival
299923d827efSSimon L. B. Nielsen		# Backup current kernel before installing a new one
300023d827efSSimon L. B. Nielsen		backup_kernel || return 1
300123d827efSSimon L. B. Nielsen
3002db6b0a61SColin Percival		# Install new files
3003db6b0a61SColin Percival		install_from_index INDEX-NEW || return 1
3004db6b0a61SColin Percival
3005db6b0a61SColin Percival		# Remove files which need to be deleted
3006db6b0a61SColin Percival		install_delete INDEX-OLD INDEX-NEW || return 1
3007db6b0a61SColin Percival
3008db6b0a61SColin Percival		# Update linker.hints if necessary
3009db6b0a61SColin Percival		if [ -s INDEX-OLD -o -s INDEX-NEW ]; then
3010c4a0c62cSThomas Quinot			kldxref -R ${BASEDIR}/boot/ 2>/dev/null
301148ffe56aSColin Percival		fi
3012db6b0a61SColin Percival
3013db6b0a61SColin Percival		# We've finished updating the kernel.
3014db6b0a61SColin Percival		touch $1/kerneldone
3015db6b0a61SColin Percival
3016db6b0a61SColin Percival		# Do we need to ask for a reboot now?
3017db6b0a61SColin Percival		if [ -f $1/kernelfirst ] &&
3018db6b0a61SColin Percival		    [ -s INDEX-OLD -o -s INDEX-NEW ]; then
3019db6b0a61SColin Percival			cat <<-EOF
3020db6b0a61SColin Percival
3021db6b0a61SColin PercivalKernel updates have been installed.  Please reboot and run
3022db6b0a61SColin Percival"$0 install" again to finish installing updates.
3023db6b0a61SColin Percival			EOF
3024db6b0a61SColin Percival			exit 0
3025db6b0a61SColin Percival		fi
3026db6b0a61SColin Percival	fi
3027db6b0a61SColin Percival
3028db6b0a61SColin Percival	# If we haven't already dealt with the world, deal with it.
3029db6b0a61SColin Percival	if ! [ -f $1/worlddone ]; then
3030cd1ab228SColin Percival		# Create any necessary directories first
3031cd1ab228SColin Percival		grep -vE '^/boot/' $1/INDEX-NEW |
3032cd1ab228SColin Percival		    grep -E '^[^|]+\|d\|' > INDEX-NEW
3033cd1ab228SColin Percival		install_from_index INDEX-NEW || return 1
3034cd1ab228SColin Percival
3035722d81b5SBrooks Davis		# Install new runtime linker
3036722d81b5SBrooks Davis		grep -vE '^/boot/' $1/INDEX-NEW |
3037722d81b5SBrooks Davis		    grep -vE '^[^|]+\|d\|' |
3038722d81b5SBrooks Davis		    grep -E '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' > INDEX-NEW
3039722d81b5SBrooks Davis		install_from_index INDEX-NEW || return 1
3040722d81b5SBrooks Davis
3041db6b0a61SColin Percival		# Install new shared libraries next
3042db6b0a61SColin Percival		grep -vE '^/boot/' $1/INDEX-NEW |
3043cd1ab228SColin Percival		    grep -vE '^[^|]+\|d\|' |
3044722d81b5SBrooks Davis		    grep -vE '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' |
30459546dbd1SColin Percival		    grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-NEW
3046db6b0a61SColin Percival		install_from_index INDEX-NEW || return 1
3047db6b0a61SColin Percival
3048db6b0a61SColin Percival		# Deal with everything else
3049db6b0a61SColin Percival		grep -vE '^/boot/' $1/INDEX-OLD |
3050cd1ab228SColin Percival		    grep -vE '^[^|]+\|d\|' |
3051722d81b5SBrooks Davis		    grep -vE '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' |
30529546dbd1SColin Percival		    grep -vE '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-OLD
3053db6b0a61SColin Percival		grep -vE '^/boot/' $1/INDEX-NEW |
3054cd1ab228SColin Percival		    grep -vE '^[^|]+\|d\|' |
3055722d81b5SBrooks Davis		    grep -vE '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' |
30569546dbd1SColin Percival		    grep -vE '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-NEW
3057db6b0a61SColin Percival		install_from_index INDEX-NEW || return 1
3058db6b0a61SColin Percival		install_delete INDEX-OLD INDEX-NEW || return 1
3059db6b0a61SColin Percival
30608ee97b19SEd Maste		# Restart host sshd if running (PR263489).  Note that this does
30618ee97b19SEd Maste		# not affect child sshd processes handling existing sessions.
30628ee97b19SEd Maste		if [ "$BASEDIR" = / ] && \
30638ee97b19SEd Maste		    service sshd status >/dev/null 2>/dev/null; then
30646cd1bc53SEd Maste			echo
30656cd1bc53SEd Maste			echo "Restarting sshd after upgrade"
30666cd1bc53SEd Maste			service sshd restart
30676cd1bc53SEd Maste		fi
30686cd1bc53SEd Maste
30692b17527cSKyle Evans		# Rehash certs if we actually have certctl installed.
30702b17527cSKyle Evans		if which certctl>/dev/null; then
30712b17527cSKyle Evans			env DESTDIR=${BASEDIR} certctl rehash
30722b17527cSKyle Evans		fi
30732b17527cSKyle Evans
3074ebebc41eSKyle Evans		# Rebuild generated pwd files and /etc/login.conf.db.
30759b659110SEd Maste		pwd_mkdb -d ${BASEDIR}/etc -p ${BASEDIR}/etc/master.passwd
3076c4a0c62cSThomas Quinot		cap_mkdb ${BASEDIR}/etc/login.conf
3077db6b0a61SColin Percival
30789c812c8dSEd Maste		# Rebuild man page databases, if necessary.
30799c812c8dSEd Maste		for D in /usr/share/man /usr/share/openssl/man; do
30809c812c8dSEd Maste			if [ ! -d ${BASEDIR}/$D ]; then
30819c812c8dSEd Maste				continue
30829c812c8dSEd Maste			fi
3083741223a6SEd Maste			if [ -f ${BASEDIR}/$D/mandoc.db ] && \
3084741223a6SEd Maste			    [ -z "$(find ${BASEDIR}/$D -type f -newer ${BASEDIR}/$D/mandoc.db)" ]; then
30859c812c8dSEd Maste				continue;
30869c812c8dSEd Maste			fi
30879c812c8dSEd Maste			makewhatis ${BASEDIR}/$D
30889c812c8dSEd Maste		done
30899c812c8dSEd Maste
3090db6b0a61SColin Percival		# We've finished installing the world and deleting old files
3091db6b0a61SColin Percival		# which are not shared libraries.
3092db6b0a61SColin Percival		touch $1/worlddone
3093db6b0a61SColin Percival
3094db6b0a61SColin Percival		# Do we need to ask the user to portupgrade now?
3095db6b0a61SColin Percival		grep -vE '^/boot/' $1/INDEX-NEW |
30969546dbd1SColin Percival		    grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' |
3097db6b0a61SColin Percival		    cut -f 1 -d '|' |
3098db6b0a61SColin Percival		    sort > newfiles
3099db6b0a61SColin Percival		if grep -vE '^/boot/' $1/INDEX-OLD |
31009546dbd1SColin Percival		    grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' |
3101db6b0a61SColin Percival		    cut -f 1 -d '|' |
3102db6b0a61SColin Percival		    sort |
3103db6b0a61SColin Percival		    join -v 1 - newfiles |
3104db6b0a61SColin Percival		    grep -q .; then
3105db6b0a61SColin Percival			cat <<-EOF
3106db6b0a61SColin Percival
3107db6b0a61SColin PercivalCompleting this upgrade requires removing old shared object files.
3108db6b0a61SColin PercivalPlease rebuild all installed 3rd party software (e.g., programs
3109db6b0a61SColin Percivalinstalled from the ports tree) and then run "$0 install"
3110db6b0a61SColin Percivalagain to finish installing updates.
3111db6b0a61SColin Percival			EOF
3112db6b0a61SColin Percival			rm newfiles
3113db6b0a61SColin Percival			exit 0
3114db6b0a61SColin Percival		fi
3115db6b0a61SColin Percival		rm newfiles
3116db6b0a61SColin Percival	fi
3117db6b0a61SColin Percival
3118db6b0a61SColin Percival	# Remove old shared libraries
3119db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-NEW |
3120cd1ab228SColin Percival	    grep -vE '^[^|]+\|d\|' |
31219546dbd1SColin Percival	    grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-NEW
3122db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
3123cd1ab228SColin Percival	    grep -vE '^[^|]+\|d\|' |
31249546dbd1SColin Percival	    grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-OLD
3125db6b0a61SColin Percival	install_delete INDEX-OLD INDEX-NEW || return 1
3126db6b0a61SColin Percival
3127cd1ab228SColin Percival	# Remove old directories
3128ebc1d19cSColin Percival	grep -vE '^/boot/' $1/INDEX-NEW |
3129ebc1d19cSColin Percival	    grep -E '^[^|]+\|d\|' > INDEX-NEW
3130cd1ab228SColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
3131cd1ab228SColin Percival	    grep -E '^[^|]+\|d\|' > INDEX-OLD
3132cd1ab228SColin Percival	install_delete INDEX-OLD INDEX-NEW || return 1
3133cd1ab228SColin Percival
3134db6b0a61SColin Percival	# Remove temporary files
3135db6b0a61SColin Percival	rm INDEX-OLD INDEX-NEW
313648ffe56aSColin Percival}
313748ffe56aSColin Percival
313848ffe56aSColin Percival# Rearrange bits to allow the installed updates to be rolled back
313948ffe56aSColin Percivalinstall_setup_rollback () {
3140db6b0a61SColin Percival	# Remove the "reboot after installing kernel", "kernel updated", and
3141db6b0a61SColin Percival	# "finished installing the world" flags if present -- they are
3142db6b0a61SColin Percival	# irrelevant when rolling back updates.
3143db6b0a61SColin Percival	if [ -f ${BDHASH}-install/kernelfirst ]; then
3144db6b0a61SColin Percival		rm ${BDHASH}-install/kernelfirst
3145db6b0a61SColin Percival		rm ${BDHASH}-install/kerneldone
3146db6b0a61SColin Percival	fi
3147db6b0a61SColin Percival	if [ -f ${BDHASH}-install/worlddone ]; then
3148db6b0a61SColin Percival		rm ${BDHASH}-install/worlddone
3149db6b0a61SColin Percival	fi
3150db6b0a61SColin Percival
315148ffe56aSColin Percival	if [ -L ${BDHASH}-rollback ]; then
315248ffe56aSColin Percival		mv ${BDHASH}-rollback ${BDHASH}-install/rollback
315348ffe56aSColin Percival	fi
315448ffe56aSColin Percival
315548ffe56aSColin Percival	mv ${BDHASH}-install ${BDHASH}-rollback
315648ffe56aSColin Percival}
315748ffe56aSColin Percival
315848ffe56aSColin Percival# Actually install updates
315948ffe56aSColin Percivalinstall_run () {
316048ffe56aSColin Percival	echo -n "Installing updates..."
316148ffe56aSColin Percival
316248ffe56aSColin Percival	# Make sure we have all the files we should have
316348ffe56aSColin Percival	install_verify ${BDHASH}-install/INDEX-OLD	\
316448ffe56aSColin Percival	    ${BDHASH}-install/INDEX-NEW || return 1
316548ffe56aSColin Percival
316648ffe56aSColin Percival	# Remove system immutable flag from files
316748ffe56aSColin Percival	install_unschg ${BDHASH}-install/INDEX-OLD	\
316848ffe56aSColin Percival	    ${BDHASH}-install/INDEX-NEW || return 1
316948ffe56aSColin Percival
3170db6b0a61SColin Percival	# Install new files, delete old files, and update linker.hints
3171db6b0a61SColin Percival	install_files ${BDHASH}-install || return 1
317248ffe56aSColin Percival
317348ffe56aSColin Percival	# Rearrange bits to allow the installed updates to be rolled back
317448ffe56aSColin Percival	install_setup_rollback
317548ffe56aSColin Percival
317648ffe56aSColin Percival	echo " done."
317748ffe56aSColin Percival}
317848ffe56aSColin Percival
317948ffe56aSColin Percival# Rearrange bits to allow the previous set of updates to be rolled back next.
318048ffe56aSColin Percivalrollback_setup_rollback () {
318148ffe56aSColin Percival	if [ -L ${BDHASH}-rollback/rollback ]; then
318248ffe56aSColin Percival		mv ${BDHASH}-rollback/rollback rollback-tmp
318348ffe56aSColin Percival		rm -r ${BDHASH}-rollback/
318448ffe56aSColin Percival		rm ${BDHASH}-rollback
318548ffe56aSColin Percival		mv rollback-tmp ${BDHASH}-rollback
318648ffe56aSColin Percival	else
318748ffe56aSColin Percival		rm -r ${BDHASH}-rollback/
318848ffe56aSColin Percival		rm ${BDHASH}-rollback
318948ffe56aSColin Percival	fi
319048ffe56aSColin Percival}
319148ffe56aSColin Percival
3192db6b0a61SColin Percival# Install old files, delete new files, and update linker.hints
3193db6b0a61SColin Percivalrollback_files () {
31941ec4fb3aSColin Percival	# Install old shared library files which don't have the same path as
31951ec4fb3aSColin Percival	# a new shared library file.
31961ec4fb3aSColin Percival	grep -vE '^/boot/' $1/INDEX-NEW |
3197fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' |
31981ec4fb3aSColin Percival	    cut -f 1 -d '|' |
31991ec4fb3aSColin Percival	    sort > INDEX-NEW.libs.flist
3200db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
3201fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' |
32021ec4fb3aSColin Percival	    sort -k 1,1 -t '|' - |
32031ec4fb3aSColin Percival	    join -t '|' -v 1 - INDEX-NEW.libs.flist > INDEX-OLD
3204db6b0a61SColin Percival	install_from_index INDEX-OLD || return 1
3205db6b0a61SColin Percival
3206db6b0a61SColin Percival	# Deal with files which are neither kernel nor shared library
3207db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
3208fd0963d1SColin Percival	    grep -vE '/lib/.*\.so\.[0-9]+\|' > INDEX-OLD
3209db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-NEW |
3210fd0963d1SColin Percival	    grep -vE '/lib/.*\.so\.[0-9]+\|' > INDEX-NEW
3211db6b0a61SColin Percival	install_from_index INDEX-OLD || return 1
3212db6b0a61SColin Percival	install_delete INDEX-NEW INDEX-OLD || return 1
3213db6b0a61SColin Percival
32141ec4fb3aSColin Percival	# Install any old shared library files which we didn't install above.
32151ec4fb3aSColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
3216fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' |
32171ec4fb3aSColin Percival	    sort -k 1,1 -t '|' - |
32181ec4fb3aSColin Percival	    join -t '|' - INDEX-NEW.libs.flist > INDEX-OLD
32191ec4fb3aSColin Percival	install_from_index INDEX-OLD || return 1
32201ec4fb3aSColin Percival
3221db6b0a61SColin Percival	# Delete unneeded shared library files
3222db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
3223fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' > INDEX-OLD
3224db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-NEW |
3225fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' > INDEX-NEW
3226db6b0a61SColin Percival	install_delete INDEX-NEW INDEX-OLD || return 1
3227db6b0a61SColin Percival
3228db6b0a61SColin Percival	# Deal with kernel files
3229db6b0a61SColin Percival	grep -E '^/boot/' $1/INDEX-OLD > INDEX-OLD
3230db6b0a61SColin Percival	grep -E '^/boot/' $1/INDEX-NEW > INDEX-NEW
3231db6b0a61SColin Percival	install_from_index INDEX-OLD || return 1
3232db6b0a61SColin Percival	install_delete INDEX-NEW INDEX-OLD || return 1
3233db6b0a61SColin Percival	if [ -s INDEX-OLD -o -s INDEX-NEW ]; then
3234db6b0a61SColin Percival		kldxref -R /boot/ 2>/dev/null
3235db6b0a61SColin Percival	fi
3236db6b0a61SColin Percival
3237db6b0a61SColin Percival	# Remove temporary files
32380e0d8d5aSColin Percival	rm INDEX-OLD INDEX-NEW INDEX-NEW.libs.flist
3239db6b0a61SColin Percival}
3240db6b0a61SColin Percival
324148ffe56aSColin Percival# Actually rollback updates
324248ffe56aSColin Percivalrollback_run () {
324348ffe56aSColin Percival	echo -n "Uninstalling updates..."
324448ffe56aSColin Percival
324548ffe56aSColin Percival	# If there are updates waiting to be installed, remove them; we
324648ffe56aSColin Percival	# want the user to re-run 'fetch' after rolling back updates.
324748ffe56aSColin Percival	if [ -L ${BDHASH}-install ]; then
324848ffe56aSColin Percival		rm -r ${BDHASH}-install/
324948ffe56aSColin Percival		rm ${BDHASH}-install
325048ffe56aSColin Percival	fi
325148ffe56aSColin Percival
325248ffe56aSColin Percival	# Make sure we have all the files we should have
325348ffe56aSColin Percival	install_verify ${BDHASH}-rollback/INDEX-NEW	\
325448ffe56aSColin Percival	    ${BDHASH}-rollback/INDEX-OLD || return 1
325548ffe56aSColin Percival
325648ffe56aSColin Percival	# Remove system immutable flag from files
325748ffe56aSColin Percival	install_unschg ${BDHASH}-rollback/INDEX-NEW	\
325848ffe56aSColin Percival	    ${BDHASH}-rollback/INDEX-OLD || return 1
325948ffe56aSColin Percival
3260db6b0a61SColin Percival	# Install old files, delete new files, and update linker.hints
3261db6b0a61SColin Percival	rollback_files ${BDHASH}-rollback || return 1
326248ffe56aSColin Percival
326348ffe56aSColin Percival	# Remove the rollback directory and the symlink pointing to it; and
326448ffe56aSColin Percival	# rearrange bits to allow the previous set of updates to be rolled
326548ffe56aSColin Percival	# back next.
326648ffe56aSColin Percival	rollback_setup_rollback
326748ffe56aSColin Percival
326848ffe56aSColin Percival	echo " done."
326948ffe56aSColin Percival}
327048ffe56aSColin Percival
327108e23beeSColin Percival# Compare INDEX-ALL and INDEX-PRESENT and print warnings about differences.
327208e23beeSColin PercivalIDS_compare () {
3273bb10a826SColin Percival	# Get all the lines which mismatch in something other than file
3274bb10a826SColin Percival	# flags.  We ignore file flags because sysinstall doesn't seem to
3275bb10a826SColin Percival	# set them when it installs FreeBSD; warning about these adds a
3276bb10a826SColin Percival	# very large amount of noise.
3277bb10a826SColin Percival	cut -f 1-5,7-8 -d '|' $1 > $1.noflags
3278bb10a826SColin Percival	sort -k 1,1 -t '|' $1.noflags > $1.sorted
3279bb10a826SColin Percival	cut -f 1-5,7-8 -d '|' $2 |
3280bb10a826SColin Percival	    comm -13 $1.noflags - |
3281bb10a826SColin Percival	    fgrep -v '|-|||||' |
328208e23beeSColin Percival	    sort -k 1,1 -t '|' |
328308e23beeSColin Percival	    join -t '|' $1.sorted - > INDEX-NOTMATCHING
328408e23beeSColin Percival
328508e23beeSColin Percival	# Ignore files which match IDSIGNOREPATHS.
328608e23beeSColin Percival	for X in ${IDSIGNOREPATHS}; do
328708e23beeSColin Percival		grep -E "^${X}" INDEX-NOTMATCHING
328808e23beeSColin Percival	done |
328908e23beeSColin Percival	    sort -u |
329008e23beeSColin Percival	    comm -13 - INDEX-NOTMATCHING > INDEX-NOTMATCHING.tmp
329108e23beeSColin Percival	mv INDEX-NOTMATCHING.tmp INDEX-NOTMATCHING
329208e23beeSColin Percival
329308e23beeSColin Percival	# Go through the lines and print warnings.
3294aa60062eSColin Percival	local IFS='|'
3295aa60062eSColin Percival	while read FPATH TYPE OWNER GROUP PERM HASH LINK P_TYPE P_OWNER P_GROUP P_PERM P_HASH P_LINK; do
329608e23beeSColin Percival		# Warn about different object types.
329708e23beeSColin Percival		if ! [ "${TYPE}" = "${P_TYPE}" ]; then
329808e23beeSColin Percival			echo -n "${FPATH} is a "
329908e23beeSColin Percival			case "${P_TYPE}" in
330008e23beeSColin Percival			f)	echo -n "regular file, "
330108e23beeSColin Percival				;;
330208e23beeSColin Percival			d)	echo -n "directory, "
330308e23beeSColin Percival				;;
330408e23beeSColin Percival			L)	echo -n "symlink, "
330508e23beeSColin Percival				;;
330608e23beeSColin Percival			esac
330708e23beeSColin Percival			echo -n "but should be a "
330808e23beeSColin Percival			case "${TYPE}" in
330908e23beeSColin Percival			f)	echo -n "regular file."
331008e23beeSColin Percival				;;
331108e23beeSColin Percival			d)	echo -n "directory."
331208e23beeSColin Percival				;;
331308e23beeSColin Percival			L)	echo -n "symlink."
331408e23beeSColin Percival				;;
331508e23beeSColin Percival			esac
331608e23beeSColin Percival			echo
331708e23beeSColin Percival
331808e23beeSColin Percival			# Skip other tests, since they don't make sense if
331908e23beeSColin Percival			# we're comparing different object types.
332008e23beeSColin Percival			continue
332108e23beeSColin Percival		fi
332208e23beeSColin Percival
332308e23beeSColin Percival		# Warn about different owners.
332408e23beeSColin Percival		if ! [ "${OWNER}" = "${P_OWNER}" ]; then
332508e23beeSColin Percival			echo -n "${FPATH} is owned by user id ${P_OWNER}, "
332608e23beeSColin Percival			echo "but should be owned by user id ${OWNER}."
332708e23beeSColin Percival		fi
332808e23beeSColin Percival
332908e23beeSColin Percival		# Warn about different groups.
333008e23beeSColin Percival		if ! [ "${GROUP}" = "${P_GROUP}" ]; then
333108e23beeSColin Percival			echo -n "${FPATH} is owned by group id ${P_GROUP}, "
333208e23beeSColin Percival			echo "but should be owned by group id ${GROUP}."
333308e23beeSColin Percival		fi
333408e23beeSColin Percival
333508e23beeSColin Percival		# Warn about different permissions.  We do not warn about
333608e23beeSColin Percival		# different permissions on symlinks, since some archivers
333708e23beeSColin Percival		# don't extract symlink permissions correctly and they are
333808e23beeSColin Percival		# ignored anyway.
333908e23beeSColin Percival		if ! [ "${PERM}" = "${P_PERM}" ] &&
334008e23beeSColin Percival		    ! [ "${TYPE}" = "L" ]; then
334108e23beeSColin Percival			echo -n "${FPATH} has ${P_PERM} permissions, "
334208e23beeSColin Percival			echo "but should have ${PERM} permissions."
334308e23beeSColin Percival		fi
334408e23beeSColin Percival
334508e23beeSColin Percival		# Warn about different file hashes / symlink destinations.
334608e23beeSColin Percival		if ! [ "${HASH}" = "${P_HASH}" ]; then
334708e23beeSColin Percival			if [ "${TYPE}" = "L" ]; then
334808e23beeSColin Percival				echo -n "${FPATH} is a symlink to ${P_HASH}, "
334908e23beeSColin Percival				echo "but should be a symlink to ${HASH}."
335008e23beeSColin Percival			fi
335108e23beeSColin Percival			if [ "${TYPE}" = "f" ]; then
335208e23beeSColin Percival				echo -n "${FPATH} has SHA256 hash ${P_HASH}, "
335308e23beeSColin Percival				echo "but should have SHA256 hash ${HASH}."
335408e23beeSColin Percival			fi
335508e23beeSColin Percival		fi
335608e23beeSColin Percival
335708e23beeSColin Percival		# We don't warn about different hard links, since some
335808e23beeSColin Percival		# some archivers break hard links, and as long as the
335908e23beeSColin Percival		# underlying data is correct they really don't matter.
336008e23beeSColin Percival	done < INDEX-NOTMATCHING
336108e23beeSColin Percival
336208e23beeSColin Percival	# Clean up
3363bb10a826SColin Percival	rm $1 $1.noflags $1.sorted $2 INDEX-NOTMATCHING
336408e23beeSColin Percival}
336508e23beeSColin Percival
336608e23beeSColin Percival# Do the work involved in comparing the system to a "known good" index
336708e23beeSColin PercivalIDS_run () {
336808e23beeSColin Percival	workdir_init || return 1
336908e23beeSColin Percival
337008e23beeSColin Percival	# Prepare the mirror list.
337108e23beeSColin Percival	fetch_pick_server_init && fetch_pick_server
337208e23beeSColin Percival
337308e23beeSColin Percival	# Try to fetch the public key until we run out of servers.
337408e23beeSColin Percival	while ! fetch_key; do
337508e23beeSColin Percival		fetch_pick_server || return 1
337608e23beeSColin Percival	done
337708e23beeSColin Percival
337808e23beeSColin Percival	# Try to fetch the metadata index signature ("tag") until we run
337908e23beeSColin Percival	# out of available servers; and sanity check the downloaded tag.
338008e23beeSColin Percival	while ! fetch_tag; do
338108e23beeSColin Percival		fetch_pick_server || return 1
338208e23beeSColin Percival	done
338308e23beeSColin Percival	fetch_tagsanity || return 1
338408e23beeSColin Percival
338508e23beeSColin Percival	# Fetch INDEX-OLD and INDEX-ALL.
338608e23beeSColin Percival	fetch_metadata INDEX-OLD INDEX-ALL || return 1
338708e23beeSColin Percival
338808e23beeSColin Percival	# Generate filtered INDEX-OLD and INDEX-ALL files containing only
338908e23beeSColin Percival	# the components we want and without anything marked as "Ignore".
339008e23beeSColin Percival	fetch_filter_metadata INDEX-OLD || return 1
339108e23beeSColin Percival	fetch_filter_metadata INDEX-ALL || return 1
339208e23beeSColin Percival
339308e23beeSColin Percival	# Merge the INDEX-OLD and INDEX-ALL files into INDEX-ALL.
339408e23beeSColin Percival	sort INDEX-OLD INDEX-ALL > INDEX-ALL.tmp
339508e23beeSColin Percival	mv INDEX-ALL.tmp INDEX-ALL
339608e23beeSColin Percival	rm INDEX-OLD
339708e23beeSColin Percival
339808e23beeSColin Percival	# Translate /boot/${KERNCONF} to ${KERNELDIR}
339908e23beeSColin Percival	fetch_filter_kernel_names INDEX-ALL ${KERNCONF}
340008e23beeSColin Percival
340108e23beeSColin Percival	# Inspect the system and generate an INDEX-PRESENT file.
340208e23beeSColin Percival	fetch_inspect_system INDEX-ALL INDEX-PRESENT /dev/null || return 1
340308e23beeSColin Percival
340408e23beeSColin Percival	# Compare INDEX-ALL and INDEX-PRESENT and print warnings about any
340508e23beeSColin Percival	# differences.
340608e23beeSColin Percival	IDS_compare INDEX-ALL INDEX-PRESENT
340708e23beeSColin Percival}
340808e23beeSColin Percival
340948ffe56aSColin Percival#### Main functions -- call parameter-handling and core functions
341048ffe56aSColin Percival
341148ffe56aSColin Percival# Using the command line, configuration file, and defaults,
341248ffe56aSColin Percival# set all the parameters which are needed later.
341348ffe56aSColin Percivalget_params () {
341448ffe56aSColin Percival	init_params
341548ffe56aSColin Percival	parse_cmdline $@
341648ffe56aSColin Percival	parse_conffile
341748ffe56aSColin Percival	default_params
341848ffe56aSColin Percival}
341948ffe56aSColin Percival
342048ffe56aSColin Percival# Fetch command.  Make sure that we're being called
342148ffe56aSColin Percival# interactively, then run fetch_check_params and fetch_run
342248ffe56aSColin Percivalcmd_fetch () {
34239a63bbc9SColin Percival	finalize_components_config ${COMPONENTS}
34248bf2dcceSAllan Jude	if [ ! -t 0 -a $NOTTYOK -eq 0 ]; then
342548ffe56aSColin Percival		echo -n "`basename $0` fetch should not "
342648ffe56aSColin Percival		echo "be run non-interactively."
342748ffe56aSColin Percival		echo "Run `basename $0` cron instead."
342848ffe56aSColin Percival		exit 1
342948ffe56aSColin Percival	fi
343048ffe56aSColin Percival	fetch_check_params
343148ffe56aSColin Percival	fetch_run || exit 1
343233bd05c3SGuangyuan Yang	ISFETCHED=1
343348ffe56aSColin Percival}
343448ffe56aSColin Percival
343548ffe56aSColin Percival# Cron command.  Make sure the parameters are sensible; wait
343648ffe56aSColin Percival# rand(3600) seconds; then fetch updates.  While fetching updates,
343748ffe56aSColin Percival# send output to a temporary file; only print that file if the
343848ffe56aSColin Percival# fetching failed.
343948ffe56aSColin Percivalcmd_cron () {
344048ffe56aSColin Percival	fetch_check_params
344148ffe56aSColin Percival	sleep `jot -r 1 0 3600`
344248ffe56aSColin Percival
344348ffe56aSColin Percival	TMPFILE=`mktemp /tmp/freebsd-update.XXXXXX` || exit 1
34449a63bbc9SColin Percival	finalize_components_config ${COMPONENTS} >> ${TMPFILE}
344548ffe56aSColin Percival	if ! fetch_run >> ${TMPFILE} ||
344648ffe56aSColin Percival	    ! grep -q "No updates needed" ${TMPFILE} ||
344748ffe56aSColin Percival	    [ ${VERBOSELEVEL} = "debug" ]; then
344848ffe56aSColin Percival		mail -s "`hostname` security updates" ${MAILTO} < ${TMPFILE}
344948ffe56aSColin Percival	fi
345048ffe56aSColin Percival
345148ffe56aSColin Percival	rm ${TMPFILE}
345248ffe56aSColin Percival}
345348ffe56aSColin Percival
3454db6b0a61SColin Percival# Fetch files for upgrading to a new release.
3455db6b0a61SColin Percivalcmd_upgrade () {
34569a63bbc9SColin Percival	finalize_components_config ${COMPONENTS}
3457db6b0a61SColin Percival	upgrade_check_params
3458db6b0a61SColin Percival	upgrade_run || exit 1
3459db6b0a61SColin Percival}
3460db6b0a61SColin Percival
3461101d33b8SMichael Gmelin# Check if there are fetched updates ready to install.
3462101d33b8SMichael Gmelin# Chdir into the working directory.
34638cfda118SMichael Gmelincmd_updatesready () {
34649a63bbc9SColin Percival	finalize_components_config ${COMPONENTS}
3465101d33b8SMichael Gmelin	# Check if working directory exists (if not, no updates pending)
3466101d33b8SMichael Gmelin	if ! [ -e "${WORKDIR}" ]; then
3467101d33b8SMichael Gmelin		echo "No updates are available to install."
3468101d33b8SMichael Gmelin		exit 2
3469101d33b8SMichael Gmelin	fi
3470101d33b8SMichael Gmelin
3471101d33b8SMichael Gmelin	# Change into working directory (fail if no permission/directory etc.)
3472101d33b8SMichael Gmelin	cd ${WORKDIR} || exit 1
3473101d33b8SMichael Gmelin
34748cfda118SMichael Gmelin	# Construct a unique name from ${BASEDIR}
34758cfda118SMichael Gmelin	BDHASH=`echo ${BASEDIR} | sha256 -q`
34768cfda118SMichael Gmelin
34778cfda118SMichael Gmelin	# Check that we have updates ready to install
34788cfda118SMichael Gmelin	if ! [ -L ${BDHASH}-install ]; then
34798cfda118SMichael Gmelin		echo "No updates are available to install."
34808cfda118SMichael Gmelin		exit 2
34818cfda118SMichael Gmelin	fi
34828cfda118SMichael Gmelin
34838cfda118SMichael Gmelin	echo "There are updates available to install."
34848cfda118SMichael Gmelin	echo "Run '$0 install' to proceed."
34858cfda118SMichael Gmelin}
34868cfda118SMichael Gmelin
348748ffe56aSColin Percival# Install downloaded updates.
348848ffe56aSColin Percivalcmd_install () {
34899a63bbc9SColin Percival	finalize_components_config ${COMPONENTS}
349048ffe56aSColin Percival	install_check_params
3491f28f1389SDave Fullard	install_create_be
349248ffe56aSColin Percival	install_run || exit 1
349348ffe56aSColin Percival}
349448ffe56aSColin Percival
349548ffe56aSColin Percival# Rollback most recently installed updates.
349648ffe56aSColin Percivalcmd_rollback () {
34979a63bbc9SColin Percival	finalize_components_config ${COMPONENTS}
349848ffe56aSColin Percival	rollback_check_params
349948ffe56aSColin Percival	rollback_run || exit 1
350048ffe56aSColin Percival}
350148ffe56aSColin Percival
350208e23beeSColin Percival# Compare system against a "known good" index.
350308e23beeSColin Percivalcmd_IDS () {
35049a63bbc9SColin Percival	finalize_components_config ${COMPONENTS}
350508e23beeSColin Percival	IDS_check_params
350608e23beeSColin Percival	IDS_run || exit 1
350708e23beeSColin Percival}
350808e23beeSColin Percival
35098cfda118SMichael Gmelin# Output configuration.
35108cfda118SMichael Gmelincmd_showconfig () {
35119a63bbc9SColin Percival	finalize_components_config ${COMPONENTS}
35128cfda118SMichael Gmelin	for X in ${CONFIGOPTIONS}; do
35138cfda118SMichael Gmelin		echo $X=$(eval echo \$${X})
35148cfda118SMichael Gmelin	done
35158cfda118SMichael Gmelin}
35168cfda118SMichael Gmelin
351748ffe56aSColin Percival#### Entry point
351848ffe56aSColin Percival
351948ffe56aSColin Percival# Make sure we find utilities from the base system
352048ffe56aSColin Percivalexport PATH=/sbin:/bin:/usr/sbin:/usr/bin:${PATH}
352148ffe56aSColin Percival
35229c990fb2SGordon Tetlow# Set a pager if the user doesn't
35239c990fb2SGordon Tetlowif [ -z "$PAGER" ]; then
352447cc9ee1SAlan Somers	PAGER=/usr/bin/less
35259c990fb2SGordon Tetlowfi
35269c990fb2SGordon Tetlow
3527f2890dbdSColin Percival# Set LC_ALL in order to avoid problems with character ranges like [A-Z].
3528f2890dbdSColin Percivalexport LC_ALL=C
3529f2890dbdSColin Percival
3530e093c61bSEd Maste# Clear environment variables that may affect operation of tools that we use.
3531e093c61bSEd Masteunset GREP_OPTIONS
3532e093c61bSEd Maste
353348ffe56aSColin Percivalget_params $@
353448ffe56aSColin Percivalfor COMMAND in ${COMMANDS}; do
353548ffe56aSColin Percival	cmd_${COMMAND}
353648ffe56aSColin Percivaldone
3537