xref: /freebsd/usr.sbin/freebsd-update/freebsd-update.sh (revision 856e158dc4aa5e43f0f15fcd3089fc0d71861b0e)
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
658bc0c6c9cSFernando Apesteguía# Check if there are any kernel modules installed from ports.
659bc0c6c9cSFernando Apesteguía# In that case warn the user that a rebuild from ports (i.e. not from
660bc0c6c9cSFernando Apesteguía# packages) might need necessary for the modules to work in the new release.
661bc0c6c9cSFernando Apesteguíaupgrade_check_kmod_ports() {
662bc0c6c9cSFernando Apesteguía	local mod_name
663bc0c6c9cSFernando Apesteguía	local modules
664bc0c6c9cSFernando Apesteguía	local pattern
665bc0c6c9cSFernando Apesteguía	local pkg_name
666bc0c6c9cSFernando Apesteguía	local port_name
667bc0c6c9cSFernando Apesteguía	local report
668bc0c6c9cSFernando Apesteguía	local w
669bc0c6c9cSFernando Apesteguía
670d76ef58dSZhenlei Huang	if ! pkg -N 2>/dev/null; then
671bc0c6c9cSFernando Apesteguía		echo "Skipping kernel modules check. pkg(8) not present."
672bc0c6c9cSFernando Apesteguía		return
673bc0c6c9cSFernando Apesteguía	fi
674bc0c6c9cSFernando Apesteguía
675bc0c6c9cSFernando Apesteguía	# Most modules are in /boot/modules but we should actually look
676d3b6d70eSFernando Apesteguía	# in every module_path passed to the kernel:
677d3b6d70eSFernando Apesteguía	pattern=$(sysctl -n kern.module_path | tr ";" "|")
678bc0c6c9cSFernando Apesteguía
679bc0c6c9cSFernando Apesteguía	if [ -z "${pattern}" ]; then
680d3b6d70eSFernando Apesteguía		echo "Empty kern.module_path sysctl. This should not happen."
681d3b6d70eSFernando Apesteguía		echo "Aborting check of kernel modules installed from ports."
682d3b6d70eSFernando Apesteguía		return
683bc0c6c9cSFernando Apesteguía	fi
684bc0c6c9cSFernando Apesteguía
685bc0c6c9cSFernando Apesteguía	# Check the pkg database for modules installed in those directories
686bc0c6c9cSFernando Apesteguía	modules=$(pkg query '%Fp' | grep -E "${pattern}")
687bc0c6c9cSFernando Apesteguía
688bc0c6c9cSFernando Apesteguía	if [ -z "${modules}" ]; then
689bc0c6c9cSFernando Apesteguía		return
690bc0c6c9cSFernando Apesteguía	fi
691bc0c6c9cSFernando Apesteguía
692bc0c6c9cSFernando Apesteguía	echo -e "\n"
693bc0c6c9cSFernando Apesteguía	echo "The following modules have been installed from packages."
694bc0c6c9cSFernando Apesteguía	echo "As a consequence they might not work when performing a major or minor upgrade."
695bc0c6c9cSFernando Apesteguía	echo -e "It is advised to rebuild these ports:\n"
696bc0c6c9cSFernando Apesteguía
697bc0c6c9cSFernando Apesteguía
698bc0c6c9cSFernando Apesteguía	report="Module Package Port\n------ ------- ----\n"
699bc0c6c9cSFernando Apesteguía	for module in ${modules}; do
700bc0c6c9cSFernando Apesteguía		w=$(pkg which "${module}")
701bc0c6c9cSFernando Apesteguía		mod_name=$(echo "${w}" | awk '{print $1;}')
702bc0c6c9cSFernando Apesteguía		pkg_name=$(echo "${w}" | awk '{print $6;}')
703bc0c6c9cSFernando Apesteguía		port_name=$(pkg info -o "${pkg_name}" | awk '{print $2;}')
704bc0c6c9cSFernando Apesteguía		report="${report}${mod_name} ${pkg_name} ${port_name}\n"
705bc0c6c9cSFernando Apesteguía	done
706bc0c6c9cSFernando Apesteguía
707bc0c6c9cSFernando Apesteguía	echo -e "${report}" | column -t
708bc0c6c9cSFernando Apesteguía	echo -e "\n"
709bc0c6c9cSFernando Apesteguía}
710bc0c6c9cSFernando Apesteguía
71148ffe56aSColin Percival# Perform sanity checks and set some final parameters
71248ffe56aSColin Percival# in preparation for fetching files.  Figure out which
71348ffe56aSColin Percival# set of updates should be downloaded: If the user is
71448ffe56aSColin Percival# running *-p[0-9]+, strip off the last part; if the
71548ffe56aSColin Percival# user is running -SECURITY, call it -RELEASE.  Chdir
71648ffe56aSColin Percival# into the working directory.
717211f2ba0SColin Percivalfetchupgrade_check_params () {
71848ffe56aSColin Percival	export HTTP_USER_AGENT="freebsd-update (${COMMAND}, `uname -r`)"
71948ffe56aSColin Percival
72048ffe56aSColin Percival	_SERVERNAME_z=\
72148ffe56aSColin Percival"SERVERNAME must be given via command line or configuration file."
72248ffe56aSColin Percival	_KEYPRINT_z="Key must be given via -k option or configuration file."
72348ffe56aSColin Percival	_KEYPRINT_bad="Invalid key fingerprint: "
72448ffe56aSColin Percival	_WORKDIR_bad="Directory does not exist or is not writable: "
725f88076f0SMark Felder	_WORKDIR_bad2="Directory is not on a persistent filesystem: "
72648ffe56aSColin Percival
72748ffe56aSColin Percival	if [ -z "${SERVERNAME}" ]; then
72848ffe56aSColin Percival		echo -n "`basename $0`: "
72948ffe56aSColin Percival		echo "${_SERVERNAME_z}"
73048ffe56aSColin Percival		exit 1
73148ffe56aSColin Percival	fi
73248ffe56aSColin Percival	if [ -z "${KEYPRINT}" ]; then
73348ffe56aSColin Percival		echo -n "`basename $0`: "
73448ffe56aSColin Percival		echo "${_KEYPRINT_z}"
73548ffe56aSColin Percival		exit 1
73648ffe56aSColin Percival	fi
73748ffe56aSColin Percival	if ! echo "${KEYPRINT}" | grep -qE "^[0-9a-f]{64}$"; then
73848ffe56aSColin Percival		echo -n "`basename $0`: "
73948ffe56aSColin Percival		echo -n "${_KEYPRINT_bad}"
74048ffe56aSColin Percival		echo ${KEYPRINT}
74148ffe56aSColin Percival		exit 1
74248ffe56aSColin Percival	fi
74348ffe56aSColin Percival	if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then
74448ffe56aSColin Percival		echo -n "`basename $0`: "
74548ffe56aSColin Percival		echo -n "${_WORKDIR_bad}"
74648ffe56aSColin Percival		echo ${WORKDIR}
74748ffe56aSColin Percival		exit 1
74848ffe56aSColin Percival	fi
749dfe9215bSMark Felder	case `df -T ${WORKDIR}` in */dev/md[0-9]* | *tmpfs*)
750f88076f0SMark Felder		echo -n "`basename $0`: "
751f88076f0SMark Felder		echo -n "${_WORKDIR_bad2}"
752f88076f0SMark Felder		echo ${WORKDIR}
753f88076f0SMark Felder		exit 1
754dfe9215bSMark Felder		;;
755dfe9215bSMark Felder	esac
756a2356430SColin Percival	chmod 700 ${WORKDIR}
75748ffe56aSColin Percival	cd ${WORKDIR} || exit 1
75848ffe56aSColin Percival
75948ffe56aSColin Percival	# Generate release number.  The s/SECURITY/RELEASE/ bit exists
76048ffe56aSColin Percival	# to provide an upgrade path for FreeBSD Update 1.x users, since
76148ffe56aSColin Percival	# the kernels provided by FreeBSD Update 1.x are always labelled
76248ffe56aSColin Percival	# as X.Y-SECURITY.
76348ffe56aSColin Percival	RELNUM=`uname -r |
76448ffe56aSColin Percival	    sed -E 's,-p[0-9]+,,' |
76548ffe56aSColin Percival	    sed -E 's,-SECURITY,-RELEASE,'`
76648ffe56aSColin Percival	ARCH=`uname -m`
76748ffe56aSColin Percival	FETCHDIR=${RELNUM}/${ARCH}
768db6b0a61SColin Percival	PATCHDIR=${RELNUM}/${ARCH}/bp
76948ffe56aSColin Percival
770d308a8bfSEd Maste	# Disallow upgrade from a version that is not a release
771d308a8bfSEd Maste	case ${RELNUM} in
772d308a8bfSEd Maste	*-RELEASE | *-ALPHA*  | *-BETA* | *-RC*)
773d308a8bfSEd Maste		;;
774d308a8bfSEd Maste	*)
7750d5c5243SEd Maste		echo -n "`basename $0`: "
7760d5c5243SEd Maste		cat <<- EOF
777d308a8bfSEd Maste			Cannot upgrade from a version that is not a release
778d308a8bfSEd Maste			(including alpha, beta and release candidates)
779d308a8bfSEd Maste			using `basename $0`. Instead, FreeBSD can be directly
780d308a8bfSEd Maste			upgraded by source or upgraded to a RELEASE/RELENG version
781d308a8bfSEd Maste			prior to running `basename $0`.
782d308a8bfSEd Maste			Currently running: ${RELNUM}
7830d5c5243SEd Maste		EOF
7840d5c5243SEd Maste		exit 1
785d308a8bfSEd Maste		;;
786d308a8bfSEd Maste	esac
7870d5c5243SEd Maste
78848ffe56aSColin Percival	# Figure out what directory contains the running kernel
78948ffe56aSColin Percival	BOOTFILE=`sysctl -n kern.bootfile`
79048ffe56aSColin Percival	KERNELDIR=${BOOTFILE%/kernel}
79148ffe56aSColin Percival	if ! [ -d ${KERNELDIR} ]; then
79248ffe56aSColin Percival		echo "Cannot identify running kernel"
79348ffe56aSColin Percival		exit 1
79448ffe56aSColin Percival	fi
79548ffe56aSColin Percival
7962c434b2cSColin Percival	# Figure out what kernel configuration is running.  We start with
7972c434b2cSColin Percival	# the output of `uname -i`, and then make the following adjustments:
7982c434b2cSColin Percival	# 1. Replace "SMP-GENERIC" with "SMP".  Why the SMP kernel config
7992c434b2cSColin Percival	# file says "ident SMP-GENERIC", I don't know...
8002c434b2cSColin Percival	# 2. If the kernel claims to be GENERIC _and_ ${ARCH} is "amd64"
8012c434b2cSColin Percival	# _and_ `sysctl kern.version` contains a line which ends "/SMP", then
8022c434b2cSColin Percival	# we're running an SMP kernel.  This mis-identification is a bug
8032c434b2cSColin Percival	# which was fixed in 6.2-STABLE.
8042c434b2cSColin Percival	KERNCONF=`uname -i`
8052c434b2cSColin Percival	if [ ${KERNCONF} = "SMP-GENERIC" ]; then
8062c434b2cSColin Percival		KERNCONF=SMP
8072c434b2cSColin Percival	fi
8082c434b2cSColin Percival	if [ ${KERNCONF} = "GENERIC" ] && [ ${ARCH} = "amd64" ]; then
8092c434b2cSColin Percival		if sysctl kern.version | grep -qE '/SMP$'; then
8102c434b2cSColin Percival			KERNCONF=SMP
8112c434b2cSColin Percival		fi
8122c434b2cSColin Percival	fi
8132c434b2cSColin Percival
81448ffe56aSColin Percival	# Define some paths
81548ffe56aSColin Percival	BSPATCH=/usr/bin/bspatch
81648ffe56aSColin Percival	SHA256=/sbin/sha256
81748ffe56aSColin Percival	PHTTPGET=/usr/libexec/phttpget
81848ffe56aSColin Percival
81948ffe56aSColin Percival	# Set up variables relating to VERBOSELEVEL
82048ffe56aSColin Percival	fetch_setup_verboselevel
82148ffe56aSColin Percival
82248ffe56aSColin Percival	# Construct a unique name from ${BASEDIR}
82348ffe56aSColin Percival	BDHASH=`echo ${BASEDIR} | sha256 -q`
82448ffe56aSColin Percival}
82548ffe56aSColin Percival
826211f2ba0SColin Percival# Perform sanity checks etc. before fetching updates.
827211f2ba0SColin Percivalfetch_check_params () {
828211f2ba0SColin Percival	fetchupgrade_check_params
829211f2ba0SColin Percival
830211f2ba0SColin Percival	if ! [ -z "${TARGETRELEASE}" ]; then
831211f2ba0SColin Percival		echo -n "`basename $0`: "
83259b02bb4SMichael Osipov		echo -n "'-r' option is meaningless with 'fetch' command.  "
833211f2ba0SColin Percival		echo "(Did you mean 'upgrade' instead?)"
834211f2ba0SColin Percival		exit 1
835211f2ba0SColin Percival	fi
8368935f242SAllan Jude
8378935f242SAllan Jude	# Check that we have updates ready to install
8388bf2dcceSAllan Jude	if [ -f ${BDHASH}-install/kerneldone -a $FORCEFETCH -eq 0 ]; then
8398935f242SAllan Jude		echo "You have a partially completed upgrade pending"
84059b02bb4SMichael Osipov		echo "Run '`basename $0` [options] install' first."
84159b02bb4SMichael Osipov		echo "Run '`basename $0` [options] fetch -F' to proceed anyway."
8428935f242SAllan Jude		exit 1
8438935f242SAllan Jude	fi
844211f2ba0SColin Percival}
845211f2ba0SColin Percival
846db6b0a61SColin Percival# Perform sanity checks etc. before fetching upgrades.
847db6b0a61SColin Percivalupgrade_check_params () {
848211f2ba0SColin Percival	fetchupgrade_check_params
849db6b0a61SColin Percival
850db6b0a61SColin Percival	# Unless set otherwise, we're upgrading to the same kernel config.
851db6b0a61SColin Percival	NKERNCONF=${KERNCONF}
852db6b0a61SColin Percival
853db6b0a61SColin Percival	# We need TARGETRELEASE set
85459b02bb4SMichael Osipov	_TARGETRELEASE_z="Release target must be specified via '-r' option."
855db6b0a61SColin Percival	if [ -z "${TARGETRELEASE}" ]; then
856db6b0a61SColin Percival		echo -n "`basename $0`: "
857db6b0a61SColin Percival		echo "${_TARGETRELEASE_z}"
858db6b0a61SColin Percival		exit 1
859db6b0a61SColin Percival	fi
860db6b0a61SColin Percival
861db6b0a61SColin Percival	# The target release should be != the current release.
862db6b0a61SColin Percival	if [ "${TARGETRELEASE}" = "${RELNUM}" ]; then
863db6b0a61SColin Percival		echo -n "`basename $0`: "
864db6b0a61SColin Percival		echo "Cannot upgrade from ${RELNUM} to itself"
865db6b0a61SColin Percival		exit 1
866db6b0a61SColin Percival	fi
867db6b0a61SColin Percival
868db6b0a61SColin Percival	# Turning off AllowAdd or AllowDelete is a bad idea for upgrades.
869db6b0a61SColin Percival	if [ "${ALLOWADD}" = "no" ]; then
870db6b0a61SColin Percival		echo -n "`basename $0`: "
871db6b0a61SColin Percival		echo -n "WARNING: \"AllowAdd no\" is a bad idea "
872db6b0a61SColin Percival		echo "when upgrading between releases."
873db6b0a61SColin Percival		echo
874db6b0a61SColin Percival	fi
875db6b0a61SColin Percival	if [ "${ALLOWDELETE}" = "no" ]; then
876db6b0a61SColin Percival		echo -n "`basename $0`: "
877db6b0a61SColin Percival		echo -n "WARNING: \"AllowDelete no\" is a bad idea "
878db6b0a61SColin Percival		echo "when upgrading between releases."
879db6b0a61SColin Percival		echo
880db6b0a61SColin Percival	fi
881db6b0a61SColin Percival
882db6b0a61SColin Percival	# Set EDITOR to /usr/bin/vi if it isn't already set
883db6b0a61SColin Percival	: ${EDITOR:='/usr/bin/vi'}
884db6b0a61SColin Percival}
885db6b0a61SColin Percival
88648ffe56aSColin Percival# Perform sanity checks and set some final parameters in
88748ffe56aSColin Percival# preparation for installing updates.
88848ffe56aSColin Percivalinstall_check_params () {
88948ffe56aSColin Percival	# Check that we are root.  All sorts of things won't work otherwise.
89048ffe56aSColin Percival	if [ `id -u` != 0 ]; then
89148ffe56aSColin Percival		echo "You must be root to run this."
89248ffe56aSColin Percival		exit 1
89348ffe56aSColin Percival	fi
89448ffe56aSColin Percival
8952328d598SColin Percival	# Check that securelevel <= 0.  Otherwise we can't update schg files.
8962328d598SColin Percival	if [ `sysctl -n kern.securelevel` -gt 0 ]; then
8972328d598SColin Percival		echo "Updates cannot be installed when the system securelevel"
8982328d598SColin Percival		echo "is greater than zero."
8992328d598SColin Percival		exit 1
9002328d598SColin Percival	fi
9012328d598SColin Percival
90248ffe56aSColin Percival	# Check that we have a working directory
90348ffe56aSColin Percival	_WORKDIR_bad="Directory does not exist or is not writable: "
90448ffe56aSColin Percival	if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then
90548ffe56aSColin Percival		echo -n "`basename $0`: "
90648ffe56aSColin Percival		echo -n "${_WORKDIR_bad}"
90748ffe56aSColin Percival		echo ${WORKDIR}
90848ffe56aSColin Percival		exit 1
90948ffe56aSColin Percival	fi
91048ffe56aSColin Percival	cd ${WORKDIR} || exit 1
91148ffe56aSColin Percival
91248ffe56aSColin Percival	# Construct a unique name from ${BASEDIR}
91348ffe56aSColin Percival	BDHASH=`echo ${BASEDIR} | sha256 -q`
91448ffe56aSColin Percival
91548ffe56aSColin Percival	# Check that we have updates ready to install
91648ffe56aSColin Percival	if ! [ -L ${BDHASH}-install ]; then
91748ffe56aSColin Percival		echo "No updates are available to install."
91833bd05c3SGuangyuan Yang		if [ $ISFETCHED -eq 0 ]; then
91959b02bb4SMichael Osipov			echo "Run '`basename $0` [options] fetch' first."
9208cfda118SMichael Gmelin			exit 2
92133bd05c3SGuangyuan Yang		fi
92233bd05c3SGuangyuan Yang		exit 0
92348ffe56aSColin Percival	fi
92448ffe56aSColin Percival	if ! [ -f ${BDHASH}-install/INDEX-OLD ] ||
92548ffe56aSColin Percival	    ! [ -f ${BDHASH}-install/INDEX-NEW ]; then
92648ffe56aSColin Percival		echo "Update manifest is corrupt -- this should never happen."
92759b02bb4SMichael Osipov		echo "Re-run '`basename $0` [options] fetch'."
92848ffe56aSColin Percival		exit 1
92948ffe56aSColin Percival	fi
93023d827efSSimon L. B. Nielsen
93123d827efSSimon L. B. Nielsen	# Figure out what directory contains the running kernel
93223d827efSSimon L. B. Nielsen	BOOTFILE=`sysctl -n kern.bootfile`
93323d827efSSimon L. B. Nielsen	KERNELDIR=${BOOTFILE%/kernel}
93423d827efSSimon L. B. Nielsen	if ! [ -d ${KERNELDIR} ]; then
93523d827efSSimon L. B. Nielsen		echo "Cannot identify running kernel"
93623d827efSSimon L. B. Nielsen		exit 1
93723d827efSSimon L. B. Nielsen	fi
93848ffe56aSColin Percival}
93948ffe56aSColin Percival
940f28f1389SDave Fullard# Creates a new boot environment
941f28f1389SDave Fullardinstall_create_be () {
942f28f1389SDave Fullard	# Figure out if we're running in a jail and return if we are
943f28f1389SDave Fullard	if [ `sysctl -n security.jail.jailed` = 1 ]; then
944f28f1389SDave Fullard		return 1
945f28f1389SDave Fullard	fi
946e01e8f91SKyle Evans	# Operating on roots that aren't located at / will, more often than not,
947e01e8f91SKyle Evans	# not touch the boot environment.
948e01e8f91SKyle Evans	if [ "$BASEDIR" != "/" ]; then
949e01e8f91SKyle Evans		return 1
950e01e8f91SKyle Evans	fi
951f28f1389SDave Fullard	# Create a boot environment if enabled
952f28f1389SDave Fullard	if [ ${BOOTENV} = yes ]; then
953f28f1389SDave Fullard		bectl check 2>/dev/null
954f28f1389SDave Fullard		case $? in
955f28f1389SDave Fullard			0)
956f28f1389SDave Fullard				# Boot environment are supported
957f28f1389SDave Fullard				CREATEBE=yes
958f28f1389SDave Fullard				;;
959f28f1389SDave Fullard			255)
960f28f1389SDave Fullard				# Boot environments are not supported
961f28f1389SDave Fullard				CREATEBE=no
962f28f1389SDave Fullard				;;
963f28f1389SDave Fullard			*)
964f28f1389SDave Fullard				# If bectl returns an unexpected exit code, don't create a BE
965f28f1389SDave Fullard				CREATEBE=no
966f28f1389SDave Fullard				;;
967f28f1389SDave Fullard		esac
968f28f1389SDave Fullard		if [ ${CREATEBE} = yes ]; then
969f28f1389SDave Fullard			echo -n "Creating snapshot of existing boot environment... "
970e01e8f91SKyle Evans			VERSION=`freebsd-version -ku | sort -V | tail -n 1`
971f28f1389SDave Fullard			TIMESTAMP=`date +"%Y-%m-%d_%H%M%S"`
972989c5f6dSKyle Evans			bectl create -r ${VERSION}_${TIMESTAMP}
973f28f1389SDave Fullard			if [ $? -eq 0 ]; then
974f28f1389SDave Fullard				echo "done.";
975f28f1389SDave Fullard			else
976f28f1389SDave Fullard				echo "failed."
977f28f1389SDave Fullard				exit 1
978f28f1389SDave Fullard			fi
979f28f1389SDave Fullard		fi
980f28f1389SDave Fullard	fi
981f28f1389SDave Fullard}
982f28f1389SDave Fullard
98348ffe56aSColin Percival# Perform sanity checks and set some final parameters in
98448ffe56aSColin Percival# preparation for UNinstalling updates.
98548ffe56aSColin Percivalrollback_check_params () {
98648ffe56aSColin Percival	# Check that we are root.  All sorts of things won't work otherwise.
98748ffe56aSColin Percival	if [ `id -u` != 0 ]; then
98848ffe56aSColin Percival		echo "You must be root to run this."
98948ffe56aSColin Percival		exit 1
99048ffe56aSColin Percival	fi
99148ffe56aSColin Percival
99248ffe56aSColin Percival	# Check that we have a working directory
99348ffe56aSColin Percival	_WORKDIR_bad="Directory does not exist or is not writable: "
99448ffe56aSColin Percival	if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then
99548ffe56aSColin Percival		echo -n "`basename $0`: "
99648ffe56aSColin Percival		echo -n "${_WORKDIR_bad}"
99748ffe56aSColin Percival		echo ${WORKDIR}
99848ffe56aSColin Percival		exit 1
99948ffe56aSColin Percival	fi
100048ffe56aSColin Percival	cd ${WORKDIR} || exit 1
100148ffe56aSColin Percival
100248ffe56aSColin Percival	# Construct a unique name from ${BASEDIR}
100348ffe56aSColin Percival	BDHASH=`echo ${BASEDIR} | sha256 -q`
100448ffe56aSColin Percival
100548ffe56aSColin Percival	# Check that we have updates ready to rollback
100648ffe56aSColin Percival	if ! [ -L ${BDHASH}-rollback ]; then
100748ffe56aSColin Percival		echo "No rollback directory found."
100848ffe56aSColin Percival		exit 1
100948ffe56aSColin Percival	fi
101048ffe56aSColin Percival	if ! [ -f ${BDHASH}-rollback/INDEX-OLD ] ||
101148ffe56aSColin Percival	    ! [ -f ${BDHASH}-rollback/INDEX-NEW ]; then
101248ffe56aSColin Percival		echo "Update manifest is corrupt -- this should never happen."
101348ffe56aSColin Percival		exit 1
101448ffe56aSColin Percival	fi
101548ffe56aSColin Percival}
101648ffe56aSColin Percival
101708e23beeSColin Percival# Perform sanity checks and set some final parameters
101808e23beeSColin Percival# in preparation for comparing the system against the
101908e23beeSColin Percival# published index.  Figure out which index we should
102008e23beeSColin Percival# compare against: If the user is running *-p[0-9]+,
102108e23beeSColin Percival# strip off the last part; if the user is running
102208e23beeSColin Percival# -SECURITY, call it -RELEASE.  Chdir into the working
102308e23beeSColin Percival# directory.
102408e23beeSColin PercivalIDS_check_params () {
102508e23beeSColin Percival	export HTTP_USER_AGENT="freebsd-update (${COMMAND}, `uname -r`)"
102608e23beeSColin Percival
102708e23beeSColin Percival	_SERVERNAME_z=\
102808e23beeSColin Percival"SERVERNAME must be given via command line or configuration file."
102959b02bb4SMichael Osipov	_KEYPRINT_z="Key must be given via '-k' option or configuration file."
103008e23beeSColin Percival	_KEYPRINT_bad="Invalid key fingerprint: "
103108e23beeSColin Percival	_WORKDIR_bad="Directory does not exist or is not writable: "
103208e23beeSColin Percival
103308e23beeSColin Percival	if [ -z "${SERVERNAME}" ]; then
103408e23beeSColin Percival		echo -n "`basename $0`: "
103508e23beeSColin Percival		echo "${_SERVERNAME_z}"
103608e23beeSColin Percival		exit 1
103708e23beeSColin Percival	fi
103808e23beeSColin Percival	if [ -z "${KEYPRINT}" ]; then
103908e23beeSColin Percival		echo -n "`basename $0`: "
104008e23beeSColin Percival		echo "${_KEYPRINT_z}"
104108e23beeSColin Percival		exit 1
104208e23beeSColin Percival	fi
104308e23beeSColin Percival	if ! echo "${KEYPRINT}" | grep -qE "^[0-9a-f]{64}$"; then
104408e23beeSColin Percival		echo -n "`basename $0`: "
104508e23beeSColin Percival		echo -n "${_KEYPRINT_bad}"
104608e23beeSColin Percival		echo ${KEYPRINT}
104708e23beeSColin Percival		exit 1
104808e23beeSColin Percival	fi
104908e23beeSColin Percival	if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then
105008e23beeSColin Percival		echo -n "`basename $0`: "
105108e23beeSColin Percival		echo -n "${_WORKDIR_bad}"
105208e23beeSColin Percival		echo ${WORKDIR}
105308e23beeSColin Percival		exit 1
105408e23beeSColin Percival	fi
105508e23beeSColin Percival	cd ${WORKDIR} || exit 1
105608e23beeSColin Percival
105708e23beeSColin Percival	# Generate release number.  The s/SECURITY/RELEASE/ bit exists
105808e23beeSColin Percival	# to provide an upgrade path for FreeBSD Update 1.x users, since
105908e23beeSColin Percival	# the kernels provided by FreeBSD Update 1.x are always labelled
106008e23beeSColin Percival	# as X.Y-SECURITY.
106108e23beeSColin Percival	RELNUM=`uname -r |
106208e23beeSColin Percival	    sed -E 's,-p[0-9]+,,' |
106308e23beeSColin Percival	    sed -E 's,-SECURITY,-RELEASE,'`
106408e23beeSColin Percival	ARCH=`uname -m`
106508e23beeSColin Percival	FETCHDIR=${RELNUM}/${ARCH}
106608e23beeSColin Percival	PATCHDIR=${RELNUM}/${ARCH}/bp
106708e23beeSColin Percival
106808e23beeSColin Percival	# Figure out what directory contains the running kernel
106908e23beeSColin Percival	BOOTFILE=`sysctl -n kern.bootfile`
107008e23beeSColin Percival	KERNELDIR=${BOOTFILE%/kernel}
107108e23beeSColin Percival	if ! [ -d ${KERNELDIR} ]; then
107208e23beeSColin Percival		echo "Cannot identify running kernel"
107308e23beeSColin Percival		exit 1
107408e23beeSColin Percival	fi
107508e23beeSColin Percival
107608e23beeSColin Percival	# Figure out what kernel configuration is running.  We start with
107708e23beeSColin Percival	# the output of `uname -i`, and then make the following adjustments:
107808e23beeSColin Percival	# 1. Replace "SMP-GENERIC" with "SMP".  Why the SMP kernel config
107908e23beeSColin Percival	# file says "ident SMP-GENERIC", I don't know...
108008e23beeSColin Percival	# 2. If the kernel claims to be GENERIC _and_ ${ARCH} is "amd64"
108108e23beeSColin Percival	# _and_ `sysctl kern.version` contains a line which ends "/SMP", then
108208e23beeSColin Percival	# we're running an SMP kernel.  This mis-identification is a bug
108308e23beeSColin Percival	# which was fixed in 6.2-STABLE.
108408e23beeSColin Percival	KERNCONF=`uname -i`
108508e23beeSColin Percival	if [ ${KERNCONF} = "SMP-GENERIC" ]; then
108608e23beeSColin Percival		KERNCONF=SMP
108708e23beeSColin Percival	fi
108808e23beeSColin Percival	if [ ${KERNCONF} = "GENERIC" ] && [ ${ARCH} = "amd64" ]; then
108908e23beeSColin Percival		if sysctl kern.version | grep -qE '/SMP$'; then
109008e23beeSColin Percival			KERNCONF=SMP
109108e23beeSColin Percival		fi
109208e23beeSColin Percival	fi
109308e23beeSColin Percival
109408e23beeSColin Percival	# Define some paths
109508e23beeSColin Percival	SHA256=/sbin/sha256
109608e23beeSColin Percival	PHTTPGET=/usr/libexec/phttpget
109708e23beeSColin Percival
109808e23beeSColin Percival	# Set up variables relating to VERBOSELEVEL
109908e23beeSColin Percival	fetch_setup_verboselevel
110008e23beeSColin Percival}
110108e23beeSColin Percival
1102cf1aba28SEd Maste# Packaged base and freebsd-update are incompatible.  Exit with an error if
1103cf1aba28SEd Maste# packaged base is in use.
1104cf1aba28SEd Mastecheck_pkgbase()
1105cf1aba28SEd Maste{
1106cf1aba28SEd Maste	# Packaged base requires that pkg is bootstrapped.
1107cf1aba28SEd Maste	if ! pkg -c ${BASEDIR} -N >/dev/null 2>/dev/null; then
1108cf1aba28SEd Maste		return
1109cf1aba28SEd Maste	fi
1110*856e158dSEd Maste	# uname(1) is used by pkg to determine ABI, so it should exist.
1111*856e158dSEd Maste	# If it comes from a package then this system uses packaged base.
1112*856e158dSEd Maste	if ! pkg -c ${BASEDIR} which /usr/bin/uname >/dev/null; then
1113cf1aba28SEd Maste		return
1114cf1aba28SEd Maste	fi
1115cf1aba28SEd Maste	cat <<EOF
1116*856e158dSEd Mastefreebsd-update is incompatible with the use of packaged base.  Please see
1117cf1aba28SEd Mastehttps://wiki.freebsd.org/PkgBase for more information.
1118cf1aba28SEd MasteEOF
1119cf1aba28SEd Maste	exit 1
1120cf1aba28SEd Maste}
1121cf1aba28SEd Maste
112248ffe56aSColin Percival#### Core functionality -- the actual work gets done here
112348ffe56aSColin Percival
112448ffe56aSColin Percival# Use an SRV query to pick a server.  If the SRV query doesn't provide
112548ffe56aSColin Percival# a useful answer, use the server name specified by the user.
112648ffe56aSColin Percival# Put another way... look up _http._tcp.${SERVERNAME} and pick a server
112748ffe56aSColin Percival# from that; or if no servers are returned, use ${SERVERNAME}.
11289b30b96cSOlivier Certner# This allows a user to specify "update.FreeBSD.org" (in which case
11299b30b96cSOlivier Certner# freebsd-update will select one of the mirrors) or "update1.freebsd.org"
11309b30b96cSOlivier Certner# (in which case freebsd-update will use that particular server, since
11319b30b96cSOlivier Certner# there won't be an SRV entry for that name).
113248ffe56aSColin Percival#
113348ffe56aSColin Percival# We ignore the Port field, since we are always going to use port 80.
113448ffe56aSColin Percival
113548ffe56aSColin Percival# Fetch the mirror list, but do not pick a mirror yet.  Returns 1 if
113648ffe56aSColin Percival# no mirrors are available for any reason.
113748ffe56aSColin Percivalfetch_pick_server_init () {
113848ffe56aSColin Percival	: > serverlist_tried
113948ffe56aSColin Percival
114048ffe56aSColin Percival# Check that host(1) exists (i.e., that the system wasn't built with the
114148ffe56aSColin Percival# WITHOUT_BIND set) and don't try to find a mirror if it doesn't exist.
114248ffe56aSColin Percival	if ! which -s host; then
114348ffe56aSColin Percival		: > serverlist_full
114448ffe56aSColin Percival		return 1
114548ffe56aSColin Percival	fi
114648ffe56aSColin Percival
114748ffe56aSColin Percival	echo -n "Looking up ${SERVERNAME} mirrors... "
114848ffe56aSColin Percival
114948ffe56aSColin Percival# Issue the SRV query and pull out the Priority, Weight, and Target fields.
115048ffe56aSColin Percival# BIND 9 prints "$name has SRV record ..." while BIND 8 prints
115148ffe56aSColin Percival# "$name server selection ..."; we allow either format.
115248ffe56aSColin Percival	MLIST="_http._tcp.${SERVERNAME}"
115348ffe56aSColin Percival	host -t srv "${MLIST}" |
1154e7fd266eSColin Percival	    sed -nE "s/${MLIST} (has SRV record|server selection) //Ip" |
115548ffe56aSColin Percival	    cut -f 1,2,4 -d ' ' |
115648ffe56aSColin Percival	    sed -e 's/\.$//' |
115748ffe56aSColin Percival	    sort > serverlist_full
115848ffe56aSColin Percival
115948ffe56aSColin Percival# If no records, give up -- we'll just use the server name we were given.
116048ffe56aSColin Percival	if [ `wc -l < serverlist_full` -eq 0 ]; then
116148ffe56aSColin Percival		echo "none found."
116248ffe56aSColin Percival		return 1
116348ffe56aSColin Percival	fi
116448ffe56aSColin Percival
116548ffe56aSColin Percival# Report how many mirrors we found.
116648ffe56aSColin Percival	echo `wc -l < serverlist_full` "mirrors found."
116748ffe56aSColin Percival
116848ffe56aSColin Percival# Generate a random seed for use in picking mirrors.  If HTTP_PROXY
116948ffe56aSColin Percival# is set, this will be used to generate the seed; otherwise, the seed
117048ffe56aSColin Percival# will be random.
117148ffe56aSColin Percival	if [ -n "${HTTP_PROXY}${http_proxy}" ]; then
117248ffe56aSColin Percival		RANDVALUE=`sha256 -qs "${HTTP_PROXY}${http_proxy}" |
117348ffe56aSColin Percival		    tr -d 'a-f' |
117448ffe56aSColin Percival		    cut -c 1-9`
117548ffe56aSColin Percival	else
117648ffe56aSColin Percival		RANDVALUE=`jot -r 1 0 999999999`
117748ffe56aSColin Percival	fi
117848ffe56aSColin Percival}
117948ffe56aSColin Percival
118048ffe56aSColin Percival# Pick a mirror.  Returns 1 if we have run out of mirrors to try.
118148ffe56aSColin Percivalfetch_pick_server () {
118248ffe56aSColin Percival# Generate a list of not-yet-tried mirrors
118348ffe56aSColin Percival	sort serverlist_tried |
118448ffe56aSColin Percival	    comm -23 serverlist_full - > serverlist
118548ffe56aSColin Percival
118648ffe56aSColin Percival# Have we run out of mirrors?
118748ffe56aSColin Percival	if [ `wc -l < serverlist` -eq 0 ]; then
11889e8c28fcSEd Maste		cat <<- EOF
11899e8c28fcSEd Maste			No mirrors remaining, giving up.
11909e8c28fcSEd Maste
11919e8c28fcSEd Maste			This may be because upgrading from this platform (${ARCH})
11929e8c28fcSEd Maste			or release (${RELNUM}) is unsupported by `basename $0`. Only
11939e8c28fcSEd Maste			platforms with Tier 1 support can be upgraded by `basename $0`.
119486d0d3aaSLi-Wen Hsu			See https://www.freebsd.org/platforms/ for more info.
11959e8c28fcSEd Maste
11969e8c28fcSEd Maste			If unsupported, FreeBSD must be upgraded by source.
11979e8c28fcSEd Maste		EOF
119848ffe56aSColin Percival		return 1
119948ffe56aSColin Percival	fi
120048ffe56aSColin Percival
120148ffe56aSColin Percival# Find the highest priority level (lowest numeric value).
120248ffe56aSColin Percival	SRV_PRIORITY=`cut -f 1 -d ' ' serverlist | sort -n | head -1`
120348ffe56aSColin Percival
120448ffe56aSColin Percival# Add up the weights of the response lines at that priority level.
120548ffe56aSColin Percival	SRV_WSUM=0;
120648ffe56aSColin Percival	while read X; do
120748ffe56aSColin Percival		case "$X" in
120848ffe56aSColin Percival		${SRV_PRIORITY}\ *)
120948ffe56aSColin Percival			SRV_W=`echo $X | cut -f 2 -d ' '`
121048ffe56aSColin Percival			SRV_WSUM=$(($SRV_WSUM + $SRV_W))
121148ffe56aSColin Percival			;;
121248ffe56aSColin Percival		esac
121348ffe56aSColin Percival	done < serverlist
121448ffe56aSColin Percival
121548ffe56aSColin Percival# If all the weights are 0, pretend that they are all 1 instead.
121648ffe56aSColin Percival	if [ ${SRV_WSUM} -eq 0 ]; then
121748ffe56aSColin Percival		SRV_WSUM=`grep -E "^${SRV_PRIORITY} " serverlist | wc -l`
121848ffe56aSColin Percival		SRV_W_ADD=1
121948ffe56aSColin Percival	else
122048ffe56aSColin Percival		SRV_W_ADD=0
122148ffe56aSColin Percival	fi
122248ffe56aSColin Percival
122348ffe56aSColin Percival# Pick a value between 0 and the sum of the weights - 1
122448ffe56aSColin Percival	SRV_RND=`expr ${RANDVALUE} % ${SRV_WSUM}`
122548ffe56aSColin Percival
122648ffe56aSColin Percival# Read through the list of mirrors and set SERVERNAME.  Write the line
122748ffe56aSColin Percival# corresponding to the mirror we selected into serverlist_tried so that
122848ffe56aSColin Percival# we won't try it again.
122948ffe56aSColin Percival	while read X; do
123048ffe56aSColin Percival		case "$X" in
123148ffe56aSColin Percival		${SRV_PRIORITY}\ *)
123248ffe56aSColin Percival			SRV_W=`echo $X | cut -f 2 -d ' '`
123348ffe56aSColin Percival			SRV_W=$(($SRV_W + $SRV_W_ADD))
123448ffe56aSColin Percival			if [ $SRV_RND -lt $SRV_W ]; then
123548ffe56aSColin Percival				SERVERNAME=`echo $X | cut -f 3 -d ' '`
123648ffe56aSColin Percival				echo "$X" >> serverlist_tried
123748ffe56aSColin Percival				break
123848ffe56aSColin Percival			else
123948ffe56aSColin Percival				SRV_RND=$(($SRV_RND - $SRV_W))
124048ffe56aSColin Percival			fi
124148ffe56aSColin Percival			;;
124248ffe56aSColin Percival		esac
124348ffe56aSColin Percival	done < serverlist
124448ffe56aSColin Percival}
124548ffe56aSColin Percival
124648ffe56aSColin Percival# Take a list of ${oldhash}|${newhash} and output a list of needed patches,
124748ffe56aSColin Percival# i.e., those for which we have ${oldhash} and don't have ${newhash}.
124848ffe56aSColin Percivalfetch_make_patchlist () {
124948ffe56aSColin Percival	grep -vE "^([0-9a-f]{64})\|\1$" |
125048ffe56aSColin Percival	    tr '|' ' ' |
125148ffe56aSColin Percival		while read X Y; do
125248ffe56aSColin Percival			if [ -f "files/${Y}.gz" ] ||
125348ffe56aSColin Percival			    [ ! -f "files/${X}.gz" ]; then
125448ffe56aSColin Percival				continue
125548ffe56aSColin Percival			fi
125648ffe56aSColin Percival			echo "${X}|${Y}"
1257f6e21461SEd Maste		done | sort -u
125848ffe56aSColin Percival}
125948ffe56aSColin Percival
126048ffe56aSColin Percival# Print user-friendly progress statistics
126148ffe56aSColin Percivalfetch_progress () {
126248ffe56aSColin Percival	LNC=0
126348ffe56aSColin Percival	while read x; do
126448ffe56aSColin Percival		LNC=$(($LNC + 1))
126548ffe56aSColin Percival		if [ $(($LNC % 10)) = 0 ]; then
126648ffe56aSColin Percival			echo -n $LNC
126748ffe56aSColin Percival		elif [ $(($LNC % 2)) = 0 ]; then
126848ffe56aSColin Percival			echo -n .
126948ffe56aSColin Percival		fi
127048ffe56aSColin Percival	done
127148ffe56aSColin Percival	echo -n " "
127248ffe56aSColin Percival}
127348ffe56aSColin Percival
1274db6b0a61SColin Percival# Function for asking the user if everything is ok
1275db6b0a61SColin Percivalcontinuep () {
1276db6b0a61SColin Percival	while read -p "Does this look reasonable (y/n)? " CONTINUE; do
1277db6b0a61SColin Percival		case "${CONTINUE}" in
127839f4633bSJuraj Lutter		[yY]*)
1279db6b0a61SColin Percival			return 0
1280db6b0a61SColin Percival			;;
128139f4633bSJuraj Lutter		[nN]*)
1282db6b0a61SColin Percival			return 1
1283db6b0a61SColin Percival			;;
1284db6b0a61SColin Percival		esac
1285db6b0a61SColin Percival	done
1286db6b0a61SColin Percival}
1287db6b0a61SColin Percival
128848ffe56aSColin Percival# Initialize the working directory
128948ffe56aSColin Percivalworkdir_init () {
129048ffe56aSColin Percival	mkdir -p files
129148ffe56aSColin Percival	touch tINDEX.present
129248ffe56aSColin Percival}
129348ffe56aSColin Percival
129448ffe56aSColin Percival# Check that we have a public key with an appropriate hash, or
129548ffe56aSColin Percival# fetch the key if it doesn't exist.  Returns 1 if the key has
129648ffe56aSColin Percival# not yet been fetched.
129748ffe56aSColin Percivalfetch_key () {
129848ffe56aSColin Percival	if [ -r pub.ssl ] && [ `${SHA256} -q pub.ssl` = ${KEYPRINT} ]; then
129948ffe56aSColin Percival		return 0
130048ffe56aSColin Percival	fi
130148ffe56aSColin Percival
130248ffe56aSColin Percival	echo -n "Fetching public key from ${SERVERNAME}... "
130348ffe56aSColin Percival	rm -f pub.ssl
130448ffe56aSColin Percival	fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/pub.ssl \
130548ffe56aSColin Percival	    2>${QUIETREDIR} || true
130648ffe56aSColin Percival	if ! [ -r pub.ssl ]; then
130748ffe56aSColin Percival		echo "failed."
130848ffe56aSColin Percival		return 1
130948ffe56aSColin Percival	fi
131048ffe56aSColin Percival	if ! [ `${SHA256} -q pub.ssl` = ${KEYPRINT} ]; then
131148ffe56aSColin Percival		echo "key has incorrect hash."
131248ffe56aSColin Percival		rm -f pub.ssl
131348ffe56aSColin Percival		return 1
131448ffe56aSColin Percival	fi
131548ffe56aSColin Percival	echo "done."
131648ffe56aSColin Percival}
131748ffe56aSColin Percival
131848ffe56aSColin Percival# Fetch metadata signature, aka "tag".
131948ffe56aSColin Percivalfetch_tag () {
1320db6b0a61SColin Percival	echo -n "Fetching metadata signature "
1321db6b0a61SColin Percival	echo ${NDEBUG} "for ${RELNUM} from ${SERVERNAME}... "
132248ffe56aSColin Percival	rm -f latest.ssl
132348ffe56aSColin Percival	fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/latest.ssl	\
132448ffe56aSColin Percival	    2>${QUIETREDIR} || true
132548ffe56aSColin Percival	if ! [ -r latest.ssl ]; then
132648ffe56aSColin Percival		echo "failed."
132748ffe56aSColin Percival		return 1
132848ffe56aSColin Percival	fi
132948ffe56aSColin Percival
13307220a45bSJose Luis Duran	openssl pkeyutl -pubin -inkey pub.ssl -verifyrecover	\
133148ffe56aSColin Percival	    < latest.ssl > tag.new 2>${QUIETREDIR} || true
133248ffe56aSColin Percival	rm latest.ssl
133348ffe56aSColin Percival
133448ffe56aSColin Percival	if ! [ `wc -l < tag.new` = 1 ] ||
133548ffe56aSColin Percival	    ! grep -qE	\
133648ffe56aSColin Percival    "^freebsd-update\|${ARCH}\|${RELNUM}\|[0-9]+\|[0-9a-f]{64}\|[0-9]{10}" \
133748ffe56aSColin Percival		tag.new; then
133848ffe56aSColin Percival		echo "invalid signature."
133948ffe56aSColin Percival		return 1
134048ffe56aSColin Percival	fi
134148ffe56aSColin Percival
134248ffe56aSColin Percival	echo "done."
134348ffe56aSColin Percival
134448ffe56aSColin Percival	RELPATCHNUM=`cut -f 4 -d '|' < tag.new`
134548ffe56aSColin Percival	TINDEXHASH=`cut -f 5 -d '|' < tag.new`
134648ffe56aSColin Percival	EOLTIME=`cut -f 6 -d '|' < tag.new`
134748ffe56aSColin Percival}
134848ffe56aSColin Percival
134948ffe56aSColin Percival# Sanity-check the patch number in a tag, to make sure that we're not
135048ffe56aSColin Percival# going to "update" backwards and to prevent replay attacks.
135148ffe56aSColin Percivalfetch_tagsanity () {
135248ffe56aSColin Percival	# Check that we're not going to move from -pX to -pY with Y < X.
135348ffe56aSColin Percival	RELPX=`uname -r | sed -E 's,.*-,,'`
135448ffe56aSColin Percival	if echo ${RELPX} | grep -qE '^p[0-9]+$'; then
135548ffe56aSColin Percival		RELPX=`echo ${RELPX} | cut -c 2-`
135648ffe56aSColin Percival	else
135748ffe56aSColin Percival		RELPX=0
135848ffe56aSColin Percival	fi
135948ffe56aSColin Percival	if [ "${RELPATCHNUM}" -lt "${RELPX}" ]; then
136048ffe56aSColin Percival		echo
136148ffe56aSColin Percival		echo -n "Files on mirror (${RELNUM}-p${RELPATCHNUM})"
136248ffe56aSColin Percival		echo " appear older than what"
136348ffe56aSColin Percival		echo "we are currently running (`uname -r`)!"
136448ffe56aSColin Percival		echo "Cowardly refusing to proceed any further."
136548ffe56aSColin Percival		return 1
136648ffe56aSColin Percival	fi
136748ffe56aSColin Percival
136848ffe56aSColin Percival	# If "tag" exists and corresponds to ${RELNUM}, make sure that
136948ffe56aSColin Percival	# it contains a patch number <= RELPATCHNUM, in order to protect
137048ffe56aSColin Percival	# against rollback (replay) attacks.
137148ffe56aSColin Percival	if [ -f tag ] &&
137248ffe56aSColin Percival	    grep -qE	\
137348ffe56aSColin Percival    "^freebsd-update\|${ARCH}\|${RELNUM}\|[0-9]+\|[0-9a-f]{64}\|[0-9]{10}" \
137448ffe56aSColin Percival		tag; then
137548ffe56aSColin Percival		LASTRELPATCHNUM=`cut -f 4 -d '|' < tag`
137648ffe56aSColin Percival
137748ffe56aSColin Percival		if [ "${RELPATCHNUM}" -lt "${LASTRELPATCHNUM}" ]; then
137848ffe56aSColin Percival			echo
137948ffe56aSColin Percival			echo -n "Files on mirror (${RELNUM}-p${RELPATCHNUM})"
138048ffe56aSColin Percival			echo " are older than the"
138148ffe56aSColin Percival			echo -n "most recently seen updates"
138248ffe56aSColin Percival			echo " (${RELNUM}-p${LASTRELPATCHNUM})."
138348ffe56aSColin Percival			echo "Cowardly refusing to proceed any further."
138448ffe56aSColin Percival			return 1
138548ffe56aSColin Percival		fi
138648ffe56aSColin Percival	fi
138748ffe56aSColin Percival}
138848ffe56aSColin Percival
138948ffe56aSColin Percival# Fetch metadata index file
139048ffe56aSColin Percivalfetch_metadata_index () {
139148ffe56aSColin Percival	echo ${NDEBUG} "Fetching metadata index... "
139248ffe56aSColin Percival	rm -f ${TINDEXHASH}
139348ffe56aSColin Percival	fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/t/${TINDEXHASH}
139448ffe56aSColin Percival	    2>${QUIETREDIR}
139548ffe56aSColin Percival	if ! [ -f ${TINDEXHASH} ]; then
139648ffe56aSColin Percival		echo "failed."
139748ffe56aSColin Percival		return 1
139848ffe56aSColin Percival	fi
139948ffe56aSColin Percival	if [ `${SHA256} -q ${TINDEXHASH}` != ${TINDEXHASH} ]; then
140048ffe56aSColin Percival		echo "update metadata index corrupt."
140148ffe56aSColin Percival		return 1
140248ffe56aSColin Percival	fi
140348ffe56aSColin Percival	echo "done."
140448ffe56aSColin Percival}
140548ffe56aSColin Percival
140648ffe56aSColin Percival# Print an error message about signed metadata being bogus.
140748ffe56aSColin Percivalfetch_metadata_bogus () {
140848ffe56aSColin Percival	echo
140948ffe56aSColin Percival	echo "The update metadata$1 is correctly signed, but"
141048ffe56aSColin Percival	echo "failed an integrity check."
141148ffe56aSColin Percival	echo "Cowardly refusing to proceed any further."
141248ffe56aSColin Percival	return 1
141348ffe56aSColin Percival}
141448ffe56aSColin Percival
141548ffe56aSColin Percival# Construct tINDEX.new by merging the lines named in $1 from ${TINDEXHASH}
141648ffe56aSColin Percival# with the lines not named in $@ from tINDEX.present (if that file exists).
141748ffe56aSColin Percivalfetch_metadata_index_merge () {
141848ffe56aSColin Percival	for METAFILE in $@; do
141948ffe56aSColin Percival		if [ `grep -E "^${METAFILE}\|" ${TINDEXHASH} | wc -l`	\
142048ffe56aSColin Percival		    -ne 1 ]; then
142148ffe56aSColin Percival			fetch_metadata_bogus " index"
142248ffe56aSColin Percival			return 1
142348ffe56aSColin Percival		fi
142448ffe56aSColin Percival
142548ffe56aSColin Percival		grep -E "${METAFILE}\|" ${TINDEXHASH}
142648ffe56aSColin Percival	done |
142748ffe56aSColin Percival	    sort > tINDEX.wanted
142848ffe56aSColin Percival
142948ffe56aSColin Percival	if [ -f tINDEX.present ]; then
143048ffe56aSColin Percival		join -t '|' -v 2 tINDEX.wanted tINDEX.present |
143148ffe56aSColin Percival		    sort -m - tINDEX.wanted > tINDEX.new
143248ffe56aSColin Percival		rm tINDEX.wanted
143348ffe56aSColin Percival	else
143448ffe56aSColin Percival		mv tINDEX.wanted tINDEX.new
143548ffe56aSColin Percival	fi
143648ffe56aSColin Percival}
143748ffe56aSColin Percival
143848ffe56aSColin Percival# Sanity check all the lines of tINDEX.new.  Even if more metadata lines
143948ffe56aSColin Percival# are added by future versions of the server, this won't cause problems,
144048ffe56aSColin Percival# since the only lines which appear in tINDEX.new are the ones which we
144148ffe56aSColin Percival# specifically grepped out of ${TINDEXHASH}.
144248ffe56aSColin Percivalfetch_metadata_index_sanity () {
144348ffe56aSColin Percival	if grep -qvE '^[0-9A-Z.-]+\|[0-9a-f]{64}$' tINDEX.new; then
144448ffe56aSColin Percival		fetch_metadata_bogus " index"
144548ffe56aSColin Percival		return 1
144648ffe56aSColin Percival	fi
144748ffe56aSColin Percival}
144848ffe56aSColin Percival
144948ffe56aSColin Percival# Sanity check the metadata file $1.
145048ffe56aSColin Percivalfetch_metadata_sanity () {
145148ffe56aSColin Percival	# Some aliases to save space later: ${P} is a character which can
145248ffe56aSColin Percival	# appear in a path; ${M} is the four numeric metadata fields; and
145348ffe56aSColin Percival	# ${H} is a sha256 hash.
14547c06c7c5SKris Moore	P="[-+./:=,%@_[~[:alnum:]]"
145548ffe56aSColin Percival	M="[0-9]+\|[0-9]+\|[0-9]+\|[0-9]+"
145648ffe56aSColin Percival	H="[0-9a-f]{64}"
145748ffe56aSColin Percival
145848ffe56aSColin Percival	# Check that the first four fields make sense.
145948ffe56aSColin Percival	if gunzip -c < files/$1.gz |
1460823c0d5fSXin LI	    grep -qvE "^[a-z]+\|[0-9a-z-]+\|${P}+\|[fdL-]\|"; then
146148ffe56aSColin Percival		fetch_metadata_bogus ""
146248ffe56aSColin Percival		return 1
146348ffe56aSColin Percival	fi
146448ffe56aSColin Percival
146548ffe56aSColin Percival	# Remove the first three fields.
146648ffe56aSColin Percival	gunzip -c < files/$1.gz |
146748ffe56aSColin Percival	    cut -f 4- -d '|' > sanitycheck.tmp
146848ffe56aSColin Percival
146948ffe56aSColin Percival	# Sanity check entries with type 'f'
147048ffe56aSColin Percival	if grep -E '^f' sanitycheck.tmp |
147148ffe56aSColin Percival	    grep -qvE "^f\|${M}\|${H}\|${P}*\$"; then
147248ffe56aSColin Percival		fetch_metadata_bogus ""
147348ffe56aSColin Percival		return 1
147448ffe56aSColin Percival	fi
147548ffe56aSColin Percival
147648ffe56aSColin Percival	# Sanity check entries with type 'd'
147748ffe56aSColin Percival	if grep -E '^d' sanitycheck.tmp |
147848ffe56aSColin Percival	    grep -qvE "^d\|${M}\|\|\$"; then
147948ffe56aSColin Percival		fetch_metadata_bogus ""
148048ffe56aSColin Percival		return 1
148148ffe56aSColin Percival	fi
148248ffe56aSColin Percival
148348ffe56aSColin Percival	# Sanity check entries with type 'L'
148448ffe56aSColin Percival	if grep -E '^L' sanitycheck.tmp |
148548ffe56aSColin Percival	    grep -qvE "^L\|${M}\|${P}*\|\$"; then
148648ffe56aSColin Percival		fetch_metadata_bogus ""
148748ffe56aSColin Percival		return 1
148848ffe56aSColin Percival	fi
148948ffe56aSColin Percival
149048ffe56aSColin Percival	# Sanity check entries with type '-'
149148ffe56aSColin Percival	if grep -E '^-' sanitycheck.tmp |
149248ffe56aSColin Percival	    grep -qvE "^-\|\|\|\|\|\|"; then
149348ffe56aSColin Percival		fetch_metadata_bogus ""
149448ffe56aSColin Percival		return 1
149548ffe56aSColin Percival	fi
149648ffe56aSColin Percival
149748ffe56aSColin Percival	# Clean up
149848ffe56aSColin Percival	rm sanitycheck.tmp
149948ffe56aSColin Percival}
150048ffe56aSColin Percival
150148ffe56aSColin Percival# Fetch the metadata index and metadata files listed in $@,
150248ffe56aSColin Percival# taking advantage of metadata patches where possible.
150348ffe56aSColin Percivalfetch_metadata () {
150448ffe56aSColin Percival	fetch_metadata_index || return 1
150548ffe56aSColin Percival	fetch_metadata_index_merge $@ || return 1
150648ffe56aSColin Percival	fetch_metadata_index_sanity || return 1
150748ffe56aSColin Percival
150848ffe56aSColin Percival	# Generate a list of wanted metadata patches
150948ffe56aSColin Percival	join -t '|' -o 1.2,2.2 tINDEX.present tINDEX.new |
151048ffe56aSColin Percival	    fetch_make_patchlist > patchlist
151148ffe56aSColin Percival
151248ffe56aSColin Percival	if [ -s patchlist ]; then
151348ffe56aSColin Percival		# Attempt to fetch metadata patches
151448ffe56aSColin Percival		echo -n "Fetching `wc -l < patchlist | tr -d ' '` "
151548ffe56aSColin Percival		echo ${NDEBUG} "metadata patches.${DDSTATS}"
151648ffe56aSColin Percival		tr '|' '-' < patchlist |
151748ffe56aSColin Percival		    lam -s "${FETCHDIR}/tp/" - -s ".gz" |
151848ffe56aSColin Percival		    xargs ${XARGST} ${PHTTPGET} ${SERVERNAME}	\
151948ffe56aSColin Percival			2>${STATSREDIR} | fetch_progress
152048ffe56aSColin Percival		echo "done."
152148ffe56aSColin Percival
152248ffe56aSColin Percival		# Attempt to apply metadata patches
152348ffe56aSColin Percival		echo -n "Applying metadata patches... "
152448ffe56aSColin Percival		tr '|' ' ' < patchlist |
152548ffe56aSColin Percival		    while read X Y; do
152648ffe56aSColin Percival			if [ ! -f "${X}-${Y}.gz" ]; then continue; fi
152748ffe56aSColin Percival			gunzip -c < ${X}-${Y}.gz > diff
152848ffe56aSColin Percival			gunzip -c < files/${X}.gz > diff-OLD
152948ffe56aSColin Percival
153048ffe56aSColin Percival			# Figure out which lines are being added and removed
153148ffe56aSColin Percival			grep -E '^-' diff |
153248ffe56aSColin Percival			    cut -c 2- |
153348ffe56aSColin Percival			    while read PREFIX; do
153448ffe56aSColin Percival				look "${PREFIX}" diff-OLD
153548ffe56aSColin Percival			    done |
153648ffe56aSColin Percival			    sort > diff-rm
153748ffe56aSColin Percival			grep -E '^\+' diff |
153848ffe56aSColin Percival			    cut -c 2- > diff-add
153948ffe56aSColin Percival
154048ffe56aSColin Percival			# Generate the new file
154148ffe56aSColin Percival			comm -23 diff-OLD diff-rm |
154248ffe56aSColin Percival			    sort - diff-add > diff-NEW
154348ffe56aSColin Percival
154448ffe56aSColin Percival			if [ `${SHA256} -q diff-NEW` = ${Y} ]; then
154548ffe56aSColin Percival				mv diff-NEW files/${Y}
154648ffe56aSColin Percival				gzip -n files/${Y}
154748ffe56aSColin Percival			else
154848ffe56aSColin Percival				mv diff-NEW ${Y}.bad
154948ffe56aSColin Percival			fi
155048ffe56aSColin Percival			rm -f ${X}-${Y}.gz diff
155148ffe56aSColin Percival			rm -f diff-OLD diff-NEW diff-add diff-rm
155248ffe56aSColin Percival		done 2>${QUIETREDIR}
155348ffe56aSColin Percival		echo "done."
155448ffe56aSColin Percival	fi
155548ffe56aSColin Percival
155648ffe56aSColin Percival	# Update metadata without patches
155748ffe56aSColin Percival	cut -f 2 -d '|' < tINDEX.new |
155848ffe56aSColin Percival	    while read Y; do
155948ffe56aSColin Percival		if [ ! -f "files/${Y}.gz" ]; then
156048ffe56aSColin Percival			echo ${Y};
156148ffe56aSColin Percival		fi
1562bce02f98SColin Percival	    done |
1563bce02f98SColin Percival	    sort -u > filelist
156448ffe56aSColin Percival
156548ffe56aSColin Percival	if [ -s filelist ]; then
156648ffe56aSColin Percival		echo -n "Fetching `wc -l < filelist | tr -d ' '` "
156748ffe56aSColin Percival		echo ${NDEBUG} "metadata files... "
156848ffe56aSColin Percival		lam -s "${FETCHDIR}/m/" - -s ".gz" < filelist |
156948ffe56aSColin Percival		    xargs ${XARGST} ${PHTTPGET} ${SERVERNAME}	\
157048ffe56aSColin Percival		    2>${QUIETREDIR}
157148ffe56aSColin Percival
157248ffe56aSColin Percival		while read Y; do
157348ffe56aSColin Percival			if ! [ -f ${Y}.gz ]; then
157448ffe56aSColin Percival				echo "failed."
157548ffe56aSColin Percival				return 1
157648ffe56aSColin Percival			fi
157748ffe56aSColin Percival			if [ `gunzip -c < ${Y}.gz |
157848ffe56aSColin Percival			    ${SHA256} -q` = ${Y} ]; then
157948ffe56aSColin Percival				mv ${Y}.gz files/${Y}.gz
158048ffe56aSColin Percival			else
158148ffe56aSColin Percival				echo "metadata is corrupt."
158248ffe56aSColin Percival				return 1
158348ffe56aSColin Percival			fi
158448ffe56aSColin Percival		done < filelist
158548ffe56aSColin Percival		echo "done."
158648ffe56aSColin Percival	fi
158748ffe56aSColin Percival
158848ffe56aSColin Percival# Sanity-check the metadata files.
158948ffe56aSColin Percival	cut -f 2 -d '|' tINDEX.new > filelist
159048ffe56aSColin Percival	while read X; do
159148ffe56aSColin Percival		fetch_metadata_sanity ${X} || return 1
159248ffe56aSColin Percival	done < filelist
159348ffe56aSColin Percival
159448ffe56aSColin Percival# Remove files which are no longer needed
159548ffe56aSColin Percival	cut -f 2 -d '|' tINDEX.present |
159648ffe56aSColin Percival	    sort > oldfiles
159748ffe56aSColin Percival	cut -f 2 -d '|' tINDEX.new |
159848ffe56aSColin Percival	    sort |
159948ffe56aSColin Percival	    comm -13 - oldfiles |
160048ffe56aSColin Percival	    lam -s "files/" - -s ".gz" |
160148ffe56aSColin Percival	    xargs rm -f
160248ffe56aSColin Percival	rm patchlist filelist oldfiles
160348ffe56aSColin Percival	rm ${TINDEXHASH}
160448ffe56aSColin Percival
160548ffe56aSColin Percival# We're done!
160648ffe56aSColin Percival	mv tINDEX.new tINDEX.present
160748ffe56aSColin Percival	mv tag.new tag
160848ffe56aSColin Percival
160948ffe56aSColin Percival	return 0
161048ffe56aSColin Percival}
161148ffe56aSColin Percival
1612db6b0a61SColin Percival# Extract a subset of a downloaded metadata file containing only the parts
1613db6b0a61SColin Percival# which are listed in COMPONENTS.
1614db6b0a61SColin Percivalfetch_filter_metadata_components () {
1615db6b0a61SColin Percival	METAHASH=`look "$1|" tINDEX.present | cut -f 2 -d '|'`
1616db6b0a61SColin Percival	gunzip -c < files/${METAHASH}.gz > $1.all
1617db6b0a61SColin Percival
1618db6b0a61SColin Percival	# Fish out the lines belonging to components we care about.
1619db6b0a61SColin Percival	for C in ${COMPONENTS}; do
1620db6b0a61SColin Percival		look "`echo ${C} | tr '/' '|'`|" $1.all
1621db6b0a61SColin Percival	done > $1
1622db6b0a61SColin Percival
1623db6b0a61SColin Percival	# Remove temporary file.
1624db6b0a61SColin Percival	rm $1.all
1625db6b0a61SColin Percival}
1626db6b0a61SColin Percival
1627b698a3abSColin Percival# Generate a filtered version of the metadata file $1 from the downloaded
162848ffe56aSColin Percival# file, by fishing out the lines corresponding to components we're trying
162948ffe56aSColin Percival# to keep updated, and then removing lines corresponding to paths we want
163048ffe56aSColin Percival# to ignore.
163148ffe56aSColin Percivalfetch_filter_metadata () {
163248ffe56aSColin Percival	# Fish out the lines belonging to components we care about.
1633db6b0a61SColin Percival	fetch_filter_metadata_components $1
1634db6b0a61SColin Percival
163548ffe56aSColin Percival	# Canonicalize directory names by removing any trailing / in
163648ffe56aSColin Percival	# order to avoid listing directories multiple times if they
163748ffe56aSColin Percival	# belong to multiple components.  Turning "/" into "" doesn't
163848ffe56aSColin Percival	# matter, since we add a leading "/" when we use paths later.
1639db6b0a61SColin Percival	cut -f 3- -d '|' $1 |
164048ffe56aSColin Percival	    sed -e 's,/|d|,|d|,' |
16417e654612SColin Percival	    sed -e 's,/|-|,|-|,' |
164248ffe56aSColin Percival	    sort -u > $1.tmp
164348ffe56aSColin Percival
164448ffe56aSColin Percival	# Figure out which lines to ignore and remove them.
164548ffe56aSColin Percival	for X in ${IGNOREPATHS}; do
164648ffe56aSColin Percival		grep -E "^${X}" $1.tmp
164748ffe56aSColin Percival	done |
164848ffe56aSColin Percival	    sort -u |
164948ffe56aSColin Percival	    comm -13 - $1.tmp > $1
165048ffe56aSColin Percival
165148ffe56aSColin Percival	# Remove temporary files.
1652db6b0a61SColin Percival	rm $1.tmp
165348ffe56aSColin Percival}
165448ffe56aSColin Percival
1655db6b0a61SColin Percival# Filter the metadata file $1 by adding lines with "/boot/$2"
1656bce02f98SColin Percival# replaced by ${KERNELDIR} (which is `sysctl -n kern.bootfile` minus the
1657db6b0a61SColin Percival# trailing "/kernel"); and if "/boot/$2" does not exist, remove
1658bce02f98SColin Percival# the original lines which start with that.
1659bce02f98SColin Percival# Put another way: Deal with the fact that the FOO kernel is sometimes
1660bce02f98SColin Percival# installed in /boot/FOO/ and is sometimes installed elsewhere.
166148ffe56aSColin Percivalfetch_filter_kernel_names () {
1662db6b0a61SColin Percival	grep ^/boot/$2 $1 |
1663db6b0a61SColin Percival	    sed -e "s,/boot/$2,${KERNELDIR},g" |
166448ffe56aSColin Percival	    sort - $1 > $1.tmp
166548ffe56aSColin Percival	mv $1.tmp $1
1666bce02f98SColin Percival
1667db6b0a61SColin Percival	if ! [ -d /boot/$2 ]; then
1668db6b0a61SColin Percival		grep -v ^/boot/$2 $1 > $1.tmp
1669bce02f98SColin Percival		mv $1.tmp $1
1670bce02f98SColin Percival	fi
167148ffe56aSColin Percival}
167248ffe56aSColin Percival
167348ffe56aSColin Percival# For all paths appearing in $1 or $3, inspect the system
167448ffe56aSColin Percival# and generate $2 describing what is currently installed.
167548ffe56aSColin Percivalfetch_inspect_system () {
167648ffe56aSColin Percival	# No errors yet...
167748ffe56aSColin Percival	rm -f .err
167848ffe56aSColin Percival
167948ffe56aSColin Percival	# Tell the user why his disk is suddenly making lots of noise
168048ffe56aSColin Percival	echo -n "Inspecting system... "
168148ffe56aSColin Percival
168248ffe56aSColin Percival	# Generate list of files to inspect
168348ffe56aSColin Percival	cat $1 $3 |
168448ffe56aSColin Percival	    cut -f 1 -d '|' |
168548ffe56aSColin Percival	    sort -u > filelist
168648ffe56aSColin Percival
168748ffe56aSColin Percival	# Examine each file and output lines of the form
168848ffe56aSColin Percival	# /path/to/file|type|device-inum|user|group|perm|flags|value
168948ffe56aSColin Percival	# sorted by device and inode number.
169048ffe56aSColin Percival	while read F; do
169148ffe56aSColin Percival		# If the symlink/file/directory does not exist, record this.
169248ffe56aSColin Percival		if ! [ -e ${BASEDIR}/${F} ]; then
169348ffe56aSColin Percival			echo "${F}|-||||||"
169448ffe56aSColin Percival			continue
169548ffe56aSColin Percival		fi
169648ffe56aSColin Percival		if ! [ -r ${BASEDIR}/${F} ]; then
169748ffe56aSColin Percival			echo "Cannot read file: ${BASEDIR}/${F}"	\
169848ffe56aSColin Percival			    >/dev/stderr
169948ffe56aSColin Percival			touch .err
170048ffe56aSColin Percival			return 1
170148ffe56aSColin Percival		fi
170248ffe56aSColin Percival
170348ffe56aSColin Percival		# Otherwise, output an index line.
170448ffe56aSColin Percival		if [ -L ${BASEDIR}/${F} ]; then
170548ffe56aSColin Percival			echo -n "${F}|L|"
170648ffe56aSColin Percival			stat -n -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F};
170748ffe56aSColin Percival			readlink ${BASEDIR}/${F};
170848ffe56aSColin Percival		elif [ -f ${BASEDIR}/${F} ]; then
170948ffe56aSColin Percival			echo -n "${F}|f|"
171048ffe56aSColin Percival			stat -n -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F};
171148ffe56aSColin Percival			sha256 -q ${BASEDIR}/${F};
171248ffe56aSColin Percival		elif [ -d ${BASEDIR}/${F} ]; then
171348ffe56aSColin Percival			echo -n "${F}|d|"
171448ffe56aSColin Percival			stat -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F};
171548ffe56aSColin Percival		else
171648ffe56aSColin Percival			echo "Unknown file type: ${BASEDIR}/${F}"	\
171748ffe56aSColin Percival			    >/dev/stderr
171848ffe56aSColin Percival			touch .err
171948ffe56aSColin Percival			return 1
172048ffe56aSColin Percival		fi
172148ffe56aSColin Percival	done < filelist |
172248ffe56aSColin Percival	    sort -k 3,3 -t '|' > $2.tmp
172348ffe56aSColin Percival	rm filelist
172448ffe56aSColin Percival
17256dcc68c8SBenedict Reuschling	# Check if an error occurred during system inspection
172648ffe56aSColin Percival	if [ -f .err ]; then
172748ffe56aSColin Percival		return 1
172848ffe56aSColin Percival	fi
172948ffe56aSColin Percival
173048ffe56aSColin Percival	# Convert to the form
173148ffe56aSColin Percival	# /path/to/file|type|user|group|perm|flags|value|hlink
173248ffe56aSColin Percival	# by resolving identical device and inode numbers into hard links.
173348ffe56aSColin Percival	cut -f 1,3 -d '|' $2.tmp |
173448ffe56aSColin Percival	    sort -k 1,1 -t '|' |
173548ffe56aSColin Percival	    sort -s -u -k 2,2 -t '|' |
173648ffe56aSColin Percival	    join -1 2 -2 3 -t '|' - $2.tmp |
173748ffe56aSColin Percival	    awk -F \| -v OFS=\|		\
173848ffe56aSColin Percival		'{
173948ffe56aSColin Percival		    if (($2 == $3) || ($4 == "-"))
174048ffe56aSColin Percival			print $3,$4,$5,$6,$7,$8,$9,""
174148ffe56aSColin Percival		    else
174248ffe56aSColin Percival			print $3,$4,$5,$6,$7,$8,$9,$2
174348ffe56aSColin Percival		}' |
174448ffe56aSColin Percival	    sort > $2
174548ffe56aSColin Percival	rm $2.tmp
174648ffe56aSColin Percival
174748ffe56aSColin Percival	# We're finished looking around
174848ffe56aSColin Percival	echo "done."
174948ffe56aSColin Percival}
175048ffe56aSColin Percival
1751c55b7e52SColin Percival# For any paths matching ${MERGECHANGES}, compare $2 against $1 and $3 and
1752c55b7e52SColin Percival# find any files with values unique to $2; generate $4 containing these paths
1753c55b7e52SColin Percival# and their corresponding hashes from $1.
1754db6b0a61SColin Percivalfetch_filter_mergechanges () {
1755db6b0a61SColin Percival	# Pull out the paths and hashes of the files matching ${MERGECHANGES}.
1756c55b7e52SColin Percival	for F in $1 $2 $3; do
1757db6b0a61SColin Percival		for X in ${MERGECHANGES}; do
1758db6b0a61SColin Percival			grep -E "^${X}" ${F}
1759db6b0a61SColin Percival		done |
1760db6b0a61SColin Percival		    cut -f 1,2,7 -d '|' |
1761db6b0a61SColin Percival		    sort > ${F}-values
1762db6b0a61SColin Percival	done
1763db6b0a61SColin Percival
1764c55b7e52SColin Percival	# Any line in $2-values which doesn't appear in $1-values or $3-values
1765c55b7e52SColin Percival	# and is a file means that we should list the path in $3.
1766c55b7e52SColin Percival	sort $1-values $3-values |
1767c55b7e52SColin Percival	    comm -13 - $2-values |
1768db6b0a61SColin Percival	    fgrep '|f|' |
1769db6b0a61SColin Percival	    cut -f 1 -d '|' > $2-paths
1770db6b0a61SColin Percival
1771db6b0a61SColin Percival	# For each path, pull out one (and only one!) entry from $1-values.
1772db6b0a61SColin Percival	# Note that we cannot distinguish which "old" version the user made
1773db6b0a61SColin Percival	# changes to; but hopefully any changes which occur due to security
1774db6b0a61SColin Percival	# updates will exist in both the "new" version and the version which
1775db6b0a61SColin Percival	# the user has installed, so the merging will still work.
1776db6b0a61SColin Percival	while read X; do
1777db6b0a61SColin Percival		look "${X}|" $1-values |
1778db6b0a61SColin Percival		    head -1
1779c55b7e52SColin Percival	done < $2-paths > $4
1780db6b0a61SColin Percival
1781db6b0a61SColin Percival	# Clean up
1782c55b7e52SColin Percival	rm $1-values $2-values $3-values $2-paths
1783db6b0a61SColin Percival}
1784db6b0a61SColin Percival
178548ffe56aSColin Percival# For any paths matching ${UPDATEIFUNMODIFIED}, remove lines from $[123]
1786db6b0a61SColin Percival# which correspond to lines in $2 with hashes not matching $1 or $3, unless
1787db6b0a61SColin Percival# the paths are listed in $4.  For entries in $2 marked "not present"
1788db6b0a61SColin Percival# (aka. type -), remove lines from $[123] unless there is a corresponding
1789db6b0a61SColin Percival# entry in $1.
179048ffe56aSColin Percivalfetch_filter_unmodified_notpresent () {
179148ffe56aSColin Percival	# Figure out which lines of $1 and $3 correspond to bits which
179248ffe56aSColin Percival	# should only be updated if they haven't changed, and fish out
179348ffe56aSColin Percival	# the (path, type, value) tuples.
179448ffe56aSColin Percival	# NOTE: We don't consider a file to be "modified" if it matches
179548ffe56aSColin Percival	# the hash from $3.
179648ffe56aSColin Percival	for X in ${UPDATEIFUNMODIFIED}; do
179748ffe56aSColin Percival		grep -E "^${X}" $1
179848ffe56aSColin Percival		grep -E "^${X}" $3
179948ffe56aSColin Percival	done |
180048ffe56aSColin Percival	    cut -f 1,2,7 -d '|' |
180148ffe56aSColin Percival	    sort > $1-values
180248ffe56aSColin Percival
180348ffe56aSColin Percival	# Do the same for $2.
180448ffe56aSColin Percival	for X in ${UPDATEIFUNMODIFIED}; do
180548ffe56aSColin Percival		grep -E "^${X}" $2
180648ffe56aSColin Percival	done |
180748ffe56aSColin Percival	    cut -f 1,2,7 -d '|' |
180848ffe56aSColin Percival	    sort > $2-values
180948ffe56aSColin Percival
181048ffe56aSColin Percival	# Any entry in $2-values which is not in $1-values corresponds to
1811db6b0a61SColin Percival	# a path which we need to remove from $1, $2, and $3, unless it
1812db6b0a61SColin Percival	# that path appears in $4.
1813db6b0a61SColin Percival	comm -13 $1-values $2-values |
1814db6b0a61SColin Percival	    sort -t '|' -k 1,1 > mlines.tmp
1815db6b0a61SColin Percival	cut -f 1 -d '|' $4 |
1816db6b0a61SColin Percival	    sort |
1817db6b0a61SColin Percival	    join -v 2 -t '|' - mlines.tmp |
1818db6b0a61SColin Percival	    sort > mlines
1819db6b0a61SColin Percival	rm $1-values $2-values mlines.tmp
182048ffe56aSColin Percival
182148ffe56aSColin Percival	# Any lines in $2 which are not in $1 AND are "not present" lines
182248ffe56aSColin Percival	# also belong in mlines.
182348ffe56aSColin Percival	comm -13 $1 $2 |
182448ffe56aSColin Percival	    cut -f 1,2,7 -d '|' |
182548ffe56aSColin Percival	    fgrep '|-|' >> mlines
182648ffe56aSColin Percival
182748ffe56aSColin Percival	# Remove lines from $1, $2, and $3
182848ffe56aSColin Percival	for X in $1 $2 $3; do
182948ffe56aSColin Percival		sort -t '|' -k 1,1 ${X} > ${X}.tmp
183048ffe56aSColin Percival		cut -f 1 -d '|' < mlines |
183148ffe56aSColin Percival		    sort |
183248ffe56aSColin Percival		    join -v 2 -t '|' - ${X}.tmp |
183348ffe56aSColin Percival		    sort > ${X}
183448ffe56aSColin Percival		rm ${X}.tmp
183548ffe56aSColin Percival	done
183648ffe56aSColin Percival
183748ffe56aSColin Percival	# Store a list of the modified files, for future reference
183848ffe56aSColin Percival	fgrep -v '|-|' mlines |
183948ffe56aSColin Percival	    cut -f 1 -d '|' > modifiedfiles
184048ffe56aSColin Percival	rm mlines
184148ffe56aSColin Percival}
184248ffe56aSColin Percival
184348ffe56aSColin Percival# For each entry in $1 of type -, remove any corresponding
184448ffe56aSColin Percival# entry from $2 if ${ALLOWADD} != "yes".  Remove all entries
184548ffe56aSColin Percival# of type - from $1.
184648ffe56aSColin Percivalfetch_filter_allowadd () {
184748ffe56aSColin Percival	cut -f 1,2 -d '|' < $1 |
184848ffe56aSColin Percival	    fgrep '|-' |
184948ffe56aSColin Percival	    cut -f 1 -d '|' > filesnotpresent
185048ffe56aSColin Percival
185148ffe56aSColin Percival	if [ ${ALLOWADD} != "yes" ]; then
185248ffe56aSColin Percival		sort < $2 |
185348ffe56aSColin Percival		    join -v 1 -t '|' - filesnotpresent |
185448ffe56aSColin Percival		    sort > $2.tmp
185548ffe56aSColin Percival		mv $2.tmp $2
185648ffe56aSColin Percival	fi
185748ffe56aSColin Percival
185848ffe56aSColin Percival	sort < $1 |
185948ffe56aSColin Percival	    join -v 1 -t '|' - filesnotpresent |
186048ffe56aSColin Percival	    sort > $1.tmp
186148ffe56aSColin Percival	mv $1.tmp $1
186248ffe56aSColin Percival	rm filesnotpresent
186348ffe56aSColin Percival}
186448ffe56aSColin Percival
186548ffe56aSColin Percival# If ${ALLOWDELETE} != "yes", then remove any entries from $1
186648ffe56aSColin Percival# which don't correspond to entries in $2.
186748ffe56aSColin Percivalfetch_filter_allowdelete () {
186848ffe56aSColin Percival	# Produce a lists ${PATH}|${TYPE}
186948ffe56aSColin Percival	for X in $1 $2; do
187048ffe56aSColin Percival		cut -f 1-2 -d '|' < ${X} |
187148ffe56aSColin Percival		    sort -u > ${X}.nodes
187248ffe56aSColin Percival	done
187348ffe56aSColin Percival
187448ffe56aSColin Percival	# Figure out which lines need to be removed from $1.
187548ffe56aSColin Percival	if [ ${ALLOWDELETE} != "yes" ]; then
187648ffe56aSColin Percival		comm -23 $1.nodes $2.nodes > $1.badnodes
187748ffe56aSColin Percival	else
187848ffe56aSColin Percival		: > $1.badnodes
187948ffe56aSColin Percival	fi
188048ffe56aSColin Percival
188148ffe56aSColin Percival	# Remove the relevant lines from $1
188248ffe56aSColin Percival	while read X; do
188348ffe56aSColin Percival		look "${X}|" $1
188448ffe56aSColin Percival	done < $1.badnodes |
188548ffe56aSColin Percival	    comm -13 - $1 > $1.tmp
188648ffe56aSColin Percival	mv $1.tmp $1
188748ffe56aSColin Percival
188848ffe56aSColin Percival	rm $1.badnodes $1.nodes $2.nodes
188948ffe56aSColin Percival}
189048ffe56aSColin Percival
189148ffe56aSColin Percival# If ${KEEPMODIFIEDMETADATA} == "yes", then for each entry in $2
189248ffe56aSColin Percival# with metadata not matching any entry in $1, replace the corresponding
189348ffe56aSColin Percival# line of $3 with one having the same metadata as the entry in $2.
189448ffe56aSColin Percivalfetch_filter_modified_metadata () {
189548ffe56aSColin Percival	# Fish out the metadata from $1 and $2
189648ffe56aSColin Percival	for X in $1 $2; do
189748ffe56aSColin Percival		cut -f 1-6 -d '|' < ${X} > ${X}.metadata
189848ffe56aSColin Percival	done
189948ffe56aSColin Percival
190048ffe56aSColin Percival	# Find the metadata we need to keep
190148ffe56aSColin Percival	if [ ${KEEPMODIFIEDMETADATA} = "yes" ]; then
190248ffe56aSColin Percival		comm -13 $1.metadata $2.metadata > keepmeta
190348ffe56aSColin Percival	else
190448ffe56aSColin Percival		: > keepmeta
190548ffe56aSColin Percival	fi
190648ffe56aSColin Percival
190748ffe56aSColin Percival	# Extract the lines which we need to remove from $3, and
190848ffe56aSColin Percival	# construct the lines which we need to add to $3.
190948ffe56aSColin Percival	: > $3.remove
191048ffe56aSColin Percival	: > $3.add
191148ffe56aSColin Percival	while read LINE; do
191248ffe56aSColin Percival		NODE=`echo "${LINE}" | cut -f 1-2 -d '|'`
191348ffe56aSColin Percival		look "${NODE}|" $3 >> $3.remove
191448ffe56aSColin Percival		look "${NODE}|" $3 |
191548ffe56aSColin Percival		    cut -f 7- -d '|' |
191648ffe56aSColin Percival		    lam -s "${LINE}|" - >> $3.add
191748ffe56aSColin Percival	done < keepmeta
191848ffe56aSColin Percival
191948ffe56aSColin Percival	# Remove the specified lines and add the new lines.
192048ffe56aSColin Percival	sort $3.remove |
192148ffe56aSColin Percival	    comm -13 - $3 |
192248ffe56aSColin Percival	    sort -u - $3.add > $3.tmp
192348ffe56aSColin Percival	mv $3.tmp $3
192448ffe56aSColin Percival
192548ffe56aSColin Percival	rm keepmeta $1.metadata $2.metadata $3.add $3.remove
192648ffe56aSColin Percival}
192748ffe56aSColin Percival
192848ffe56aSColin Percival# Remove lines from $1 and $2 which are identical;
192948ffe56aSColin Percival# no need to update a file if it isn't changing.
193048ffe56aSColin Percivalfetch_filter_uptodate () {
193148ffe56aSColin Percival	comm -23 $1 $2 > $1.tmp
193248ffe56aSColin Percival	comm -13 $1 $2 > $2.tmp
193348ffe56aSColin Percival
193448ffe56aSColin Percival	mv $1.tmp $1
193548ffe56aSColin Percival	mv $2.tmp $2
193648ffe56aSColin Percival}
193748ffe56aSColin Percival
1938db6b0a61SColin Percival# Fetch any "clean" old versions of files we need for merging changes.
1939db6b0a61SColin Percivalfetch_files_premerge () {
1940db6b0a61SColin Percival	# We only need to do anything if $1 is non-empty.
1941db6b0a61SColin Percival	if [ -s $1 ]; then
1942db6b0a61SColin Percival		# Tell the user what we're doing
1943db6b0a61SColin Percival		echo -n "Fetching files from ${OLDRELNUM} for merging... "
1944db6b0a61SColin Percival
1945db6b0a61SColin Percival		# List of files wanted
1946db6b0a61SColin Percival		fgrep '|f|' < $1 |
1947db6b0a61SColin Percival		    cut -f 3 -d '|' |
1948db6b0a61SColin Percival		    sort -u > files.wanted
1949db6b0a61SColin Percival
1950db6b0a61SColin Percival		# Only fetch the files we don't already have
1951db6b0a61SColin Percival		while read Y; do
1952db6b0a61SColin Percival			if [ ! -f "files/${Y}.gz" ]; then
1953db6b0a61SColin Percival				echo ${Y};
1954db6b0a61SColin Percival			fi
1955db6b0a61SColin Percival		done < files.wanted > filelist
1956db6b0a61SColin Percival
1957db6b0a61SColin Percival		# Actually fetch them
1958db6b0a61SColin Percival		lam -s "${OLDFETCHDIR}/f/" - -s ".gz" < filelist |
1959db6b0a61SColin Percival		    xargs ${XARGST} ${PHTTPGET} ${SERVERNAME}	\
1960db6b0a61SColin Percival		    2>${QUIETREDIR}
1961db6b0a61SColin Percival
1962db6b0a61SColin Percival		# Make sure we got them all, and move them into /files/
1963db6b0a61SColin Percival		while read Y; do
1964db6b0a61SColin Percival			if ! [ -f ${Y}.gz ]; then
1965db6b0a61SColin Percival				echo "failed."
1966db6b0a61SColin Percival				return 1
1967db6b0a61SColin Percival			fi
1968db6b0a61SColin Percival			if [ `gunzip -c < ${Y}.gz |
1969db6b0a61SColin Percival			    ${SHA256} -q` = ${Y} ]; then
1970db6b0a61SColin Percival				mv ${Y}.gz files/${Y}.gz
1971db6b0a61SColin Percival			else
1972db6b0a61SColin Percival				echo "${Y} has incorrect hash."
1973db6b0a61SColin Percival				return 1
1974db6b0a61SColin Percival			fi
1975db6b0a61SColin Percival		done < filelist
1976db6b0a61SColin Percival		echo "done."
1977db6b0a61SColin Percival
1978db6b0a61SColin Percival		# Clean up
1979db6b0a61SColin Percival		rm filelist files.wanted
1980db6b0a61SColin Percival	fi
1981db6b0a61SColin Percival}
1982db6b0a61SColin Percival
198348ffe56aSColin Percival# Prepare to fetch files: Generate a list of the files we need,
198448ffe56aSColin Percival# copy the unmodified files we have into /files/, and generate
198548ffe56aSColin Percival# a list of patches to download.
198648ffe56aSColin Percivalfetch_files_prepare () {
198748ffe56aSColin Percival	# Tell the user why his disk is suddenly making lots of noise
198848ffe56aSColin Percival	echo -n "Preparing to download files... "
198948ffe56aSColin Percival
199048ffe56aSColin Percival	# Reduce indices to ${PATH}|${HASH} pairs
199148ffe56aSColin Percival	for X in $1 $2 $3; do
199248ffe56aSColin Percival		cut -f 1,2,7 -d '|' < ${X} |
199348ffe56aSColin Percival		    fgrep '|f|' |
199448ffe56aSColin Percival		    cut -f 1,3 -d '|' |
199548ffe56aSColin Percival		    sort > ${X}.hashes
199648ffe56aSColin Percival	done
199748ffe56aSColin Percival
199848ffe56aSColin Percival	# List of files wanted
199948ffe56aSColin Percival	cut -f 2 -d '|' < $3.hashes |
20002328d598SColin Percival	    sort -u |
20012328d598SColin Percival	    while read HASH; do
20022328d598SColin Percival		if ! [ -f files/${HASH}.gz ]; then
20032328d598SColin Percival			echo ${HASH}
20042328d598SColin Percival		fi
20052328d598SColin Percival	done > files.wanted
200648ffe56aSColin Percival
200748ffe56aSColin Percival	# Generate a list of unmodified files
200848ffe56aSColin Percival	comm -12 $1.hashes $2.hashes |
200948ffe56aSColin Percival	    sort -k 1,1 -t '|' > unmodified.files
201048ffe56aSColin Percival
201148ffe56aSColin Percival	# Copy all files into /files/.  We only need the unmodified files
201248ffe56aSColin Percival	# for use in patching; but we'll want all of them if the user asks
201348ffe56aSColin Percival	# to rollback the updates later.
2014210b8123SColin Percival	while read LINE; do
2015210b8123SColin Percival		F=`echo "${LINE}" | cut -f 1 -d '|'`
2016210b8123SColin Percival		HASH=`echo "${LINE}" | cut -f 2 -d '|'`
2017210b8123SColin Percival
2018210b8123SColin Percival		# Skip files we already have.
2019210b8123SColin Percival		if [ -f files/${HASH}.gz ]; then
2020210b8123SColin Percival			continue
2021210b8123SColin Percival		fi
2022210b8123SColin Percival
2023210b8123SColin Percival		# Make sure the file hasn't changed.
202448ffe56aSColin Percival		cp "${BASEDIR}/${F}" tmpfile
2025210b8123SColin Percival		if [ `sha256 -q tmpfile` != ${HASH} ]; then
2026210b8123SColin Percival			echo
2027210b8123SColin Percival			echo "File changed while FreeBSD Update running: ${F}"
2028210b8123SColin Percival			return 1
2029210b8123SColin Percival		fi
2030210b8123SColin Percival
2031210b8123SColin Percival		# Place the file into storage.
2032210b8123SColin Percival		gzip -c < tmpfile > files/${HASH}.gz
203348ffe56aSColin Percival		rm tmpfile
2034210b8123SColin Percival	done < $2.hashes
203548ffe56aSColin Percival
203648ffe56aSColin Percival	# Produce a list of patches to download
203748ffe56aSColin Percival	sort -k 1,1 -t '|' $3.hashes |
203848ffe56aSColin Percival	    join -t '|' -o 2.2,1.2 - unmodified.files |
203948ffe56aSColin Percival	    fetch_make_patchlist > patchlist
204048ffe56aSColin Percival
204148ffe56aSColin Percival	# Garbage collect
204248ffe56aSColin Percival	rm unmodified.files $1.hashes $2.hashes $3.hashes
204348ffe56aSColin Percival
204448ffe56aSColin Percival	# We don't need the list of possible old files any more.
204548ffe56aSColin Percival	rm $1
204648ffe56aSColin Percival
204748ffe56aSColin Percival	# We're finished making noise
204848ffe56aSColin Percival	echo "done."
204948ffe56aSColin Percival}
205048ffe56aSColin Percival
205148ffe56aSColin Percival# Fetch files.
205248ffe56aSColin Percivalfetch_files () {
205348ffe56aSColin Percival	# Attempt to fetch patches
205448ffe56aSColin Percival	if [ -s patchlist ]; then
205548ffe56aSColin Percival		echo -n "Fetching `wc -l < patchlist | tr -d ' '` "
205648ffe56aSColin Percival		echo ${NDEBUG} "patches.${DDSTATS}"
205748ffe56aSColin Percival		tr '|' '-' < patchlist |
2058db6b0a61SColin Percival		    lam -s "${PATCHDIR}/" - |
205948ffe56aSColin Percival		    xargs ${XARGST} ${PHTTPGET} ${SERVERNAME}	\
206048ffe56aSColin Percival			2>${STATSREDIR} | fetch_progress
206148ffe56aSColin Percival		echo "done."
206248ffe56aSColin Percival
206348ffe56aSColin Percival		# Attempt to apply patches
206448ffe56aSColin Percival		echo -n "Applying patches... "
206548ffe56aSColin Percival		tr '|' ' ' < patchlist |
206648ffe56aSColin Percival		    while read X Y; do
206748ffe56aSColin Percival			if [ ! -f "${X}-${Y}" ]; then continue; fi
206848ffe56aSColin Percival			gunzip -c < files/${X}.gz > OLD
206948ffe56aSColin Percival
207048ffe56aSColin Percival			bspatch OLD NEW ${X}-${Y}
207148ffe56aSColin Percival
207248ffe56aSColin Percival			if [ `${SHA256} -q NEW` = ${Y} ]; then
207348ffe56aSColin Percival				mv NEW files/${Y}
207448ffe56aSColin Percival				gzip -n files/${Y}
207548ffe56aSColin Percival			fi
207648ffe56aSColin Percival			rm -f diff OLD NEW ${X}-${Y}
207748ffe56aSColin Percival		done 2>${QUIETREDIR}
207848ffe56aSColin Percival		echo "done."
207948ffe56aSColin Percival	fi
208048ffe56aSColin Percival
208148ffe56aSColin Percival	# Download files which couldn't be generate via patching
208248ffe56aSColin Percival	while read Y; do
208348ffe56aSColin Percival		if [ ! -f "files/${Y}.gz" ]; then
208448ffe56aSColin Percival			echo ${Y};
208548ffe56aSColin Percival		fi
208648ffe56aSColin Percival	done < files.wanted > filelist
208748ffe56aSColin Percival
208848ffe56aSColin Percival	if [ -s filelist ]; then
208948ffe56aSColin Percival		echo -n "Fetching `wc -l < filelist | tr -d ' '` "
209048ffe56aSColin Percival		echo ${NDEBUG} "files... "
209148ffe56aSColin Percival		lam -s "${FETCHDIR}/f/" - -s ".gz" < filelist |
209248ffe56aSColin Percival		    xargs ${XARGST} ${PHTTPGET} ${SERVERNAME}	\
2093d6e1e31aSConrad Meyer			2>${STATSREDIR} | fetch_progress
209448ffe56aSColin Percival
209548ffe56aSColin Percival		while read Y; do
209648ffe56aSColin Percival			if ! [ -f ${Y}.gz ]; then
209748ffe56aSColin Percival				echo "failed."
209848ffe56aSColin Percival				return 1
209948ffe56aSColin Percival			fi
210048ffe56aSColin Percival			if [ `gunzip -c < ${Y}.gz |
210148ffe56aSColin Percival			    ${SHA256} -q` = ${Y} ]; then
210248ffe56aSColin Percival				mv ${Y}.gz files/${Y}.gz
210348ffe56aSColin Percival			else
210448ffe56aSColin Percival				echo "${Y} has incorrect hash."
210548ffe56aSColin Percival				return 1
210648ffe56aSColin Percival			fi
210748ffe56aSColin Percival		done < filelist
210848ffe56aSColin Percival		echo "done."
210948ffe56aSColin Percival	fi
211048ffe56aSColin Percival
211148ffe56aSColin Percival	# Clean up
211248ffe56aSColin Percival	rm files.wanted filelist patchlist
211348ffe56aSColin Percival}
211448ffe56aSColin Percival
211548ffe56aSColin Percival# Create and populate install manifest directory; and report what updates
211648ffe56aSColin Percival# are available.
211748ffe56aSColin Percivalfetch_create_manifest () {
211848ffe56aSColin Percival	# If we have an existing install manifest, nuke it.
211948ffe56aSColin Percival	if [ -L "${BDHASH}-install" ]; then
212048ffe56aSColin Percival		rm -r ${BDHASH}-install/
212148ffe56aSColin Percival		rm ${BDHASH}-install
212248ffe56aSColin Percival	fi
212348ffe56aSColin Percival
212448ffe56aSColin Percival	# Report to the user if any updates were avoided due to local changes
212548ffe56aSColin Percival	if [ -s modifiedfiles ]; then
2126fc24ba59SEd Maste		cat - modifiedfiles <<- EOF | ${PAGER}
2127b882e02bSEnji Cooper			The following files are affected by updates. No changes have
2128b882e02bSEnji Cooper			been downloaded, however, because the files have been modified
2129b882e02bSEnji Cooper			locally:
2130fc24ba59SEd Maste		EOF
2131fc24ba59SEd Maste	fi
213248ffe56aSColin Percival	rm modifiedfiles
213348ffe56aSColin Percival
213448ffe56aSColin Percival	# If no files will be updated, tell the user and exit
213548ffe56aSColin Percival	if ! [ -s INDEX-PRESENT ] &&
213648ffe56aSColin Percival	    ! [ -s INDEX-NEW ]; then
213748ffe56aSColin Percival		rm INDEX-PRESENT INDEX-NEW
213848ffe56aSColin Percival		echo
213948ffe56aSColin Percival		echo -n "No updates needed to update system to "
214048ffe56aSColin Percival		echo "${RELNUM}-p${RELPATCHNUM}."
214148ffe56aSColin Percival		return
214248ffe56aSColin Percival	fi
214348ffe56aSColin Percival
214448ffe56aSColin Percival	# Divide files into (a) removed files, (b) added files, and
214548ffe56aSColin Percival	# (c) updated files.
214648ffe56aSColin Percival	cut -f 1 -d '|' < INDEX-PRESENT |
214748ffe56aSColin Percival	    sort > INDEX-PRESENT.flist
214848ffe56aSColin Percival	cut -f 1 -d '|' < INDEX-NEW |
214948ffe56aSColin Percival	    sort > INDEX-NEW.flist
215048ffe56aSColin Percival	comm -23 INDEX-PRESENT.flist INDEX-NEW.flist > files.removed
215148ffe56aSColin Percival	comm -13 INDEX-PRESENT.flist INDEX-NEW.flist > files.added
215248ffe56aSColin Percival	comm -12 INDEX-PRESENT.flist INDEX-NEW.flist > files.updated
215348ffe56aSColin Percival	rm INDEX-PRESENT.flist INDEX-NEW.flist
215448ffe56aSColin Percival
215548ffe56aSColin Percival	# Report removed files, if any
215648ffe56aSColin Percival	if [ -s files.removed ]; then
2157fc24ba59SEd Maste		cat - files.removed <<- EOF | ${PAGER}
2158fc24ba59SEd Maste			The following files will be removed as part of updating to
2159fc24ba59SEd Maste			${RELNUM}-p${RELPATCHNUM}:
2160fc24ba59SEd Maste		EOF
2161fc24ba59SEd Maste	fi
216248ffe56aSColin Percival	rm files.removed
216348ffe56aSColin Percival
216448ffe56aSColin Percival	# Report added files, if any
216548ffe56aSColin Percival	if [ -s files.added ]; then
2166fc24ba59SEd Maste		cat - files.added <<- EOF | ${PAGER}
2167fc24ba59SEd Maste			The following files will be added as part of updating to
2168fc24ba59SEd Maste			${RELNUM}-p${RELPATCHNUM}:
2169fc24ba59SEd Maste		EOF
2170fc24ba59SEd Maste	fi
217148ffe56aSColin Percival	rm files.added
217248ffe56aSColin Percival
217348ffe56aSColin Percival	# Report updated files, if any
217448ffe56aSColin Percival	if [ -s files.updated ]; then
2175fc24ba59SEd Maste		cat - files.updated <<- EOF | ${PAGER}
2176fc24ba59SEd Maste			The following files will be updated as part of updating to
2177fc24ba59SEd Maste			${RELNUM}-p${RELPATCHNUM}:
2178fc24ba59SEd Maste		EOF
2179fc24ba59SEd Maste	fi
218048ffe56aSColin Percival	rm files.updated
218148ffe56aSColin Percival
218248ffe56aSColin Percival	# Create a directory for the install manifest.
218348ffe56aSColin Percival	MDIR=`mktemp -d install.XXXXXX` || return 1
218448ffe56aSColin Percival
218548ffe56aSColin Percival	# Populate it
218648ffe56aSColin Percival	mv INDEX-PRESENT ${MDIR}/INDEX-OLD
218748ffe56aSColin Percival	mv INDEX-NEW ${MDIR}/INDEX-NEW
218848ffe56aSColin Percival
218948ffe56aSColin Percival	# Link it into place
219048ffe56aSColin Percival	ln -s ${MDIR} ${BDHASH}-install
219148ffe56aSColin Percival}
219248ffe56aSColin Percival
219348ffe56aSColin Percival# Warn about any upcoming EoL
219448ffe56aSColin Percivalfetch_warn_eol () {
219548ffe56aSColin Percival	# What's the current time?
219648ffe56aSColin Percival	NOWTIME=`date "+%s"`
219748ffe56aSColin Percival
219848ffe56aSColin Percival	# When did we last warn about the EoL date?
219948ffe56aSColin Percival	if [ -f lasteolwarn ]; then
220048ffe56aSColin Percival		LASTWARN=`cat lasteolwarn`
220148ffe56aSColin Percival	else
220248ffe56aSColin Percival		LASTWARN=`expr ${NOWTIME} - 63072000`
220348ffe56aSColin Percival	fi
220448ffe56aSColin Percival
220548ffe56aSColin Percival	# If the EoL time is past, warn.
220648ffe56aSColin Percival	if [ ${EOLTIME} -lt ${NOWTIME} ]; then
220748ffe56aSColin Percival		echo
220848ffe56aSColin Percival		cat <<-EOF
2209b698a3abSColin Percival		WARNING: `uname -sr` HAS PASSED ITS END-OF-LIFE DATE.
221048ffe56aSColin Percival		Any security issues discovered after `date -r ${EOLTIME}`
221148ffe56aSColin Percival		will not have been corrected.
221248ffe56aSColin Percival		EOF
221348ffe56aSColin Percival		return 1
221448ffe56aSColin Percival	fi
221548ffe56aSColin Percival
221648ffe56aSColin Percival	# Figure out how long it has been since we last warned about the
221748ffe56aSColin Percival	# upcoming EoL, and how much longer we have left.
221848ffe56aSColin Percival	SINCEWARN=`expr ${NOWTIME} - ${LASTWARN}`
221948ffe56aSColin Percival	TIMELEFT=`expr ${EOLTIME} - ${NOWTIME}`
222048ffe56aSColin Percival
222189b14566SColin Percival	# Don't warn if the EoL is more than 3 months away
222289b14566SColin Percival	if [ ${TIMELEFT} -gt 7884000 ]; then
222348ffe56aSColin Percival		return 0
222448ffe56aSColin Percival	fi
222548ffe56aSColin Percival
222648ffe56aSColin Percival	# Don't warn if the time remaining is more than 3 times the time
222748ffe56aSColin Percival	# since the last warning.
222848ffe56aSColin Percival	if [ ${TIMELEFT} -gt `expr ${SINCEWARN} \* 3` ]; then
222948ffe56aSColin Percival		return 0
223048ffe56aSColin Percival	fi
223148ffe56aSColin Percival
223248ffe56aSColin Percival	# Figure out what time units to use.
223348ffe56aSColin Percival	if [ ${TIMELEFT} -lt 604800 ]; then
223448ffe56aSColin Percival		UNIT="day"
223548ffe56aSColin Percival		SIZE=86400
223648ffe56aSColin Percival	elif [ ${TIMELEFT} -lt 2678400 ]; then
223748ffe56aSColin Percival		UNIT="week"
223848ffe56aSColin Percival		SIZE=604800
223948ffe56aSColin Percival	else
224048ffe56aSColin Percival		UNIT="month"
224148ffe56aSColin Percival		SIZE=2678400
224248ffe56aSColin Percival	fi
224348ffe56aSColin Percival
224448ffe56aSColin Percival	# Compute the right number of units
224548ffe56aSColin Percival	NUM=`expr ${TIMELEFT} / ${SIZE}`
224648ffe56aSColin Percival	if [ ${NUM} != 1 ]; then
224748ffe56aSColin Percival		UNIT="${UNIT}s"
224848ffe56aSColin Percival	fi
224948ffe56aSColin Percival
225048ffe56aSColin Percival	# Print the warning
225148ffe56aSColin Percival	echo
225248ffe56aSColin Percival	cat <<-EOF
225348ffe56aSColin Percival		WARNING: `uname -sr` is approaching its End-of-Life date.
225448ffe56aSColin Percival		It is strongly recommended that you upgrade to a newer
225548ffe56aSColin Percival		release within the next ${NUM} ${UNIT}.
225648ffe56aSColin Percival	EOF
225748ffe56aSColin Percival
225848ffe56aSColin Percival	# Update the stored time of last warning
225948ffe56aSColin Percival	echo ${NOWTIME} > lasteolwarn
226048ffe56aSColin Percival}
226148ffe56aSColin Percival
226248ffe56aSColin Percival# Do the actual work involved in "fetch" / "cron".
226348ffe56aSColin Percivalfetch_run () {
226448ffe56aSColin Percival	workdir_init || return 1
226548ffe56aSColin Percival
226648ffe56aSColin Percival	# Prepare the mirror list.
226748ffe56aSColin Percival	fetch_pick_server_init && fetch_pick_server
226848ffe56aSColin Percival
226948ffe56aSColin Percival	# Try to fetch the public key until we run out of servers.
227048ffe56aSColin Percival	while ! fetch_key; do
227148ffe56aSColin Percival		fetch_pick_server || return 1
227248ffe56aSColin Percival	done
227348ffe56aSColin Percival
227448ffe56aSColin Percival	# Try to fetch the metadata index signature ("tag") until we run
227548ffe56aSColin Percival	# out of available servers; and sanity check the downloaded tag.
227648ffe56aSColin Percival	while ! fetch_tag; do
227748ffe56aSColin Percival		fetch_pick_server || return 1
227848ffe56aSColin Percival	done
227948ffe56aSColin Percival	fetch_tagsanity || return 1
228048ffe56aSColin Percival
228148ffe56aSColin Percival	# Fetch the latest INDEX-NEW and INDEX-OLD files.
228248ffe56aSColin Percival	fetch_metadata INDEX-NEW INDEX-OLD || return 1
228348ffe56aSColin Percival
228448ffe56aSColin Percival	# Generate filtered INDEX-NEW and INDEX-OLD files containing only
228548ffe56aSColin Percival	# the lines which (a) belong to components we care about, and (b)
228648ffe56aSColin Percival	# don't correspond to paths we're explicitly ignoring.
228748ffe56aSColin Percival	fetch_filter_metadata INDEX-NEW || return 1
228848ffe56aSColin Percival	fetch_filter_metadata INDEX-OLD || return 1
228948ffe56aSColin Percival
2290db6b0a61SColin Percival	# Translate /boot/${KERNCONF} into ${KERNELDIR}
2291db6b0a61SColin Percival	fetch_filter_kernel_names INDEX-NEW ${KERNCONF}
2292db6b0a61SColin Percival	fetch_filter_kernel_names INDEX-OLD ${KERNCONF}
229348ffe56aSColin Percival
229448ffe56aSColin Percival	# For all paths appearing in INDEX-OLD or INDEX-NEW, inspect the
229548ffe56aSColin Percival	# system and generate an INDEX-PRESENT file.
229648ffe56aSColin Percival	fetch_inspect_system INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1
229748ffe56aSColin Percival
229848ffe56aSColin Percival	# Based on ${UPDATEIFUNMODIFIED}, remove lines from INDEX-* which
229948ffe56aSColin Percival	# correspond to lines in INDEX-PRESENT with hashes not appearing
230048ffe56aSColin Percival	# in INDEX-OLD or INDEX-NEW.  Also remove lines where the entry in
230148ffe56aSColin Percival	# INDEX-PRESENT has type - and there isn't a corresponding entry in
230248ffe56aSColin Percival	# INDEX-OLD with type -.
2303db6b0a61SColin Percival	fetch_filter_unmodified_notpresent	\
2304db6b0a61SColin Percival	    INDEX-OLD INDEX-PRESENT INDEX-NEW /dev/null
230548ffe56aSColin Percival
230648ffe56aSColin Percival	# For each entry in INDEX-PRESENT of type -, remove any corresponding
230748ffe56aSColin Percival	# entry from INDEX-NEW if ${ALLOWADD} != "yes".  Remove all entries
230848ffe56aSColin Percival	# of type - from INDEX-PRESENT.
230948ffe56aSColin Percival	fetch_filter_allowadd INDEX-PRESENT INDEX-NEW
231048ffe56aSColin Percival
231148ffe56aSColin Percival	# If ${ALLOWDELETE} != "yes", then remove any entries from
231248ffe56aSColin Percival	# INDEX-PRESENT which don't correspond to entries in INDEX-NEW.
231348ffe56aSColin Percival	fetch_filter_allowdelete INDEX-PRESENT INDEX-NEW
231448ffe56aSColin Percival
231548ffe56aSColin Percival	# If ${KEEPMODIFIEDMETADATA} == "yes", then for each entry in
231648ffe56aSColin Percival	# INDEX-PRESENT with metadata not matching any entry in INDEX-OLD,
231748ffe56aSColin Percival	# replace the corresponding line of INDEX-NEW with one having the
231848ffe56aSColin Percival	# same metadata as the entry in INDEX-PRESENT.
231948ffe56aSColin Percival	fetch_filter_modified_metadata INDEX-OLD INDEX-PRESENT INDEX-NEW
232048ffe56aSColin Percival
232148ffe56aSColin Percival	# Remove lines from INDEX-PRESENT and INDEX-NEW which are identical;
232248ffe56aSColin Percival	# no need to update a file if it isn't changing.
232348ffe56aSColin Percival	fetch_filter_uptodate INDEX-PRESENT INDEX-NEW
232448ffe56aSColin Percival
232548ffe56aSColin Percival	# Prepare to fetch files: Generate a list of the files we need,
232648ffe56aSColin Percival	# copy the unmodified files we have into /files/, and generate
232748ffe56aSColin Percival	# a list of patches to download.
2328210b8123SColin Percival	fetch_files_prepare INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1
232948ffe56aSColin Percival
233048ffe56aSColin Percival	# Fetch files.
233148ffe56aSColin Percival	fetch_files || return 1
233248ffe56aSColin Percival
233348ffe56aSColin Percival	# Create and populate install manifest directory; and report what
233448ffe56aSColin Percival	# updates are available.
233548ffe56aSColin Percival	fetch_create_manifest || return 1
233648ffe56aSColin Percival
233748ffe56aSColin Percival	# Warn about any upcoming EoL
233848ffe56aSColin Percival	fetch_warn_eol || return 1
233948ffe56aSColin Percival}
234048ffe56aSColin Percival
2341db6b0a61SColin Percival# If StrictComponents is not "yes", generate a new components list
2342db6b0a61SColin Percival# with only the components which appear to be installed.
2343db6b0a61SColin Percivalupgrade_guess_components () {
2344db6b0a61SColin Percival	if [ "${STRICTCOMPONENTS}" = "no" ]; then
2345db6b0a61SColin Percival		# Generate filtered INDEX-ALL with only the components listed
2346db6b0a61SColin Percival		# in COMPONENTS.
2347db6b0a61SColin Percival		fetch_filter_metadata_components $1 || return 1
2348db6b0a61SColin Percival
2349db6b0a61SColin Percival		# Tell the user why his disk is suddenly making lots of noise
2350db6b0a61SColin Percival		echo -n "Inspecting system... "
2351db6b0a61SColin Percival
2352db6b0a61SColin Percival		# Look at the files on disk, and assume that a component is
2353db6b0a61SColin Percival		# supposed to be present if it is more than half-present.
2354db6b0a61SColin Percival		cut -f 1-3 -d '|' < INDEX-ALL |
2355db6b0a61SColin Percival		    tr '|' ' ' |
2356db6b0a61SColin Percival		    while read C S F; do
2357db6b0a61SColin Percival			if [ -e ${BASEDIR}/${F} ]; then
2358db6b0a61SColin Percival				echo "+ ${C}|${S}"
2359db6b0a61SColin Percival			fi
2360db6b0a61SColin Percival			echo "= ${C}|${S}"
2361db6b0a61SColin Percival		    done |
2362db6b0a61SColin Percival		    sort |
2363db6b0a61SColin Percival		    uniq -c |
2364db6b0a61SColin Percival		    sed -E 's,^ +,,' > compfreq
2365db6b0a61SColin Percival		grep ' = ' compfreq |
2366db6b0a61SColin Percival		    cut -f 1,3 -d ' ' |
2367db6b0a61SColin Percival		    sort -k 2,2 -t ' ' > compfreq.total
2368db6b0a61SColin Percival		grep ' + ' compfreq |
2369db6b0a61SColin Percival		    cut -f 1,3 -d ' ' |
2370db6b0a61SColin Percival		    sort -k 2,2 -t ' ' > compfreq.present
2371db6b0a61SColin Percival		join -t ' ' -1 2 -2 2 compfreq.present compfreq.total |
2372db6b0a61SColin Percival		    while read S P T; do
2373ae97aa98SEd Maste			if [ ${T} -ne 0 -a ${P} -gt `expr ${T} / 2` ]; then
2374db6b0a61SColin Percival				echo ${S}
2375db6b0a61SColin Percival			fi
2376db6b0a61SColin Percival		    done > comp.present
2377db6b0a61SColin Percival		cut -f 2 -d ' ' < compfreq.total > comp.total
2378db6b0a61SColin Percival		rm INDEX-ALL compfreq compfreq.total compfreq.present
2379db6b0a61SColin Percival
2380db6b0a61SColin Percival		# We're done making noise.
2381db6b0a61SColin Percival		echo "done."
2382db6b0a61SColin Percival
2383db6b0a61SColin Percival		# Sometimes the kernel isn't installed where INDEX-ALL
2384db6b0a61SColin Percival		# thinks that it should be: In particular, it is often in
2385db6b0a61SColin Percival		# /boot/kernel instead of /boot/GENERIC or /boot/SMP.  To
2386db6b0a61SColin Percival		# deal with this, if "kernel|X" is listed in comp.total
2387db6b0a61SColin Percival		# (i.e., is a component which would be upgraded if it is
2388db6b0a61SColin Percival		# found to be present) we will add it to comp.present.
2389db6b0a61SColin Percival		# If "kernel|<anything>" is in comp.total but "kernel|X" is
2390db6b0a61SColin Percival		# not, we print a warning -- the user is running a kernel
2391db6b0a61SColin Percival		# which isn't part of the release.
2392db6b0a61SColin Percival		KCOMP=`echo ${KERNCONF} | tr 'A-Z' 'a-z'`
2393db6b0a61SColin Percival		grep -E "^kernel\|${KCOMP}\$" comp.total >> comp.present
2394db6b0a61SColin Percival
2395db6b0a61SColin Percival		if grep -qE "^kernel\|" comp.total &&
2396db6b0a61SColin Percival		    ! grep -qE "^kernel\|${KCOMP}\$" comp.total; then
2397db6b0a61SColin Percival			cat <<-EOF
2398db6b0a61SColin Percival
2399db6b0a61SColin PercivalWARNING: This system is running a "${KCOMP}" kernel, which is not a
2400db6b0a61SColin Percivalkernel configuration distributed as part of FreeBSD ${RELNUM}.
2401db6b0a61SColin PercivalThis kernel will not be updated: you MUST update the kernel manually
240259b02bb4SMichael Osipovbefore running '`basename $0` [options] install'.
2403db6b0a61SColin Percival			EOF
2404db6b0a61SColin Percival		fi
2405db6b0a61SColin Percival
2406db6b0a61SColin Percival		# Re-sort the list of installed components and generate
2407db6b0a61SColin Percival		# the list of non-installed components.
2408db6b0a61SColin Percival		sort -u < comp.present > comp.present.tmp
2409db6b0a61SColin Percival		mv comp.present.tmp comp.present
2410db6b0a61SColin Percival		comm -13 comp.present comp.total > comp.absent
2411db6b0a61SColin Percival
2412db6b0a61SColin Percival		# Ask the user to confirm that what we have is correct.  To
2413db6b0a61SColin Percival		# reduce user confusion, translate "X|Y" back to "X/Y" (as
2414db6b0a61SColin Percival		# subcomponents must be listed in the configuration file).
2415db6b0a61SColin Percival		echo
2416db6b0a61SColin Percival		echo -n "The following components of FreeBSD "
2417db6b0a61SColin Percival		echo "seem to be installed:"
2418db6b0a61SColin Percival		tr '|' '/' < comp.present |
2419db6b0a61SColin Percival		    fmt -72
2420db6b0a61SColin Percival		echo
2421db6b0a61SColin Percival		echo -n "The following components of FreeBSD "
2422db6b0a61SColin Percival		echo "do not seem to be installed:"
2423db6b0a61SColin Percival		tr '|' '/' < comp.absent |
2424db6b0a61SColin Percival		    fmt -72
2425db6b0a61SColin Percival		echo
2426db6b0a61SColin Percival		continuep || return 1
2427db6b0a61SColin Percival		echo
2428db6b0a61SColin Percival
2429db6b0a61SColin Percival		# Suck the generated list of components into ${COMPONENTS}.
2430db6b0a61SColin Percival		# Note that comp.present.tmp is used due to issues with
2431db6b0a61SColin Percival		# pipelines and setting variables.
2432db6b0a61SColin Percival		COMPONENTS=""
2433db6b0a61SColin Percival		tr '|' '/' < comp.present > comp.present.tmp
2434db6b0a61SColin Percival		while read C; do
2435db6b0a61SColin Percival			COMPONENTS="${COMPONENTS} ${C}"
2436db6b0a61SColin Percival		done < comp.present.tmp
2437db6b0a61SColin Percival
2438db6b0a61SColin Percival		# Delete temporary files
2439db6b0a61SColin Percival		rm comp.present comp.present.tmp comp.absent comp.total
2440db6b0a61SColin Percival	fi
2441db6b0a61SColin Percival}
2442db6b0a61SColin Percival
2443db6b0a61SColin Percival# If StrictComponents is not "yes", COMPONENTS contains an entry
2444db6b0a61SColin Percival# corresponding to the currently running kernel, and said kernel
2445db6b0a61SColin Percival# does not exist in the new release, add "kernel/generic" to the
2446db6b0a61SColin Percival# list of components.
2447db6b0a61SColin Percivalupgrade_guess_new_kernel () {
2448db6b0a61SColin Percival	if [ "${STRICTCOMPONENTS}" = "no" ]; then
2449db6b0a61SColin Percival		# Grab the unfiltered metadata file.
2450db6b0a61SColin Percival		METAHASH=`look "$1|" tINDEX.present | cut -f 2 -d '|'`
2451db6b0a61SColin Percival		gunzip -c < files/${METAHASH}.gz > $1.all
2452db6b0a61SColin Percival
2453db6b0a61SColin Percival		# If "kernel/${KCOMP}" is in ${COMPONENTS} and that component
2454db6b0a61SColin Percival		# isn't in $1.all, we need to add kernel/generic.
2455db6b0a61SColin Percival		for C in ${COMPONENTS}; do
2456db6b0a61SColin Percival			if [ ${C} = "kernel/${KCOMP}" ] &&
2457db6b0a61SColin Percival			    ! grep -qE "^kernel\|${KCOMP}\|" $1.all; then
2458db6b0a61SColin Percival				COMPONENTS="${COMPONENTS} kernel/generic"
2459db6b0a61SColin Percival				NKERNCONF="GENERIC"
2460db6b0a61SColin Percival				cat <<-EOF
2461db6b0a61SColin Percival
2462db6b0a61SColin PercivalWARNING: This system is running a "${KCOMP}" kernel, which is not a
2463db6b0a61SColin Percivalkernel configuration distributed as part of FreeBSD ${RELNUM}.
2464db6b0a61SColin PercivalAs part of upgrading to FreeBSD ${RELNUM}, this kernel will be
2465db6b0a61SColin Percivalreplaced with a "generic" kernel.
2466db6b0a61SColin Percival				EOF
2467db6b0a61SColin Percival				continuep || return 1
2468db6b0a61SColin Percival			fi
2469db6b0a61SColin Percival		done
2470db6b0a61SColin Percival
2471db6b0a61SColin Percival		# Don't need this any more...
2472db6b0a61SColin Percival		rm $1.all
2473db6b0a61SColin Percival	fi
2474db6b0a61SColin Percival}
2475db6b0a61SColin Percival
2476db6b0a61SColin Percival# Convert INDEX-OLD (last release) and INDEX-ALL (new release) into
2477db6b0a61SColin Percival# INDEX-OLD and INDEX-NEW files (in the sense of normal upgrades).
2478db6b0a61SColin Percivalupgrade_oldall_to_oldnew () {
2479db6b0a61SColin Percival	# For each ${F}|... which appears in INDEX-ALL but does not appear
2480db6b0a61SColin Percival	# in INDEX-OLD, add ${F}|-|||||| to INDEX-OLD.
2481db6b0a61SColin Percival	cut -f 1 -d '|' < $1 |
2482db6b0a61SColin Percival	    sort -u > $1.paths
2483db6b0a61SColin Percival	cut -f 1 -d '|' < $2 |
2484db6b0a61SColin Percival	    sort -u |
2485db6b0a61SColin Percival	    comm -13 $1.paths - |
2486db6b0a61SColin Percival	    lam - -s "|-||||||" |
2487db6b0a61SColin Percival	    sort - $1 > $1.tmp
2488db6b0a61SColin Percival	mv $1.tmp $1
2489db6b0a61SColin Percival
2490db6b0a61SColin Percival	# Remove lines from INDEX-OLD which also appear in INDEX-ALL
2491db6b0a61SColin Percival	comm -23 $1 $2 > $1.tmp
2492db6b0a61SColin Percival	mv $1.tmp $1
2493db6b0a61SColin Percival
2494db6b0a61SColin Percival	# Remove lines from INDEX-ALL which have a file name not appearing
2495db6b0a61SColin Percival	# anywhere in INDEX-OLD (since these must be files which haven't
2496db6b0a61SColin Percival	# changed -- if they were new, there would be an entry of type "-").
2497db6b0a61SColin Percival	cut -f 1 -d '|' < $1 |
2498db6b0a61SColin Percival	    sort -u > $1.paths
2499db6b0a61SColin Percival	sort -k 1,1 -t '|' < $2 |
2500db6b0a61SColin Percival	    join -t '|' - $1.paths |
2501db6b0a61SColin Percival	    sort > $2.tmp
2502db6b0a61SColin Percival	rm $1.paths
2503db6b0a61SColin Percival	mv $2.tmp $2
2504db6b0a61SColin Percival
2505db6b0a61SColin Percival	# Rename INDEX-ALL to INDEX-NEW.
2506db6b0a61SColin Percival	mv $2 $3
2507db6b0a61SColin Percival}
2508db6b0a61SColin Percival
25097449d2f5SColin Percival# Helper for upgrade_merge: Return zero true iff the two files differ only
25106d514f10SDag-Erling Smørgrav# in the contents of their RCS tags.
25117449d2f5SColin Percivalsamef () {
25127449d2f5SColin Percival	X=`sed -E 's/\\$FreeBSD.*\\$/\$FreeBSD\$/' < $1 | ${SHA256}`
25137449d2f5SColin Percival	Y=`sed -E 's/\\$FreeBSD.*\\$/\$FreeBSD\$/' < $2 | ${SHA256}`
25147449d2f5SColin Percival
25157449d2f5SColin Percival	if [ $X = $Y ]; then
25167449d2f5SColin Percival		return 0;
25177449d2f5SColin Percival	else
25187449d2f5SColin Percival		return 1;
25197449d2f5SColin Percival	fi
25207449d2f5SColin Percival}
25217449d2f5SColin Percival
2522db6b0a61SColin Percival# From the list of "old" files in $1, merge changes in $2 with those in $3,
2523db6b0a61SColin Percival# and update $3 to reflect the hashes of merged files.
2524db6b0a61SColin Percivalupgrade_merge () {
2525db6b0a61SColin Percival	# We only need to do anything if $1 is non-empty.
2526db6b0a61SColin Percival	if [ -s $1 ]; then
2527db6b0a61SColin Percival		cut -f 1 -d '|' $1 |
2528db6b0a61SColin Percival		    sort > $1-paths
2529db6b0a61SColin Percival
2530db6b0a61SColin Percival		# Create staging area for merging files
2531db6b0a61SColin Percival		rm -rf merge/
2532db6b0a61SColin Percival		while read F; do
2533db6b0a61SColin Percival			D=`dirname ${F}`
2534db6b0a61SColin Percival			mkdir -p merge/old/${D}
2535db6b0a61SColin Percival			mkdir -p merge/${OLDRELNUM}/${D}
2536db6b0a61SColin Percival			mkdir -p merge/${RELNUM}/${D}
2537db6b0a61SColin Percival			mkdir -p merge/new/${D}
2538db6b0a61SColin Percival		done < $1-paths
2539db6b0a61SColin Percival
2540db6b0a61SColin Percival		# Copy in files
2541db6b0a61SColin Percival		while read F; do
2542db6b0a61SColin Percival			# Currently installed file
2543db6b0a61SColin Percival			V=`look "${F}|" $2 | cut -f 7 -d '|'`
2544db6b0a61SColin Percival			gunzip < files/${V}.gz > merge/old/${F}
2545db6b0a61SColin Percival
2546db6b0a61SColin Percival			# Old release
2547db6b0a61SColin Percival			if look "${F}|" $1 | fgrep -q "|f|"; then
2548db6b0a61SColin Percival				V=`look "${F}|" $1 | cut -f 3 -d '|'`
2549db6b0a61SColin Percival				gunzip < files/${V}.gz		\
2550db6b0a61SColin Percival				    > merge/${OLDRELNUM}/${F}
2551db6b0a61SColin Percival			fi
2552db6b0a61SColin Percival
2553db6b0a61SColin Percival			# New release
2554db6b0a61SColin Percival			if look "${F}|" $3 | cut -f 1,2,7 -d '|' |
2555db6b0a61SColin Percival			    fgrep -q "|f|"; then
2556db6b0a61SColin Percival				V=`look "${F}|" $3 | cut -f 7 -d '|'`
2557db6b0a61SColin Percival				gunzip < files/${V}.gz		\
2558db6b0a61SColin Percival				    > merge/${RELNUM}/${F}
2559db6b0a61SColin Percival			fi
2560db6b0a61SColin Percival		done < $1-paths
2561db6b0a61SColin Percival
2562db6b0a61SColin Percival		# Attempt to automatically merge changes
2563db6b0a61SColin Percival		echo -n "Attempting to automatically merge "
2564db6b0a61SColin Percival		echo -n "changes in files..."
2565db6b0a61SColin Percival		: > failed.merges
2566db6b0a61SColin Percival		while read F; do
2567db6b0a61SColin Percival			# If the file doesn't exist in the new release,
2568db6b0a61SColin Percival			# the result of "merging changes" is having the file
2569db6b0a61SColin Percival			# not exist.
2570db6b0a61SColin Percival			if ! [ -f merge/${RELNUM}/${F} ]; then
2571db6b0a61SColin Percival				continue
2572db6b0a61SColin Percival			fi
2573db6b0a61SColin Percival
2574db6b0a61SColin Percival			# If the file didn't exist in the old release, we're
2575db6b0a61SColin Percival			# going to throw away the existing file and hope that
2576db6b0a61SColin Percival			# the version from the new release is what we want.
2577db6b0a61SColin Percival			if ! [ -f merge/${OLDRELNUM}/${F} ]; then
2578db6b0a61SColin Percival				cp merge/${RELNUM}/${F} merge/new/${F}
2579db6b0a61SColin Percival				continue
2580db6b0a61SColin Percival			fi
2581db6b0a61SColin Percival
2582db6b0a61SColin Percival			# Some files need special treatment.
2583db6b0a61SColin Percival			case ${F} in
2584db6b0a61SColin Percival			/etc/spwd.db | /etc/pwd.db | /etc/login.conf.db)
2585db6b0a61SColin Percival				# Don't merge these -- we're rebuild them
2586db6b0a61SColin Percival				# after updates are installed.
2587db6b0a61SColin Percival				cp merge/old/${F} merge/new/${F}
2588db6b0a61SColin Percival				;;
2589db6b0a61SColin Percival			*)
2590073dd712SBaptiste Daroussin				if ! diff3 -E -m -L "current version"	\
2591db6b0a61SColin Percival				    -L "${OLDRELNUM}" -L "${RELNUM}"	\
2592db6b0a61SColin Percival				    merge/old/${F}			\
2593db6b0a61SColin Percival				    merge/${OLDRELNUM}/${F}		\
2594db6b0a61SColin Percival				    merge/${RELNUM}/${F}		\
2595db6b0a61SColin Percival				    > merge/new/${F} 2>/dev/null; then
2596db6b0a61SColin Percival					echo ${F} >> failed.merges
2597db6b0a61SColin Percival				fi
2598db6b0a61SColin Percival				;;
2599db6b0a61SColin Percival			esac
2600db6b0a61SColin Percival		done < $1-paths
2601db6b0a61SColin Percival		echo " done."
2602db6b0a61SColin Percival
2603db6b0a61SColin Percival		# Ask the user to handle any files which didn't merge.
2604db6b0a61SColin Percival		while read F; do
26057449d2f5SColin Percival			# If the installed file differs from the version in
26066d514f10SDag-Erling Smørgrav			# the old release only due to RCS tag expansion
26077449d2f5SColin Percival			# then just use the version in the new release.
26087449d2f5SColin Percival			if samef merge/old/${F} merge/${OLDRELNUM}/${F}; then
26097449d2f5SColin Percival				cp merge/${RELNUM}/${F} merge/new/${F}
26107449d2f5SColin Percival				continue
26117449d2f5SColin Percival			fi
26127449d2f5SColin Percival
2613db6b0a61SColin Percival			cat <<-EOF
2614db6b0a61SColin Percival
2615db6b0a61SColin PercivalThe following file could not be merged automatically: ${F}
2616db6b0a61SColin PercivalPress Enter to edit this file in ${EDITOR} and resolve the conflicts
2617db6b0a61SColin Percivalmanually...
2618db6b0a61SColin Percival			EOF
2619ceb5f28bSEd Maste			while true; do
26203d442415SEd Maste				read response </dev/tty
26213d442415SEd Maste				if expr "${response}" : '[Aa][Cc][Cc][Ee][Pp][Tt]' > /dev/null; then
26223d442415SEd Maste					echo
26233d442415SEd Maste					break
26243d442415SEd Maste				fi
2625db6b0a61SColin Percival				${EDITOR} `pwd`/merge/new/${F} < /dev/tty
2626ceb5f28bSEd Maste
2627e27ded83SEd Maste				if ! grep -qE '^(<<<<<<<|=======|>>>>>>>)([[:space:]].*)?$' $(pwd)/merge/new/${F} ; then
2628ceb5f28bSEd Maste					break
2629ceb5f28bSEd Maste				fi
2630ceb5f28bSEd Maste				cat <<-EOF
2631ceb5f28bSEd Maste
2632ceb5f28bSEd MasteMerge conflict markers remain in: ${F}
2633ceb5f28bSEd MasteThese must be resolved for the system to be functional.
2634ceb5f28bSEd Maste
26353d442415SEd MastePress Enter to return to editing this file, or type "ACCEPT" to carry on with
26363d442415SEd Mastethese lines remaining in the file.
2637ceb5f28bSEd Maste				EOF
2638ceb5f28bSEd Maste			done
2639db6b0a61SColin Percival		done < failed.merges
2640db6b0a61SColin Percival		rm failed.merges
2641db6b0a61SColin Percival
2642db6b0a61SColin Percival		# Ask the user to confirm that he likes how the result
2643db6b0a61SColin Percival		# of merging files.
2644db6b0a61SColin Percival		while read F; do
26457449d2f5SColin Percival			# Skip files which haven't changed except possibly
26466d514f10SDag-Erling Smørgrav			# in their RCS tags.
26477449d2f5SColin Percival			if [ -f merge/old/${F} ] && [ -f merge/new/${F} ] &&
26487449d2f5SColin Percival			    samef merge/old/${F} merge/new/${F}; then
26497449d2f5SColin Percival				continue
26507449d2f5SColin Percival			fi
26517449d2f5SColin Percival
26527449d2f5SColin Percival			# Skip files where the installed file differs from
26536d514f10SDag-Erling Smørgrav			# the old file only due to RCS tags.
26547449d2f5SColin Percival			if [ -f merge/old/${F} ] &&
26557449d2f5SColin Percival			    [ -f merge/${OLDRELNUM}/${F} ] &&
26567449d2f5SColin Percival			    samef merge/old/${F} merge/${OLDRELNUM}/${F}; then
2657db6b0a61SColin Percival				continue
2658db6b0a61SColin Percival			fi
2659db6b0a61SColin Percival
2660db6b0a61SColin Percival			# Warn about files which are ceasing to exist.
2661db6b0a61SColin Percival			if ! [ -f merge/new/${F} ]; then
2662db6b0a61SColin Percival				cat <<-EOF
2663db6b0a61SColin Percival
2664db6b0a61SColin PercivalThe following file will be removed, as it no longer exists in
2665db6b0a61SColin PercivalFreeBSD ${RELNUM}: ${F}
2666db6b0a61SColin Percival				EOF
2667db6b0a61SColin Percival				continuep < /dev/tty || return 1
2668db6b0a61SColin Percival				continue
2669db6b0a61SColin Percival			fi
2670db6b0a61SColin Percival
2671db6b0a61SColin Percival			# Print changes for the user's approval.
2672db6b0a61SColin Percival			cat <<-EOF
2673db6b0a61SColin Percival
2674db6b0a61SColin PercivalThe following changes, which occurred between FreeBSD ${OLDRELNUM} and
2675db6b0a61SColin PercivalFreeBSD ${RELNUM} have been merged into ${F}:
2676db6b0a61SColin PercivalEOF
2677db6b0a61SColin Percival			diff -U 5 -L "current version" -L "new version"	\
2678db6b0a61SColin Percival			    merge/old/${F} merge/new/${F} || true
2679db6b0a61SColin Percival			continuep < /dev/tty || return 1
2680db6b0a61SColin Percival		done < $1-paths
2681db6b0a61SColin Percival
2682db6b0a61SColin Percival		# Store merged files.
2683db6b0a61SColin Percival		while read F; do
2684c58b62efSColin Percival			if [ -f merge/new/${F} ]; then
2685db6b0a61SColin Percival				V=`${SHA256} -q merge/new/${F}`
2686db6b0a61SColin Percival
2687db6b0a61SColin Percival				gzip -c < merge/new/${F} > files/${V}.gz
2688db6b0a61SColin Percival				echo "${F}|${V}"
2689db6b0a61SColin Percival			fi
2690db6b0a61SColin Percival		done < $1-paths > newhashes
2691db6b0a61SColin Percival
2692db6b0a61SColin Percival		# Pull lines out from $3 which need to be updated to
2693db6b0a61SColin Percival		# reflect merged files.
2694db6b0a61SColin Percival		while read F; do
2695db6b0a61SColin Percival			look "${F}|" $3
2696db6b0a61SColin Percival		done < $1-paths > $3-oldlines
2697db6b0a61SColin Percival
2698db6b0a61SColin Percival		# Update lines to reflect merged files
2699db6b0a61SColin Percival		join -t '|' -o 1.1,1.2,1.3,1.4,1.5,1.6,2.2,1.8		\
2700db6b0a61SColin Percival		    $3-oldlines newhashes > $3-newlines
2701db6b0a61SColin Percival
2702db6b0a61SColin Percival		# Remove old lines from $3 and add new lines.
2703db6b0a61SColin Percival		sort $3-oldlines |
2704db6b0a61SColin Percival		    comm -13 - $3 |
2705db6b0a61SColin Percival		    sort - $3-newlines > $3.tmp
2706db6b0a61SColin Percival		mv $3.tmp $3
2707db6b0a61SColin Percival
2708db6b0a61SColin Percival		# Clean up
2709db6b0a61SColin Percival		rm $1-paths newhashes $3-oldlines $3-newlines
2710db6b0a61SColin Percival		rm -rf merge/
2711db6b0a61SColin Percival	fi
2712db6b0a61SColin Percival
2713db6b0a61SColin Percival	# We're done with merging files.
2714db6b0a61SColin Percival	rm $1
2715db6b0a61SColin Percival}
2716db6b0a61SColin Percival
2717db6b0a61SColin Percival# Do the work involved in fetching upgrades to a new release
2718db6b0a61SColin Percivalupgrade_run () {
2719db6b0a61SColin Percival	workdir_init || return 1
2720db6b0a61SColin Percival
2721db6b0a61SColin Percival	# Prepare the mirror list.
2722db6b0a61SColin Percival	fetch_pick_server_init && fetch_pick_server
2723db6b0a61SColin Percival
2724db6b0a61SColin Percival	# Try to fetch the public key until we run out of servers.
2725db6b0a61SColin Percival	while ! fetch_key; do
2726db6b0a61SColin Percival		fetch_pick_server || return 1
2727db6b0a61SColin Percival	done
2728db6b0a61SColin Percival
2729db6b0a61SColin Percival	# Try to fetch the metadata index signature ("tag") until we run
2730db6b0a61SColin Percival	# out of available servers; and sanity check the downloaded tag.
2731db6b0a61SColin Percival	while ! fetch_tag; do
2732db6b0a61SColin Percival		fetch_pick_server || return 1
2733db6b0a61SColin Percival	done
2734db6b0a61SColin Percival	fetch_tagsanity || return 1
2735db6b0a61SColin Percival
2736db6b0a61SColin Percival	# Fetch the INDEX-OLD and INDEX-ALL.
2737db6b0a61SColin Percival	fetch_metadata INDEX-OLD INDEX-ALL || return 1
2738db6b0a61SColin Percival
2739db6b0a61SColin Percival	# If StrictComponents is not "yes", generate a new components list
2740db6b0a61SColin Percival	# with only the components which appear to be installed.
2741db6b0a61SColin Percival	upgrade_guess_components INDEX-ALL || return 1
2742db6b0a61SColin Percival
2743db6b0a61SColin Percival	# Generate filtered INDEX-OLD and INDEX-ALL files containing only
2744db6b0a61SColin Percival	# the components we want and without anything marked as "Ignore".
2745db6b0a61SColin Percival	fetch_filter_metadata INDEX-OLD || return 1
2746db6b0a61SColin Percival	fetch_filter_metadata INDEX-ALL || return 1
2747db6b0a61SColin Percival
2748db6b0a61SColin Percival	# Merge the INDEX-OLD and INDEX-ALL files into INDEX-OLD.
2749db6b0a61SColin Percival	sort INDEX-OLD INDEX-ALL > INDEX-OLD.tmp
2750db6b0a61SColin Percival	mv INDEX-OLD.tmp INDEX-OLD
2751db6b0a61SColin Percival	rm INDEX-ALL
2752db6b0a61SColin Percival
2753db6b0a61SColin Percival	# Adjust variables for fetching files from the new release.
2754db6b0a61SColin Percival	OLDRELNUM=${RELNUM}
2755db6b0a61SColin Percival	RELNUM=${TARGETRELEASE}
2756db6b0a61SColin Percival	OLDFETCHDIR=${FETCHDIR}
2757db6b0a61SColin Percival	FETCHDIR=${RELNUM}/${ARCH}
2758db6b0a61SColin Percival
2759db6b0a61SColin Percival	# Try to fetch the NEW metadata index signature ("tag") until we run
2760db6b0a61SColin Percival	# out of available servers; and sanity check the downloaded tag.
2761db6b0a61SColin Percival	while ! fetch_tag; do
2762db6b0a61SColin Percival		fetch_pick_server || return 1
2763db6b0a61SColin Percival	done
2764db6b0a61SColin Percival
2765db6b0a61SColin Percival	# Fetch the new INDEX-ALL.
2766db6b0a61SColin Percival	fetch_metadata INDEX-ALL || return 1
2767db6b0a61SColin Percival
2768db6b0a61SColin Percival	# If StrictComponents is not "yes", COMPONENTS contains an entry
2769db6b0a61SColin Percival	# corresponding to the currently running kernel, and said kernel
2770db6b0a61SColin Percival	# does not exist in the new release, add "kernel/generic" to the
2771db6b0a61SColin Percival	# list of components.
2772db6b0a61SColin Percival	upgrade_guess_new_kernel INDEX-ALL || return 1
2773db6b0a61SColin Percival
2774db6b0a61SColin Percival	# Filter INDEX-ALL to contain only the components we want and without
2775db6b0a61SColin Percival	# anything marked as "Ignore".
2776db6b0a61SColin Percival	fetch_filter_metadata INDEX-ALL || return 1
2777db6b0a61SColin Percival
2778db6b0a61SColin Percival	# Convert INDEX-OLD (last release) and INDEX-ALL (new release) into
2779db6b0a61SColin Percival	# INDEX-OLD and INDEX-NEW files (in the sense of normal upgrades).
2780db6b0a61SColin Percival	upgrade_oldall_to_oldnew INDEX-OLD INDEX-ALL INDEX-NEW
2781db6b0a61SColin Percival
2782db6b0a61SColin Percival	# Translate /boot/${KERNCONF} or /boot/${NKERNCONF} into ${KERNELDIR}
2783db6b0a61SColin Percival	fetch_filter_kernel_names INDEX-NEW ${NKERNCONF}
2784db6b0a61SColin Percival	fetch_filter_kernel_names INDEX-OLD ${KERNCONF}
2785db6b0a61SColin Percival
2786db6b0a61SColin Percival	# For all paths appearing in INDEX-OLD or INDEX-NEW, inspect the
2787db6b0a61SColin Percival	# system and generate an INDEX-PRESENT file.
2788db6b0a61SColin Percival	fetch_inspect_system INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1
2789db6b0a61SColin Percival
2790db6b0a61SColin Percival	# Based on ${MERGECHANGES}, generate a file tomerge-old with the
2791db6b0a61SColin Percival	# paths and hashes of old versions of files to merge.
2792c55b7e52SColin Percival	fetch_filter_mergechanges INDEX-OLD INDEX-PRESENT INDEX-NEW tomerge-old
2793db6b0a61SColin Percival
2794db6b0a61SColin Percival	# Based on ${UPDATEIFUNMODIFIED}, remove lines from INDEX-* which
2795db6b0a61SColin Percival	# correspond to lines in INDEX-PRESENT with hashes not appearing
2796db6b0a61SColin Percival	# in INDEX-OLD or INDEX-NEW.  Also remove lines where the entry in
2797db6b0a61SColin Percival	# INDEX-PRESENT has type - and there isn't a corresponding entry in
2798db6b0a61SColin Percival	# INDEX-OLD with type -.
2799db6b0a61SColin Percival	fetch_filter_unmodified_notpresent	\
2800db6b0a61SColin Percival	    INDEX-OLD INDEX-PRESENT INDEX-NEW tomerge-old
2801db6b0a61SColin Percival
2802db6b0a61SColin Percival	# For each entry in INDEX-PRESENT of type -, remove any corresponding
2803db6b0a61SColin Percival	# entry from INDEX-NEW if ${ALLOWADD} != "yes".  Remove all entries
2804db6b0a61SColin Percival	# of type - from INDEX-PRESENT.
2805db6b0a61SColin Percival	fetch_filter_allowadd INDEX-PRESENT INDEX-NEW
2806db6b0a61SColin Percival
2807db6b0a61SColin Percival	# If ${ALLOWDELETE} != "yes", then remove any entries from
2808db6b0a61SColin Percival	# INDEX-PRESENT which don't correspond to entries in INDEX-NEW.
2809db6b0a61SColin Percival	fetch_filter_allowdelete INDEX-PRESENT INDEX-NEW
2810db6b0a61SColin Percival
2811db6b0a61SColin Percival	# If ${KEEPMODIFIEDMETADATA} == "yes", then for each entry in
2812db6b0a61SColin Percival	# INDEX-PRESENT with metadata not matching any entry in INDEX-OLD,
2813db6b0a61SColin Percival	# replace the corresponding line of INDEX-NEW with one having the
2814db6b0a61SColin Percival	# same metadata as the entry in INDEX-PRESENT.
2815db6b0a61SColin Percival	fetch_filter_modified_metadata INDEX-OLD INDEX-PRESENT INDEX-NEW
2816db6b0a61SColin Percival
2817db6b0a61SColin Percival	# Remove lines from INDEX-PRESENT and INDEX-NEW which are identical;
2818db6b0a61SColin Percival	# no need to update a file if it isn't changing.
2819db6b0a61SColin Percival	fetch_filter_uptodate INDEX-PRESENT INDEX-NEW
2820db6b0a61SColin Percival
2821db6b0a61SColin Percival	# Fetch "clean" files from the old release for merging changes.
2822db6b0a61SColin Percival	fetch_files_premerge tomerge-old
2823db6b0a61SColin Percival
2824db6b0a61SColin Percival	# Prepare to fetch files: Generate a list of the files we need,
2825db6b0a61SColin Percival	# copy the unmodified files we have into /files/, and generate
2826db6b0a61SColin Percival	# a list of patches to download.
2827db6b0a61SColin Percival	fetch_files_prepare INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1
2828db6b0a61SColin Percival
2829db6b0a61SColin Percival	# Fetch patches from to-${RELNUM}/${ARCH}/bp/
2830db6b0a61SColin Percival	PATCHDIR=to-${RELNUM}/${ARCH}/bp
2831db6b0a61SColin Percival	fetch_files || return 1
2832db6b0a61SColin Percival
2833db6b0a61SColin Percival	# Merge configuration file changes.
2834db6b0a61SColin Percival	upgrade_merge tomerge-old INDEX-PRESENT INDEX-NEW || return 1
2835db6b0a61SColin Percival
2836db6b0a61SColin Percival	# Create and populate install manifest directory; and report what
2837db6b0a61SColin Percival	# updates are available.
2838db6b0a61SColin Percival	fetch_create_manifest || return 1
2839db6b0a61SColin Percival
2840db6b0a61SColin Percival	# Leave a note behind to tell the "install" command that the kernel
2841db6b0a61SColin Percival	# needs to be installed before the world.
2842db6b0a61SColin Percival	touch ${BDHASH}-install/kernelfirst
284385451f90SColin Percival
284485451f90SColin Percival	# Remind the user that they need to run "freebsd-update install"
284585451f90SColin Percival	# to install the downloaded bits, in case they didn't RTFM.
284659b02bb4SMichael Osipov	echo "To install the downloaded upgrades, run '`basename $0` [options] install'."
2847db6b0a61SColin Percival}
2848db6b0a61SColin Percival
284948ffe56aSColin Percival# Make sure that all the file hashes mentioned in $@ have corresponding
285048ffe56aSColin Percival# gzipped files stored in /files/.
285148ffe56aSColin Percivalinstall_verify () {
285248ffe56aSColin Percival	# Generate a list of hashes
285348ffe56aSColin Percival	cat $@ |
285448ffe56aSColin Percival	    cut -f 2,7 -d '|' |
285548ffe56aSColin Percival	    grep -E '^f' |
285648ffe56aSColin Percival	    cut -f 2 -d '|' |
285748ffe56aSColin Percival	    sort -u > filelist
285848ffe56aSColin Percival
285948ffe56aSColin Percival	# Make sure all the hashes exist
286048ffe56aSColin Percival	while read HASH; do
286148ffe56aSColin Percival		if ! [ -f files/${HASH}.gz ]; then
286248ffe56aSColin Percival			echo -n "Update files missing -- "
286348ffe56aSColin Percival			echo "this should never happen."
286459b02bb4SMichael Osipov			echo "Re-run '`basename $0` [options] fetch'."
286548ffe56aSColin Percival			return 1
286648ffe56aSColin Percival		fi
286748ffe56aSColin Percival	done < filelist
286848ffe56aSColin Percival
286948ffe56aSColin Percival	# Clean up
287048ffe56aSColin Percival	rm filelist
287148ffe56aSColin Percival}
287248ffe56aSColin Percival
287348ffe56aSColin Percival# Remove the system immutable flag from files
287448ffe56aSColin Percivalinstall_unschg () {
287548ffe56aSColin Percival	# Generate file list
287648ffe56aSColin Percival	cat $@ |
287748ffe56aSColin Percival	    cut -f 1 -d '|' > filelist
287848ffe56aSColin Percival
287948ffe56aSColin Percival	# Remove flags
288048ffe56aSColin Percival	while read F; do
2881e829ed67SColin Percival		if ! [ -e ${BASEDIR}/${F} ]; then
288248ffe56aSColin Percival			continue
28835a74378cSXin LI		else
28845a74378cSXin LI			echo ${BASEDIR}/${F}
288548ffe56aSColin Percival		fi
28865a74378cSXin LI	done < filelist | xargs chflags noschg || return 1
288748ffe56aSColin Percival
288848ffe56aSColin Percival	# Clean up
288948ffe56aSColin Percival	rm filelist
289048ffe56aSColin Percival}
289148ffe56aSColin Percival
289223d827efSSimon L. B. Nielsen# Decide which directory name to use for kernel backups.
289323d827efSSimon L. B. Nielsenbackup_kernel_finddir () {
289423d827efSSimon L. B. Nielsen	CNT=0
289523d827efSSimon L. B. Nielsen	while true ; do
289623d827efSSimon L. B. Nielsen		# Pathname does not exist, so it is OK use that name
289723d827efSSimon L. B. Nielsen		# for backup directory.
2898c4a0c62cSThomas Quinot		if [ ! -e $BASEDIR/$BACKUPKERNELDIR ]; then
289923d827efSSimon L. B. Nielsen			return 0
290023d827efSSimon L. B. Nielsen		fi
290123d827efSSimon L. B. Nielsen
290223d827efSSimon L. B. Nielsen		# If directory do exist, we only use if it has our
290323d827efSSimon L. B. Nielsen		# marker file.
2904c4a0c62cSThomas Quinot		if [ -d $BASEDIR/$BACKUPKERNELDIR -a \
2905c4a0c62cSThomas Quinot			-e $BASEDIR/$BACKUPKERNELDIR/.freebsd-update ]; then
290623d827efSSimon L. B. Nielsen			return 0
290723d827efSSimon L. B. Nielsen		fi
290823d827efSSimon L. B. Nielsen
290923d827efSSimon L. B. Nielsen		# We could not use current directory name, so add counter to
291023d827efSSimon L. B. Nielsen		# the end and try again.
291123d827efSSimon L. B. Nielsen		CNT=$((CNT + 1))
291223d827efSSimon L. B. Nielsen		if [ $CNT -gt 9 ]; then
2913c4a0c62cSThomas Quinot			echo "Could not find valid backup dir ($BASEDIR/$BACKUPKERNELDIR)"
291423d827efSSimon L. B. Nielsen			exit 1
291523d827efSSimon L. B. Nielsen		fi
291623d827efSSimon L. B. Nielsen		BACKUPKERNELDIR="`echo $BACKUPKERNELDIR | sed -Ee 's/[0-9]\$//'`"
291723d827efSSimon L. B. Nielsen		BACKUPKERNELDIR="${BACKUPKERNELDIR}${CNT}"
291823d827efSSimon L. B. Nielsen	done
291923d827efSSimon L. B. Nielsen}
292023d827efSSimon L. B. Nielsen
292123d827efSSimon L. B. Nielsen# Backup the current kernel using hardlinks, if not disabled by user.
292223d827efSSimon L. B. Nielsen# Since we delete all files in the directory used for previous backups
292323d827efSSimon L. B. Nielsen# we create a marker file called ".freebsd-update" in the directory so
292423d827efSSimon L. B. Nielsen# we can determine on the next run that the directory was created by
292523d827efSSimon L. B. Nielsen# freebsd-update and we then do not accidentally remove user files in
292623d827efSSimon L. B. Nielsen# the unlikely case that the user has created a directory with a
292723d827efSSimon L. B. Nielsen# conflicting name.
292823d827efSSimon L. B. Nielsenbackup_kernel () {
292923d827efSSimon L. B. Nielsen	# Only make kernel backup is so configured.
293023d827efSSimon L. B. Nielsen	if [ $BACKUPKERNEL != yes ]; then
293123d827efSSimon L. B. Nielsen		return 0
293223d827efSSimon L. B. Nielsen	fi
293323d827efSSimon L. B. Nielsen
293423d827efSSimon L. B. Nielsen	# Decide which directory name to use for kernel backups.
293523d827efSSimon L. B. Nielsen	backup_kernel_finddir
293623d827efSSimon L. B. Nielsen
293723d827efSSimon L. B. Nielsen	# Remove old kernel backup files.  If $BACKUPKERNELDIR was
293823d827efSSimon L. B. Nielsen	# "not ours", backup_kernel_finddir would have exited, so
293923d827efSSimon L. B. Nielsen	# deleting the directory content is as safe as we can make it.
2940c4a0c62cSThomas Quinot	if [ -d $BASEDIR/$BACKUPKERNELDIR ]; then
2941c4a0c62cSThomas Quinot		rm -fr $BASEDIR/$BACKUPKERNELDIR
294223d827efSSimon L. B. Nielsen	fi
294323d827efSSimon L. B. Nielsen
2944ab7d0151SJaakko Heinonen	# Create directories for backup.
2945c4a0c62cSThomas Quinot	mkdir -p $BASEDIR/$BACKUPKERNELDIR
2946c4a0c62cSThomas Quinot	mtree -cdn -p "${BASEDIR}/${KERNELDIR}" | \
2947c4a0c62cSThomas Quinot	    mtree -Ue -p "${BASEDIR}/${BACKUPKERNELDIR}" > /dev/null
294823d827efSSimon L. B. Nielsen
294923d827efSSimon L. B. Nielsen	# Mark the directory as having been created by freebsd-update.
2950c4a0c62cSThomas Quinot	touch $BASEDIR/$BACKUPKERNELDIR/.freebsd-update
295123d827efSSimon L. B. Nielsen	if [ $? -ne 0 ]; then
295223d827efSSimon L. B. Nielsen		echo "Could not create kernel backup directory"
295323d827efSSimon L. B. Nielsen		exit 1
295423d827efSSimon L. B. Nielsen	fi
295523d827efSSimon L. B. Nielsen
295623d827efSSimon L. B. Nielsen	# Disable pathname expansion to be sure *.symbols is not
295723d827efSSimon L. B. Nielsen	# expanded.
295823d827efSSimon L. B. Nielsen	set -f
295923d827efSSimon L. B. Nielsen
296023d827efSSimon L. B. Nielsen	# Use find to ignore symbol files, unless disabled by user.
296123d827efSSimon L. B. Nielsen	if [ $BACKUPKERNELSYMBOLFILES = yes ]; then
296223d827efSSimon L. B. Nielsen		FINDFILTER=""
296323d827efSSimon L. B. Nielsen	else
29647e1ed2c7SEd Maste		FINDFILTER="-a ! -name *.debug -a ! -name *.symbols"
296523d827efSSimon L. B. Nielsen	fi
296623d827efSSimon L. B. Nielsen
296723d827efSSimon L. B. Nielsen	# Backup all the kernel files using hardlinks.
2968c4a0c62cSThomas Quinot	(cd ${BASEDIR}/${KERNELDIR} && find . -type f $FINDFILTER -exec \
2969c4a0c62cSThomas Quinot	    cp -pl '{}' ${BASEDIR}/${BACKUPKERNELDIR}/'{}' \;)
297023d827efSSimon L. B. Nielsen
297191811711Sa-biardi	# Re-enable pathname expansion.
297223d827efSSimon L. B. Nielsen	set +f
297323d827efSSimon L. B. Nielsen}
297423d827efSSimon L. B. Nielsen
2975c0f52443SEd Maste# Check for and remove an existing directory that conflicts with the file or
2976c0f52443SEd Maste# symlink that we are going to install.
2977c0f52443SEd Mastedir_conflict () {
2978c0f52443SEd Maste	if [ -d "$1" ]; then
2979c0f52443SEd Maste		echo "Removing conflicting directory $1"
2980c0f52443SEd Maste		rm -rf -- "$1"
2981c0f52443SEd Maste	fi
2982c0f52443SEd Maste}
2983c0f52443SEd Maste
298448ffe56aSColin Percival# Install new files
298548ffe56aSColin Percivalinstall_from_index () {
298648ffe56aSColin Percival	# First pass: Do everything apart from setting file flags.  We
298748ffe56aSColin Percival	# can't set flags yet, because schg inhibits hard linking.
298848ffe56aSColin Percival	sort -k 1,1 -t '|' $1 |
298948ffe56aSColin Percival	    tr '|' ' ' |
299048ffe56aSColin Percival	    while read FPATH TYPE OWNER GROUP PERM FLAGS HASH LINK; do
299148ffe56aSColin Percival		case ${TYPE} in
299248ffe56aSColin Percival		d)
2993f6d37c9cSEd Maste			# Create a directory.  A file may change to a directory
2994f6d37c9cSEd Maste			# on upgrade (PR273661).  If that happens, remove the
2995f6d37c9cSEd Maste			# file first.
2996f6d37c9cSEd Maste			if [ -e "${BASEDIR}/${FPATH}" ] && \
2997f6d37c9cSEd Maste			    ! [ -d "${BASEDIR}/${FPATH}" ]; then
2998f6d37c9cSEd Maste				rm -f -- "${BASEDIR}/${FPATH}"
2999f6d37c9cSEd Maste			fi
300048ffe56aSColin Percival			install -d -o ${OWNER} -g ${GROUP}		\
300148ffe56aSColin Percival			    -m ${PERM} ${BASEDIR}/${FPATH}
300248ffe56aSColin Percival			;;
300348ffe56aSColin Percival		f)
3004c0f52443SEd Maste			dir_conflict "${BASEDIR}/${FPATH}"
300548ffe56aSColin Percival			if [ -z "${LINK}" ]; then
300648ffe56aSColin Percival				# Create a file, without setting flags.
300748ffe56aSColin Percival				gunzip < files/${HASH}.gz > ${HASH}
300848ffe56aSColin Percival				install -S -o ${OWNER} -g ${GROUP}	\
300948ffe56aSColin Percival				    -m ${PERM} ${HASH} ${BASEDIR}/${FPATH}
301048ffe56aSColin Percival				rm ${HASH}
301148ffe56aSColin Percival			else
301248ffe56aSColin Percival				# Create a hard link.
3013e829ed67SColin Percival				ln -f ${BASEDIR}/${LINK} ${BASEDIR}/${FPATH}
301448ffe56aSColin Percival			fi
301548ffe56aSColin Percival			;;
301648ffe56aSColin Percival		L)
3017c0f52443SEd Maste			dir_conflict "${BASEDIR}/${FPATH}"
301848ffe56aSColin Percival			# Create a symlink
301948ffe56aSColin Percival			ln -sfh ${HASH} ${BASEDIR}/${FPATH}
302048ffe56aSColin Percival			;;
302148ffe56aSColin Percival		esac
302248ffe56aSColin Percival	    done
302348ffe56aSColin Percival
302448ffe56aSColin Percival	# Perform a second pass, adding file flags.
302548ffe56aSColin Percival	tr '|' ' ' < $1 |
302648ffe56aSColin Percival	    while read FPATH TYPE OWNER GROUP PERM FLAGS HASH LINK; do
302748ffe56aSColin Percival		if [ ${TYPE} = "f" ] &&
302848ffe56aSColin Percival		    ! [ ${FLAGS} = "0" ]; then
302948ffe56aSColin Percival			chflags ${FLAGS} ${BASEDIR}/${FPATH}
303048ffe56aSColin Percival		fi
303148ffe56aSColin Percival	    done
303248ffe56aSColin Percival}
303348ffe56aSColin Percival
303448ffe56aSColin Percival# Remove files which we want to delete
303548ffe56aSColin Percivalinstall_delete () {
303648ffe56aSColin Percival	# Generate list of new files
303748ffe56aSColin Percival	cut -f 1 -d '|' < $2 |
303848ffe56aSColin Percival	    sort > newfiles
303948ffe56aSColin Percival
304048ffe56aSColin Percival	# Generate subindex of old files we want to nuke
304148ffe56aSColin Percival	sort -k 1,1 -t '|' $1 |
304248ffe56aSColin Percival	    join -t '|' -v 1 - newfiles |
3043bce02f98SColin Percival	    sort -r -k 1,1 -t '|' |
304448ffe56aSColin Percival	    cut -f 1,2 -d '|' |
304548ffe56aSColin Percival	    tr '|' ' ' > killfiles
304648ffe56aSColin Percival
304748ffe56aSColin Percival	# Remove the offending bits
304848ffe56aSColin Percival	while read FPATH TYPE; do
304948ffe56aSColin Percival		case ${TYPE} in
305048ffe56aSColin Percival		d)
305148ffe56aSColin Percival			rmdir ${BASEDIR}/${FPATH}
305248ffe56aSColin Percival			;;
305348ffe56aSColin Percival		f)
3054c0f52443SEd Maste			if [ -f "${BASEDIR}/${FPATH}" ]; then
3055c0f52443SEd Maste				rm "${BASEDIR}/${FPATH}"
3056c0f52443SEd Maste			fi
305748ffe56aSColin Percival			;;
305848ffe56aSColin Percival		L)
3059c0f52443SEd Maste			if [ -L "${BASEDIR}/${FPATH}" ]; then
3060c0f52443SEd Maste				rm "${BASEDIR}/${FPATH}"
3061c0f52443SEd Maste			fi
306248ffe56aSColin Percival			;;
306348ffe56aSColin Percival		esac
306448ffe56aSColin Percival	done < killfiles
306548ffe56aSColin Percival
306648ffe56aSColin Percival	# Clean up
306748ffe56aSColin Percival	rm newfiles killfiles
306848ffe56aSColin Percival}
306948ffe56aSColin Percival
30702b17527cSKyle Evans# Install new files, delete old files, and update generated files
3071db6b0a61SColin Percivalinstall_files () {
3072db6b0a61SColin Percival	# If we haven't already dealt with the kernel, deal with it.
3073db6b0a61SColin Percival	if ! [ -f $1/kerneldone ]; then
3074db6b0a61SColin Percival		grep -E '^/boot/' $1/INDEX-OLD > INDEX-OLD
3075db6b0a61SColin Percival		grep -E '^/boot/' $1/INDEX-NEW > INDEX-NEW
3076db6b0a61SColin Percival
307723d827efSSimon L. B. Nielsen		# Backup current kernel before installing a new one
307823d827efSSimon L. B. Nielsen		backup_kernel || return 1
307923d827efSSimon L. B. Nielsen
3080db6b0a61SColin Percival		# Install new files
3081db6b0a61SColin Percival		install_from_index INDEX-NEW || return 1
3082db6b0a61SColin Percival
3083db6b0a61SColin Percival		# Remove files which need to be deleted
3084db6b0a61SColin Percival		install_delete INDEX-OLD INDEX-NEW || return 1
3085db6b0a61SColin Percival
3086db6b0a61SColin Percival		# Update linker.hints if necessary
3087db6b0a61SColin Percival		if [ -s INDEX-OLD -o -s INDEX-NEW ]; then
3088c4a0c62cSThomas Quinot			kldxref -R ${BASEDIR}/boot/ 2>/dev/null
308948ffe56aSColin Percival		fi
3090db6b0a61SColin Percival
3091db6b0a61SColin Percival		# We've finished updating the kernel.
3092db6b0a61SColin Percival		touch $1/kerneldone
3093db6b0a61SColin Percival
3094db6b0a61SColin Percival		# Do we need to ask for a reboot now?
3095db6b0a61SColin Percival		if [ -f $1/kernelfirst ] &&
3096db6b0a61SColin Percival		    [ -s INDEX-OLD -o -s INDEX-NEW ]; then
3097db6b0a61SColin Percival			cat <<-EOF
3098db6b0a61SColin Percival
3099db6b0a61SColin PercivalKernel updates have been installed.  Please reboot and run
310059b02bb4SMichael Osipov'`basename $0` [options] install' again to finish installing updates.
3101db6b0a61SColin Percival			EOF
3102db6b0a61SColin Percival			exit 0
3103db6b0a61SColin Percival		fi
3104db6b0a61SColin Percival	fi
3105db6b0a61SColin Percival
3106db6b0a61SColin Percival	# If we haven't already dealt with the world, deal with it.
3107db6b0a61SColin Percival	if ! [ -f $1/worlddone ]; then
3108cd1ab228SColin Percival		# Create any necessary directories first
3109cd1ab228SColin Percival		grep -vE '^/boot/' $1/INDEX-NEW |
3110cd1ab228SColin Percival		    grep -E '^[^|]+\|d\|' > INDEX-NEW
3111cd1ab228SColin Percival		install_from_index INDEX-NEW || return 1
3112cd1ab228SColin Percival
3113722d81b5SBrooks Davis		# Install new runtime linker
3114722d81b5SBrooks Davis		grep -vE '^/boot/' $1/INDEX-NEW |
3115722d81b5SBrooks Davis		    grep -vE '^[^|]+\|d\|' |
3116722d81b5SBrooks Davis		    grep -E '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' > INDEX-NEW
3117722d81b5SBrooks Davis		install_from_index INDEX-NEW || return 1
3118722d81b5SBrooks Davis
3119db6b0a61SColin Percival		# Install new shared libraries next
3120db6b0a61SColin Percival		grep -vE '^/boot/' $1/INDEX-NEW |
3121cd1ab228SColin Percival		    grep -vE '^[^|]+\|d\|' |
3122722d81b5SBrooks Davis		    grep -vE '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' |
31239546dbd1SColin Percival		    grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-NEW
3124db6b0a61SColin Percival		install_from_index INDEX-NEW || return 1
3125db6b0a61SColin Percival
3126db6b0a61SColin Percival		# Deal with everything else
3127db6b0a61SColin Percival		grep -vE '^/boot/' $1/INDEX-OLD |
3128cd1ab228SColin Percival		    grep -vE '^[^|]+\|d\|' |
3129722d81b5SBrooks Davis		    grep -vE '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' |
31309546dbd1SColin Percival		    grep -vE '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-OLD
3131db6b0a61SColin Percival		grep -vE '^/boot/' $1/INDEX-NEW |
3132cd1ab228SColin Percival		    grep -vE '^[^|]+\|d\|' |
3133722d81b5SBrooks Davis		    grep -vE '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' |
31349546dbd1SColin Percival		    grep -vE '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-NEW
3135db6b0a61SColin Percival		install_from_index INDEX-NEW || return 1
3136db6b0a61SColin Percival		install_delete INDEX-OLD INDEX-NEW || return 1
3137db6b0a61SColin Percival
31388ee97b19SEd Maste		# Restart host sshd if running (PR263489).  Note that this does
31398ee97b19SEd Maste		# not affect child sshd processes handling existing sessions.
31408ee97b19SEd Maste		if [ "$BASEDIR" = / ] && \
31418ee97b19SEd Maste		    service sshd status >/dev/null 2>/dev/null; then
31426cd1bc53SEd Maste			echo
31436cd1bc53SEd Maste			echo "Restarting sshd after upgrade"
31446cd1bc53SEd Maste			service sshd restart
31456cd1bc53SEd Maste		fi
31466cd1bc53SEd Maste
31472b17527cSKyle Evans		# Rehash certs if we actually have certctl installed.
31482b17527cSKyle Evans		if which certctl>/dev/null; then
31492b17527cSKyle Evans			env DESTDIR=${BASEDIR} certctl rehash
31502b17527cSKyle Evans		fi
31512b17527cSKyle Evans
3152ebebc41eSKyle Evans		# Rebuild generated pwd files and /etc/login.conf.db.
31539b659110SEd Maste		pwd_mkdb -d ${BASEDIR}/etc -p ${BASEDIR}/etc/master.passwd
3154c4a0c62cSThomas Quinot		cap_mkdb ${BASEDIR}/etc/login.conf
3155db6b0a61SColin Percival
31569c812c8dSEd Maste		# Rebuild man page databases, if necessary.
31579c812c8dSEd Maste		for D in /usr/share/man /usr/share/openssl/man; do
31589c812c8dSEd Maste			if [ ! -d ${BASEDIR}/$D ]; then
31599c812c8dSEd Maste				continue
31609c812c8dSEd Maste			fi
3161741223a6SEd Maste			if [ -f ${BASEDIR}/$D/mandoc.db ] && \
3162741223a6SEd Maste			    [ -z "$(find ${BASEDIR}/$D -type f -newer ${BASEDIR}/$D/mandoc.db)" ]; then
31639c812c8dSEd Maste				continue;
31649c812c8dSEd Maste			fi
31659c812c8dSEd Maste			makewhatis ${BASEDIR}/$D
31669c812c8dSEd Maste		done
31679c812c8dSEd Maste
3168db6b0a61SColin Percival		# We've finished installing the world and deleting old files
3169db6b0a61SColin Percival		# which are not shared libraries.
3170db6b0a61SColin Percival		touch $1/worlddone
3171db6b0a61SColin Percival
3172db6b0a61SColin Percival		# Do we need to ask the user to portupgrade now?
3173db6b0a61SColin Percival		grep -vE '^/boot/' $1/INDEX-NEW |
31749546dbd1SColin Percival		    grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' |
3175db6b0a61SColin Percival		    cut -f 1 -d '|' |
3176db6b0a61SColin Percival		    sort > newfiles
3177db6b0a61SColin Percival		if grep -vE '^/boot/' $1/INDEX-OLD |
31789546dbd1SColin Percival		    grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' |
3179db6b0a61SColin Percival		    cut -f 1 -d '|' |
3180db6b0a61SColin Percival		    sort |
3181db6b0a61SColin Percival		    join -v 1 - newfiles |
3182db6b0a61SColin Percival		    grep -q .; then
3183db6b0a61SColin Percival			cat <<-EOF
3184db6b0a61SColin Percival
3185db6b0a61SColin PercivalCompleting this upgrade requires removing old shared object files.
3186db6b0a61SColin PercivalPlease rebuild all installed 3rd party software (e.g., programs
318759b02bb4SMichael Osipovinstalled from the ports tree) and then run
318859b02bb4SMichael Osipov'`basename $0` [options] install' again to finish installing updates.
3189db6b0a61SColin Percival			EOF
3190db6b0a61SColin Percival			rm newfiles
3191db6b0a61SColin Percival			exit 0
3192db6b0a61SColin Percival		fi
3193db6b0a61SColin Percival		rm newfiles
3194db6b0a61SColin Percival	fi
3195db6b0a61SColin Percival
3196db6b0a61SColin Percival	# Remove old shared libraries
3197db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-NEW |
3198cd1ab228SColin Percival	    grep -vE '^[^|]+\|d\|' |
31999546dbd1SColin Percival	    grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-NEW
3200db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
3201cd1ab228SColin Percival	    grep -vE '^[^|]+\|d\|' |
32029546dbd1SColin Percival	    grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-OLD
3203db6b0a61SColin Percival	install_delete INDEX-OLD INDEX-NEW || return 1
3204db6b0a61SColin Percival
3205cd1ab228SColin Percival	# Remove old directories
3206ebc1d19cSColin Percival	grep -vE '^/boot/' $1/INDEX-NEW |
3207ebc1d19cSColin Percival	    grep -E '^[^|]+\|d\|' > INDEX-NEW
3208cd1ab228SColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
3209cd1ab228SColin Percival	    grep -E '^[^|]+\|d\|' > INDEX-OLD
3210cd1ab228SColin Percival	install_delete INDEX-OLD INDEX-NEW || return 1
3211cd1ab228SColin Percival
3212db6b0a61SColin Percival	# Remove temporary files
3213db6b0a61SColin Percival	rm INDEX-OLD INDEX-NEW
321448ffe56aSColin Percival}
321548ffe56aSColin Percival
321648ffe56aSColin Percival# Rearrange bits to allow the installed updates to be rolled back
321748ffe56aSColin Percivalinstall_setup_rollback () {
3218db6b0a61SColin Percival	# Remove the "reboot after installing kernel", "kernel updated", and
3219db6b0a61SColin Percival	# "finished installing the world" flags if present -- they are
3220db6b0a61SColin Percival	# irrelevant when rolling back updates.
3221db6b0a61SColin Percival	if [ -f ${BDHASH}-install/kernelfirst ]; then
3222db6b0a61SColin Percival		rm ${BDHASH}-install/kernelfirst
3223db6b0a61SColin Percival		rm ${BDHASH}-install/kerneldone
3224db6b0a61SColin Percival	fi
3225db6b0a61SColin Percival	if [ -f ${BDHASH}-install/worlddone ]; then
3226db6b0a61SColin Percival		rm ${BDHASH}-install/worlddone
3227db6b0a61SColin Percival	fi
3228db6b0a61SColin Percival
322948ffe56aSColin Percival	if [ -L ${BDHASH}-rollback ]; then
323048ffe56aSColin Percival		mv ${BDHASH}-rollback ${BDHASH}-install/rollback
323148ffe56aSColin Percival	fi
323248ffe56aSColin Percival
323348ffe56aSColin Percival	mv ${BDHASH}-install ${BDHASH}-rollback
323448ffe56aSColin Percival}
323548ffe56aSColin Percival
323648ffe56aSColin Percival# Actually install updates
323748ffe56aSColin Percivalinstall_run () {
323848ffe56aSColin Percival	echo -n "Installing updates..."
323948ffe56aSColin Percival
324048ffe56aSColin Percival	# Make sure we have all the files we should have
324148ffe56aSColin Percival	install_verify ${BDHASH}-install/INDEX-OLD	\
324248ffe56aSColin Percival	    ${BDHASH}-install/INDEX-NEW || return 1
324348ffe56aSColin Percival
324448ffe56aSColin Percival	# Remove system immutable flag from files
324548ffe56aSColin Percival	install_unschg ${BDHASH}-install/INDEX-OLD	\
324648ffe56aSColin Percival	    ${BDHASH}-install/INDEX-NEW || return 1
324748ffe56aSColin Percival
3248db6b0a61SColin Percival	# Install new files, delete old files, and update linker.hints
3249db6b0a61SColin Percival	install_files ${BDHASH}-install || return 1
325048ffe56aSColin Percival
325148ffe56aSColin Percival	# Rearrange bits to allow the installed updates to be rolled back
325248ffe56aSColin Percival	install_setup_rollback
325348ffe56aSColin Percival
325448ffe56aSColin Percival	echo " done."
325548ffe56aSColin Percival}
325648ffe56aSColin Percival
325748ffe56aSColin Percival# Rearrange bits to allow the previous set of updates to be rolled back next.
325848ffe56aSColin Percivalrollback_setup_rollback () {
325948ffe56aSColin Percival	if [ -L ${BDHASH}-rollback/rollback ]; then
326048ffe56aSColin Percival		mv ${BDHASH}-rollback/rollback rollback-tmp
326148ffe56aSColin Percival		rm -r ${BDHASH}-rollback/
326248ffe56aSColin Percival		rm ${BDHASH}-rollback
326348ffe56aSColin Percival		mv rollback-tmp ${BDHASH}-rollback
326448ffe56aSColin Percival	else
326548ffe56aSColin Percival		rm -r ${BDHASH}-rollback/
326648ffe56aSColin Percival		rm ${BDHASH}-rollback
326748ffe56aSColin Percival	fi
326848ffe56aSColin Percival}
326948ffe56aSColin Percival
3270db6b0a61SColin Percival# Install old files, delete new files, and update linker.hints
3271db6b0a61SColin Percivalrollback_files () {
32726b27e1f2SEd Maste	# Create directories first.  They may be needed by files we will
32736b27e1f2SEd Maste	# install in subsequent steps (PR273950).
32746b27e1f2SEd Maste	awk -F \| '{if ($2 == "d") print }' $1/INDEX-OLD > INDEX-OLD
32756b27e1f2SEd Maste	install_from_index INDEX-OLD || return 1
32766b27e1f2SEd Maste
32771ec4fb3aSColin Percival	# Install old shared library files which don't have the same path as
32781ec4fb3aSColin Percival	# a new shared library file.
32791ec4fb3aSColin Percival	grep -vE '^/boot/' $1/INDEX-NEW |
3280fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' |
32811ec4fb3aSColin Percival	    cut -f 1 -d '|' |
32821ec4fb3aSColin Percival	    sort > INDEX-NEW.libs.flist
3283db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
3284fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' |
32851ec4fb3aSColin Percival	    sort -k 1,1 -t '|' - |
32861ec4fb3aSColin Percival	    join -t '|' -v 1 - INDEX-NEW.libs.flist > INDEX-OLD
3287db6b0a61SColin Percival	install_from_index INDEX-OLD || return 1
3288db6b0a61SColin Percival
3289db6b0a61SColin Percival	# Deal with files which are neither kernel nor shared library
3290db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
3291fd0963d1SColin Percival	    grep -vE '/lib/.*\.so\.[0-9]+\|' > INDEX-OLD
3292db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-NEW |
3293fd0963d1SColin Percival	    grep -vE '/lib/.*\.so\.[0-9]+\|' > INDEX-NEW
3294db6b0a61SColin Percival	install_from_index INDEX-OLD || return 1
3295db6b0a61SColin Percival	install_delete INDEX-NEW INDEX-OLD || return 1
3296db6b0a61SColin Percival
32971ec4fb3aSColin Percival	# Install any old shared library files which we didn't install above.
32981ec4fb3aSColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
3299fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' |
33001ec4fb3aSColin Percival	    sort -k 1,1 -t '|' - |
33011ec4fb3aSColin Percival	    join -t '|' - INDEX-NEW.libs.flist > INDEX-OLD
33021ec4fb3aSColin Percival	install_from_index INDEX-OLD || return 1
33031ec4fb3aSColin Percival
3304db6b0a61SColin Percival	# Delete unneeded shared library files
3305db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-OLD |
3306fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' > INDEX-OLD
3307db6b0a61SColin Percival	grep -vE '^/boot/' $1/INDEX-NEW |
3308fd0963d1SColin Percival	    grep -E '/lib/.*\.so\.[0-9]+\|' > INDEX-NEW
3309db6b0a61SColin Percival	install_delete INDEX-NEW INDEX-OLD || return 1
3310db6b0a61SColin Percival
3311db6b0a61SColin Percival	# Deal with kernel files
3312db6b0a61SColin Percival	grep -E '^/boot/' $1/INDEX-OLD > INDEX-OLD
3313db6b0a61SColin Percival	grep -E '^/boot/' $1/INDEX-NEW > INDEX-NEW
3314db6b0a61SColin Percival	install_from_index INDEX-OLD || return 1
3315db6b0a61SColin Percival	install_delete INDEX-NEW INDEX-OLD || return 1
3316db6b0a61SColin Percival	if [ -s INDEX-OLD -o -s INDEX-NEW ]; then
3317db6b0a61SColin Percival		kldxref -R /boot/ 2>/dev/null
3318db6b0a61SColin Percival	fi
3319db6b0a61SColin Percival
3320db6b0a61SColin Percival	# Remove temporary files
33210e0d8d5aSColin Percival	rm INDEX-OLD INDEX-NEW INDEX-NEW.libs.flist
3322db6b0a61SColin Percival}
3323db6b0a61SColin Percival
332448ffe56aSColin Percival# Actually rollback updates
332548ffe56aSColin Percivalrollback_run () {
332648ffe56aSColin Percival	echo -n "Uninstalling updates..."
332748ffe56aSColin Percival
332848ffe56aSColin Percival	# If there are updates waiting to be installed, remove them; we
332948ffe56aSColin Percival	# want the user to re-run 'fetch' after rolling back updates.
333048ffe56aSColin Percival	if [ -L ${BDHASH}-install ]; then
333148ffe56aSColin Percival		rm -r ${BDHASH}-install/
333248ffe56aSColin Percival		rm ${BDHASH}-install
333348ffe56aSColin Percival	fi
333448ffe56aSColin Percival
333548ffe56aSColin Percival	# Make sure we have all the files we should have
333648ffe56aSColin Percival	install_verify ${BDHASH}-rollback/INDEX-NEW	\
333748ffe56aSColin Percival	    ${BDHASH}-rollback/INDEX-OLD || return 1
333848ffe56aSColin Percival
333948ffe56aSColin Percival	# Remove system immutable flag from files
334048ffe56aSColin Percival	install_unschg ${BDHASH}-rollback/INDEX-NEW	\
334148ffe56aSColin Percival	    ${BDHASH}-rollback/INDEX-OLD || return 1
334248ffe56aSColin Percival
3343db6b0a61SColin Percival	# Install old files, delete new files, and update linker.hints
3344db6b0a61SColin Percival	rollback_files ${BDHASH}-rollback || return 1
334548ffe56aSColin Percival
334648ffe56aSColin Percival	# Remove the rollback directory and the symlink pointing to it; and
334748ffe56aSColin Percival	# rearrange bits to allow the previous set of updates to be rolled
334848ffe56aSColin Percival	# back next.
334948ffe56aSColin Percival	rollback_setup_rollback
335048ffe56aSColin Percival
335148ffe56aSColin Percival	echo " done."
335248ffe56aSColin Percival}
335348ffe56aSColin Percival
335408e23beeSColin Percival# Compare INDEX-ALL and INDEX-PRESENT and print warnings about differences.
335508e23beeSColin PercivalIDS_compare () {
3356bb10a826SColin Percival	# Get all the lines which mismatch in something other than file
3357bb10a826SColin Percival	# flags.  We ignore file flags because sysinstall doesn't seem to
3358bb10a826SColin Percival	# set them when it installs FreeBSD; warning about these adds a
3359bb10a826SColin Percival	# very large amount of noise.
3360bb10a826SColin Percival	cut -f 1-5,7-8 -d '|' $1 > $1.noflags
3361bb10a826SColin Percival	sort -k 1,1 -t '|' $1.noflags > $1.sorted
3362bb10a826SColin Percival	cut -f 1-5,7-8 -d '|' $2 |
3363bb10a826SColin Percival	    comm -13 $1.noflags - |
3364bb10a826SColin Percival	    fgrep -v '|-|||||' |
336508e23beeSColin Percival	    sort -k 1,1 -t '|' |
336608e23beeSColin Percival	    join -t '|' $1.sorted - > INDEX-NOTMATCHING
336708e23beeSColin Percival
336808e23beeSColin Percival	# Ignore files which match IDSIGNOREPATHS.
336908e23beeSColin Percival	for X in ${IDSIGNOREPATHS}; do
337008e23beeSColin Percival		grep -E "^${X}" INDEX-NOTMATCHING
337108e23beeSColin Percival	done |
337208e23beeSColin Percival	    sort -u |
337308e23beeSColin Percival	    comm -13 - INDEX-NOTMATCHING > INDEX-NOTMATCHING.tmp
337408e23beeSColin Percival	mv INDEX-NOTMATCHING.tmp INDEX-NOTMATCHING
337508e23beeSColin Percival
337608e23beeSColin Percival	# Go through the lines and print warnings.
3377aa60062eSColin Percival	local IFS='|'
3378aa60062eSColin Percival	while read FPATH TYPE OWNER GROUP PERM HASH LINK P_TYPE P_OWNER P_GROUP P_PERM P_HASH P_LINK; do
337908e23beeSColin Percival		# Warn about different object types.
338008e23beeSColin Percival		if ! [ "${TYPE}" = "${P_TYPE}" ]; then
338108e23beeSColin Percival			echo -n "${FPATH} is a "
338208e23beeSColin Percival			case "${P_TYPE}" in
338308e23beeSColin Percival			f)	echo -n "regular file, "
338408e23beeSColin Percival				;;
338508e23beeSColin Percival			d)	echo -n "directory, "
338608e23beeSColin Percival				;;
338708e23beeSColin Percival			L)	echo -n "symlink, "
338808e23beeSColin Percival				;;
338908e23beeSColin Percival			esac
339008e23beeSColin Percival			echo -n "but should be a "
339108e23beeSColin Percival			case "${TYPE}" in
339208e23beeSColin Percival			f)	echo -n "regular file."
339308e23beeSColin Percival				;;
339408e23beeSColin Percival			d)	echo -n "directory."
339508e23beeSColin Percival				;;
339608e23beeSColin Percival			L)	echo -n "symlink."
339708e23beeSColin Percival				;;
339808e23beeSColin Percival			esac
339908e23beeSColin Percival			echo
340008e23beeSColin Percival
340108e23beeSColin Percival			# Skip other tests, since they don't make sense if
340208e23beeSColin Percival			# we're comparing different object types.
340308e23beeSColin Percival			continue
340408e23beeSColin Percival		fi
340508e23beeSColin Percival
340608e23beeSColin Percival		# Warn about different owners.
340708e23beeSColin Percival		if ! [ "${OWNER}" = "${P_OWNER}" ]; then
340808e23beeSColin Percival			echo -n "${FPATH} is owned by user id ${P_OWNER}, "
340908e23beeSColin Percival			echo "but should be owned by user id ${OWNER}."
341008e23beeSColin Percival		fi
341108e23beeSColin Percival
341208e23beeSColin Percival		# Warn about different groups.
341308e23beeSColin Percival		if ! [ "${GROUP}" = "${P_GROUP}" ]; then
341408e23beeSColin Percival			echo -n "${FPATH} is owned by group id ${P_GROUP}, "
341508e23beeSColin Percival			echo "but should be owned by group id ${GROUP}."
341608e23beeSColin Percival		fi
341708e23beeSColin Percival
341808e23beeSColin Percival		# Warn about different permissions.  We do not warn about
341908e23beeSColin Percival		# different permissions on symlinks, since some archivers
342008e23beeSColin Percival		# don't extract symlink permissions correctly and they are
342108e23beeSColin Percival		# ignored anyway.
342208e23beeSColin Percival		if ! [ "${PERM}" = "${P_PERM}" ] &&
342308e23beeSColin Percival		    ! [ "${TYPE}" = "L" ]; then
342408e23beeSColin Percival			echo -n "${FPATH} has ${P_PERM} permissions, "
342508e23beeSColin Percival			echo "but should have ${PERM} permissions."
342608e23beeSColin Percival		fi
342708e23beeSColin Percival
342808e23beeSColin Percival		# Warn about different file hashes / symlink destinations.
342908e23beeSColin Percival		if ! [ "${HASH}" = "${P_HASH}" ]; then
343008e23beeSColin Percival			if [ "${TYPE}" = "L" ]; then
343108e23beeSColin Percival				echo -n "${FPATH} is a symlink to ${P_HASH}, "
343208e23beeSColin Percival				echo "but should be a symlink to ${HASH}."
343308e23beeSColin Percival			fi
343408e23beeSColin Percival			if [ "${TYPE}" = "f" ]; then
343508e23beeSColin Percival				echo -n "${FPATH} has SHA256 hash ${P_HASH}, "
343608e23beeSColin Percival				echo "but should have SHA256 hash ${HASH}."
343708e23beeSColin Percival			fi
343808e23beeSColin Percival		fi
343908e23beeSColin Percival
344008e23beeSColin Percival		# We don't warn about different hard links, since some
344108e23beeSColin Percival		# some archivers break hard links, and as long as the
344208e23beeSColin Percival		# underlying data is correct they really don't matter.
344308e23beeSColin Percival	done < INDEX-NOTMATCHING
344408e23beeSColin Percival
344508e23beeSColin Percival	# Clean up
3446bb10a826SColin Percival	rm $1 $1.noflags $1.sorted $2 INDEX-NOTMATCHING
344708e23beeSColin Percival}
344808e23beeSColin Percival
344908e23beeSColin Percival# Do the work involved in comparing the system to a "known good" index
345008e23beeSColin PercivalIDS_run () {
345108e23beeSColin Percival	workdir_init || return 1
345208e23beeSColin Percival
345308e23beeSColin Percival	# Prepare the mirror list.
345408e23beeSColin Percival	fetch_pick_server_init && fetch_pick_server
345508e23beeSColin Percival
345608e23beeSColin Percival	# Try to fetch the public key until we run out of servers.
345708e23beeSColin Percival	while ! fetch_key; do
345808e23beeSColin Percival		fetch_pick_server || return 1
345908e23beeSColin Percival	done
346008e23beeSColin Percival
346108e23beeSColin Percival	# Try to fetch the metadata index signature ("tag") until we run
346208e23beeSColin Percival	# out of available servers; and sanity check the downloaded tag.
346308e23beeSColin Percival	while ! fetch_tag; do
346408e23beeSColin Percival		fetch_pick_server || return 1
346508e23beeSColin Percival	done
346608e23beeSColin Percival	fetch_tagsanity || return 1
346708e23beeSColin Percival
346808e23beeSColin Percival	# Fetch INDEX-OLD and INDEX-ALL.
346908e23beeSColin Percival	fetch_metadata INDEX-OLD INDEX-ALL || return 1
347008e23beeSColin Percival
347108e23beeSColin Percival	# Generate filtered INDEX-OLD and INDEX-ALL files containing only
347208e23beeSColin Percival	# the components we want and without anything marked as "Ignore".
347308e23beeSColin Percival	fetch_filter_metadata INDEX-OLD || return 1
347408e23beeSColin Percival	fetch_filter_metadata INDEX-ALL || return 1
347508e23beeSColin Percival
347608e23beeSColin Percival	# Merge the INDEX-OLD and INDEX-ALL files into INDEX-ALL.
347708e23beeSColin Percival	sort INDEX-OLD INDEX-ALL > INDEX-ALL.tmp
347808e23beeSColin Percival	mv INDEX-ALL.tmp INDEX-ALL
347908e23beeSColin Percival	rm INDEX-OLD
348008e23beeSColin Percival
348108e23beeSColin Percival	# Translate /boot/${KERNCONF} to ${KERNELDIR}
348208e23beeSColin Percival	fetch_filter_kernel_names INDEX-ALL ${KERNCONF}
348308e23beeSColin Percival
348408e23beeSColin Percival	# Inspect the system and generate an INDEX-PRESENT file.
348508e23beeSColin Percival	fetch_inspect_system INDEX-ALL INDEX-PRESENT /dev/null || return 1
348608e23beeSColin Percival
348708e23beeSColin Percival	# Compare INDEX-ALL and INDEX-PRESENT and print warnings about any
348808e23beeSColin Percival	# differences.
348908e23beeSColin Percival	IDS_compare INDEX-ALL INDEX-PRESENT
349008e23beeSColin Percival}
349108e23beeSColin Percival
349248ffe56aSColin Percival#### Main functions -- call parameter-handling and core functions
349348ffe56aSColin Percival
349448ffe56aSColin Percival# Using the command line, configuration file, and defaults,
349548ffe56aSColin Percival# set all the parameters which are needed later.
349648ffe56aSColin Percivalget_params () {
349748ffe56aSColin Percival	init_params
349848ffe56aSColin Percival	parse_cmdline $@
349948ffe56aSColin Percival	parse_conffile
350048ffe56aSColin Percival	default_params
350148ffe56aSColin Percival}
350248ffe56aSColin Percival
350348ffe56aSColin Percival# Fetch command.  Make sure that we're being called
350448ffe56aSColin Percival# interactively, then run fetch_check_params and fetch_run
350548ffe56aSColin Percivalcmd_fetch () {
35069a63bbc9SColin Percival	finalize_components_config ${COMPONENTS}
35078bf2dcceSAllan Jude	if [ ! -t 0 -a $NOTTYOK -eq 0 ]; then
350848ffe56aSColin Percival		echo -n "`basename $0` fetch should not "
350948ffe56aSColin Percival		echo "be run non-interactively."
351048ffe56aSColin Percival		echo "Run `basename $0` cron instead."
351148ffe56aSColin Percival		exit 1
351248ffe56aSColin Percival	fi
351348ffe56aSColin Percival	fetch_check_params
351448ffe56aSColin Percival	fetch_run || exit 1
351533bd05c3SGuangyuan Yang	ISFETCHED=1
351648ffe56aSColin Percival}
351748ffe56aSColin Percival
351848ffe56aSColin Percival# Cron command.  Make sure the parameters are sensible; wait
351948ffe56aSColin Percival# rand(3600) seconds; then fetch updates.  While fetching updates,
352048ffe56aSColin Percival# send output to a temporary file; only print that file if the
352148ffe56aSColin Percival# fetching failed.
352248ffe56aSColin Percivalcmd_cron () {
352348ffe56aSColin Percival	fetch_check_params
352448ffe56aSColin Percival	sleep `jot -r 1 0 3600`
352548ffe56aSColin Percival
352648ffe56aSColin Percival	TMPFILE=`mktemp /tmp/freebsd-update.XXXXXX` || exit 1
35279a63bbc9SColin Percival	finalize_components_config ${COMPONENTS} >> ${TMPFILE}
352848ffe56aSColin Percival	if ! fetch_run >> ${TMPFILE} ||
352948ffe56aSColin Percival	    ! grep -q "No updates needed" ${TMPFILE} ||
353048ffe56aSColin Percival	    [ ${VERBOSELEVEL} = "debug" ]; then
353148ffe56aSColin Percival		mail -s "`hostname` security updates" ${MAILTO} < ${TMPFILE}
353248ffe56aSColin Percival	fi
353385c3ef77SMichael Osipov	ISFETCHED=1
353448ffe56aSColin Percival
353548ffe56aSColin Percival	rm ${TMPFILE}
353648ffe56aSColin Percival}
353748ffe56aSColin Percival
3538db6b0a61SColin Percival# Fetch files for upgrading to a new release.
3539db6b0a61SColin Percivalcmd_upgrade () {
35409a63bbc9SColin Percival	finalize_components_config ${COMPONENTS}
3541db6b0a61SColin Percival	upgrade_check_params
3542bc0c6c9cSFernando Apesteguía	upgrade_check_kmod_ports
3543db6b0a61SColin Percival	upgrade_run || exit 1
3544db6b0a61SColin Percival}
3545db6b0a61SColin Percival
3546101d33b8SMichael Gmelin# Check if there are fetched updates ready to install.
3547101d33b8SMichael Gmelin# Chdir into the working directory.
35488cfda118SMichael Gmelincmd_updatesready () {
35499a63bbc9SColin Percival	finalize_components_config ${COMPONENTS}
3550101d33b8SMichael Gmelin	# Check if working directory exists (if not, no updates pending)
3551101d33b8SMichael Gmelin	if ! [ -e "${WORKDIR}" ]; then
3552101d33b8SMichael Gmelin		echo "No updates are available to install."
3553101d33b8SMichael Gmelin		exit 2
3554101d33b8SMichael Gmelin	fi
3555101d33b8SMichael Gmelin
3556101d33b8SMichael Gmelin	# Change into working directory (fail if no permission/directory etc.)
3557101d33b8SMichael Gmelin	cd ${WORKDIR} || exit 1
3558101d33b8SMichael Gmelin
35598cfda118SMichael Gmelin	# Construct a unique name from ${BASEDIR}
35608cfda118SMichael Gmelin	BDHASH=`echo ${BASEDIR} | sha256 -q`
35618cfda118SMichael Gmelin
35628cfda118SMichael Gmelin	# Check that we have updates ready to install
35638cfda118SMichael Gmelin	if ! [ -L ${BDHASH}-install ]; then
35648cfda118SMichael Gmelin		echo "No updates are available to install."
35658cfda118SMichael Gmelin		exit 2
35668cfda118SMichael Gmelin	fi
35678cfda118SMichael Gmelin
35688cfda118SMichael Gmelin	echo "There are updates available to install."
356959b02bb4SMichael Osipov	echo "Run '`basename $0` [options] install' to proceed."
35708cfda118SMichael Gmelin}
35718cfda118SMichael Gmelin
357248ffe56aSColin Percival# Install downloaded updates.
357348ffe56aSColin Percivalcmd_install () {
35749a63bbc9SColin Percival	finalize_components_config ${COMPONENTS}
357548ffe56aSColin Percival	install_check_params
3576f28f1389SDave Fullard	install_create_be
357748ffe56aSColin Percival	install_run || exit 1
357848ffe56aSColin Percival}
357948ffe56aSColin Percival
358048ffe56aSColin Percival# Rollback most recently installed updates.
358148ffe56aSColin Percivalcmd_rollback () {
35829a63bbc9SColin Percival	finalize_components_config ${COMPONENTS}
358348ffe56aSColin Percival	rollback_check_params
358448ffe56aSColin Percival	rollback_run || exit 1
358548ffe56aSColin Percival}
358648ffe56aSColin Percival
358708e23beeSColin Percival# Compare system against a "known good" index.
358808e23beeSColin Percivalcmd_IDS () {
35899a63bbc9SColin Percival	finalize_components_config ${COMPONENTS}
359008e23beeSColin Percival	IDS_check_params
359108e23beeSColin Percival	IDS_run || exit 1
359208e23beeSColin Percival}
359308e23beeSColin Percival
35948cfda118SMichael Gmelin# Output configuration.
35958cfda118SMichael Gmelincmd_showconfig () {
35969a63bbc9SColin Percival	finalize_components_config ${COMPONENTS}
35978cfda118SMichael Gmelin	for X in ${CONFIGOPTIONS}; do
35988cfda118SMichael Gmelin		echo $X=$(eval echo \$${X})
35998cfda118SMichael Gmelin	done
36008cfda118SMichael Gmelin}
36018cfda118SMichael Gmelin
360248ffe56aSColin Percival#### Entry point
360348ffe56aSColin Percival
360448ffe56aSColin Percival# Make sure we find utilities from the base system
360548ffe56aSColin Percivalexport PATH=/sbin:/bin:/usr/sbin:/usr/bin:${PATH}
360648ffe56aSColin Percival
36079c990fb2SGordon Tetlow# Set a pager if the user doesn't
36089c990fb2SGordon Tetlowif [ -z "$PAGER" ]; then
360947cc9ee1SAlan Somers	PAGER=/usr/bin/less
36109c990fb2SGordon Tetlowfi
36119c990fb2SGordon Tetlow
3612f2890dbdSColin Percival# Set LC_ALL in order to avoid problems with character ranges like [A-Z].
3613f2890dbdSColin Percivalexport LC_ALL=C
3614f2890dbdSColin Percival
3615e093c61bSEd Maste# Clear environment variables that may affect operation of tools that we use.
3616e093c61bSEd Masteunset GREP_OPTIONS
3617e093c61bSEd Maste
3618*856e158dSEd Maste# Disallow use with packaged base.
3619*856e158dSEd Mastecheck_pkgbase
3620*856e158dSEd Maste
362148ffe56aSColin Percivalget_params $@
362248ffe56aSColin Percivalfor COMMAND in ${COMMANDS}; do
362348ffe56aSColin Percival	cmd_${COMMAND}
362448ffe56aSColin Percivaldone
3625