148ffe56aSColin Percival#!/bin/sh 248ffe56aSColin Percival 348ffe56aSColin Percival#- 448ffe56aSColin Percival# Copyright 2004-2006 Colin Percival 548ffe56aSColin Percival# All rights reserved 648ffe56aSColin Percival# 748ffe56aSColin Percival# Redistribution and use in source and binary forms, with or without 848ffe56aSColin Percival# modification, are permitted providing that the following conditions 948ffe56aSColin Percival# are met: 1048ffe56aSColin Percival# 1. Redistributions of source code must retain the above copyright 1148ffe56aSColin Percival# notice, this list of conditions and the following disclaimer. 1248ffe56aSColin Percival# 2. Redistributions in binary form must reproduce the above copyright 1348ffe56aSColin Percival# notice, this list of conditions and the following disclaimer in the 1448ffe56aSColin Percival# documentation and/or other materials provided with the distribution. 1548ffe56aSColin Percival# 1648ffe56aSColin Percival# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1748ffe56aSColin Percival# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 1848ffe56aSColin Percival# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1948ffe56aSColin Percival# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 2048ffe56aSColin Percival# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2148ffe56aSColin Percival# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2248ffe56aSColin Percival# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2348ffe56aSColin Percival# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 2448ffe56aSColin Percival# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 2548ffe56aSColin Percival# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2648ffe56aSColin Percival# POSSIBILITY OF SUCH DAMAGE. 2748ffe56aSColin Percival 2848ffe56aSColin Percival# $FreeBSD$ 2948ffe56aSColin Percival 3048ffe56aSColin Percival#### Usage function -- called from command-line handling code. 3148ffe56aSColin Percival 3248ffe56aSColin Percival# Usage instructions. Options not listed: 3348ffe56aSColin Percival# --debug -- don't filter output from utilities 3448ffe56aSColin Percival# --no-stats -- don't show progress statistics while fetching files 3548ffe56aSColin Percivalusage () { 3648ffe56aSColin Percival cat <<EOF 3748ffe56aSColin Percivalusage: `basename $0` [options] command ... [path] 3848ffe56aSColin Percival 3948ffe56aSColin PercivalOptions: 4048ffe56aSColin Percival -b basedir -- Operate on a system mounted at basedir 4148ffe56aSColin Percival (default: /) 4248ffe56aSColin Percival -d workdir -- Store working files in workdir 4348ffe56aSColin Percival (default: /var/db/freebsd-update/) 4448ffe56aSColin Percival -f conffile -- Read configuration options from conffile 4548ffe56aSColin Percival (default: /etc/freebsd-update.conf) 4648ffe56aSColin Percival -k KEY -- Trust an RSA key with SHA256 hash of KEY 4748ffe56aSColin Percival -s server -- Server from which to fetch updates 4848ffe56aSColin Percival (default: update.FreeBSD.org) 4948ffe56aSColin Percival -t address -- Mail output of cron command, if any, to address 5048ffe56aSColin Percival (default: root) 5148ffe56aSColin PercivalCommands: 5248ffe56aSColin Percival fetch -- Fetch updates from server 5348ffe56aSColin Percival cron -- Sleep rand(3600) seconds, fetch updates, and send an 5448ffe56aSColin Percival email if updates were found 5548ffe56aSColin Percival install -- Install downloaded updates 5648ffe56aSColin Percival rollback -- Uninstall most recently installed updates 5748ffe56aSColin PercivalEOF 5848ffe56aSColin Percival exit 0 5948ffe56aSColin Percival} 6048ffe56aSColin Percival 6148ffe56aSColin Percival#### Configuration processing functions 6248ffe56aSColin Percival 6348ffe56aSColin Percival#- 6448ffe56aSColin Percival# Configuration options are set in the following order of priority: 6548ffe56aSColin Percival# 1. Command line options 6648ffe56aSColin Percival# 2. Configuration file options 6748ffe56aSColin Percival# 3. Default options 6848ffe56aSColin Percival# In addition, certain options (e.g., IgnorePaths) can be specified multiple 6948ffe56aSColin Percival# times and (as long as these are all in the same place, e.g., inside the 7048ffe56aSColin Percival# configuration file) they will accumulate. Finally, because the path to the 7148ffe56aSColin Percival# configuration file can be specified at the command line, the entire command 7248ffe56aSColin Percival# line must be processed before we start reading the configuration file. 7348ffe56aSColin Percival# 7448ffe56aSColin Percival# Sound like a mess? It is. Here's how we handle this: 7548ffe56aSColin Percival# 1. Initialize CONFFILE and all the options to "". 7648ffe56aSColin Percival# 2. Process the command line. Throw an error if a non-accumulating option 7748ffe56aSColin Percival# is specified twice. 7848ffe56aSColin Percival# 3. If CONFFILE is "", set CONFFILE to /etc/freebsd-update.conf . 7948ffe56aSColin Percival# 4. For all the configuration options X, set X_saved to X. 8048ffe56aSColin Percival# 5. Initialize all the options to "". 8148ffe56aSColin Percival# 6. Read CONFFILE line by line, parsing options. 8248ffe56aSColin Percival# 7. For each configuration option X, set X to X_saved iff X_saved is not "". 8348ffe56aSColin Percival# 8. Repeat steps 4-7, except setting options to their default values at (6). 8448ffe56aSColin Percival 8548ffe56aSColin PercivalCONFIGOPTIONS="KEYPRINT WORKDIR SERVERNAME MAILTO ALLOWADD ALLOWDELETE 8648ffe56aSColin Percival KEEPMODIFIEDMETADATA COMPONENTS IGNOREPATHS UPDATEIFUNMODIFIED 8748ffe56aSColin Percival BASEDIR VERBOSELEVEL" 8848ffe56aSColin Percival 8948ffe56aSColin Percival# Set all the configuration options to "". 9048ffe56aSColin Percivalnullconfig () { 9148ffe56aSColin Percival for X in ${CONFIGOPTIONS}; do 9248ffe56aSColin Percival eval ${X}="" 9348ffe56aSColin Percival done 9448ffe56aSColin Percival} 9548ffe56aSColin Percival 9648ffe56aSColin Percival# For each configuration option X, set X_saved to X. 9748ffe56aSColin Percivalsaveconfig () { 9848ffe56aSColin Percival for X in ${CONFIGOPTIONS}; do 9948ffe56aSColin Percival eval ${X}_saved=\$${X} 10048ffe56aSColin Percival done 10148ffe56aSColin Percival} 10248ffe56aSColin Percival 10348ffe56aSColin Percival# For each configuration option X, set X to X_saved if X_saved is not "". 10448ffe56aSColin Percivalmergeconfig () { 10548ffe56aSColin Percival for X in ${CONFIGOPTIONS}; do 10648ffe56aSColin Percival eval _=\$${X}_saved 10748ffe56aSColin Percival if ! [ -z "${_}" ]; then 10848ffe56aSColin Percival eval ${X}=\$${X}_saved 10948ffe56aSColin Percival fi 11048ffe56aSColin Percival done 11148ffe56aSColin Percival} 11248ffe56aSColin Percival 11348ffe56aSColin Percival# Set the trusted keyprint. 11448ffe56aSColin Percivalconfig_KeyPrint () { 11548ffe56aSColin Percival if [ -z ${KEYPRINT} ]; then 11648ffe56aSColin Percival KEYPRINT=$1 11748ffe56aSColin Percival else 11848ffe56aSColin Percival return 1 11948ffe56aSColin Percival fi 12048ffe56aSColin Percival} 12148ffe56aSColin Percival 12248ffe56aSColin Percival# Set the working directory. 12348ffe56aSColin Percivalconfig_WorkDir () { 12448ffe56aSColin Percival if [ -z ${WORKDIR} ]; then 12548ffe56aSColin Percival WORKDIR=$1 12648ffe56aSColin Percival else 12748ffe56aSColin Percival return 1 12848ffe56aSColin Percival fi 12948ffe56aSColin Percival} 13048ffe56aSColin Percival 13148ffe56aSColin Percival# Set the name of the server (pool) from which to fetch updates 13248ffe56aSColin Percivalconfig_ServerName () { 13348ffe56aSColin Percival if [ -z ${SERVERNAME} ]; then 13448ffe56aSColin Percival SERVERNAME=$1 13548ffe56aSColin Percival else 13648ffe56aSColin Percival return 1 13748ffe56aSColin Percival fi 13848ffe56aSColin Percival} 13948ffe56aSColin Percival 14048ffe56aSColin Percival# Set the address to which 'cron' output will be mailed. 14148ffe56aSColin Percivalconfig_MailTo () { 14248ffe56aSColin Percival if [ -z ${MAILTO} ]; then 14348ffe56aSColin Percival MAILTO=$1 14448ffe56aSColin Percival else 14548ffe56aSColin Percival return 1 14648ffe56aSColin Percival fi 14748ffe56aSColin Percival} 14848ffe56aSColin Percival 14948ffe56aSColin Percival# Set whether FreeBSD Update is allowed to add files (or directories, or 15048ffe56aSColin Percival# symlinks) which did not previously exist. 15148ffe56aSColin Percivalconfig_AllowAdd () { 15248ffe56aSColin Percival if [ -z ${ALLOWADD} ]; then 15348ffe56aSColin Percival case $1 in 15448ffe56aSColin Percival [Yy][Ee][Ss]) 15548ffe56aSColin Percival ALLOWADD=yes 15648ffe56aSColin Percival ;; 15748ffe56aSColin Percival [Nn][Oo]) 15848ffe56aSColin Percival ALLOWADD=no 15948ffe56aSColin Percival ;; 16048ffe56aSColin Percival *) 16148ffe56aSColin Percival return 1 16248ffe56aSColin Percival ;; 16348ffe56aSColin Percival esac 16448ffe56aSColin Percival else 16548ffe56aSColin Percival return 1 16648ffe56aSColin Percival fi 16748ffe56aSColin Percival} 16848ffe56aSColin Percival 16948ffe56aSColin Percival# Set whether FreeBSD Update is allowed to remove files/directories/symlinks. 17048ffe56aSColin Percivalconfig_AllowDelete () { 17148ffe56aSColin Percival if [ -z ${ALLOWDELETE} ]; then 17248ffe56aSColin Percival case $1 in 17348ffe56aSColin Percival [Yy][Ee][Ss]) 17448ffe56aSColin Percival ALLOWDELETE=yes 17548ffe56aSColin Percival ;; 17648ffe56aSColin Percival [Nn][Oo]) 17748ffe56aSColin Percival ALLOWDELETE=no 17848ffe56aSColin Percival ;; 17948ffe56aSColin Percival *) 18048ffe56aSColin Percival return 1 18148ffe56aSColin Percival ;; 18248ffe56aSColin Percival esac 18348ffe56aSColin Percival else 18448ffe56aSColin Percival return 1 18548ffe56aSColin Percival fi 18648ffe56aSColin Percival} 18748ffe56aSColin Percival 18848ffe56aSColin Percival# Set whether FreeBSD Update should keep existing inode ownership, 18948ffe56aSColin Percival# permissions, and flags, in the event that they have been modified locally 19048ffe56aSColin Percival# after the release. 19148ffe56aSColin Percivalconfig_KeepModifiedMetadata () { 19248ffe56aSColin Percival if [ -z ${KEEPMODIFIEDMETADATA} ]; then 19348ffe56aSColin Percival case $1 in 19448ffe56aSColin Percival [Yy][Ee][Ss]) 19548ffe56aSColin Percival KEEPMODIFIEDMETADATA=yes 19648ffe56aSColin Percival ;; 19748ffe56aSColin Percival [Nn][Oo]) 19848ffe56aSColin Percival KEEPMODIFIEDMETADATA=no 19948ffe56aSColin Percival ;; 20048ffe56aSColin Percival *) 20148ffe56aSColin Percival return 1 20248ffe56aSColin Percival ;; 20348ffe56aSColin Percival esac 20448ffe56aSColin Percival else 20548ffe56aSColin Percival return 1 20648ffe56aSColin Percival fi 20748ffe56aSColin Percival} 20848ffe56aSColin Percival 20948ffe56aSColin Percival# Add to the list of components which should be kept updated. 21048ffe56aSColin Percivalconfig_Components () { 21148ffe56aSColin Percival for C in $@; do 21248ffe56aSColin Percival COMPONENTS="${COMPONENTS} ${C}" 21348ffe56aSColin Percival done 21448ffe56aSColin Percival} 21548ffe56aSColin Percival 21648ffe56aSColin Percival# Add to the list of paths under which updates will be ignored. 21748ffe56aSColin Percivalconfig_IgnorePaths () { 21848ffe56aSColin Percival for C in $@; do 21948ffe56aSColin Percival IGNOREPATHS="${IGNOREPATHS} ${C}" 22048ffe56aSColin Percival done 22148ffe56aSColin Percival} 22248ffe56aSColin Percival 22348ffe56aSColin Percival# Add to the list of paths within which updates will be performed only if the 22448ffe56aSColin Percival# file on disk has not been modified locally. 22548ffe56aSColin Percivalconfig_UpdateIfUnmodified () { 22648ffe56aSColin Percival for C in $@; do 22748ffe56aSColin Percival UPDATEIFUNMODIFIED="${UPDATEIFUNMODIFIED} ${C}" 22848ffe56aSColin Percival done 22948ffe56aSColin Percival} 23048ffe56aSColin Percival 23148ffe56aSColin Percival# Work on a FreeBSD installation mounted under $1 23248ffe56aSColin Percivalconfig_BaseDir () { 23348ffe56aSColin Percival if [ -z ${BASEDIR} ]; then 23448ffe56aSColin Percival BASEDIR=$1 23548ffe56aSColin Percival else 23648ffe56aSColin Percival return 1 23748ffe56aSColin Percival fi 23848ffe56aSColin Percival} 23948ffe56aSColin Percival 24048ffe56aSColin Percival# Define what happens to output of utilities 24148ffe56aSColin Percivalconfig_VerboseLevel () { 24248ffe56aSColin Percival if [ -z ${VERBOSELEVEL} ]; then 24348ffe56aSColin Percival case $1 in 24448ffe56aSColin Percival [Dd][Ee][Bb][Uu][Gg]) 24548ffe56aSColin Percival VERBOSELEVEL=debug 24648ffe56aSColin Percival ;; 24748ffe56aSColin Percival [Nn][Oo][Ss][Tt][Aa][Tt][Ss]) 24848ffe56aSColin Percival VERBOSELEVEL=nostats 24948ffe56aSColin Percival ;; 25048ffe56aSColin Percival [Ss][Tt][Aa][Tt][Ss]) 25148ffe56aSColin Percival VERBOSELEVEL=stats 25248ffe56aSColin Percival ;; 25348ffe56aSColin Percival *) 25448ffe56aSColin Percival return 1 25548ffe56aSColin Percival ;; 25648ffe56aSColin Percival esac 25748ffe56aSColin Percival else 25848ffe56aSColin Percival return 1 25948ffe56aSColin Percival fi 26048ffe56aSColin Percival} 26148ffe56aSColin Percival 26248ffe56aSColin Percival# Handle one line of configuration 26348ffe56aSColin Percivalconfigline () { 26448ffe56aSColin Percival if [ $# -eq 0 ]; then 26548ffe56aSColin Percival return 26648ffe56aSColin Percival fi 26748ffe56aSColin Percival 26848ffe56aSColin Percival OPT=$1 26948ffe56aSColin Percival shift 27048ffe56aSColin Percival config_${OPT} $@ 27148ffe56aSColin Percival} 27248ffe56aSColin Percival 27348ffe56aSColin Percival#### Parameter handling functions. 27448ffe56aSColin Percival 27548ffe56aSColin Percival# Initialize parameters to null, just in case they're 27648ffe56aSColin Percival# set in the environment. 27748ffe56aSColin Percivalinit_params () { 27848ffe56aSColin Percival # Configration settings 27948ffe56aSColin Percival nullconfig 28048ffe56aSColin Percival 28148ffe56aSColin Percival # No configuration file set yet 28248ffe56aSColin Percival CONFFILE="" 28348ffe56aSColin Percival 28448ffe56aSColin Percival # No commands specified yet 28548ffe56aSColin Percival COMMANDS="" 28648ffe56aSColin Percival} 28748ffe56aSColin Percival 28848ffe56aSColin Percival# Parse the command line 28948ffe56aSColin Percivalparse_cmdline () { 29048ffe56aSColin Percival while [ $# -gt 0 ]; do 29148ffe56aSColin Percival case "$1" in 29248ffe56aSColin Percival # Location of configuration file 29348ffe56aSColin Percival -f) 29448ffe56aSColin Percival if [ $# -eq 1 ]; then usage; fi 29548ffe56aSColin Percival if [ ! -z "${CONFFILE}" ]; then usage; fi 29648ffe56aSColin Percival shift; CONFFILE="$1" 29748ffe56aSColin Percival ;; 29848ffe56aSColin Percival 29948ffe56aSColin Percival # Configuration file equivalents 30048ffe56aSColin Percival -b) 30148ffe56aSColin Percival if [ $# -eq 1 ]; then usage; fi; shift 30248ffe56aSColin Percival config_BaseDir $1 || usage 30348ffe56aSColin Percival ;; 30448ffe56aSColin Percival -d) 30548ffe56aSColin Percival if [ $# -eq 1 ]; then usage; fi; shift 30648ffe56aSColin Percival config_WorkDir $1 || usage 30748ffe56aSColin Percival ;; 30848ffe56aSColin Percival -k) 30948ffe56aSColin Percival if [ $# -eq 1 ]; then usage; fi; shift 31048ffe56aSColin Percival config_KeyPrint $1 || usage 31148ffe56aSColin Percival ;; 31248ffe56aSColin Percival -s) 31348ffe56aSColin Percival if [ $# -eq 1 ]; then usage; fi; shift 31448ffe56aSColin Percival config_ServerName $1 || usage 31548ffe56aSColin Percival ;; 31648ffe56aSColin Percival -t) 31748ffe56aSColin Percival if [ $# -eq 1 ]; then usage; fi; shift 31848ffe56aSColin Percival config_MailTo $1 || usage 31948ffe56aSColin Percival ;; 32048ffe56aSColin Percival -v) 32148ffe56aSColin Percival if [ $# -eq 1 ]; then usage; fi; shift 32248ffe56aSColin Percival config_VerboseLevel $1 || usage 32348ffe56aSColin Percival ;; 32448ffe56aSColin Percival 32548ffe56aSColin Percival # Aliases for "-v debug" and "-v nostats" 32648ffe56aSColin Percival --debug) 32748ffe56aSColin Percival config_VerboseLevel debug || usage 32848ffe56aSColin Percival ;; 32948ffe56aSColin Percival --no-stats) 33048ffe56aSColin Percival config_VerboseLevel nostats || usage 33148ffe56aSColin Percival ;; 33248ffe56aSColin Percival 33348ffe56aSColin Percival # Commands 33448ffe56aSColin Percival cron | fetch | install | rollback) 33548ffe56aSColin Percival COMMANDS="${COMMANDS} $1" 33648ffe56aSColin Percival ;; 33748ffe56aSColin Percival 33848ffe56aSColin Percival # Anything else is an error 33948ffe56aSColin Percival *) 34048ffe56aSColin Percival usage 34148ffe56aSColin Percival ;; 34248ffe56aSColin Percival esac 34348ffe56aSColin Percival shift 34448ffe56aSColin Percival done 34548ffe56aSColin Percival 34648ffe56aSColin Percival # Make sure we have at least one command 34748ffe56aSColin Percival if [ -z "${COMMANDS}" ]; then 34848ffe56aSColin Percival usage 34948ffe56aSColin Percival fi 35048ffe56aSColin Percival} 35148ffe56aSColin Percival 35248ffe56aSColin Percival# Parse the configuration file 35348ffe56aSColin Percivalparse_conffile () { 35448ffe56aSColin Percival # If a configuration file was specified on the command line, check 35548ffe56aSColin Percival # that it exists and is readable. 35648ffe56aSColin Percival if [ ! -z "${CONFFILE}" ] && [ ! -r "${CONFFILE}" ]; then 35748ffe56aSColin Percival echo -n "File does not exist " 35848ffe56aSColin Percival echo -n "or is not readable: " 35948ffe56aSColin Percival echo ${CONFFILE} 36048ffe56aSColin Percival exit 1 36148ffe56aSColin Percival fi 36248ffe56aSColin Percival 36348ffe56aSColin Percival # If a configuration file was not specified on the command line, 36448ffe56aSColin Percival # use the default configuration file path. If that default does 36548ffe56aSColin Percival # not exist, give up looking for any configuration. 36648ffe56aSColin Percival if [ -z "${CONFFILE}" ]; then 36748ffe56aSColin Percival CONFFILE="/etc/freebsd-update.conf" 36848ffe56aSColin Percival if [ ! -r "${CONFFILE}" ]; then 36948ffe56aSColin Percival return 37048ffe56aSColin Percival fi 37148ffe56aSColin Percival fi 37248ffe56aSColin Percival 37348ffe56aSColin Percival # Save the configuration options specified on the command line, and 37448ffe56aSColin Percival # clear all the options in preparation for reading the config file. 37548ffe56aSColin Percival saveconfig 37648ffe56aSColin Percival nullconfig 37748ffe56aSColin Percival 37848ffe56aSColin Percival # Read the configuration file. Anything after the first '#' is 37948ffe56aSColin Percival # ignored, and any blank lines are ignored. 38048ffe56aSColin Percival L=0 38148ffe56aSColin Percival while read LINE; do 38248ffe56aSColin Percival L=$(($L + 1)) 38348ffe56aSColin Percival LINEX=`echo "${LINE}" | cut -f 1 -d '#'` 38448ffe56aSColin Percival if ! configline ${LINEX}; then 38548ffe56aSColin Percival echo "Error processing configuration file, line $L:" 38648ffe56aSColin Percival echo "==> ${LINE}" 38748ffe56aSColin Percival exit 1 38848ffe56aSColin Percival fi 38948ffe56aSColin Percival done < ${CONFFILE} 39048ffe56aSColin Percival 39148ffe56aSColin Percival # Merge the settings read from the configuration file with those 39248ffe56aSColin Percival # provided at the command line. 39348ffe56aSColin Percival mergeconfig 39448ffe56aSColin Percival} 39548ffe56aSColin Percival 39648ffe56aSColin Percival# Provide some default parameters 39748ffe56aSColin Percivaldefault_params () { 39848ffe56aSColin Percival # Save any parameters already configured, and clear the slate 39948ffe56aSColin Percival saveconfig 40048ffe56aSColin Percival nullconfig 40148ffe56aSColin Percival 40248ffe56aSColin Percival # Default configurations 40348ffe56aSColin Percival config_WorkDir /var/db/freebsd-update 40448ffe56aSColin Percival config_MailTo root 40548ffe56aSColin Percival config_AllowAdd yes 40648ffe56aSColin Percival config_AllowDelete yes 40748ffe56aSColin Percival config_KeepModifiedMetadata yes 40848ffe56aSColin Percival config_BaseDir / 40948ffe56aSColin Percival config_VerboseLevel stats 41048ffe56aSColin Percival 41148ffe56aSColin Percival # Merge these defaults into the earlier-configured settings 41248ffe56aSColin Percival mergeconfig 41348ffe56aSColin Percival} 41448ffe56aSColin Percival 41548ffe56aSColin Percival# Set utility output filtering options, based on ${VERBOSELEVEL} 41648ffe56aSColin Percivalfetch_setup_verboselevel () { 41748ffe56aSColin Percival case ${VERBOSELEVEL} in 41848ffe56aSColin Percival debug) 41948ffe56aSColin Percival QUIETREDIR="/dev/stderr" 42048ffe56aSColin Percival QUIETFLAG=" " 42148ffe56aSColin Percival STATSREDIR="/dev/stderr" 42248ffe56aSColin Percival DDSTATS=".." 42348ffe56aSColin Percival XARGST="-t" 42448ffe56aSColin Percival NDEBUG=" " 42548ffe56aSColin Percival ;; 42648ffe56aSColin Percival nostats) 42748ffe56aSColin Percival QUIETREDIR="" 42848ffe56aSColin Percival QUIETFLAG="" 42948ffe56aSColin Percival STATSREDIR="/dev/null" 43048ffe56aSColin Percival DDSTATS=".." 43148ffe56aSColin Percival XARGST="" 43248ffe56aSColin Percival NDEBUG="" 43348ffe56aSColin Percival ;; 43448ffe56aSColin Percival stats) 43548ffe56aSColin Percival QUIETREDIR="/dev/null" 43648ffe56aSColin Percival QUIETFLAG="-q" 43748ffe56aSColin Percival STATSREDIR="/dev/stdout" 43848ffe56aSColin Percival DDSTATS="" 43948ffe56aSColin Percival XARGST="" 44048ffe56aSColin Percival NDEBUG="-n" 44148ffe56aSColin Percival ;; 44248ffe56aSColin Percival esac 44348ffe56aSColin Percival} 44448ffe56aSColin Percival 44548ffe56aSColin Percival# Perform sanity checks and set some final parameters 44648ffe56aSColin Percival# in preparation for fetching files. Figure out which 44748ffe56aSColin Percival# set of updates should be downloaded: If the user is 44848ffe56aSColin Percival# running *-p[0-9]+, strip off the last part; if the 44948ffe56aSColin Percival# user is running -SECURITY, call it -RELEASE. Chdir 45048ffe56aSColin Percival# into the working directory. 45148ffe56aSColin Percivalfetch_check_params () { 45248ffe56aSColin Percival export HTTP_USER_AGENT="freebsd-update (${COMMAND}, `uname -r`)" 45348ffe56aSColin Percival 45448ffe56aSColin Percival _SERVERNAME_z=\ 45548ffe56aSColin Percival"SERVERNAME must be given via command line or configuration file." 45648ffe56aSColin Percival _KEYPRINT_z="Key must be given via -k option or configuration file." 45748ffe56aSColin Percival _KEYPRINT_bad="Invalid key fingerprint: " 45848ffe56aSColin Percival _WORKDIR_bad="Directory does not exist or is not writable: " 45948ffe56aSColin Percival 46048ffe56aSColin Percival if [ -z "${SERVERNAME}" ]; then 46148ffe56aSColin Percival echo -n "`basename $0`: " 46248ffe56aSColin Percival echo "${_SERVERNAME_z}" 46348ffe56aSColin Percival exit 1 46448ffe56aSColin Percival fi 46548ffe56aSColin Percival if [ -z "${KEYPRINT}" ]; then 46648ffe56aSColin Percival echo -n "`basename $0`: " 46748ffe56aSColin Percival echo "${_KEYPRINT_z}" 46848ffe56aSColin Percival exit 1 46948ffe56aSColin Percival fi 47048ffe56aSColin Percival if ! echo "${KEYPRINT}" | grep -qE "^[0-9a-f]{64}$"; then 47148ffe56aSColin Percival echo -n "`basename $0`: " 47248ffe56aSColin Percival echo -n "${_KEYPRINT_bad}" 47348ffe56aSColin Percival echo ${KEYPRINT} 47448ffe56aSColin Percival exit 1 47548ffe56aSColin Percival fi 47648ffe56aSColin Percival if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then 47748ffe56aSColin Percival echo -n "`basename $0`: " 47848ffe56aSColin Percival echo -n "${_WORKDIR_bad}" 47948ffe56aSColin Percival echo ${WORKDIR} 48048ffe56aSColin Percival exit 1 48148ffe56aSColin Percival fi 48248ffe56aSColin Percival cd ${WORKDIR} || exit 1 48348ffe56aSColin Percival 48448ffe56aSColin Percival # Generate release number. The s/SECURITY/RELEASE/ bit exists 48548ffe56aSColin Percival # to provide an upgrade path for FreeBSD Update 1.x users, since 48648ffe56aSColin Percival # the kernels provided by FreeBSD Update 1.x are always labelled 48748ffe56aSColin Percival # as X.Y-SECURITY. 48848ffe56aSColin Percival RELNUM=`uname -r | 48948ffe56aSColin Percival sed -E 's,-p[0-9]+,,' | 49048ffe56aSColin Percival sed -E 's,-SECURITY,-RELEASE,'` 49148ffe56aSColin Percival ARCH=`uname -m` 49248ffe56aSColin Percival FETCHDIR=${RELNUM}/${ARCH} 49348ffe56aSColin Percival 49448ffe56aSColin Percival # Figure out what directory contains the running kernel 49548ffe56aSColin Percival BOOTFILE=`sysctl -n kern.bootfile` 49648ffe56aSColin Percival KERNELDIR=${BOOTFILE%/kernel} 49748ffe56aSColin Percival if ! [ -d ${KERNELDIR} ]; then 49848ffe56aSColin Percival echo "Cannot identify running kernel" 49948ffe56aSColin Percival exit 1 50048ffe56aSColin Percival fi 50148ffe56aSColin Percival 5022c434b2cSColin Percival # Figure out what kernel configuration is running. We start with 5032c434b2cSColin Percival # the output of `uname -i`, and then make the following adjustments: 5042c434b2cSColin Percival # 1. Replace "SMP-GENERIC" with "SMP". Why the SMP kernel config 5052c434b2cSColin Percival # file says "ident SMP-GENERIC", I don't know... 5062c434b2cSColin Percival # 2. If the kernel claims to be GENERIC _and_ ${ARCH} is "amd64" 5072c434b2cSColin Percival # _and_ `sysctl kern.version` contains a line which ends "/SMP", then 5082c434b2cSColin Percival # we're running an SMP kernel. This mis-identification is a bug 5092c434b2cSColin Percival # which was fixed in 6.2-STABLE. 5102c434b2cSColin Percival KERNCONF=`uname -i` 5112c434b2cSColin Percival if [ ${KERNCONF} = "SMP-GENERIC" ]; then 5122c434b2cSColin Percival KERNCONF=SMP 5132c434b2cSColin Percival fi 5142c434b2cSColin Percival if [ ${KERNCONF} = "GENERIC" ] && [ ${ARCH} = "amd64" ]; then 5152c434b2cSColin Percival if sysctl kern.version | grep -qE '/SMP$'; then 5162c434b2cSColin Percival KERNCONF=SMP 5172c434b2cSColin Percival fi 5182c434b2cSColin Percival fi 5192c434b2cSColin Percival 52048ffe56aSColin Percival # Define some paths 52148ffe56aSColin Percival BSPATCH=/usr/bin/bspatch 52248ffe56aSColin Percival SHA256=/sbin/sha256 52348ffe56aSColin Percival PHTTPGET=/usr/libexec/phttpget 52448ffe56aSColin Percival 52548ffe56aSColin Percival # Set up variables relating to VERBOSELEVEL 52648ffe56aSColin Percival fetch_setup_verboselevel 52748ffe56aSColin Percival 52848ffe56aSColin Percival # Construct a unique name from ${BASEDIR} 52948ffe56aSColin Percival BDHASH=`echo ${BASEDIR} | sha256 -q` 53048ffe56aSColin Percival} 53148ffe56aSColin Percival 53248ffe56aSColin Percival# Perform sanity checks and set some final parameters in 53348ffe56aSColin Percival# preparation for installing updates. 53448ffe56aSColin Percivalinstall_check_params () { 53548ffe56aSColin Percival # Check that we are root. All sorts of things won't work otherwise. 53648ffe56aSColin Percival if [ `id -u` != 0 ]; then 53748ffe56aSColin Percival echo "You must be root to run this." 53848ffe56aSColin Percival exit 1 53948ffe56aSColin Percival fi 54048ffe56aSColin Percival 54148ffe56aSColin Percival # Check that we have a working directory 54248ffe56aSColin Percival _WORKDIR_bad="Directory does not exist or is not writable: " 54348ffe56aSColin Percival if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then 54448ffe56aSColin Percival echo -n "`basename $0`: " 54548ffe56aSColin Percival echo -n "${_WORKDIR_bad}" 54648ffe56aSColin Percival echo ${WORKDIR} 54748ffe56aSColin Percival exit 1 54848ffe56aSColin Percival fi 54948ffe56aSColin Percival cd ${WORKDIR} || exit 1 55048ffe56aSColin Percival 55148ffe56aSColin Percival # Construct a unique name from ${BASEDIR} 55248ffe56aSColin Percival BDHASH=`echo ${BASEDIR} | sha256 -q` 55348ffe56aSColin Percival 55448ffe56aSColin Percival # Check that we have updates ready to install 55548ffe56aSColin Percival if ! [ -L ${BDHASH}-install ]; then 55648ffe56aSColin Percival echo "No updates are available to install." 55748ffe56aSColin Percival echo "Run '$0 fetch' first." 55848ffe56aSColin Percival exit 1 55948ffe56aSColin Percival fi 56048ffe56aSColin Percival if ! [ -f ${BDHASH}-install/INDEX-OLD ] || 56148ffe56aSColin Percival ! [ -f ${BDHASH}-install/INDEX-NEW ]; then 56248ffe56aSColin Percival echo "Update manifest is corrupt -- this should never happen." 56348ffe56aSColin Percival echo "Re-run '$0 fetch'." 56448ffe56aSColin Percival exit 1 56548ffe56aSColin Percival fi 56648ffe56aSColin Percival} 56748ffe56aSColin Percival 56848ffe56aSColin Percival# Perform sanity checks and set some final parameters in 56948ffe56aSColin Percival# preparation for UNinstalling updates. 57048ffe56aSColin Percivalrollback_check_params () { 57148ffe56aSColin Percival # Check that we are root. All sorts of things won't work otherwise. 57248ffe56aSColin Percival if [ `id -u` != 0 ]; then 57348ffe56aSColin Percival echo "You must be root to run this." 57448ffe56aSColin Percival exit 1 57548ffe56aSColin Percival fi 57648ffe56aSColin Percival 57748ffe56aSColin Percival # Check that we have a working directory 57848ffe56aSColin Percival _WORKDIR_bad="Directory does not exist or is not writable: " 57948ffe56aSColin Percival if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then 58048ffe56aSColin Percival echo -n "`basename $0`: " 58148ffe56aSColin Percival echo -n "${_WORKDIR_bad}" 58248ffe56aSColin Percival echo ${WORKDIR} 58348ffe56aSColin Percival exit 1 58448ffe56aSColin Percival fi 58548ffe56aSColin Percival cd ${WORKDIR} || exit 1 58648ffe56aSColin Percival 58748ffe56aSColin Percival # Construct a unique name from ${BASEDIR} 58848ffe56aSColin Percival BDHASH=`echo ${BASEDIR} | sha256 -q` 58948ffe56aSColin Percival 59048ffe56aSColin Percival # Check that we have updates ready to rollback 59148ffe56aSColin Percival if ! [ -L ${BDHASH}-rollback ]; then 59248ffe56aSColin Percival echo "No rollback directory found." 59348ffe56aSColin Percival exit 1 59448ffe56aSColin Percival fi 59548ffe56aSColin Percival if ! [ -f ${BDHASH}-rollback/INDEX-OLD ] || 59648ffe56aSColin Percival ! [ -f ${BDHASH}-rollback/INDEX-NEW ]; then 59748ffe56aSColin Percival echo "Update manifest is corrupt -- this should never happen." 59848ffe56aSColin Percival exit 1 59948ffe56aSColin Percival fi 60048ffe56aSColin Percival} 60148ffe56aSColin Percival 60248ffe56aSColin Percival#### Core functionality -- the actual work gets done here 60348ffe56aSColin Percival 60448ffe56aSColin Percival# Use an SRV query to pick a server. If the SRV query doesn't provide 60548ffe56aSColin Percival# a useful answer, use the server name specified by the user. 60648ffe56aSColin Percival# Put another way... look up _http._tcp.${SERVERNAME} and pick a server 60748ffe56aSColin Percival# from that; or if no servers are returned, use ${SERVERNAME}. 60848ffe56aSColin Percival# This allows a user to specify "portsnap.freebsd.org" (in which case 60948ffe56aSColin Percival# portsnap will select one of the mirrors) or "portsnap5.tld.freebsd.org" 61048ffe56aSColin Percival# (in which case portsnap will use that particular server, since there 61148ffe56aSColin Percival# won't be an SRV entry for that name). 61248ffe56aSColin Percival# 61348ffe56aSColin Percival# We ignore the Port field, since we are always going to use port 80. 61448ffe56aSColin Percival 61548ffe56aSColin Percival# Fetch the mirror list, but do not pick a mirror yet. Returns 1 if 61648ffe56aSColin Percival# no mirrors are available for any reason. 61748ffe56aSColin Percivalfetch_pick_server_init () { 61848ffe56aSColin Percival : > serverlist_tried 61948ffe56aSColin Percival 62048ffe56aSColin Percival# Check that host(1) exists (i.e., that the system wasn't built with the 62148ffe56aSColin Percival# WITHOUT_BIND set) and don't try to find a mirror if it doesn't exist. 62248ffe56aSColin Percival if ! which -s host; then 62348ffe56aSColin Percival : > serverlist_full 62448ffe56aSColin Percival return 1 62548ffe56aSColin Percival fi 62648ffe56aSColin Percival 62748ffe56aSColin Percival echo -n "Looking up ${SERVERNAME} mirrors... " 62848ffe56aSColin Percival 62948ffe56aSColin Percival# Issue the SRV query and pull out the Priority, Weight, and Target fields. 63048ffe56aSColin Percival# BIND 9 prints "$name has SRV record ..." while BIND 8 prints 63148ffe56aSColin Percival# "$name server selection ..."; we allow either format. 63248ffe56aSColin Percival MLIST="_http._tcp.${SERVERNAME}" 63348ffe56aSColin Percival host -t srv "${MLIST}" | 63448ffe56aSColin Percival sed -nE "s/${MLIST} (has SRV record|server selection) //p" | 63548ffe56aSColin Percival cut -f 1,2,4 -d ' ' | 63648ffe56aSColin Percival sed -e 's/\.$//' | 63748ffe56aSColin Percival sort > serverlist_full 63848ffe56aSColin Percival 63948ffe56aSColin Percival# If no records, give up -- we'll just use the server name we were given. 64048ffe56aSColin Percival if [ `wc -l < serverlist_full` -eq 0 ]; then 64148ffe56aSColin Percival echo "none found." 64248ffe56aSColin Percival return 1 64348ffe56aSColin Percival fi 64448ffe56aSColin Percival 64548ffe56aSColin Percival# Report how many mirrors we found. 64648ffe56aSColin Percival echo `wc -l < serverlist_full` "mirrors found." 64748ffe56aSColin Percival 64848ffe56aSColin Percival# Generate a random seed for use in picking mirrors. If HTTP_PROXY 64948ffe56aSColin Percival# is set, this will be used to generate the seed; otherwise, the seed 65048ffe56aSColin Percival# will be random. 65148ffe56aSColin Percival if [ -n "${HTTP_PROXY}${http_proxy}" ]; then 65248ffe56aSColin Percival RANDVALUE=`sha256 -qs "${HTTP_PROXY}${http_proxy}" | 65348ffe56aSColin Percival tr -d 'a-f' | 65448ffe56aSColin Percival cut -c 1-9` 65548ffe56aSColin Percival else 65648ffe56aSColin Percival RANDVALUE=`jot -r 1 0 999999999` 65748ffe56aSColin Percival fi 65848ffe56aSColin Percival} 65948ffe56aSColin Percival 66048ffe56aSColin Percival# Pick a mirror. Returns 1 if we have run out of mirrors to try. 66148ffe56aSColin Percivalfetch_pick_server () { 66248ffe56aSColin Percival# Generate a list of not-yet-tried mirrors 66348ffe56aSColin Percival sort serverlist_tried | 66448ffe56aSColin Percival comm -23 serverlist_full - > serverlist 66548ffe56aSColin Percival 66648ffe56aSColin Percival# Have we run out of mirrors? 66748ffe56aSColin Percival if [ `wc -l < serverlist` -eq 0 ]; then 66848ffe56aSColin Percival echo "No mirrors remaining, giving up." 66948ffe56aSColin Percival return 1 67048ffe56aSColin Percival fi 67148ffe56aSColin Percival 67248ffe56aSColin Percival# Find the highest priority level (lowest numeric value). 67348ffe56aSColin Percival SRV_PRIORITY=`cut -f 1 -d ' ' serverlist | sort -n | head -1` 67448ffe56aSColin Percival 67548ffe56aSColin Percival# Add up the weights of the response lines at that priority level. 67648ffe56aSColin Percival SRV_WSUM=0; 67748ffe56aSColin Percival while read X; do 67848ffe56aSColin Percival case "$X" in 67948ffe56aSColin Percival ${SRV_PRIORITY}\ *) 68048ffe56aSColin Percival SRV_W=`echo $X | cut -f 2 -d ' '` 68148ffe56aSColin Percival SRV_WSUM=$(($SRV_WSUM + $SRV_W)) 68248ffe56aSColin Percival ;; 68348ffe56aSColin Percival esac 68448ffe56aSColin Percival done < serverlist 68548ffe56aSColin Percival 68648ffe56aSColin Percival# If all the weights are 0, pretend that they are all 1 instead. 68748ffe56aSColin Percival if [ ${SRV_WSUM} -eq 0 ]; then 68848ffe56aSColin Percival SRV_WSUM=`grep -E "^${SRV_PRIORITY} " serverlist | wc -l` 68948ffe56aSColin Percival SRV_W_ADD=1 69048ffe56aSColin Percival else 69148ffe56aSColin Percival SRV_W_ADD=0 69248ffe56aSColin Percival fi 69348ffe56aSColin Percival 69448ffe56aSColin Percival# Pick a value between 0 and the sum of the weights - 1 69548ffe56aSColin Percival SRV_RND=`expr ${RANDVALUE} % ${SRV_WSUM}` 69648ffe56aSColin Percival 69748ffe56aSColin Percival# Read through the list of mirrors and set SERVERNAME. Write the line 69848ffe56aSColin Percival# corresponding to the mirror we selected into serverlist_tried so that 69948ffe56aSColin Percival# we won't try it again. 70048ffe56aSColin Percival while read X; do 70148ffe56aSColin Percival case "$X" in 70248ffe56aSColin Percival ${SRV_PRIORITY}\ *) 70348ffe56aSColin Percival SRV_W=`echo $X | cut -f 2 -d ' '` 70448ffe56aSColin Percival SRV_W=$(($SRV_W + $SRV_W_ADD)) 70548ffe56aSColin Percival if [ $SRV_RND -lt $SRV_W ]; then 70648ffe56aSColin Percival SERVERNAME=`echo $X | cut -f 3 -d ' '` 70748ffe56aSColin Percival echo "$X" >> serverlist_tried 70848ffe56aSColin Percival break 70948ffe56aSColin Percival else 71048ffe56aSColin Percival SRV_RND=$(($SRV_RND - $SRV_W)) 71148ffe56aSColin Percival fi 71248ffe56aSColin Percival ;; 71348ffe56aSColin Percival esac 71448ffe56aSColin Percival done < serverlist 71548ffe56aSColin Percival} 71648ffe56aSColin Percival 71748ffe56aSColin Percival# Take a list of ${oldhash}|${newhash} and output a list of needed patches, 71848ffe56aSColin Percival# i.e., those for which we have ${oldhash} and don't have ${newhash}. 71948ffe56aSColin Percivalfetch_make_patchlist () { 72048ffe56aSColin Percival grep -vE "^([0-9a-f]{64})\|\1$" | 72148ffe56aSColin Percival tr '|' ' ' | 72248ffe56aSColin Percival while read X Y; do 72348ffe56aSColin Percival if [ -f "files/${Y}.gz" ] || 72448ffe56aSColin Percival [ ! -f "files/${X}.gz" ]; then 72548ffe56aSColin Percival continue 72648ffe56aSColin Percival fi 72748ffe56aSColin Percival echo "${X}|${Y}" 72848ffe56aSColin Percival done | uniq 72948ffe56aSColin Percival} 73048ffe56aSColin Percival 73148ffe56aSColin Percival# Print user-friendly progress statistics 73248ffe56aSColin Percivalfetch_progress () { 73348ffe56aSColin Percival LNC=0 73448ffe56aSColin Percival while read x; do 73548ffe56aSColin Percival LNC=$(($LNC + 1)) 73648ffe56aSColin Percival if [ $(($LNC % 10)) = 0 ]; then 73748ffe56aSColin Percival echo -n $LNC 73848ffe56aSColin Percival elif [ $(($LNC % 2)) = 0 ]; then 73948ffe56aSColin Percival echo -n . 74048ffe56aSColin Percival fi 74148ffe56aSColin Percival done 74248ffe56aSColin Percival echo -n " " 74348ffe56aSColin Percival} 74448ffe56aSColin Percival 74548ffe56aSColin Percival# Initialize the working directory 74648ffe56aSColin Percivalworkdir_init () { 74748ffe56aSColin Percival mkdir -p files 74848ffe56aSColin Percival touch tINDEX.present 74948ffe56aSColin Percival} 75048ffe56aSColin Percival 75148ffe56aSColin Percival# Check that we have a public key with an appropriate hash, or 75248ffe56aSColin Percival# fetch the key if it doesn't exist. Returns 1 if the key has 75348ffe56aSColin Percival# not yet been fetched. 75448ffe56aSColin Percivalfetch_key () { 75548ffe56aSColin Percival if [ -r pub.ssl ] && [ `${SHA256} -q pub.ssl` = ${KEYPRINT} ]; then 75648ffe56aSColin Percival return 0 75748ffe56aSColin Percival fi 75848ffe56aSColin Percival 75948ffe56aSColin Percival echo -n "Fetching public key from ${SERVERNAME}... " 76048ffe56aSColin Percival rm -f pub.ssl 76148ffe56aSColin Percival fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/pub.ssl \ 76248ffe56aSColin Percival 2>${QUIETREDIR} || true 76348ffe56aSColin Percival if ! [ -r pub.ssl ]; then 76448ffe56aSColin Percival echo "failed." 76548ffe56aSColin Percival return 1 76648ffe56aSColin Percival fi 76748ffe56aSColin Percival if ! [ `${SHA256} -q pub.ssl` = ${KEYPRINT} ]; then 76848ffe56aSColin Percival echo "key has incorrect hash." 76948ffe56aSColin Percival rm -f pub.ssl 77048ffe56aSColin Percival return 1 77148ffe56aSColin Percival fi 77248ffe56aSColin Percival echo "done." 77348ffe56aSColin Percival} 77448ffe56aSColin Percival 77548ffe56aSColin Percival# Fetch metadata signature, aka "tag". 77648ffe56aSColin Percivalfetch_tag () { 77748ffe56aSColin Percival echo ${NDEBUG} "Fetching metadata signature from ${SERVERNAME}... " 77848ffe56aSColin Percival rm -f latest.ssl 77948ffe56aSColin Percival fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/latest.ssl \ 78048ffe56aSColin Percival 2>${QUIETREDIR} || true 78148ffe56aSColin Percival if ! [ -r latest.ssl ]; then 78248ffe56aSColin Percival echo "failed." 78348ffe56aSColin Percival return 1 78448ffe56aSColin Percival fi 78548ffe56aSColin Percival 78648ffe56aSColin Percival openssl rsautl -pubin -inkey pub.ssl -verify \ 78748ffe56aSColin Percival < latest.ssl > tag.new 2>${QUIETREDIR} || true 78848ffe56aSColin Percival rm latest.ssl 78948ffe56aSColin Percival 79048ffe56aSColin Percival if ! [ `wc -l < tag.new` = 1 ] || 79148ffe56aSColin Percival ! grep -qE \ 79248ffe56aSColin Percival "^freebsd-update\|${ARCH}\|${RELNUM}\|[0-9]+\|[0-9a-f]{64}\|[0-9]{10}" \ 79348ffe56aSColin Percival tag.new; then 79448ffe56aSColin Percival echo "invalid signature." 79548ffe56aSColin Percival return 1 79648ffe56aSColin Percival fi 79748ffe56aSColin Percival 79848ffe56aSColin Percival echo "done." 79948ffe56aSColin Percival 80048ffe56aSColin Percival RELPATCHNUM=`cut -f 4 -d '|' < tag.new` 80148ffe56aSColin Percival TINDEXHASH=`cut -f 5 -d '|' < tag.new` 80248ffe56aSColin Percival EOLTIME=`cut -f 6 -d '|' < tag.new` 80348ffe56aSColin Percival} 80448ffe56aSColin Percival 80548ffe56aSColin Percival# Sanity-check the patch number in a tag, to make sure that we're not 80648ffe56aSColin Percival# going to "update" backwards and to prevent replay attacks. 80748ffe56aSColin Percivalfetch_tagsanity () { 80848ffe56aSColin Percival # Check that we're not going to move from -pX to -pY with Y < X. 80948ffe56aSColin Percival RELPX=`uname -r | sed -E 's,.*-,,'` 81048ffe56aSColin Percival if echo ${RELPX} | grep -qE '^p[0-9]+$'; then 81148ffe56aSColin Percival RELPX=`echo ${RELPX} | cut -c 2-` 81248ffe56aSColin Percival else 81348ffe56aSColin Percival RELPX=0 81448ffe56aSColin Percival fi 81548ffe56aSColin Percival if [ "${RELPATCHNUM}" -lt "${RELPX}" ]; then 81648ffe56aSColin Percival echo 81748ffe56aSColin Percival echo -n "Files on mirror (${RELNUM}-p${RELPATCHNUM})" 81848ffe56aSColin Percival echo " appear older than what" 81948ffe56aSColin Percival echo "we are currently running (`uname -r`)!" 82048ffe56aSColin Percival echo "Cowardly refusing to proceed any further." 82148ffe56aSColin Percival return 1 82248ffe56aSColin Percival fi 82348ffe56aSColin Percival 82448ffe56aSColin Percival # If "tag" exists and corresponds to ${RELNUM}, make sure that 82548ffe56aSColin Percival # it contains a patch number <= RELPATCHNUM, in order to protect 82648ffe56aSColin Percival # against rollback (replay) attacks. 82748ffe56aSColin Percival if [ -f tag ] && 82848ffe56aSColin Percival grep -qE \ 82948ffe56aSColin Percival "^freebsd-update\|${ARCH}\|${RELNUM}\|[0-9]+\|[0-9a-f]{64}\|[0-9]{10}" \ 83048ffe56aSColin Percival tag; then 83148ffe56aSColin Percival LASTRELPATCHNUM=`cut -f 4 -d '|' < tag` 83248ffe56aSColin Percival 83348ffe56aSColin Percival if [ "${RELPATCHNUM}" -lt "${LASTRELPATCHNUM}" ]; then 83448ffe56aSColin Percival echo 83548ffe56aSColin Percival echo -n "Files on mirror (${RELNUM}-p${RELPATCHNUM})" 83648ffe56aSColin Percival echo " are older than the" 83748ffe56aSColin Percival echo -n "most recently seen updates" 83848ffe56aSColin Percival echo " (${RELNUM}-p${LASTRELPATCHNUM})." 83948ffe56aSColin Percival echo "Cowardly refusing to proceed any further." 84048ffe56aSColin Percival return 1 84148ffe56aSColin Percival fi 84248ffe56aSColin Percival fi 84348ffe56aSColin Percival} 84448ffe56aSColin Percival 84548ffe56aSColin Percival# Fetch metadata index file 84648ffe56aSColin Percivalfetch_metadata_index () { 84748ffe56aSColin Percival echo ${NDEBUG} "Fetching metadata index... " 84848ffe56aSColin Percival rm -f ${TINDEXHASH} 84948ffe56aSColin Percival fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/t/${TINDEXHASH} 85048ffe56aSColin Percival 2>${QUIETREDIR} 85148ffe56aSColin Percival if ! [ -f ${TINDEXHASH} ]; then 85248ffe56aSColin Percival echo "failed." 85348ffe56aSColin Percival return 1 85448ffe56aSColin Percival fi 85548ffe56aSColin Percival if [ `${SHA256} -q ${TINDEXHASH}` != ${TINDEXHASH} ]; then 85648ffe56aSColin Percival echo "update metadata index corrupt." 85748ffe56aSColin Percival return 1 85848ffe56aSColin Percival fi 85948ffe56aSColin Percival echo "done." 86048ffe56aSColin Percival} 86148ffe56aSColin Percival 86248ffe56aSColin Percival# Print an error message about signed metadata being bogus. 86348ffe56aSColin Percivalfetch_metadata_bogus () { 86448ffe56aSColin Percival echo 86548ffe56aSColin Percival echo "The update metadata$1 is correctly signed, but" 86648ffe56aSColin Percival echo "failed an integrity check." 86748ffe56aSColin Percival echo "Cowardly refusing to proceed any further." 86848ffe56aSColin Percival return 1 86948ffe56aSColin Percival} 87048ffe56aSColin Percival 87148ffe56aSColin Percival# Construct tINDEX.new by merging the lines named in $1 from ${TINDEXHASH} 87248ffe56aSColin Percival# with the lines not named in $@ from tINDEX.present (if that file exists). 87348ffe56aSColin Percivalfetch_metadata_index_merge () { 87448ffe56aSColin Percival for METAFILE in $@; do 87548ffe56aSColin Percival if [ `grep -E "^${METAFILE}\|" ${TINDEXHASH} | wc -l` \ 87648ffe56aSColin Percival -ne 1 ]; then 87748ffe56aSColin Percival fetch_metadata_bogus " index" 87848ffe56aSColin Percival return 1 87948ffe56aSColin Percival fi 88048ffe56aSColin Percival 88148ffe56aSColin Percival grep -E "${METAFILE}\|" ${TINDEXHASH} 88248ffe56aSColin Percival done | 88348ffe56aSColin Percival sort > tINDEX.wanted 88448ffe56aSColin Percival 88548ffe56aSColin Percival if [ -f tINDEX.present ]; then 88648ffe56aSColin Percival join -t '|' -v 2 tINDEX.wanted tINDEX.present | 88748ffe56aSColin Percival sort -m - tINDEX.wanted > tINDEX.new 88848ffe56aSColin Percival rm tINDEX.wanted 88948ffe56aSColin Percival else 89048ffe56aSColin Percival mv tINDEX.wanted tINDEX.new 89148ffe56aSColin Percival fi 89248ffe56aSColin Percival} 89348ffe56aSColin Percival 89448ffe56aSColin Percival# Sanity check all the lines of tINDEX.new. Even if more metadata lines 89548ffe56aSColin Percival# are added by future versions of the server, this won't cause problems, 89648ffe56aSColin Percival# since the only lines which appear in tINDEX.new are the ones which we 89748ffe56aSColin Percival# specifically grepped out of ${TINDEXHASH}. 89848ffe56aSColin Percivalfetch_metadata_index_sanity () { 89948ffe56aSColin Percival if grep -qvE '^[0-9A-Z.-]+\|[0-9a-f]{64}$' tINDEX.new; then 90048ffe56aSColin Percival fetch_metadata_bogus " index" 90148ffe56aSColin Percival return 1 90248ffe56aSColin Percival fi 90348ffe56aSColin Percival} 90448ffe56aSColin Percival 90548ffe56aSColin Percival# Sanity check the metadata file $1. 90648ffe56aSColin Percivalfetch_metadata_sanity () { 90748ffe56aSColin Percival # Some aliases to save space later: ${P} is a character which can 90848ffe56aSColin Percival # appear in a path; ${M} is the four numeric metadata fields; and 90948ffe56aSColin Percival # ${H} is a sha256 hash. 91048ffe56aSColin Percival P="[-+./:=_[[:alnum:]]" 91148ffe56aSColin Percival M="[0-9]+\|[0-9]+\|[0-9]+\|[0-9]+" 91248ffe56aSColin Percival H="[0-9a-f]{64}" 91348ffe56aSColin Percival 91448ffe56aSColin Percival # Check that the first four fields make sense. 91548ffe56aSColin Percival if gunzip -c < files/$1.gz | 91648ffe56aSColin Percival grep -qvE "^[a-z]+\|[0-9a-z]+\|${P}+\|[fdL-]\|"; then 91748ffe56aSColin Percival fetch_metadata_bogus "" 91848ffe56aSColin Percival return 1 91948ffe56aSColin Percival fi 92048ffe56aSColin Percival 92148ffe56aSColin Percival # Remove the first three fields. 92248ffe56aSColin Percival gunzip -c < files/$1.gz | 92348ffe56aSColin Percival cut -f 4- -d '|' > sanitycheck.tmp 92448ffe56aSColin Percival 92548ffe56aSColin Percival # Sanity check entries with type 'f' 92648ffe56aSColin Percival if grep -E '^f' sanitycheck.tmp | 92748ffe56aSColin Percival grep -qvE "^f\|${M}\|${H}\|${P}*\$"; then 92848ffe56aSColin Percival fetch_metadata_bogus "" 92948ffe56aSColin Percival return 1 93048ffe56aSColin Percival fi 93148ffe56aSColin Percival 93248ffe56aSColin Percival # Sanity check entries with type 'd' 93348ffe56aSColin Percival if grep -E '^d' sanitycheck.tmp | 93448ffe56aSColin Percival grep -qvE "^d\|${M}\|\|\$"; then 93548ffe56aSColin Percival fetch_metadata_bogus "" 93648ffe56aSColin Percival return 1 93748ffe56aSColin Percival fi 93848ffe56aSColin Percival 93948ffe56aSColin Percival # Sanity check entries with type 'L' 94048ffe56aSColin Percival if grep -E '^L' sanitycheck.tmp | 94148ffe56aSColin Percival grep -qvE "^L\|${M}\|${P}*\|\$"; then 94248ffe56aSColin Percival fetch_metadata_bogus "" 94348ffe56aSColin Percival return 1 94448ffe56aSColin Percival fi 94548ffe56aSColin Percival 94648ffe56aSColin Percival # Sanity check entries with type '-' 94748ffe56aSColin Percival if grep -E '^-' sanitycheck.tmp | 94848ffe56aSColin Percival grep -qvE "^-\|\|\|\|\|\|"; then 94948ffe56aSColin Percival fetch_metadata_bogus "" 95048ffe56aSColin Percival return 1 95148ffe56aSColin Percival fi 95248ffe56aSColin Percival 95348ffe56aSColin Percival # Clean up 95448ffe56aSColin Percival rm sanitycheck.tmp 95548ffe56aSColin Percival} 95648ffe56aSColin Percival 95748ffe56aSColin Percival# Fetch the metadata index and metadata files listed in $@, 95848ffe56aSColin Percival# taking advantage of metadata patches where possible. 95948ffe56aSColin Percivalfetch_metadata () { 96048ffe56aSColin Percival fetch_metadata_index || return 1 96148ffe56aSColin Percival fetch_metadata_index_merge $@ || return 1 96248ffe56aSColin Percival fetch_metadata_index_sanity || return 1 96348ffe56aSColin Percival 96448ffe56aSColin Percival # Generate a list of wanted metadata patches 96548ffe56aSColin Percival join -t '|' -o 1.2,2.2 tINDEX.present tINDEX.new | 96648ffe56aSColin Percival fetch_make_patchlist > patchlist 96748ffe56aSColin Percival 96848ffe56aSColin Percival if [ -s patchlist ]; then 96948ffe56aSColin Percival # Attempt to fetch metadata patches 97048ffe56aSColin Percival echo -n "Fetching `wc -l < patchlist | tr -d ' '` " 97148ffe56aSColin Percival echo ${NDEBUG} "metadata patches.${DDSTATS}" 97248ffe56aSColin Percival tr '|' '-' < patchlist | 97348ffe56aSColin Percival lam -s "${FETCHDIR}/tp/" - -s ".gz" | 97448ffe56aSColin Percival xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ 97548ffe56aSColin Percival 2>${STATSREDIR} | fetch_progress 97648ffe56aSColin Percival echo "done." 97748ffe56aSColin Percival 97848ffe56aSColin Percival # Attempt to apply metadata patches 97948ffe56aSColin Percival echo -n "Applying metadata patches... " 98048ffe56aSColin Percival tr '|' ' ' < patchlist | 98148ffe56aSColin Percival while read X Y; do 98248ffe56aSColin Percival if [ ! -f "${X}-${Y}.gz" ]; then continue; fi 98348ffe56aSColin Percival gunzip -c < ${X}-${Y}.gz > diff 98448ffe56aSColin Percival gunzip -c < files/${X}.gz > diff-OLD 98548ffe56aSColin Percival 98648ffe56aSColin Percival # Figure out which lines are being added and removed 98748ffe56aSColin Percival grep -E '^-' diff | 98848ffe56aSColin Percival cut -c 2- | 98948ffe56aSColin Percival while read PREFIX; do 99048ffe56aSColin Percival look "${PREFIX}" diff-OLD 99148ffe56aSColin Percival done | 99248ffe56aSColin Percival sort > diff-rm 99348ffe56aSColin Percival grep -E '^\+' diff | 99448ffe56aSColin Percival cut -c 2- > diff-add 99548ffe56aSColin Percival 99648ffe56aSColin Percival # Generate the new file 99748ffe56aSColin Percival comm -23 diff-OLD diff-rm | 99848ffe56aSColin Percival sort - diff-add > diff-NEW 99948ffe56aSColin Percival 100048ffe56aSColin Percival if [ `${SHA256} -q diff-NEW` = ${Y} ]; then 100148ffe56aSColin Percival mv diff-NEW files/${Y} 100248ffe56aSColin Percival gzip -n files/${Y} 100348ffe56aSColin Percival else 100448ffe56aSColin Percival mv diff-NEW ${Y}.bad 100548ffe56aSColin Percival fi 100648ffe56aSColin Percival rm -f ${X}-${Y}.gz diff 100748ffe56aSColin Percival rm -f diff-OLD diff-NEW diff-add diff-rm 100848ffe56aSColin Percival done 2>${QUIETREDIR} 100948ffe56aSColin Percival echo "done." 101048ffe56aSColin Percival fi 101148ffe56aSColin Percival 101248ffe56aSColin Percival # Update metadata without patches 101348ffe56aSColin Percival cut -f 2 -d '|' < tINDEX.new | 101448ffe56aSColin Percival while read Y; do 101548ffe56aSColin Percival if [ ! -f "files/${Y}.gz" ]; then 101648ffe56aSColin Percival echo ${Y}; 101748ffe56aSColin Percival fi 1018bce02f98SColin Percival done | 1019bce02f98SColin Percival sort -u > filelist 102048ffe56aSColin Percival 102148ffe56aSColin Percival if [ -s filelist ]; then 102248ffe56aSColin Percival echo -n "Fetching `wc -l < filelist | tr -d ' '` " 102348ffe56aSColin Percival echo ${NDEBUG} "metadata files... " 102448ffe56aSColin Percival lam -s "${FETCHDIR}/m/" - -s ".gz" < filelist | 102548ffe56aSColin Percival xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ 102648ffe56aSColin Percival 2>${QUIETREDIR} 102748ffe56aSColin Percival 102848ffe56aSColin Percival while read Y; do 102948ffe56aSColin Percival if ! [ -f ${Y}.gz ]; then 103048ffe56aSColin Percival echo "failed." 103148ffe56aSColin Percival return 1 103248ffe56aSColin Percival fi 103348ffe56aSColin Percival if [ `gunzip -c < ${Y}.gz | 103448ffe56aSColin Percival ${SHA256} -q` = ${Y} ]; then 103548ffe56aSColin Percival mv ${Y}.gz files/${Y}.gz 103648ffe56aSColin Percival else 103748ffe56aSColin Percival echo "metadata is corrupt." 103848ffe56aSColin Percival return 1 103948ffe56aSColin Percival fi 104048ffe56aSColin Percival done < filelist 104148ffe56aSColin Percival echo "done." 104248ffe56aSColin Percival fi 104348ffe56aSColin Percival 104448ffe56aSColin Percival# Sanity-check the metadata files. 104548ffe56aSColin Percival cut -f 2 -d '|' tINDEX.new > filelist 104648ffe56aSColin Percival while read X; do 104748ffe56aSColin Percival fetch_metadata_sanity ${X} || return 1 104848ffe56aSColin Percival done < filelist 104948ffe56aSColin Percival 105048ffe56aSColin Percival# Remove files which are no longer needed 105148ffe56aSColin Percival cut -f 2 -d '|' tINDEX.present | 105248ffe56aSColin Percival sort > oldfiles 105348ffe56aSColin Percival cut -f 2 -d '|' tINDEX.new | 105448ffe56aSColin Percival sort | 105548ffe56aSColin Percival comm -13 - oldfiles | 105648ffe56aSColin Percival lam -s "files/" - -s ".gz" | 105748ffe56aSColin Percival xargs rm -f 105848ffe56aSColin Percival rm patchlist filelist oldfiles 105948ffe56aSColin Percival rm ${TINDEXHASH} 106048ffe56aSColin Percival 106148ffe56aSColin Percival# We're done! 106248ffe56aSColin Percival mv tINDEX.new tINDEX.present 106348ffe56aSColin Percival mv tag.new tag 106448ffe56aSColin Percival 106548ffe56aSColin Percival return 0 106648ffe56aSColin Percival} 106748ffe56aSColin Percival 1068b698a3abSColin Percival# Generate a filtered version of the metadata file $1 from the downloaded 106948ffe56aSColin Percival# file, by fishing out the lines corresponding to components we're trying 107048ffe56aSColin Percival# to keep updated, and then removing lines corresponding to paths we want 107148ffe56aSColin Percival# to ignore. 107248ffe56aSColin Percivalfetch_filter_metadata () { 107348ffe56aSColin Percival METAHASH=`look "$1|" tINDEX.present | cut -f 2 -d '|'` 107448ffe56aSColin Percival gunzip -c < files/${METAHASH}.gz > $1.all 107548ffe56aSColin Percival 107648ffe56aSColin Percival # Fish out the lines belonging to components we care about. 107748ffe56aSColin Percival # Canonicalize directory names by removing any trailing / in 107848ffe56aSColin Percival # order to avoid listing directories multiple times if they 107948ffe56aSColin Percival # belong to multiple components. Turning "/" into "" doesn't 108048ffe56aSColin Percival # matter, since we add a leading "/" when we use paths later. 108148ffe56aSColin Percival for C in ${COMPONENTS}; do 108248ffe56aSColin Percival look "`echo ${C} | tr '/' '|'`|" $1.all 108348ffe56aSColin Percival done | 108448ffe56aSColin Percival cut -f 3- -d '|' | 108548ffe56aSColin Percival sed -e 's,/|d|,|d|,' | 108648ffe56aSColin Percival sort -u > $1.tmp 108748ffe56aSColin Percival 108848ffe56aSColin Percival # Figure out which lines to ignore and remove them. 108948ffe56aSColin Percival for X in ${IGNOREPATHS}; do 109048ffe56aSColin Percival grep -E "^${X}" $1.tmp 109148ffe56aSColin Percival done | 109248ffe56aSColin Percival sort -u | 109348ffe56aSColin Percival comm -13 - $1.tmp > $1 109448ffe56aSColin Percival 109548ffe56aSColin Percival # Remove temporary files. 109648ffe56aSColin Percival rm $1.all $1.tmp 109748ffe56aSColin Percival} 109848ffe56aSColin Percival 10992c434b2cSColin Percival# Filter the metadata file $1 by adding lines with "/boot/${KERNCONF}" 1100bce02f98SColin Percival# replaced by ${KERNELDIR} (which is `sysctl -n kern.bootfile` minus the 11012c434b2cSColin Percival# trailing "/kernel"); and if "/boot/${KERNCONF}" does not exist, remove 1102bce02f98SColin Percival# the original lines which start with that. 1103bce02f98SColin Percival# Put another way: Deal with the fact that the FOO kernel is sometimes 1104bce02f98SColin Percival# installed in /boot/FOO/ and is sometimes installed elsewhere. 110548ffe56aSColin Percivalfetch_filter_kernel_names () { 1106bce02f98SColin Percival 1107bce02f98SColin Percival grep ^/boot/${KERNCONF} $1 | 1108bce02f98SColin Percival sed -e "s,/boot/${KERNCONF},${KERNELDIR},g" | 110948ffe56aSColin Percival sort - $1 > $1.tmp 111048ffe56aSColin Percival mv $1.tmp $1 1111bce02f98SColin Percival 1112bce02f98SColin Percival if ! [ -d /boot/${KERNCONF} ]; then 1113bce02f98SColin Percival grep -v ^/boot/${KERNCONF} $1 > $1.tmp 1114bce02f98SColin Percival mv $1.tmp $1 1115bce02f98SColin Percival fi 111648ffe56aSColin Percival} 111748ffe56aSColin Percival 111848ffe56aSColin Percival# For all paths appearing in $1 or $3, inspect the system 111948ffe56aSColin Percival# and generate $2 describing what is currently installed. 112048ffe56aSColin Percivalfetch_inspect_system () { 112148ffe56aSColin Percival # No errors yet... 112248ffe56aSColin Percival rm -f .err 112348ffe56aSColin Percival 112448ffe56aSColin Percival # Tell the user why his disk is suddenly making lots of noise 112548ffe56aSColin Percival echo -n "Inspecting system... " 112648ffe56aSColin Percival 112748ffe56aSColin Percival # Generate list of files to inspect 112848ffe56aSColin Percival cat $1 $3 | 112948ffe56aSColin Percival cut -f 1 -d '|' | 113048ffe56aSColin Percival sort -u > filelist 113148ffe56aSColin Percival 113248ffe56aSColin Percival # Examine each file and output lines of the form 113348ffe56aSColin Percival # /path/to/file|type|device-inum|user|group|perm|flags|value 113448ffe56aSColin Percival # sorted by device and inode number. 113548ffe56aSColin Percival while read F; do 113648ffe56aSColin Percival # If the symlink/file/directory does not exist, record this. 113748ffe56aSColin Percival if ! [ -e ${BASEDIR}/${F} ]; then 113848ffe56aSColin Percival echo "${F}|-||||||" 113948ffe56aSColin Percival continue 114048ffe56aSColin Percival fi 114148ffe56aSColin Percival if ! [ -r ${BASEDIR}/${F} ]; then 114248ffe56aSColin Percival echo "Cannot read file: ${BASEDIR}/${F}" \ 114348ffe56aSColin Percival >/dev/stderr 114448ffe56aSColin Percival touch .err 114548ffe56aSColin Percival return 1 114648ffe56aSColin Percival fi 114748ffe56aSColin Percival 114848ffe56aSColin Percival # Otherwise, output an index line. 114948ffe56aSColin Percival if [ -L ${BASEDIR}/${F} ]; then 115048ffe56aSColin Percival echo -n "${F}|L|" 115148ffe56aSColin Percival stat -n -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F}; 115248ffe56aSColin Percival readlink ${BASEDIR}/${F}; 115348ffe56aSColin Percival elif [ -f ${BASEDIR}/${F} ]; then 115448ffe56aSColin Percival echo -n "${F}|f|" 115548ffe56aSColin Percival stat -n -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F}; 115648ffe56aSColin Percival sha256 -q ${BASEDIR}/${F}; 115748ffe56aSColin Percival elif [ -d ${BASEDIR}/${F} ]; then 115848ffe56aSColin Percival echo -n "${F}|d|" 115948ffe56aSColin Percival stat -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F}; 116048ffe56aSColin Percival else 116148ffe56aSColin Percival echo "Unknown file type: ${BASEDIR}/${F}" \ 116248ffe56aSColin Percival >/dev/stderr 116348ffe56aSColin Percival touch .err 116448ffe56aSColin Percival return 1 116548ffe56aSColin Percival fi 116648ffe56aSColin Percival done < filelist | 116748ffe56aSColin Percival sort -k 3,3 -t '|' > $2.tmp 116848ffe56aSColin Percival rm filelist 116948ffe56aSColin Percival 117048ffe56aSColin Percival # Check if an error occured during system inspection 117148ffe56aSColin Percival if [ -f .err ]; then 117248ffe56aSColin Percival return 1 117348ffe56aSColin Percival fi 117448ffe56aSColin Percival 117548ffe56aSColin Percival # Convert to the form 117648ffe56aSColin Percival # /path/to/file|type|user|group|perm|flags|value|hlink 117748ffe56aSColin Percival # by resolving identical device and inode numbers into hard links. 117848ffe56aSColin Percival cut -f 1,3 -d '|' $2.tmp | 117948ffe56aSColin Percival sort -k 1,1 -t '|' | 118048ffe56aSColin Percival sort -s -u -k 2,2 -t '|' | 118148ffe56aSColin Percival join -1 2 -2 3 -t '|' - $2.tmp | 118248ffe56aSColin Percival awk -F \| -v OFS=\| \ 118348ffe56aSColin Percival '{ 118448ffe56aSColin Percival if (($2 == $3) || ($4 == "-")) 118548ffe56aSColin Percival print $3,$4,$5,$6,$7,$8,$9,"" 118648ffe56aSColin Percival else 118748ffe56aSColin Percival print $3,$4,$5,$6,$7,$8,$9,$2 118848ffe56aSColin Percival }' | 118948ffe56aSColin Percival sort > $2 119048ffe56aSColin Percival rm $2.tmp 119148ffe56aSColin Percival 119248ffe56aSColin Percival # We're finished looking around 119348ffe56aSColin Percival echo "done." 119448ffe56aSColin Percival} 119548ffe56aSColin Percival 119648ffe56aSColin Percival# For any paths matching ${UPDATEIFUNMODIFIED}, remove lines from $[123] 119748ffe56aSColin Percival# which correspond to lines in $2 with hashes not matching $1 or $3. For 119848ffe56aSColin Percival# entries in $2 marked "not present" (aka. type -), remove lines from $[123] 119948ffe56aSColin Percival# unless there is a corresponding entry in $1. 120048ffe56aSColin Percivalfetch_filter_unmodified_notpresent () { 120148ffe56aSColin Percival # Figure out which lines of $1 and $3 correspond to bits which 120248ffe56aSColin Percival # should only be updated if they haven't changed, and fish out 120348ffe56aSColin Percival # the (path, type, value) tuples. 120448ffe56aSColin Percival # NOTE: We don't consider a file to be "modified" if it matches 120548ffe56aSColin Percival # the hash from $3. 120648ffe56aSColin Percival for X in ${UPDATEIFUNMODIFIED}; do 120748ffe56aSColin Percival grep -E "^${X}" $1 120848ffe56aSColin Percival grep -E "^${X}" $3 120948ffe56aSColin Percival done | 121048ffe56aSColin Percival cut -f 1,2,7 -d '|' | 121148ffe56aSColin Percival sort > $1-values 121248ffe56aSColin Percival 121348ffe56aSColin Percival # Do the same for $2. 121448ffe56aSColin Percival for X in ${UPDATEIFUNMODIFIED}; do 121548ffe56aSColin Percival grep -E "^${X}" $2 121648ffe56aSColin Percival done | 121748ffe56aSColin Percival cut -f 1,2,7 -d '|' | 121848ffe56aSColin Percival sort > $2-values 121948ffe56aSColin Percival 122048ffe56aSColin Percival # Any entry in $2-values which is not in $1-values corresponds to 122148ffe56aSColin Percival # a path which we need to remove from $1, $2, and $3. 122248ffe56aSColin Percival comm -13 $1-values $2-values > mlines 122348ffe56aSColin Percival rm $1-values $2-values 122448ffe56aSColin Percival 122548ffe56aSColin Percival # Any lines in $2 which are not in $1 AND are "not present" lines 122648ffe56aSColin Percival # also belong in mlines. 122748ffe56aSColin Percival comm -13 $1 $2 | 122848ffe56aSColin Percival cut -f 1,2,7 -d '|' | 122948ffe56aSColin Percival fgrep '|-|' >> mlines 123048ffe56aSColin Percival 123148ffe56aSColin Percival # Remove lines from $1, $2, and $3 123248ffe56aSColin Percival for X in $1 $2 $3; do 123348ffe56aSColin Percival sort -t '|' -k 1,1 ${X} > ${X}.tmp 123448ffe56aSColin Percival cut -f 1 -d '|' < mlines | 123548ffe56aSColin Percival sort | 123648ffe56aSColin Percival join -v 2 -t '|' - ${X}.tmp | 123748ffe56aSColin Percival sort > ${X} 123848ffe56aSColin Percival rm ${X}.tmp 123948ffe56aSColin Percival done 124048ffe56aSColin Percival 124148ffe56aSColin Percival # Store a list of the modified files, for future reference 124248ffe56aSColin Percival fgrep -v '|-|' mlines | 124348ffe56aSColin Percival cut -f 1 -d '|' > modifiedfiles 124448ffe56aSColin Percival rm mlines 124548ffe56aSColin Percival} 124648ffe56aSColin Percival 124748ffe56aSColin Percival# For each entry in $1 of type -, remove any corresponding 124848ffe56aSColin Percival# entry from $2 if ${ALLOWADD} != "yes". Remove all entries 124948ffe56aSColin Percival# of type - from $1. 125048ffe56aSColin Percivalfetch_filter_allowadd () { 125148ffe56aSColin Percival cut -f 1,2 -d '|' < $1 | 125248ffe56aSColin Percival fgrep '|-' | 125348ffe56aSColin Percival cut -f 1 -d '|' > filesnotpresent 125448ffe56aSColin Percival 125548ffe56aSColin Percival if [ ${ALLOWADD} != "yes" ]; then 125648ffe56aSColin Percival sort < $2 | 125748ffe56aSColin Percival join -v 1 -t '|' - filesnotpresent | 125848ffe56aSColin Percival sort > $2.tmp 125948ffe56aSColin Percival mv $2.tmp $2 126048ffe56aSColin Percival fi 126148ffe56aSColin Percival 126248ffe56aSColin Percival sort < $1 | 126348ffe56aSColin Percival join -v 1 -t '|' - filesnotpresent | 126448ffe56aSColin Percival sort > $1.tmp 126548ffe56aSColin Percival mv $1.tmp $1 126648ffe56aSColin Percival rm filesnotpresent 126748ffe56aSColin Percival} 126848ffe56aSColin Percival 126948ffe56aSColin Percival# If ${ALLOWDELETE} != "yes", then remove any entries from $1 127048ffe56aSColin Percival# which don't correspond to entries in $2. 127148ffe56aSColin Percivalfetch_filter_allowdelete () { 127248ffe56aSColin Percival # Produce a lists ${PATH}|${TYPE} 127348ffe56aSColin Percival for X in $1 $2; do 127448ffe56aSColin Percival cut -f 1-2 -d '|' < ${X} | 127548ffe56aSColin Percival sort -u > ${X}.nodes 127648ffe56aSColin Percival done 127748ffe56aSColin Percival 127848ffe56aSColin Percival # Figure out which lines need to be removed from $1. 127948ffe56aSColin Percival if [ ${ALLOWDELETE} != "yes" ]; then 128048ffe56aSColin Percival comm -23 $1.nodes $2.nodes > $1.badnodes 128148ffe56aSColin Percival else 128248ffe56aSColin Percival : > $1.badnodes 128348ffe56aSColin Percival fi 128448ffe56aSColin Percival 128548ffe56aSColin Percival # Remove the relevant lines from $1 128648ffe56aSColin Percival while read X; do 128748ffe56aSColin Percival look "${X}|" $1 128848ffe56aSColin Percival done < $1.badnodes | 128948ffe56aSColin Percival comm -13 - $1 > $1.tmp 129048ffe56aSColin Percival mv $1.tmp $1 129148ffe56aSColin Percival 129248ffe56aSColin Percival rm $1.badnodes $1.nodes $2.nodes 129348ffe56aSColin Percival} 129448ffe56aSColin Percival 129548ffe56aSColin Percival# If ${KEEPMODIFIEDMETADATA} == "yes", then for each entry in $2 129648ffe56aSColin Percival# with metadata not matching any entry in $1, replace the corresponding 129748ffe56aSColin Percival# line of $3 with one having the same metadata as the entry in $2. 129848ffe56aSColin Percivalfetch_filter_modified_metadata () { 129948ffe56aSColin Percival # Fish out the metadata from $1 and $2 130048ffe56aSColin Percival for X in $1 $2; do 130148ffe56aSColin Percival cut -f 1-6 -d '|' < ${X} > ${X}.metadata 130248ffe56aSColin Percival done 130348ffe56aSColin Percival 130448ffe56aSColin Percival # Find the metadata we need to keep 130548ffe56aSColin Percival if [ ${KEEPMODIFIEDMETADATA} = "yes" ]; then 130648ffe56aSColin Percival comm -13 $1.metadata $2.metadata > keepmeta 130748ffe56aSColin Percival else 130848ffe56aSColin Percival : > keepmeta 130948ffe56aSColin Percival fi 131048ffe56aSColin Percival 131148ffe56aSColin Percival # Extract the lines which we need to remove from $3, and 131248ffe56aSColin Percival # construct the lines which we need to add to $3. 131348ffe56aSColin Percival : > $3.remove 131448ffe56aSColin Percival : > $3.add 131548ffe56aSColin Percival while read LINE; do 131648ffe56aSColin Percival NODE=`echo "${LINE}" | cut -f 1-2 -d '|'` 131748ffe56aSColin Percival look "${NODE}|" $3 >> $3.remove 131848ffe56aSColin Percival look "${NODE}|" $3 | 131948ffe56aSColin Percival cut -f 7- -d '|' | 132048ffe56aSColin Percival lam -s "${LINE}|" - >> $3.add 132148ffe56aSColin Percival done < keepmeta 132248ffe56aSColin Percival 132348ffe56aSColin Percival # Remove the specified lines and add the new lines. 132448ffe56aSColin Percival sort $3.remove | 132548ffe56aSColin Percival comm -13 - $3 | 132648ffe56aSColin Percival sort -u - $3.add > $3.tmp 132748ffe56aSColin Percival mv $3.tmp $3 132848ffe56aSColin Percival 132948ffe56aSColin Percival rm keepmeta $1.metadata $2.metadata $3.add $3.remove 133048ffe56aSColin Percival} 133148ffe56aSColin Percival 133248ffe56aSColin Percival# Remove lines from $1 and $2 which are identical; 133348ffe56aSColin Percival# no need to update a file if it isn't changing. 133448ffe56aSColin Percivalfetch_filter_uptodate () { 133548ffe56aSColin Percival comm -23 $1 $2 > $1.tmp 133648ffe56aSColin Percival comm -13 $1 $2 > $2.tmp 133748ffe56aSColin Percival 133848ffe56aSColin Percival mv $1.tmp $1 133948ffe56aSColin Percival mv $2.tmp $2 134048ffe56aSColin Percival} 134148ffe56aSColin Percival 134248ffe56aSColin Percival# Prepare to fetch files: Generate a list of the files we need, 134348ffe56aSColin Percival# copy the unmodified files we have into /files/, and generate 134448ffe56aSColin Percival# a list of patches to download. 134548ffe56aSColin Percivalfetch_files_prepare () { 134648ffe56aSColin Percival # Tell the user why his disk is suddenly making lots of noise 134748ffe56aSColin Percival echo -n "Preparing to download files... " 134848ffe56aSColin Percival 134948ffe56aSColin Percival # Reduce indices to ${PATH}|${HASH} pairs 135048ffe56aSColin Percival for X in $1 $2 $3; do 135148ffe56aSColin Percival cut -f 1,2,7 -d '|' < ${X} | 135248ffe56aSColin Percival fgrep '|f|' | 135348ffe56aSColin Percival cut -f 1,3 -d '|' | 135448ffe56aSColin Percival sort > ${X}.hashes 135548ffe56aSColin Percival done 135648ffe56aSColin Percival 135748ffe56aSColin Percival # List of files wanted 135848ffe56aSColin Percival cut -f 2 -d '|' < $3.hashes | 135948ffe56aSColin Percival sort -u > files.wanted 136048ffe56aSColin Percival 136148ffe56aSColin Percival # Generate a list of unmodified files 136248ffe56aSColin Percival comm -12 $1.hashes $2.hashes | 136348ffe56aSColin Percival sort -k 1,1 -t '|' > unmodified.files 136448ffe56aSColin Percival 136548ffe56aSColin Percival # Copy all files into /files/. We only need the unmodified files 136648ffe56aSColin Percival # for use in patching; but we'll want all of them if the user asks 136748ffe56aSColin Percival # to rollback the updates later. 136848ffe56aSColin Percival cut -f 1 -d '|' < $2.hashes | 136948ffe56aSColin Percival while read F; do 137048ffe56aSColin Percival cp "${BASEDIR}/${F}" tmpfile 137148ffe56aSColin Percival gzip -c < tmpfile > files/`sha256 -q tmpfile`.gz 137248ffe56aSColin Percival rm tmpfile 137348ffe56aSColin Percival done 137448ffe56aSColin Percival 137548ffe56aSColin Percival # Produce a list of patches to download 137648ffe56aSColin Percival sort -k 1,1 -t '|' $3.hashes | 137748ffe56aSColin Percival join -t '|' -o 2.2,1.2 - unmodified.files | 137848ffe56aSColin Percival fetch_make_patchlist > patchlist 137948ffe56aSColin Percival 138048ffe56aSColin Percival # Garbage collect 138148ffe56aSColin Percival rm unmodified.files $1.hashes $2.hashes $3.hashes 138248ffe56aSColin Percival 138348ffe56aSColin Percival # We don't need the list of possible old files any more. 138448ffe56aSColin Percival rm $1 138548ffe56aSColin Percival 138648ffe56aSColin Percival # We're finished making noise 138748ffe56aSColin Percival echo "done." 138848ffe56aSColin Percival} 138948ffe56aSColin Percival 139048ffe56aSColin Percival# Fetch files. 139148ffe56aSColin Percivalfetch_files () { 139248ffe56aSColin Percival # Attempt to fetch patches 139348ffe56aSColin Percival if [ -s patchlist ]; then 139448ffe56aSColin Percival echo -n "Fetching `wc -l < patchlist | tr -d ' '` " 139548ffe56aSColin Percival echo ${NDEBUG} "patches.${DDSTATS}" 139648ffe56aSColin Percival tr '|' '-' < patchlist | 139748ffe56aSColin Percival lam -s "${FETCHDIR}/bp/" - | 139848ffe56aSColin Percival xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ 139948ffe56aSColin Percival 2>${STATSREDIR} | fetch_progress 140048ffe56aSColin Percival echo "done." 140148ffe56aSColin Percival 140248ffe56aSColin Percival # Attempt to apply patches 140348ffe56aSColin Percival echo -n "Applying patches... " 140448ffe56aSColin Percival tr '|' ' ' < patchlist | 140548ffe56aSColin Percival while read X Y; do 140648ffe56aSColin Percival if [ ! -f "${X}-${Y}" ]; then continue; fi 140748ffe56aSColin Percival gunzip -c < files/${X}.gz > OLD 140848ffe56aSColin Percival 140948ffe56aSColin Percival bspatch OLD NEW ${X}-${Y} 141048ffe56aSColin Percival 141148ffe56aSColin Percival if [ `${SHA256} -q NEW` = ${Y} ]; then 141248ffe56aSColin Percival mv NEW files/${Y} 141348ffe56aSColin Percival gzip -n files/${Y} 141448ffe56aSColin Percival fi 141548ffe56aSColin Percival rm -f diff OLD NEW ${X}-${Y} 141648ffe56aSColin Percival done 2>${QUIETREDIR} 141748ffe56aSColin Percival echo "done." 141848ffe56aSColin Percival fi 141948ffe56aSColin Percival 142048ffe56aSColin Percival # Download files which couldn't be generate via patching 142148ffe56aSColin Percival while read Y; do 142248ffe56aSColin Percival if [ ! -f "files/${Y}.gz" ]; then 142348ffe56aSColin Percival echo ${Y}; 142448ffe56aSColin Percival fi 142548ffe56aSColin Percival done < files.wanted > filelist 142648ffe56aSColin Percival 142748ffe56aSColin Percival if [ -s filelist ]; then 142848ffe56aSColin Percival echo -n "Fetching `wc -l < filelist | tr -d ' '` " 142948ffe56aSColin Percival echo ${NDEBUG} "files... " 143048ffe56aSColin Percival lam -s "${FETCHDIR}/f/" - -s ".gz" < filelist | 143148ffe56aSColin Percival xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ 143248ffe56aSColin Percival 2>${QUIETREDIR} 143348ffe56aSColin Percival 143448ffe56aSColin Percival while read Y; do 143548ffe56aSColin Percival if ! [ -f ${Y}.gz ]; then 143648ffe56aSColin Percival echo "failed." 143748ffe56aSColin Percival return 1 143848ffe56aSColin Percival fi 143948ffe56aSColin Percival if [ `gunzip -c < ${Y}.gz | 144048ffe56aSColin Percival ${SHA256} -q` = ${Y} ]; then 144148ffe56aSColin Percival mv ${Y}.gz files/${Y}.gz 144248ffe56aSColin Percival else 144348ffe56aSColin Percival echo "${Y} has incorrect hash." 144448ffe56aSColin Percival return 1 144548ffe56aSColin Percival fi 144648ffe56aSColin Percival done < filelist 144748ffe56aSColin Percival echo "done." 144848ffe56aSColin Percival fi 144948ffe56aSColin Percival 145048ffe56aSColin Percival # Clean up 145148ffe56aSColin Percival rm files.wanted filelist patchlist 145248ffe56aSColin Percival} 145348ffe56aSColin Percival 145448ffe56aSColin Percival# Create and populate install manifest directory; and report what updates 145548ffe56aSColin Percival# are available. 145648ffe56aSColin Percivalfetch_create_manifest () { 145748ffe56aSColin Percival # If we have an existing install manifest, nuke it. 145848ffe56aSColin Percival if [ -L "${BDHASH}-install" ]; then 145948ffe56aSColin Percival rm -r ${BDHASH}-install/ 146048ffe56aSColin Percival rm ${BDHASH}-install 146148ffe56aSColin Percival fi 146248ffe56aSColin Percival 146348ffe56aSColin Percival # Report to the user if any updates were avoided due to local changes 146448ffe56aSColin Percival if [ -s modifiedfiles ]; then 146548ffe56aSColin Percival echo 146648ffe56aSColin Percival echo -n "The following files are affected by updates, " 146748ffe56aSColin Percival echo "but no changes have" 146848ffe56aSColin Percival echo -n "been downloaded because the files have been " 146948ffe56aSColin Percival echo "modified locally:" 147048ffe56aSColin Percival cat modifiedfiles 147148ffe56aSColin Percival fi 147248ffe56aSColin Percival rm modifiedfiles 147348ffe56aSColin Percival 147448ffe56aSColin Percival # If no files will be updated, tell the user and exit 147548ffe56aSColin Percival if ! [ -s INDEX-PRESENT ] && 147648ffe56aSColin Percival ! [ -s INDEX-NEW ]; then 147748ffe56aSColin Percival rm INDEX-PRESENT INDEX-NEW 147848ffe56aSColin Percival echo 147948ffe56aSColin Percival echo -n "No updates needed to update system to " 148048ffe56aSColin Percival echo "${RELNUM}-p${RELPATCHNUM}." 148148ffe56aSColin Percival return 148248ffe56aSColin Percival fi 148348ffe56aSColin Percival 148448ffe56aSColin Percival # Divide files into (a) removed files, (b) added files, and 148548ffe56aSColin Percival # (c) updated files. 148648ffe56aSColin Percival cut -f 1 -d '|' < INDEX-PRESENT | 148748ffe56aSColin Percival sort > INDEX-PRESENT.flist 148848ffe56aSColin Percival cut -f 1 -d '|' < INDEX-NEW | 148948ffe56aSColin Percival sort > INDEX-NEW.flist 149048ffe56aSColin Percival comm -23 INDEX-PRESENT.flist INDEX-NEW.flist > files.removed 149148ffe56aSColin Percival comm -13 INDEX-PRESENT.flist INDEX-NEW.flist > files.added 149248ffe56aSColin Percival comm -12 INDEX-PRESENT.flist INDEX-NEW.flist > files.updated 149348ffe56aSColin Percival rm INDEX-PRESENT.flist INDEX-NEW.flist 149448ffe56aSColin Percival 149548ffe56aSColin Percival # Report removed files, if any 149648ffe56aSColin Percival if [ -s files.removed ]; then 149748ffe56aSColin Percival echo 149848ffe56aSColin Percival echo -n "The following files will be removed " 149948ffe56aSColin Percival echo "as part of updating to ${RELNUM}-p${RELPATCHNUM}:" 150048ffe56aSColin Percival cat files.removed 150148ffe56aSColin Percival fi 150248ffe56aSColin Percival rm files.removed 150348ffe56aSColin Percival 150448ffe56aSColin Percival # Report added files, if any 150548ffe56aSColin Percival if [ -s files.added ]; then 150648ffe56aSColin Percival echo 150748ffe56aSColin Percival echo -n "The following files will be added " 150848ffe56aSColin Percival echo "as part of updating to ${RELNUM}-p${RELPATCHNUM}:" 150948ffe56aSColin Percival cat files.added 151048ffe56aSColin Percival fi 151148ffe56aSColin Percival rm files.added 151248ffe56aSColin Percival 151348ffe56aSColin Percival # Report updated files, if any 151448ffe56aSColin Percival if [ -s files.updated ]; then 151548ffe56aSColin Percival echo 151648ffe56aSColin Percival echo -n "The following files will be updated " 151748ffe56aSColin Percival echo "as part of updating to ${RELNUM}-p${RELPATCHNUM}:" 151848ffe56aSColin Percival 151948ffe56aSColin Percival cat files.updated 152048ffe56aSColin Percival fi 152148ffe56aSColin Percival rm files.updated 152248ffe56aSColin Percival 152348ffe56aSColin Percival # Create a directory for the install manifest. 152448ffe56aSColin Percival MDIR=`mktemp -d install.XXXXXX` || return 1 152548ffe56aSColin Percival 152648ffe56aSColin Percival # Populate it 152748ffe56aSColin Percival mv INDEX-PRESENT ${MDIR}/INDEX-OLD 152848ffe56aSColin Percival mv INDEX-NEW ${MDIR}/INDEX-NEW 152948ffe56aSColin Percival 153048ffe56aSColin Percival # Link it into place 153148ffe56aSColin Percival ln -s ${MDIR} ${BDHASH}-install 153248ffe56aSColin Percival} 153348ffe56aSColin Percival 153448ffe56aSColin Percival# Warn about any upcoming EoL 153548ffe56aSColin Percivalfetch_warn_eol () { 153648ffe56aSColin Percival # What's the current time? 153748ffe56aSColin Percival NOWTIME=`date "+%s"` 153848ffe56aSColin Percival 153948ffe56aSColin Percival # When did we last warn about the EoL date? 154048ffe56aSColin Percival if [ -f lasteolwarn ]; then 154148ffe56aSColin Percival LASTWARN=`cat lasteolwarn` 154248ffe56aSColin Percival else 154348ffe56aSColin Percival LASTWARN=`expr ${NOWTIME} - 63072000` 154448ffe56aSColin Percival fi 154548ffe56aSColin Percival 154648ffe56aSColin Percival # If the EoL time is past, warn. 154748ffe56aSColin Percival if [ ${EOLTIME} -lt ${NOWTIME} ]; then 154848ffe56aSColin Percival echo 154948ffe56aSColin Percival cat <<-EOF 1550b698a3abSColin Percival WARNING: `uname -sr` HAS PASSED ITS END-OF-LIFE DATE. 155148ffe56aSColin Percival Any security issues discovered after `date -r ${EOLTIME}` 155248ffe56aSColin Percival will not have been corrected. 155348ffe56aSColin Percival EOF 155448ffe56aSColin Percival return 1 155548ffe56aSColin Percival fi 155648ffe56aSColin Percival 155748ffe56aSColin Percival # Figure out how long it has been since we last warned about the 155848ffe56aSColin Percival # upcoming EoL, and how much longer we have left. 155948ffe56aSColin Percival SINCEWARN=`expr ${NOWTIME} - ${LASTWARN}` 156048ffe56aSColin Percival TIMELEFT=`expr ${EOLTIME} - ${NOWTIME}` 156148ffe56aSColin Percival 156248ffe56aSColin Percival # Don't warn if the EoL is more than 6 months away 156348ffe56aSColin Percival if [ ${TIMELEFT} -gt 15768000 ]; then 156448ffe56aSColin Percival return 0 156548ffe56aSColin Percival fi 156648ffe56aSColin Percival 156748ffe56aSColin Percival # Don't warn if the time remaining is more than 3 times the time 156848ffe56aSColin Percival # since the last warning. 156948ffe56aSColin Percival if [ ${TIMELEFT} -gt `expr ${SINCEWARN} \* 3` ]; then 157048ffe56aSColin Percival return 0 157148ffe56aSColin Percival fi 157248ffe56aSColin Percival 157348ffe56aSColin Percival # Figure out what time units to use. 157448ffe56aSColin Percival if [ ${TIMELEFT} -lt 604800 ]; then 157548ffe56aSColin Percival UNIT="day" 157648ffe56aSColin Percival SIZE=86400 157748ffe56aSColin Percival elif [ ${TIMELEFT} -lt 2678400 ]; then 157848ffe56aSColin Percival UNIT="week" 157948ffe56aSColin Percival SIZE=604800 158048ffe56aSColin Percival else 158148ffe56aSColin Percival UNIT="month" 158248ffe56aSColin Percival SIZE=2678400 158348ffe56aSColin Percival fi 158448ffe56aSColin Percival 158548ffe56aSColin Percival # Compute the right number of units 158648ffe56aSColin Percival NUM=`expr ${TIMELEFT} / ${SIZE}` 158748ffe56aSColin Percival if [ ${NUM} != 1 ]; then 158848ffe56aSColin Percival UNIT="${UNIT}s" 158948ffe56aSColin Percival fi 159048ffe56aSColin Percival 159148ffe56aSColin Percival # Print the warning 159248ffe56aSColin Percival echo 159348ffe56aSColin Percival cat <<-EOF 159448ffe56aSColin Percival WARNING: `uname -sr` is approaching its End-of-Life date. 159548ffe56aSColin Percival It is strongly recommended that you upgrade to a newer 159648ffe56aSColin Percival release within the next ${NUM} ${UNIT}. 159748ffe56aSColin Percival EOF 159848ffe56aSColin Percival 159948ffe56aSColin Percival # Update the stored time of last warning 160048ffe56aSColin Percival echo ${NOWTIME} > lasteolwarn 160148ffe56aSColin Percival} 160248ffe56aSColin Percival 160348ffe56aSColin Percival# Do the actual work involved in "fetch" / "cron". 160448ffe56aSColin Percivalfetch_run () { 160548ffe56aSColin Percival workdir_init || return 1 160648ffe56aSColin Percival 160748ffe56aSColin Percival # Prepare the mirror list. 160848ffe56aSColin Percival fetch_pick_server_init && fetch_pick_server 160948ffe56aSColin Percival 161048ffe56aSColin Percival # Try to fetch the public key until we run out of servers. 161148ffe56aSColin Percival while ! fetch_key; do 161248ffe56aSColin Percival fetch_pick_server || return 1 161348ffe56aSColin Percival done 161448ffe56aSColin Percival 161548ffe56aSColin Percival # Try to fetch the metadata index signature ("tag") until we run 161648ffe56aSColin Percival # out of available servers; and sanity check the downloaded tag. 161748ffe56aSColin Percival while ! fetch_tag; do 161848ffe56aSColin Percival fetch_pick_server || return 1 161948ffe56aSColin Percival done 162048ffe56aSColin Percival fetch_tagsanity || return 1 162148ffe56aSColin Percival 162248ffe56aSColin Percival # Fetch the latest INDEX-NEW and INDEX-OLD files. 162348ffe56aSColin Percival fetch_metadata INDEX-NEW INDEX-OLD || return 1 162448ffe56aSColin Percival 162548ffe56aSColin Percival # Generate filtered INDEX-NEW and INDEX-OLD files containing only 162648ffe56aSColin Percival # the lines which (a) belong to components we care about, and (b) 162748ffe56aSColin Percival # don't correspond to paths we're explicitly ignoring. 162848ffe56aSColin Percival fetch_filter_metadata INDEX-NEW || return 1 162948ffe56aSColin Percival fetch_filter_metadata INDEX-OLD || return 1 163048ffe56aSColin Percival 163148ffe56aSColin Percival # Translate /boot/`uname -i` into ${KERNELDIR} 163248ffe56aSColin Percival fetch_filter_kernel_names INDEX-NEW 163348ffe56aSColin Percival fetch_filter_kernel_names INDEX-OLD 163448ffe56aSColin Percival 163548ffe56aSColin Percival # For all paths appearing in INDEX-OLD or INDEX-NEW, inspect the 163648ffe56aSColin Percival # system and generate an INDEX-PRESENT file. 163748ffe56aSColin Percival fetch_inspect_system INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1 163848ffe56aSColin Percival 163948ffe56aSColin Percival # Based on ${UPDATEIFUNMODIFIED}, remove lines from INDEX-* which 164048ffe56aSColin Percival # correspond to lines in INDEX-PRESENT with hashes not appearing 164148ffe56aSColin Percival # in INDEX-OLD or INDEX-NEW. Also remove lines where the entry in 164248ffe56aSColin Percival # INDEX-PRESENT has type - and there isn't a corresponding entry in 164348ffe56aSColin Percival # INDEX-OLD with type -. 164448ffe56aSColin Percival fetch_filter_unmodified_notpresent INDEX-OLD INDEX-PRESENT INDEX-NEW 164548ffe56aSColin Percival 164648ffe56aSColin Percival # For each entry in INDEX-PRESENT of type -, remove any corresponding 164748ffe56aSColin Percival # entry from INDEX-NEW if ${ALLOWADD} != "yes". Remove all entries 164848ffe56aSColin Percival # of type - from INDEX-PRESENT. 164948ffe56aSColin Percival fetch_filter_allowadd INDEX-PRESENT INDEX-NEW 165048ffe56aSColin Percival 165148ffe56aSColin Percival # If ${ALLOWDELETE} != "yes", then remove any entries from 165248ffe56aSColin Percival # INDEX-PRESENT which don't correspond to entries in INDEX-NEW. 165348ffe56aSColin Percival fetch_filter_allowdelete INDEX-PRESENT INDEX-NEW 165448ffe56aSColin Percival 165548ffe56aSColin Percival # If ${KEEPMODIFIEDMETADATA} == "yes", then for each entry in 165648ffe56aSColin Percival # INDEX-PRESENT with metadata not matching any entry in INDEX-OLD, 165748ffe56aSColin Percival # replace the corresponding line of INDEX-NEW with one having the 165848ffe56aSColin Percival # same metadata as the entry in INDEX-PRESENT. 165948ffe56aSColin Percival fetch_filter_modified_metadata INDEX-OLD INDEX-PRESENT INDEX-NEW 166048ffe56aSColin Percival 166148ffe56aSColin Percival # Remove lines from INDEX-PRESENT and INDEX-NEW which are identical; 166248ffe56aSColin Percival # no need to update a file if it isn't changing. 166348ffe56aSColin Percival fetch_filter_uptodate INDEX-PRESENT INDEX-NEW 166448ffe56aSColin Percival 166548ffe56aSColin Percival # Prepare to fetch files: Generate a list of the files we need, 166648ffe56aSColin Percival # copy the unmodified files we have into /files/, and generate 166748ffe56aSColin Percival # a list of patches to download. 166848ffe56aSColin Percival fetch_files_prepare INDEX-OLD INDEX-PRESENT INDEX-NEW 166948ffe56aSColin Percival 167048ffe56aSColin Percival # Fetch files. 167148ffe56aSColin Percival fetch_files || return 1 167248ffe56aSColin Percival 167348ffe56aSColin Percival # Create and populate install manifest directory; and report what 167448ffe56aSColin Percival # updates are available. 167548ffe56aSColin Percival fetch_create_manifest || return 1 167648ffe56aSColin Percival 167748ffe56aSColin Percival # Warn about any upcoming EoL 167848ffe56aSColin Percival fetch_warn_eol || return 1 167948ffe56aSColin Percival} 168048ffe56aSColin Percival 168148ffe56aSColin Percival# Make sure that all the file hashes mentioned in $@ have corresponding 168248ffe56aSColin Percival# gzipped files stored in /files/. 168348ffe56aSColin Percivalinstall_verify () { 168448ffe56aSColin Percival # Generate a list of hashes 168548ffe56aSColin Percival cat $@ | 168648ffe56aSColin Percival cut -f 2,7 -d '|' | 168748ffe56aSColin Percival grep -E '^f' | 168848ffe56aSColin Percival cut -f 2 -d '|' | 168948ffe56aSColin Percival sort -u > filelist 169048ffe56aSColin Percival 169148ffe56aSColin Percival # Make sure all the hashes exist 169248ffe56aSColin Percival while read HASH; do 169348ffe56aSColin Percival if ! [ -f files/${HASH}.gz ]; then 169448ffe56aSColin Percival echo -n "Update files missing -- " 169548ffe56aSColin Percival echo "this should never happen." 169648ffe56aSColin Percival echo "Re-run '$0 fetch'." 169748ffe56aSColin Percival return 1 169848ffe56aSColin Percival fi 169948ffe56aSColin Percival done < filelist 170048ffe56aSColin Percival 170148ffe56aSColin Percival # Clean up 170248ffe56aSColin Percival rm filelist 170348ffe56aSColin Percival} 170448ffe56aSColin Percival 170548ffe56aSColin Percival# Remove the system immutable flag from files 170648ffe56aSColin Percivalinstall_unschg () { 170748ffe56aSColin Percival # Generate file list 170848ffe56aSColin Percival cat $@ | 170948ffe56aSColin Percival cut -f 1 -d '|' > filelist 171048ffe56aSColin Percival 171148ffe56aSColin Percival # Remove flags 171248ffe56aSColin Percival while read F; do 171348ffe56aSColin Percival if ! [ -e ${F} ]; then 171448ffe56aSColin Percival continue 171548ffe56aSColin Percival fi 171648ffe56aSColin Percival 171748ffe56aSColin Percival chflags noschg ${F} || return 1 171848ffe56aSColin Percival done < filelist 171948ffe56aSColin Percival 172048ffe56aSColin Percival # Clean up 172148ffe56aSColin Percival rm filelist 172248ffe56aSColin Percival} 172348ffe56aSColin Percival 172448ffe56aSColin Percival# Install new files 172548ffe56aSColin Percivalinstall_from_index () { 172648ffe56aSColin Percival # First pass: Do everything apart from setting file flags. We 172748ffe56aSColin Percival # can't set flags yet, because schg inhibits hard linking. 172848ffe56aSColin Percival sort -k 1,1 -t '|' $1 | 172948ffe56aSColin Percival tr '|' ' ' | 173048ffe56aSColin Percival while read FPATH TYPE OWNER GROUP PERM FLAGS HASH LINK; do 173148ffe56aSColin Percival case ${TYPE} in 173248ffe56aSColin Percival d) 173348ffe56aSColin Percival # Create a directory 173448ffe56aSColin Percival install -d -o ${OWNER} -g ${GROUP} \ 173548ffe56aSColin Percival -m ${PERM} ${BASEDIR}/${FPATH} 173648ffe56aSColin Percival ;; 173748ffe56aSColin Percival f) 173848ffe56aSColin Percival if [ -z "${LINK}" ]; then 173948ffe56aSColin Percival # Create a file, without setting flags. 174048ffe56aSColin Percival gunzip < files/${HASH}.gz > ${HASH} 174148ffe56aSColin Percival install -S -o ${OWNER} -g ${GROUP} \ 174248ffe56aSColin Percival -m ${PERM} ${HASH} ${BASEDIR}/${FPATH} 174348ffe56aSColin Percival rm ${HASH} 174448ffe56aSColin Percival else 174548ffe56aSColin Percival # Create a hard link. 174648ffe56aSColin Percival ln -f ${LINK} ${BASEDIR}/${FPATH} 174748ffe56aSColin Percival fi 174848ffe56aSColin Percival ;; 174948ffe56aSColin Percival L) 175048ffe56aSColin Percival # Create a symlink 175148ffe56aSColin Percival ln -sfh ${HASH} ${BASEDIR}/${FPATH} 175248ffe56aSColin Percival ;; 175348ffe56aSColin Percival esac 175448ffe56aSColin Percival done 175548ffe56aSColin Percival 175648ffe56aSColin Percival # Perform a second pass, adding file flags. 175748ffe56aSColin Percival tr '|' ' ' < $1 | 175848ffe56aSColin Percival while read FPATH TYPE OWNER GROUP PERM FLAGS HASH LINK; do 175948ffe56aSColin Percival if [ ${TYPE} = "f" ] && 176048ffe56aSColin Percival ! [ ${FLAGS} = "0" ]; then 176148ffe56aSColin Percival chflags ${FLAGS} ${BASEDIR}/${FPATH} 176248ffe56aSColin Percival fi 176348ffe56aSColin Percival done 176448ffe56aSColin Percival} 176548ffe56aSColin Percival 176648ffe56aSColin Percival# Remove files which we want to delete 176748ffe56aSColin Percivalinstall_delete () { 176848ffe56aSColin Percival # Generate list of new files 176948ffe56aSColin Percival cut -f 1 -d '|' < $2 | 177048ffe56aSColin Percival sort > newfiles 177148ffe56aSColin Percival 177248ffe56aSColin Percival # Generate subindex of old files we want to nuke 177348ffe56aSColin Percival sort -k 1,1 -t '|' $1 | 177448ffe56aSColin Percival join -t '|' -v 1 - newfiles | 1775bce02f98SColin Percival sort -r -k 1,1 -t '|' | 177648ffe56aSColin Percival cut -f 1,2 -d '|' | 177748ffe56aSColin Percival tr '|' ' ' > killfiles 177848ffe56aSColin Percival 177948ffe56aSColin Percival # Remove the offending bits 178048ffe56aSColin Percival while read FPATH TYPE; do 178148ffe56aSColin Percival case ${TYPE} in 178248ffe56aSColin Percival d) 178348ffe56aSColin Percival rmdir ${BASEDIR}/${FPATH} 178448ffe56aSColin Percival ;; 178548ffe56aSColin Percival f) 178648ffe56aSColin Percival rm ${BASEDIR}/${FPATH} 178748ffe56aSColin Percival ;; 178848ffe56aSColin Percival L) 178948ffe56aSColin Percival rm ${BASEDIR}/${FPATH} 179048ffe56aSColin Percival ;; 179148ffe56aSColin Percival esac 179248ffe56aSColin Percival done < killfiles 179348ffe56aSColin Percival 179448ffe56aSColin Percival # Clean up 179548ffe56aSColin Percival rm newfiles killfiles 179648ffe56aSColin Percival} 179748ffe56aSColin Percival 179848ffe56aSColin Percival# Update linker.hints if anything in /boot/ was touched 179948ffe56aSColin Percivalinstall_kldxref () { 180048ffe56aSColin Percival if cat $@ | 180148ffe56aSColin Percival grep -qE '^/boot/'; then 180248ffe56aSColin Percival kldxref -R /boot/ 180348ffe56aSColin Percival fi 180448ffe56aSColin Percival} 180548ffe56aSColin Percival 180648ffe56aSColin Percival# Rearrange bits to allow the installed updates to be rolled back 180748ffe56aSColin Percivalinstall_setup_rollback () { 180848ffe56aSColin Percival if [ -L ${BDHASH}-rollback ]; then 180948ffe56aSColin Percival mv ${BDHASH}-rollback ${BDHASH}-install/rollback 181048ffe56aSColin Percival fi 181148ffe56aSColin Percival 181248ffe56aSColin Percival mv ${BDHASH}-install ${BDHASH}-rollback 181348ffe56aSColin Percival} 181448ffe56aSColin Percival 181548ffe56aSColin Percival# Actually install updates 181648ffe56aSColin Percivalinstall_run () { 181748ffe56aSColin Percival echo -n "Installing updates..." 181848ffe56aSColin Percival 181948ffe56aSColin Percival # Make sure we have all the files we should have 182048ffe56aSColin Percival install_verify ${BDHASH}-install/INDEX-OLD \ 182148ffe56aSColin Percival ${BDHASH}-install/INDEX-NEW || return 1 182248ffe56aSColin Percival 182348ffe56aSColin Percival # Remove system immutable flag from files 182448ffe56aSColin Percival install_unschg ${BDHASH}-install/INDEX-OLD \ 182548ffe56aSColin Percival ${BDHASH}-install/INDEX-NEW || return 1 182648ffe56aSColin Percival 182748ffe56aSColin Percival # Install new files 182848ffe56aSColin Percival install_from_index \ 182948ffe56aSColin Percival ${BDHASH}-install/INDEX-NEW || return 1 183048ffe56aSColin Percival 183148ffe56aSColin Percival # Remove files which we want to delete 183248ffe56aSColin Percival install_delete ${BDHASH}-install/INDEX-OLD \ 183348ffe56aSColin Percival ${BDHASH}-install/INDEX-NEW || return 1 183448ffe56aSColin Percival 183548ffe56aSColin Percival # Update linker.hints if anything in /boot/ was touched 183648ffe56aSColin Percival install_kldxref ${BDHASH}-install/INDEX-OLD \ 183748ffe56aSColin Percival ${BDHASH}-install/INDEX-NEW 183848ffe56aSColin Percival 183948ffe56aSColin Percival # Rearrange bits to allow the installed updates to be rolled back 184048ffe56aSColin Percival install_setup_rollback 184148ffe56aSColin Percival 184248ffe56aSColin Percival echo " done." 184348ffe56aSColin Percival} 184448ffe56aSColin Percival 184548ffe56aSColin Percival# Rearrange bits to allow the previous set of updates to be rolled back next. 184648ffe56aSColin Percivalrollback_setup_rollback () { 184748ffe56aSColin Percival if [ -L ${BDHASH}-rollback/rollback ]; then 184848ffe56aSColin Percival mv ${BDHASH}-rollback/rollback rollback-tmp 184948ffe56aSColin Percival rm -r ${BDHASH}-rollback/ 185048ffe56aSColin Percival rm ${BDHASH}-rollback 185148ffe56aSColin Percival mv rollback-tmp ${BDHASH}-rollback 185248ffe56aSColin Percival else 185348ffe56aSColin Percival rm -r ${BDHASH}-rollback/ 185448ffe56aSColin Percival rm ${BDHASH}-rollback 185548ffe56aSColin Percival fi 185648ffe56aSColin Percival} 185748ffe56aSColin Percival 185848ffe56aSColin Percival# Actually rollback updates 185948ffe56aSColin Percivalrollback_run () { 186048ffe56aSColin Percival echo -n "Uninstalling updates..." 186148ffe56aSColin Percival 186248ffe56aSColin Percival # If there are updates waiting to be installed, remove them; we 186348ffe56aSColin Percival # want the user to re-run 'fetch' after rolling back updates. 186448ffe56aSColin Percival if [ -L ${BDHASH}-install ]; then 186548ffe56aSColin Percival rm -r ${BDHASH}-install/ 186648ffe56aSColin Percival rm ${BDHASH}-install 186748ffe56aSColin Percival fi 186848ffe56aSColin Percival 186948ffe56aSColin Percival # Make sure we have all the files we should have 187048ffe56aSColin Percival install_verify ${BDHASH}-rollback/INDEX-NEW \ 187148ffe56aSColin Percival ${BDHASH}-rollback/INDEX-OLD || return 1 187248ffe56aSColin Percival 187348ffe56aSColin Percival # Remove system immutable flag from files 187448ffe56aSColin Percival install_unschg ${BDHASH}-rollback/INDEX-NEW \ 187548ffe56aSColin Percival ${BDHASH}-rollback/INDEX-OLD || return 1 187648ffe56aSColin Percival 187748ffe56aSColin Percival # Install new files 187848ffe56aSColin Percival install_from_index \ 187948ffe56aSColin Percival ${BDHASH}-rollback/INDEX-OLD || return 1 188048ffe56aSColin Percival 188148ffe56aSColin Percival # Remove files which we want to delete 188248ffe56aSColin Percival install_delete ${BDHASH}-rollback/INDEX-NEW \ 188348ffe56aSColin Percival ${BDHASH}-rollback/INDEX-OLD || return 1 188448ffe56aSColin Percival 188548ffe56aSColin Percival # Update linker.hints if anything in /boot/ was touched 188648ffe56aSColin Percival install_kldxref ${BDHASH}-rollback/INDEX-NEW \ 188748ffe56aSColin Percival ${BDHASH}-rollback/INDEX-OLD 188848ffe56aSColin Percival 188948ffe56aSColin Percival # Remove the rollback directory and the symlink pointing to it; and 189048ffe56aSColin Percival # rearrange bits to allow the previous set of updates to be rolled 189148ffe56aSColin Percival # back next. 189248ffe56aSColin Percival rollback_setup_rollback 189348ffe56aSColin Percival 189448ffe56aSColin Percival echo " done." 189548ffe56aSColin Percival} 189648ffe56aSColin Percival 189748ffe56aSColin Percival#### Main functions -- call parameter-handling and core functions 189848ffe56aSColin Percival 189948ffe56aSColin Percival# Using the command line, configuration file, and defaults, 190048ffe56aSColin Percival# set all the parameters which are needed later. 190148ffe56aSColin Percivalget_params () { 190248ffe56aSColin Percival init_params 190348ffe56aSColin Percival parse_cmdline $@ 190448ffe56aSColin Percival parse_conffile 190548ffe56aSColin Percival default_params 190648ffe56aSColin Percival} 190748ffe56aSColin Percival 190848ffe56aSColin Percival# Fetch command. Make sure that we're being called 190948ffe56aSColin Percival# interactively, then run fetch_check_params and fetch_run 191048ffe56aSColin Percivalcmd_fetch () { 191148ffe56aSColin Percival if [ ! -t 0 ]; then 191248ffe56aSColin Percival echo -n "`basename $0` fetch should not " 191348ffe56aSColin Percival echo "be run non-interactively." 191448ffe56aSColin Percival echo "Run `basename $0` cron instead." 191548ffe56aSColin Percival exit 1 191648ffe56aSColin Percival fi 191748ffe56aSColin Percival fetch_check_params 191848ffe56aSColin Percival fetch_run || exit 1 191948ffe56aSColin Percival} 192048ffe56aSColin Percival 192148ffe56aSColin Percival# Cron command. Make sure the parameters are sensible; wait 192248ffe56aSColin Percival# rand(3600) seconds; then fetch updates. While fetching updates, 192348ffe56aSColin Percival# send output to a temporary file; only print that file if the 192448ffe56aSColin Percival# fetching failed. 192548ffe56aSColin Percivalcmd_cron () { 192648ffe56aSColin Percival fetch_check_params 192748ffe56aSColin Percival sleep `jot -r 1 0 3600` 192848ffe56aSColin Percival 192948ffe56aSColin Percival TMPFILE=`mktemp /tmp/freebsd-update.XXXXXX` || exit 1 193048ffe56aSColin Percival if ! fetch_run >> ${TMPFILE} || 193148ffe56aSColin Percival ! grep -q "No updates needed" ${TMPFILE} || 193248ffe56aSColin Percival [ ${VERBOSELEVEL} = "debug" ]; then 193348ffe56aSColin Percival mail -s "`hostname` security updates" ${MAILTO} < ${TMPFILE} 193448ffe56aSColin Percival fi 193548ffe56aSColin Percival 193648ffe56aSColin Percival rm ${TMPFILE} 193748ffe56aSColin Percival} 193848ffe56aSColin Percival 193948ffe56aSColin Percival# Install downloaded updates. 194048ffe56aSColin Percivalcmd_install () { 194148ffe56aSColin Percival install_check_params 194248ffe56aSColin Percival install_run || exit 1 194348ffe56aSColin Percival} 194448ffe56aSColin Percival 194548ffe56aSColin Percival# Rollback most recently installed updates. 194648ffe56aSColin Percivalcmd_rollback () { 194748ffe56aSColin Percival rollback_check_params 194848ffe56aSColin Percival rollback_run || exit 1 194948ffe56aSColin Percival} 195048ffe56aSColin Percival 195148ffe56aSColin Percival#### Entry point 195248ffe56aSColin Percival 195348ffe56aSColin Percival# Make sure we find utilities from the base system 195448ffe56aSColin Percivalexport PATH=/sbin:/bin:/usr/sbin:/usr/bin:${PATH} 195548ffe56aSColin Percival 1956f2890dbdSColin Percival# Set LC_ALL in order to avoid problems with character ranges like [A-Z]. 1957f2890dbdSColin Percivalexport LC_ALL=C 1958f2890dbdSColin Percival 195948ffe56aSColin Percivalget_params $@ 196048ffe56aSColin Percivalfor COMMAND in ${COMMANDS}; do 196148ffe56aSColin Percival cmd_${COMMAND} 196248ffe56aSColin Percivaldone 1963