1161748Scperciva#!/bin/sh 2161748Scperciva 3161748Scperciva#- 4173441Scperciva# Copyright 2004-2007 Colin Percival 5161748Scperciva# All rights reserved 6161748Scperciva# 7161748Scperciva# Redistribution and use in source and binary forms, with or without 8161748Scperciva# modification, are permitted providing that the following conditions 9161748Scperciva# are met: 10161748Scperciva# 1. Redistributions of source code must retain the above copyright 11161748Scperciva# notice, this list of conditions and the following disclaimer. 12161748Scperciva# 2. Redistributions in binary form must reproduce the above copyright 13161748Scperciva# notice, this list of conditions and the following disclaimer in the 14161748Scperciva# documentation and/or other materials provided with the distribution. 15161748Scperciva# 16161748Scperciva# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17161748Scperciva# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18161748Scperciva# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19161748Scperciva# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20161748Scperciva# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21161748Scperciva# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22161748Scperciva# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23161748Scperciva# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24161748Scperciva# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25161748Scperciva# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26161748Scperciva# POSSIBILITY OF SUCH DAMAGE. 27161748Scperciva 28161748Scperciva# $FreeBSD: releng/10.2/usr.sbin/freebsd-update/freebsd-update.sh 303304 2016-07-25 15:04:17Z delphij $ 29161748Scperciva 30161748Scperciva#### Usage function -- called from command-line handling code. 31161748Scperciva 32161748Scperciva# Usage instructions. Options not listed: 33161748Scperciva# --debug -- don't filter output from utilities 34161748Scperciva# --no-stats -- don't show progress statistics while fetching files 35161748Scpercivausage () { 36161748Scperciva cat <<EOF 37161748Scpercivausage: `basename $0` [options] command ... [path] 38161748Scperciva 39161748ScpercivaOptions: 40161748Scperciva -b basedir -- Operate on a system mounted at basedir 41161748Scperciva (default: /) 42161748Scperciva -d workdir -- Store working files in workdir 43161748Scperciva (default: /var/db/freebsd-update/) 44161748Scperciva -f conffile -- Read configuration options from conffile 45161748Scperciva (default: /etc/freebsd-update.conf) 46282870Sdelphij -F -- Force a fetch operation to proceed 47161748Scperciva -k KEY -- Trust an RSA key with SHA256 hash of KEY 48173564Scperciva -r release -- Target for upgrade (e.g., 6.2-RELEASE) 49161748Scperciva -s server -- Server from which to fetch updates 50161748Scperciva (default: update.FreeBSD.org) 51161748Scperciva -t address -- Mail output of cron command, if any, to address 52161748Scperciva (default: root) 53282870Sdelphij --not-running-from-cron 54282870Sdelphij -- Run without a tty, for use by automated tools 55161748ScpercivaCommands: 56161748Scperciva fetch -- Fetch updates from server 57161748Scperciva cron -- Sleep rand(3600) seconds, fetch updates, and send an 58161748Scperciva email if updates were found 59173564Scperciva upgrade -- Fetch upgrades to FreeBSD version specified via -r option 60173564Scperciva install -- Install downloaded updates or upgrades 61161748Scperciva rollback -- Uninstall most recently installed updates 62181142Scperciva IDS -- Compare the system against an index of "known good" files. 63161748ScpercivaEOF 64161748Scperciva exit 0 65161748Scperciva} 66161748Scperciva 67161748Scperciva#### Configuration processing functions 68161748Scperciva 69161748Scperciva#- 70161748Scperciva# Configuration options are set in the following order of priority: 71161748Scperciva# 1. Command line options 72161748Scperciva# 2. Configuration file options 73161748Scperciva# 3. Default options 74161748Scperciva# In addition, certain options (e.g., IgnorePaths) can be specified multiple 75161748Scperciva# times and (as long as these are all in the same place, e.g., inside the 76161748Scperciva# configuration file) they will accumulate. Finally, because the path to the 77161748Scperciva# configuration file can be specified at the command line, the entire command 78161748Scperciva# line must be processed before we start reading the configuration file. 79161748Scperciva# 80161748Scperciva# Sound like a mess? It is. Here's how we handle this: 81161748Scperciva# 1. Initialize CONFFILE and all the options to "". 82161748Scperciva# 2. Process the command line. Throw an error if a non-accumulating option 83161748Scperciva# is specified twice. 84161748Scperciva# 3. If CONFFILE is "", set CONFFILE to /etc/freebsd-update.conf . 85161748Scperciva# 4. For all the configuration options X, set X_saved to X. 86161748Scperciva# 5. Initialize all the options to "". 87161748Scperciva# 6. Read CONFFILE line by line, parsing options. 88161748Scperciva# 7. For each configuration option X, set X to X_saved iff X_saved is not "". 89161748Scperciva# 8. Repeat steps 4-7, except setting options to their default values at (6). 90161748Scperciva 91161748ScpercivaCONFIGOPTIONS="KEYPRINT WORKDIR SERVERNAME MAILTO ALLOWADD ALLOWDELETE 92161748Scperciva KEEPMODIFIEDMETADATA COMPONENTS IGNOREPATHS UPDATEIFUNMODIFIED 93181142Scperciva BASEDIR VERBOSELEVEL TARGETRELEASE STRICTCOMPONENTS MERGECHANGES 94196392Ssimon IDSIGNOREPATHS BACKUPKERNEL BACKUPKERNELDIR BACKUPKERNELSYMBOLFILES" 95161748Scperciva 96161748Scperciva# Set all the configuration options to "". 97161748Scpercivanullconfig () { 98161748Scperciva for X in ${CONFIGOPTIONS}; do 99161748Scperciva eval ${X}="" 100161748Scperciva done 101161748Scperciva} 102161748Scperciva 103161748Scperciva# For each configuration option X, set X_saved to X. 104161748Scpercivasaveconfig () { 105161748Scperciva for X in ${CONFIGOPTIONS}; do 106161748Scperciva eval ${X}_saved=\$${X} 107161748Scperciva done 108161748Scperciva} 109161748Scperciva 110161748Scperciva# For each configuration option X, set X to X_saved if X_saved is not "". 111161748Scpercivamergeconfig () { 112161748Scperciva for X in ${CONFIGOPTIONS}; do 113161748Scperciva eval _=\$${X}_saved 114161748Scperciva if ! [ -z "${_}" ]; then 115161748Scperciva eval ${X}=\$${X}_saved 116161748Scperciva fi 117161748Scperciva done 118161748Scperciva} 119161748Scperciva 120161748Scperciva# Set the trusted keyprint. 121161748Scpercivaconfig_KeyPrint () { 122161748Scperciva if [ -z ${KEYPRINT} ]; then 123161748Scperciva KEYPRINT=$1 124161748Scperciva else 125161748Scperciva return 1 126161748Scperciva fi 127161748Scperciva} 128161748Scperciva 129161748Scperciva# Set the working directory. 130161748Scpercivaconfig_WorkDir () { 131161748Scperciva if [ -z ${WORKDIR} ]; then 132161748Scperciva WORKDIR=$1 133161748Scperciva else 134161748Scperciva return 1 135161748Scperciva fi 136161748Scperciva} 137161748Scperciva 138161748Scperciva# Set the name of the server (pool) from which to fetch updates 139161748Scpercivaconfig_ServerName () { 140161748Scperciva if [ -z ${SERVERNAME} ]; then 141161748Scperciva SERVERNAME=$1 142161748Scperciva else 143161748Scperciva return 1 144161748Scperciva fi 145161748Scperciva} 146161748Scperciva 147161748Scperciva# Set the address to which 'cron' output will be mailed. 148161748Scpercivaconfig_MailTo () { 149161748Scperciva if [ -z ${MAILTO} ]; then 150161748Scperciva MAILTO=$1 151161748Scperciva else 152161748Scperciva return 1 153161748Scperciva fi 154161748Scperciva} 155161748Scperciva 156161748Scperciva# Set whether FreeBSD Update is allowed to add files (or directories, or 157161748Scperciva# symlinks) which did not previously exist. 158161748Scpercivaconfig_AllowAdd () { 159161748Scperciva if [ -z ${ALLOWADD} ]; then 160161748Scperciva case $1 in 161161748Scperciva [Yy][Ee][Ss]) 162161748Scperciva ALLOWADD=yes 163161748Scperciva ;; 164161748Scperciva [Nn][Oo]) 165161748Scperciva ALLOWADD=no 166161748Scperciva ;; 167161748Scperciva *) 168161748Scperciva return 1 169161748Scperciva ;; 170161748Scperciva esac 171161748Scperciva else 172161748Scperciva return 1 173161748Scperciva fi 174161748Scperciva} 175161748Scperciva 176161748Scperciva# Set whether FreeBSD Update is allowed to remove files/directories/symlinks. 177161748Scpercivaconfig_AllowDelete () { 178161748Scperciva if [ -z ${ALLOWDELETE} ]; then 179161748Scperciva case $1 in 180161748Scperciva [Yy][Ee][Ss]) 181161748Scperciva ALLOWDELETE=yes 182161748Scperciva ;; 183161748Scperciva [Nn][Oo]) 184161748Scperciva ALLOWDELETE=no 185161748Scperciva ;; 186161748Scperciva *) 187161748Scperciva return 1 188161748Scperciva ;; 189161748Scperciva esac 190161748Scperciva else 191161748Scperciva return 1 192161748Scperciva fi 193161748Scperciva} 194161748Scperciva 195161748Scperciva# Set whether FreeBSD Update should keep existing inode ownership, 196161748Scperciva# permissions, and flags, in the event that they have been modified locally 197161748Scperciva# after the release. 198161748Scpercivaconfig_KeepModifiedMetadata () { 199161748Scperciva if [ -z ${KEEPMODIFIEDMETADATA} ]; then 200161748Scperciva case $1 in 201161748Scperciva [Yy][Ee][Ss]) 202161748Scperciva KEEPMODIFIEDMETADATA=yes 203161748Scperciva ;; 204161748Scperciva [Nn][Oo]) 205161748Scperciva KEEPMODIFIEDMETADATA=no 206161748Scperciva ;; 207161748Scperciva *) 208161748Scperciva return 1 209161748Scperciva ;; 210161748Scperciva esac 211161748Scperciva else 212161748Scperciva return 1 213161748Scperciva fi 214161748Scperciva} 215161748Scperciva 216161748Scperciva# Add to the list of components which should be kept updated. 217161748Scpercivaconfig_Components () { 218161748Scperciva for C in $@; do 219284936Sdelphij if [ "$C" = "src" ]; then 220284936Sdelphij if [ -e /usr/src/COPYRIGHT ]; then 221284936Sdelphij COMPONENTS="${COMPONENTS} ${C}" 222284936Sdelphij else 223284936Sdelphij echo "src component not installed, skipped" 224284936Sdelphij fi 225284936Sdelphij else 226284936Sdelphij COMPONENTS="${COMPONENTS} ${C}" 227284936Sdelphij fi 228161748Scperciva done 229161748Scperciva} 230161748Scperciva 231161748Scperciva# Add to the list of paths under which updates will be ignored. 232161748Scpercivaconfig_IgnorePaths () { 233161748Scperciva for C in $@; do 234161748Scperciva IGNOREPATHS="${IGNOREPATHS} ${C}" 235161748Scperciva done 236161748Scperciva} 237161748Scperciva 238181142Scperciva# Add to the list of paths which IDS should ignore. 239181142Scpercivaconfig_IDSIgnorePaths () { 240181142Scperciva for C in $@; do 241181142Scperciva IDSIGNOREPATHS="${IDSIGNOREPATHS} ${C}" 242181142Scperciva done 243181142Scperciva} 244181142Scperciva 245161748Scperciva# Add to the list of paths within which updates will be performed only if the 246161748Scperciva# file on disk has not been modified locally. 247161748Scpercivaconfig_UpdateIfUnmodified () { 248161748Scperciva for C in $@; do 249161748Scperciva UPDATEIFUNMODIFIED="${UPDATEIFUNMODIFIED} ${C}" 250161748Scperciva done 251161748Scperciva} 252161748Scperciva 253173564Scperciva# Add to the list of paths within which updates to text files will be merged 254173564Scperciva# instead of overwritten. 255173564Scpercivaconfig_MergeChanges () { 256173564Scperciva for C in $@; do 257173564Scperciva MERGECHANGES="${MERGECHANGES} ${C}" 258173564Scperciva done 259173564Scperciva} 260173564Scperciva 261161748Scperciva# Work on a FreeBSD installation mounted under $1 262161748Scpercivaconfig_BaseDir () { 263161748Scperciva if [ -z ${BASEDIR} ]; then 264161748Scperciva BASEDIR=$1 265161748Scperciva else 266161748Scperciva return 1 267161748Scperciva fi 268161748Scperciva} 269161748Scperciva 270173564Scperciva# When fetching upgrades, should we assume the user wants exactly the 271173564Scperciva# components listed in COMPONENTS, rather than trying to guess based on 272173564Scperciva# what's currently installed? 273173564Scpercivaconfig_StrictComponents () { 274173564Scperciva if [ -z ${STRICTCOMPONENTS} ]; then 275173564Scperciva case $1 in 276173564Scperciva [Yy][Ee][Ss]) 277173564Scperciva STRICTCOMPONENTS=yes 278173564Scperciva ;; 279173564Scperciva [Nn][Oo]) 280173564Scperciva STRICTCOMPONENTS=no 281173564Scperciva ;; 282173564Scperciva *) 283173564Scperciva return 1 284173564Scperciva ;; 285173564Scperciva esac 286173564Scperciva else 287173564Scperciva return 1 288173564Scperciva fi 289173564Scperciva} 290173564Scperciva 291173564Scperciva# Upgrade to FreeBSD $1 292173564Scpercivaconfig_TargetRelease () { 293173564Scperciva if [ -z ${TARGETRELEASE} ]; then 294173564Scperciva TARGETRELEASE=$1 295173564Scperciva else 296173564Scperciva return 1 297173564Scperciva fi 298197618Scperciva if echo ${TARGETRELEASE} | grep -qE '^[0-9.]+$'; then 299197618Scperciva TARGETRELEASE="${TARGETRELEASE}-RELEASE" 300197618Scperciva fi 301173564Scperciva} 302173564Scperciva 303161748Scperciva# Define what happens to output of utilities 304161748Scpercivaconfig_VerboseLevel () { 305161748Scperciva if [ -z ${VERBOSELEVEL} ]; then 306161748Scperciva case $1 in 307161748Scperciva [Dd][Ee][Bb][Uu][Gg]) 308161748Scperciva VERBOSELEVEL=debug 309161748Scperciva ;; 310161748Scperciva [Nn][Oo][Ss][Tt][Aa][Tt][Ss]) 311161748Scperciva VERBOSELEVEL=nostats 312161748Scperciva ;; 313161748Scperciva [Ss][Tt][Aa][Tt][Ss]) 314161748Scperciva VERBOSELEVEL=stats 315161748Scperciva ;; 316161748Scperciva *) 317161748Scperciva return 1 318161748Scperciva ;; 319161748Scperciva esac 320161748Scperciva else 321161748Scperciva return 1 322161748Scperciva fi 323161748Scperciva} 324161748Scperciva 325196392Ssimonconfig_BackupKernel () { 326196392Ssimon if [ -z ${BACKUPKERNEL} ]; then 327196392Ssimon case $1 in 328196392Ssimon [Yy][Ee][Ss]) 329196392Ssimon BACKUPKERNEL=yes 330196392Ssimon ;; 331196392Ssimon [Nn][Oo]) 332196392Ssimon BACKUPKERNEL=no 333196392Ssimon ;; 334196392Ssimon *) 335196392Ssimon return 1 336196392Ssimon ;; 337196392Ssimon esac 338196392Ssimon else 339196392Ssimon return 1 340196392Ssimon fi 341196392Ssimon} 342196392Ssimon 343196392Ssimonconfig_BackupKernelDir () { 344196392Ssimon if [ -z ${BACKUPKERNELDIR} ]; then 345196392Ssimon if [ -z "$1" ]; then 346196392Ssimon echo "BackupKernelDir set to empty dir" 347196392Ssimon return 1 348196392Ssimon fi 349196392Ssimon 350196392Ssimon # We check for some paths which would be extremely odd 351196392Ssimon # to use, but which could cause a lot of problems if 352196392Ssimon # used. 353196392Ssimon case $1 in 354196392Ssimon /|/bin|/boot|/etc|/lib|/libexec|/sbin|/usr|/var) 355196392Ssimon echo "BackupKernelDir set to invalid path $1" 356196392Ssimon return 1 357196392Ssimon ;; 358196392Ssimon /*) 359196392Ssimon BACKUPKERNELDIR=$1 360196392Ssimon ;; 361196392Ssimon *) 362196392Ssimon echo "BackupKernelDir ($1) is not an absolute path" 363196392Ssimon return 1 364196392Ssimon ;; 365196392Ssimon esac 366196392Ssimon else 367196392Ssimon return 1 368196392Ssimon fi 369196392Ssimon} 370196392Ssimon 371196392Ssimonconfig_BackupKernelSymbolFiles () { 372196392Ssimon if [ -z ${BACKUPKERNELSYMBOLFILES} ]; then 373196392Ssimon case $1 in 374196392Ssimon [Yy][Ee][Ss]) 375196392Ssimon BACKUPKERNELSYMBOLFILES=yes 376196392Ssimon ;; 377196392Ssimon [Nn][Oo]) 378196392Ssimon BACKUPKERNELSYMBOLFILES=no 379196392Ssimon ;; 380196392Ssimon *) 381196392Ssimon return 1 382196392Ssimon ;; 383196392Ssimon esac 384196392Ssimon else 385196392Ssimon return 1 386196392Ssimon fi 387196392Ssimon} 388196392Ssimon 389161748Scperciva# Handle one line of configuration 390161748Scpercivaconfigline () { 391161748Scperciva if [ $# -eq 0 ]; then 392161748Scperciva return 393161748Scperciva fi 394161748Scperciva 395161748Scperciva OPT=$1 396161748Scperciva shift 397161748Scperciva config_${OPT} $@ 398161748Scperciva} 399161748Scperciva 400161748Scperciva#### Parameter handling functions. 401161748Scperciva 402161748Scperciva# Initialize parameters to null, just in case they're 403161748Scperciva# set in the environment. 404161748Scpercivainit_params () { 405161748Scperciva # Configration settings 406161748Scperciva nullconfig 407161748Scperciva 408161748Scperciva # No configuration file set yet 409161748Scperciva CONFFILE="" 410161748Scperciva 411161748Scperciva # No commands specified yet 412161748Scperciva COMMANDS="" 413282870Sdelphij 414282870Sdelphij # Force fetch to proceed 415282870Sdelphij FORCEFETCH=0 416282870Sdelphij 417282870Sdelphij # Run without a TTY 418282870Sdelphij NOTTYOK=0 419161748Scperciva} 420161748Scperciva 421161748Scperciva# Parse the command line 422161748Scpercivaparse_cmdline () { 423161748Scperciva while [ $# -gt 0 ]; do 424161748Scperciva case "$1" in 425161748Scperciva # Location of configuration file 426161748Scperciva -f) 427161748Scperciva if [ $# -eq 1 ]; then usage; fi 428161748Scperciva if [ ! -z "${CONFFILE}" ]; then usage; fi 429161748Scperciva shift; CONFFILE="$1" 430161748Scperciva ;; 431282870Sdelphij -F) 432282870Sdelphij FORCEFETCH=1 433282870Sdelphij ;; 434282870Sdelphij --not-running-from-cron) 435282870Sdelphij NOTTYOK=1 436282870Sdelphij ;; 437161748Scperciva 438161748Scperciva # Configuration file equivalents 439161748Scperciva -b) 440161748Scperciva if [ $# -eq 1 ]; then usage; fi; shift 441161748Scperciva config_BaseDir $1 || usage 442161748Scperciva ;; 443161748Scperciva -d) 444161748Scperciva if [ $# -eq 1 ]; then usage; fi; shift 445161748Scperciva config_WorkDir $1 || usage 446161748Scperciva ;; 447161748Scperciva -k) 448161748Scperciva if [ $# -eq 1 ]; then usage; fi; shift 449161748Scperciva config_KeyPrint $1 || usage 450161748Scperciva ;; 451161748Scperciva -s) 452161748Scperciva if [ $# -eq 1 ]; then usage; fi; shift 453161748Scperciva config_ServerName $1 || usage 454161748Scperciva ;; 455173564Scperciva -r) 456173564Scperciva if [ $# -eq 1 ]; then usage; fi; shift 457173564Scperciva config_TargetRelease $1 || usage 458173564Scperciva ;; 459161748Scperciva -t) 460161748Scperciva if [ $# -eq 1 ]; then usage; fi; shift 461161748Scperciva config_MailTo $1 || usage 462161748Scperciva ;; 463161748Scperciva -v) 464161748Scperciva if [ $# -eq 1 ]; then usage; fi; shift 465161748Scperciva config_VerboseLevel $1 || usage 466161748Scperciva ;; 467161748Scperciva 468161748Scperciva # Aliases for "-v debug" and "-v nostats" 469161748Scperciva --debug) 470161748Scperciva config_VerboseLevel debug || usage 471161748Scperciva ;; 472161748Scperciva --no-stats) 473161748Scperciva config_VerboseLevel nostats || usage 474161748Scperciva ;; 475161748Scperciva 476161748Scperciva # Commands 477181142Scperciva cron | fetch | upgrade | install | rollback | IDS) 478161748Scperciva COMMANDS="${COMMANDS} $1" 479161748Scperciva ;; 480161748Scperciva 481161748Scperciva # Anything else is an error 482161748Scperciva *) 483161748Scperciva usage 484161748Scperciva ;; 485161748Scperciva esac 486161748Scperciva shift 487161748Scperciva done 488161748Scperciva 489161748Scperciva # Make sure we have at least one command 490161748Scperciva if [ -z "${COMMANDS}" ]; then 491161748Scperciva usage 492161748Scperciva fi 493161748Scperciva} 494161748Scperciva 495161748Scperciva# Parse the configuration file 496161748Scpercivaparse_conffile () { 497161748Scperciva # If a configuration file was specified on the command line, check 498161748Scperciva # that it exists and is readable. 499161748Scperciva if [ ! -z "${CONFFILE}" ] && [ ! -r "${CONFFILE}" ]; then 500161748Scperciva echo -n "File does not exist " 501161748Scperciva echo -n "or is not readable: " 502161748Scperciva echo ${CONFFILE} 503161748Scperciva exit 1 504161748Scperciva fi 505161748Scperciva 506161748Scperciva # If a configuration file was not specified on the command line, 507161748Scperciva # use the default configuration file path. If that default does 508161748Scperciva # not exist, give up looking for any configuration. 509161748Scperciva if [ -z "${CONFFILE}" ]; then 510161748Scperciva CONFFILE="/etc/freebsd-update.conf" 511161748Scperciva if [ ! -r "${CONFFILE}" ]; then 512161748Scperciva return 513161748Scperciva fi 514161748Scperciva fi 515161748Scperciva 516161748Scperciva # Save the configuration options specified on the command line, and 517161748Scperciva # clear all the options in preparation for reading the config file. 518161748Scperciva saveconfig 519161748Scperciva nullconfig 520161748Scperciva 521161748Scperciva # Read the configuration file. Anything after the first '#' is 522161748Scperciva # ignored, and any blank lines are ignored. 523161748Scperciva L=0 524161748Scperciva while read LINE; do 525161748Scperciva L=$(($L + 1)) 526161748Scperciva LINEX=`echo "${LINE}" | cut -f 1 -d '#'` 527161748Scperciva if ! configline ${LINEX}; then 528161748Scperciva echo "Error processing configuration file, line $L:" 529161748Scperciva echo "==> ${LINE}" 530161748Scperciva exit 1 531161748Scperciva fi 532161748Scperciva done < ${CONFFILE} 533161748Scperciva 534161748Scperciva # Merge the settings read from the configuration file with those 535161748Scperciva # provided at the command line. 536161748Scperciva mergeconfig 537161748Scperciva} 538161748Scperciva 539161748Scperciva# Provide some default parameters 540161748Scpercivadefault_params () { 541161748Scperciva # Save any parameters already configured, and clear the slate 542161748Scperciva saveconfig 543161748Scperciva nullconfig 544161748Scperciva 545161748Scperciva # Default configurations 546161748Scperciva config_WorkDir /var/db/freebsd-update 547161748Scperciva config_MailTo root 548161748Scperciva config_AllowAdd yes 549161748Scperciva config_AllowDelete yes 550161748Scperciva config_KeepModifiedMetadata yes 551161748Scperciva config_BaseDir / 552161748Scperciva config_VerboseLevel stats 553173564Scperciva config_StrictComponents no 554196392Ssimon config_BackupKernel yes 555196392Ssimon config_BackupKernelDir /boot/kernel.old 556196392Ssimon config_BackupKernelSymbolFiles no 557161748Scperciva 558161748Scperciva # Merge these defaults into the earlier-configured settings 559161748Scperciva mergeconfig 560161748Scperciva} 561161748Scperciva 562161748Scperciva# Set utility output filtering options, based on ${VERBOSELEVEL} 563161748Scpercivafetch_setup_verboselevel () { 564161748Scperciva case ${VERBOSELEVEL} in 565161748Scperciva debug) 566161748Scperciva QUIETREDIR="/dev/stderr" 567161748Scperciva QUIETFLAG=" " 568161748Scperciva STATSREDIR="/dev/stderr" 569161748Scperciva DDSTATS=".." 570161748Scperciva XARGST="-t" 571161748Scperciva NDEBUG=" " 572161748Scperciva ;; 573161748Scperciva nostats) 574161748Scperciva QUIETREDIR="" 575161748Scperciva QUIETFLAG="" 576161748Scperciva STATSREDIR="/dev/null" 577161748Scperciva DDSTATS=".." 578161748Scperciva XARGST="" 579161748Scperciva NDEBUG="" 580161748Scperciva ;; 581161748Scperciva stats) 582161748Scperciva QUIETREDIR="/dev/null" 583161748Scperciva QUIETFLAG="-q" 584161748Scperciva STATSREDIR="/dev/stdout" 585161748Scperciva DDSTATS="" 586161748Scperciva XARGST="" 587161748Scperciva NDEBUG="-n" 588161748Scperciva ;; 589161748Scperciva esac 590161748Scperciva} 591161748Scperciva 592161748Scperciva# Perform sanity checks and set some final parameters 593161748Scperciva# in preparation for fetching files. Figure out which 594161748Scperciva# set of updates should be downloaded: If the user is 595161748Scperciva# running *-p[0-9]+, strip off the last part; if the 596161748Scperciva# user is running -SECURITY, call it -RELEASE. Chdir 597161748Scperciva# into the working directory. 598212434Scpercivafetchupgrade_check_params () { 599161748Scperciva export HTTP_USER_AGENT="freebsd-update (${COMMAND}, `uname -r`)" 600161748Scperciva 601161748Scperciva _SERVERNAME_z=\ 602161748Scperciva"SERVERNAME must be given via command line or configuration file." 603161748Scperciva _KEYPRINT_z="Key must be given via -k option or configuration file." 604161748Scperciva _KEYPRINT_bad="Invalid key fingerprint: " 605161748Scperciva _WORKDIR_bad="Directory does not exist or is not writable: " 606284938Sdelphij _WORKDIR_bad2="Directory is not on a persistent filesystem: " 607161748Scperciva 608161748Scperciva if [ -z "${SERVERNAME}" ]; then 609161748Scperciva echo -n "`basename $0`: " 610161748Scperciva echo "${_SERVERNAME_z}" 611161748Scperciva exit 1 612161748Scperciva fi 613161748Scperciva if [ -z "${KEYPRINT}" ]; then 614161748Scperciva echo -n "`basename $0`: " 615161748Scperciva echo "${_KEYPRINT_z}" 616161748Scperciva exit 1 617161748Scperciva fi 618161748Scperciva if ! echo "${KEYPRINT}" | grep -qE "^[0-9a-f]{64}$"; then 619161748Scperciva echo -n "`basename $0`: " 620161748Scperciva echo -n "${_KEYPRINT_bad}" 621161748Scperciva echo ${KEYPRINT} 622161748Scperciva exit 1 623161748Scperciva fi 624161748Scperciva if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then 625161748Scperciva echo -n "`basename $0`: " 626161748Scperciva echo -n "${_WORKDIR_bad}" 627161748Scperciva echo ${WORKDIR} 628161748Scperciva exit 1 629161748Scperciva fi 630284938Sdelphij case `df -T ${WORKDIR}` in */dev/md[0-9]* | *tmpfs*) 631284938Sdelphij echo -n "`basename $0`: " 632284938Sdelphij echo -n "${_WORKDIR_bad2}" 633284938Sdelphij echo ${WORKDIR} 634284938Sdelphij exit 1 635284938Sdelphij ;; 636284938Sdelphij esac 637200054Scperciva chmod 700 ${WORKDIR} 638161748Scperciva cd ${WORKDIR} || exit 1 639161748Scperciva 640161748Scperciva # Generate release number. The s/SECURITY/RELEASE/ bit exists 641161748Scperciva # to provide an upgrade path for FreeBSD Update 1.x users, since 642161748Scperciva # the kernels provided by FreeBSD Update 1.x are always labelled 643161748Scperciva # as X.Y-SECURITY. 644161748Scperciva RELNUM=`uname -r | 645161748Scperciva sed -E 's,-p[0-9]+,,' | 646161748Scperciva sed -E 's,-SECURITY,-RELEASE,'` 647161748Scperciva ARCH=`uname -m` 648161748Scperciva FETCHDIR=${RELNUM}/${ARCH} 649173564Scperciva PATCHDIR=${RELNUM}/${ARCH}/bp 650161748Scperciva 651161748Scperciva # Figure out what directory contains the running kernel 652161748Scperciva BOOTFILE=`sysctl -n kern.bootfile` 653161748Scperciva KERNELDIR=${BOOTFILE%/kernel} 654161748Scperciva if ! [ -d ${KERNELDIR} ]; then 655161748Scperciva echo "Cannot identify running kernel" 656161748Scperciva exit 1 657161748Scperciva fi 658161748Scperciva 659167189Scperciva # Figure out what kernel configuration is running. We start with 660167189Scperciva # the output of `uname -i`, and then make the following adjustments: 661167189Scperciva # 1. Replace "SMP-GENERIC" with "SMP". Why the SMP kernel config 662167189Scperciva # file says "ident SMP-GENERIC", I don't know... 663167189Scperciva # 2. If the kernel claims to be GENERIC _and_ ${ARCH} is "amd64" 664167189Scperciva # _and_ `sysctl kern.version` contains a line which ends "/SMP", then 665167189Scperciva # we're running an SMP kernel. This mis-identification is a bug 666167189Scperciva # which was fixed in 6.2-STABLE. 667167189Scperciva KERNCONF=`uname -i` 668167189Scperciva if [ ${KERNCONF} = "SMP-GENERIC" ]; then 669167189Scperciva KERNCONF=SMP 670167189Scperciva fi 671167189Scperciva if [ ${KERNCONF} = "GENERIC" ] && [ ${ARCH} = "amd64" ]; then 672167189Scperciva if sysctl kern.version | grep -qE '/SMP$'; then 673167189Scperciva KERNCONF=SMP 674167189Scperciva fi 675167189Scperciva fi 676167189Scperciva 677161748Scperciva # Define some paths 678161748Scperciva BSPATCH=/usr/bin/bspatch 679161748Scperciva SHA256=/sbin/sha256 680161748Scperciva PHTTPGET=/usr/libexec/phttpget 681161748Scperciva 682161748Scperciva # Set up variables relating to VERBOSELEVEL 683161748Scperciva fetch_setup_verboselevel 684161748Scperciva 685161748Scperciva # Construct a unique name from ${BASEDIR} 686161748Scperciva BDHASH=`echo ${BASEDIR} | sha256 -q` 687161748Scperciva} 688161748Scperciva 689212434Scperciva# Perform sanity checks etc. before fetching updates. 690212434Scpercivafetch_check_params () { 691212434Scperciva fetchupgrade_check_params 692212434Scperciva 693212434Scperciva if ! [ -z "${TARGETRELEASE}" ]; then 694212434Scperciva echo -n "`basename $0`: " 695212434Scperciva echo -n "-r option is meaningless with 'fetch' command. " 696212434Scperciva echo "(Did you mean 'upgrade' instead?)" 697212434Scperciva exit 1 698212434Scperciva fi 699282870Sdelphij 700282870Sdelphij # Check that we have updates ready to install 701282870Sdelphij if [ -f ${BDHASH}-install/kerneldone -a $FORCEFETCH -eq 0 ]; then 702282870Sdelphij echo "You have a partially completed upgrade pending" 703282870Sdelphij echo "Run '$0 install' first." 704282870Sdelphij echo "Run '$0 fetch -F' to proceed anyway." 705282870Sdelphij exit 1 706282870Sdelphij fi 707212434Scperciva} 708212434Scperciva 709173564Scperciva# Perform sanity checks etc. before fetching upgrades. 710173564Scpercivaupgrade_check_params () { 711212434Scperciva fetchupgrade_check_params 712173564Scperciva 713173564Scperciva # Unless set otherwise, we're upgrading to the same kernel config. 714173564Scperciva NKERNCONF=${KERNCONF} 715173564Scperciva 716173564Scperciva # We need TARGETRELEASE set 717173564Scperciva _TARGETRELEASE_z="Release target must be specified via -r option." 718173564Scperciva if [ -z "${TARGETRELEASE}" ]; then 719173564Scperciva echo -n "`basename $0`: " 720173564Scperciva echo "${_TARGETRELEASE_z}" 721173564Scperciva exit 1 722173564Scperciva fi 723173564Scperciva 724173564Scperciva # The target release should be != the current release. 725173564Scperciva if [ "${TARGETRELEASE}" = "${RELNUM}" ]; then 726173564Scperciva echo -n "`basename $0`: " 727173564Scperciva echo "Cannot upgrade from ${RELNUM} to itself" 728173564Scperciva exit 1 729173564Scperciva fi 730173564Scperciva 731173564Scperciva # Turning off AllowAdd or AllowDelete is a bad idea for upgrades. 732173564Scperciva if [ "${ALLOWADD}" = "no" ]; then 733173564Scperciva echo -n "`basename $0`: " 734173564Scperciva echo -n "WARNING: \"AllowAdd no\" is a bad idea " 735173564Scperciva echo "when upgrading between releases." 736173564Scperciva echo 737173564Scperciva fi 738173564Scperciva if [ "${ALLOWDELETE}" = "no" ]; then 739173564Scperciva echo -n "`basename $0`: " 740173564Scperciva echo -n "WARNING: \"AllowDelete no\" is a bad idea " 741173564Scperciva echo "when upgrading between releases." 742173564Scperciva echo 743173564Scperciva fi 744173564Scperciva 745173564Scperciva # Set EDITOR to /usr/bin/vi if it isn't already set 746173564Scperciva : ${EDITOR:='/usr/bin/vi'} 747173564Scperciva} 748173564Scperciva 749161748Scperciva# Perform sanity checks and set some final parameters in 750161748Scperciva# preparation for installing updates. 751161748Scpercivainstall_check_params () { 752161748Scperciva # Check that we are root. All sorts of things won't work otherwise. 753161748Scperciva if [ `id -u` != 0 ]; then 754161748Scperciva echo "You must be root to run this." 755161748Scperciva exit 1 756161748Scperciva fi 757161748Scperciva 758173441Scperciva # Check that securelevel <= 0. Otherwise we can't update schg files. 759173441Scperciva if [ `sysctl -n kern.securelevel` -gt 0 ]; then 760173441Scperciva echo "Updates cannot be installed when the system securelevel" 761173441Scperciva echo "is greater than zero." 762173441Scperciva exit 1 763173441Scperciva fi 764173441Scperciva 765161748Scperciva # Check that we have a working directory 766161748Scperciva _WORKDIR_bad="Directory does not exist or is not writable: " 767161748Scperciva if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then 768161748Scperciva echo -n "`basename $0`: " 769161748Scperciva echo -n "${_WORKDIR_bad}" 770161748Scperciva echo ${WORKDIR} 771161748Scperciva exit 1 772161748Scperciva fi 773161748Scperciva cd ${WORKDIR} || exit 1 774161748Scperciva 775161748Scperciva # Construct a unique name from ${BASEDIR} 776161748Scperciva BDHASH=`echo ${BASEDIR} | sha256 -q` 777161748Scperciva 778161748Scperciva # Check that we have updates ready to install 779161748Scperciva if ! [ -L ${BDHASH}-install ]; then 780161748Scperciva echo "No updates are available to install." 781161748Scperciva echo "Run '$0 fetch' first." 782161748Scperciva exit 1 783161748Scperciva fi 784161748Scperciva if ! [ -f ${BDHASH}-install/INDEX-OLD ] || 785161748Scperciva ! [ -f ${BDHASH}-install/INDEX-NEW ]; then 786161748Scperciva echo "Update manifest is corrupt -- this should never happen." 787161748Scperciva echo "Re-run '$0 fetch'." 788161748Scperciva exit 1 789161748Scperciva fi 790196392Ssimon 791196392Ssimon # Figure out what directory contains the running kernel 792196392Ssimon BOOTFILE=`sysctl -n kern.bootfile` 793196392Ssimon KERNELDIR=${BOOTFILE%/kernel} 794196392Ssimon if ! [ -d ${KERNELDIR} ]; then 795196392Ssimon echo "Cannot identify running kernel" 796196392Ssimon exit 1 797196392Ssimon fi 798161748Scperciva} 799161748Scperciva 800161748Scperciva# Perform sanity checks and set some final parameters in 801161748Scperciva# preparation for UNinstalling updates. 802161748Scpercivarollback_check_params () { 803161748Scperciva # Check that we are root. All sorts of things won't work otherwise. 804161748Scperciva if [ `id -u` != 0 ]; then 805161748Scperciva echo "You must be root to run this." 806161748Scperciva exit 1 807161748Scperciva fi 808161748Scperciva 809161748Scperciva # Check that we have a working directory 810161748Scperciva _WORKDIR_bad="Directory does not exist or is not writable: " 811161748Scperciva if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then 812161748Scperciva echo -n "`basename $0`: " 813161748Scperciva echo -n "${_WORKDIR_bad}" 814161748Scperciva echo ${WORKDIR} 815161748Scperciva exit 1 816161748Scperciva fi 817161748Scperciva cd ${WORKDIR} || exit 1 818161748Scperciva 819161748Scperciva # Construct a unique name from ${BASEDIR} 820161748Scperciva BDHASH=`echo ${BASEDIR} | sha256 -q` 821161748Scperciva 822161748Scperciva # Check that we have updates ready to rollback 823161748Scperciva if ! [ -L ${BDHASH}-rollback ]; then 824161748Scperciva echo "No rollback directory found." 825161748Scperciva exit 1 826161748Scperciva fi 827161748Scperciva if ! [ -f ${BDHASH}-rollback/INDEX-OLD ] || 828161748Scperciva ! [ -f ${BDHASH}-rollback/INDEX-NEW ]; then 829161748Scperciva echo "Update manifest is corrupt -- this should never happen." 830161748Scperciva exit 1 831161748Scperciva fi 832161748Scperciva} 833161748Scperciva 834181142Scperciva# Perform sanity checks and set some final parameters 835181142Scperciva# in preparation for comparing the system against the 836181142Scperciva# published index. Figure out which index we should 837181142Scperciva# compare against: If the user is running *-p[0-9]+, 838181142Scperciva# strip off the last part; if the user is running 839181142Scperciva# -SECURITY, call it -RELEASE. Chdir into the working 840181142Scperciva# directory. 841181142ScpercivaIDS_check_params () { 842181142Scperciva export HTTP_USER_AGENT="freebsd-update (${COMMAND}, `uname -r`)" 843181142Scperciva 844181142Scperciva _SERVERNAME_z=\ 845181142Scperciva"SERVERNAME must be given via command line or configuration file." 846181142Scperciva _KEYPRINT_z="Key must be given via -k option or configuration file." 847181142Scperciva _KEYPRINT_bad="Invalid key fingerprint: " 848181142Scperciva _WORKDIR_bad="Directory does not exist or is not writable: " 849181142Scperciva 850181142Scperciva if [ -z "${SERVERNAME}" ]; then 851181142Scperciva echo -n "`basename $0`: " 852181142Scperciva echo "${_SERVERNAME_z}" 853181142Scperciva exit 1 854181142Scperciva fi 855181142Scperciva if [ -z "${KEYPRINT}" ]; then 856181142Scperciva echo -n "`basename $0`: " 857181142Scperciva echo "${_KEYPRINT_z}" 858181142Scperciva exit 1 859181142Scperciva fi 860181142Scperciva if ! echo "${KEYPRINT}" | grep -qE "^[0-9a-f]{64}$"; then 861181142Scperciva echo -n "`basename $0`: " 862181142Scperciva echo -n "${_KEYPRINT_bad}" 863181142Scperciva echo ${KEYPRINT} 864181142Scperciva exit 1 865181142Scperciva fi 866181142Scperciva if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then 867181142Scperciva echo -n "`basename $0`: " 868181142Scperciva echo -n "${_WORKDIR_bad}" 869181142Scperciva echo ${WORKDIR} 870181142Scperciva exit 1 871181142Scperciva fi 872181142Scperciva cd ${WORKDIR} || exit 1 873181142Scperciva 874181142Scperciva # Generate release number. The s/SECURITY/RELEASE/ bit exists 875181142Scperciva # to provide an upgrade path for FreeBSD Update 1.x users, since 876181142Scperciva # the kernels provided by FreeBSD Update 1.x are always labelled 877181142Scperciva # as X.Y-SECURITY. 878181142Scperciva RELNUM=`uname -r | 879181142Scperciva sed -E 's,-p[0-9]+,,' | 880181142Scperciva sed -E 's,-SECURITY,-RELEASE,'` 881181142Scperciva ARCH=`uname -m` 882181142Scperciva FETCHDIR=${RELNUM}/${ARCH} 883181142Scperciva PATCHDIR=${RELNUM}/${ARCH}/bp 884181142Scperciva 885181142Scperciva # Figure out what directory contains the running kernel 886181142Scperciva BOOTFILE=`sysctl -n kern.bootfile` 887181142Scperciva KERNELDIR=${BOOTFILE%/kernel} 888181142Scperciva if ! [ -d ${KERNELDIR} ]; then 889181142Scperciva echo "Cannot identify running kernel" 890181142Scperciva exit 1 891181142Scperciva fi 892181142Scperciva 893181142Scperciva # Figure out what kernel configuration is running. We start with 894181142Scperciva # the output of `uname -i`, and then make the following adjustments: 895181142Scperciva # 1. Replace "SMP-GENERIC" with "SMP". Why the SMP kernel config 896181142Scperciva # file says "ident SMP-GENERIC", I don't know... 897181142Scperciva # 2. If the kernel claims to be GENERIC _and_ ${ARCH} is "amd64" 898181142Scperciva # _and_ `sysctl kern.version` contains a line which ends "/SMP", then 899181142Scperciva # we're running an SMP kernel. This mis-identification is a bug 900181142Scperciva # which was fixed in 6.2-STABLE. 901181142Scperciva KERNCONF=`uname -i` 902181142Scperciva if [ ${KERNCONF} = "SMP-GENERIC" ]; then 903181142Scperciva KERNCONF=SMP 904181142Scperciva fi 905181142Scperciva if [ ${KERNCONF} = "GENERIC" ] && [ ${ARCH} = "amd64" ]; then 906181142Scperciva if sysctl kern.version | grep -qE '/SMP$'; then 907181142Scperciva KERNCONF=SMP 908181142Scperciva fi 909181142Scperciva fi 910181142Scperciva 911181142Scperciva # Define some paths 912181142Scperciva SHA256=/sbin/sha256 913181142Scperciva PHTTPGET=/usr/libexec/phttpget 914181142Scperciva 915181142Scperciva # Set up variables relating to VERBOSELEVEL 916181142Scperciva fetch_setup_verboselevel 917181142Scperciva} 918181142Scperciva 919161748Scperciva#### Core functionality -- the actual work gets done here 920161748Scperciva 921161748Scperciva# Use an SRV query to pick a server. If the SRV query doesn't provide 922161748Scperciva# a useful answer, use the server name specified by the user. 923161748Scperciva# Put another way... look up _http._tcp.${SERVERNAME} and pick a server 924161748Scperciva# from that; or if no servers are returned, use ${SERVERNAME}. 925161748Scperciva# This allows a user to specify "portsnap.freebsd.org" (in which case 926161748Scperciva# portsnap will select one of the mirrors) or "portsnap5.tld.freebsd.org" 927161748Scperciva# (in which case portsnap will use that particular server, since there 928161748Scperciva# won't be an SRV entry for that name). 929161748Scperciva# 930161748Scperciva# We ignore the Port field, since we are always going to use port 80. 931161748Scperciva 932161748Scperciva# Fetch the mirror list, but do not pick a mirror yet. Returns 1 if 933161748Scperciva# no mirrors are available for any reason. 934161748Scpercivafetch_pick_server_init () { 935161748Scperciva : > serverlist_tried 936161748Scperciva 937161748Scperciva# Check that host(1) exists (i.e., that the system wasn't built with the 938161748Scperciva# WITHOUT_BIND set) and don't try to find a mirror if it doesn't exist. 939161748Scperciva if ! which -s host; then 940161748Scperciva : > serverlist_full 941161748Scperciva return 1 942161748Scperciva fi 943161748Scperciva 944161748Scperciva echo -n "Looking up ${SERVERNAME} mirrors... " 945161748Scperciva 946161748Scperciva# Issue the SRV query and pull out the Priority, Weight, and Target fields. 947161748Scperciva# BIND 9 prints "$name has SRV record ..." while BIND 8 prints 948161748Scperciva# "$name server selection ..."; we allow either format. 949161748Scperciva MLIST="_http._tcp.${SERVERNAME}" 950161748Scperciva host -t srv "${MLIST}" | 951161748Scperciva sed -nE "s/${MLIST} (has SRV record|server selection) //p" | 952161748Scperciva cut -f 1,2,4 -d ' ' | 953161748Scperciva sed -e 's/\.$//' | 954161748Scperciva sort > serverlist_full 955161748Scperciva 956161748Scperciva# If no records, give up -- we'll just use the server name we were given. 957161748Scperciva if [ `wc -l < serverlist_full` -eq 0 ]; then 958161748Scperciva echo "none found." 959161748Scperciva return 1 960161748Scperciva fi 961161748Scperciva 962161748Scperciva# Report how many mirrors we found. 963161748Scperciva echo `wc -l < serverlist_full` "mirrors found." 964161748Scperciva 965161748Scperciva# Generate a random seed for use in picking mirrors. If HTTP_PROXY 966161748Scperciva# is set, this will be used to generate the seed; otherwise, the seed 967161748Scperciva# will be random. 968161748Scperciva if [ -n "${HTTP_PROXY}${http_proxy}" ]; then 969161748Scperciva RANDVALUE=`sha256 -qs "${HTTP_PROXY}${http_proxy}" | 970161748Scperciva tr -d 'a-f' | 971161748Scperciva cut -c 1-9` 972161748Scperciva else 973161748Scperciva RANDVALUE=`jot -r 1 0 999999999` 974161748Scperciva fi 975161748Scperciva} 976161748Scperciva 977161748Scperciva# Pick a mirror. Returns 1 if we have run out of mirrors to try. 978161748Scpercivafetch_pick_server () { 979161748Scperciva# Generate a list of not-yet-tried mirrors 980161748Scperciva sort serverlist_tried | 981161748Scperciva comm -23 serverlist_full - > serverlist 982161748Scperciva 983161748Scperciva# Have we run out of mirrors? 984161748Scperciva if [ `wc -l < serverlist` -eq 0 ]; then 985161748Scperciva echo "No mirrors remaining, giving up." 986161748Scperciva return 1 987161748Scperciva fi 988161748Scperciva 989161748Scperciva# Find the highest priority level (lowest numeric value). 990161748Scperciva SRV_PRIORITY=`cut -f 1 -d ' ' serverlist | sort -n | head -1` 991161748Scperciva 992161748Scperciva# Add up the weights of the response lines at that priority level. 993161748Scperciva SRV_WSUM=0; 994161748Scperciva while read X; do 995161748Scperciva case "$X" in 996161748Scperciva ${SRV_PRIORITY}\ *) 997161748Scperciva SRV_W=`echo $X | cut -f 2 -d ' '` 998161748Scperciva SRV_WSUM=$(($SRV_WSUM + $SRV_W)) 999161748Scperciva ;; 1000161748Scperciva esac 1001161748Scperciva done < serverlist 1002161748Scperciva 1003161748Scperciva# If all the weights are 0, pretend that they are all 1 instead. 1004161748Scperciva if [ ${SRV_WSUM} -eq 0 ]; then 1005161748Scperciva SRV_WSUM=`grep -E "^${SRV_PRIORITY} " serverlist | wc -l` 1006161748Scperciva SRV_W_ADD=1 1007161748Scperciva else 1008161748Scperciva SRV_W_ADD=0 1009161748Scperciva fi 1010161748Scperciva 1011161748Scperciva# Pick a value between 0 and the sum of the weights - 1 1012161748Scperciva SRV_RND=`expr ${RANDVALUE} % ${SRV_WSUM}` 1013161748Scperciva 1014161748Scperciva# Read through the list of mirrors and set SERVERNAME. Write the line 1015161748Scperciva# corresponding to the mirror we selected into serverlist_tried so that 1016161748Scperciva# we won't try it again. 1017161748Scperciva while read X; do 1018161748Scperciva case "$X" in 1019161748Scperciva ${SRV_PRIORITY}\ *) 1020161748Scperciva SRV_W=`echo $X | cut -f 2 -d ' '` 1021161748Scperciva SRV_W=$(($SRV_W + $SRV_W_ADD)) 1022161748Scperciva if [ $SRV_RND -lt $SRV_W ]; then 1023161748Scperciva SERVERNAME=`echo $X | cut -f 3 -d ' '` 1024161748Scperciva echo "$X" >> serverlist_tried 1025161748Scperciva break 1026161748Scperciva else 1027161748Scperciva SRV_RND=$(($SRV_RND - $SRV_W)) 1028161748Scperciva fi 1029161748Scperciva ;; 1030161748Scperciva esac 1031161748Scperciva done < serverlist 1032161748Scperciva} 1033161748Scperciva 1034161748Scperciva# Take a list of ${oldhash}|${newhash} and output a list of needed patches, 1035161748Scperciva# i.e., those for which we have ${oldhash} and don't have ${newhash}. 1036161748Scpercivafetch_make_patchlist () { 1037161748Scperciva grep -vE "^([0-9a-f]{64})\|\1$" | 1038161748Scperciva tr '|' ' ' | 1039161748Scperciva while read X Y; do 1040161748Scperciva if [ -f "files/${Y}.gz" ] || 1041161748Scperciva [ ! -f "files/${X}.gz" ]; then 1042161748Scperciva continue 1043161748Scperciva fi 1044161748Scperciva echo "${X}|${Y}" 1045161748Scperciva done | uniq 1046161748Scperciva} 1047161748Scperciva 1048161748Scperciva# Print user-friendly progress statistics 1049161748Scpercivafetch_progress () { 1050161748Scperciva LNC=0 1051161748Scperciva while read x; do 1052161748Scperciva LNC=$(($LNC + 1)) 1053161748Scperciva if [ $(($LNC % 10)) = 0 ]; then 1054161748Scperciva echo -n $LNC 1055161748Scperciva elif [ $(($LNC % 2)) = 0 ]; then 1056161748Scperciva echo -n . 1057161748Scperciva fi 1058161748Scperciva done 1059161748Scperciva echo -n " " 1060161748Scperciva} 1061161748Scperciva 1062173564Scperciva# Function for asking the user if everything is ok 1063173564Scpercivacontinuep () { 1064173564Scperciva while read -p "Does this look reasonable (y/n)? " CONTINUE; do 1065173564Scperciva case "${CONTINUE}" in 1066173564Scperciva y*) 1067173564Scperciva return 0 1068173564Scperciva ;; 1069173564Scperciva n*) 1070173564Scperciva return 1 1071173564Scperciva ;; 1072173564Scperciva esac 1073173564Scperciva done 1074173564Scperciva} 1075173564Scperciva 1076161748Scperciva# Initialize the working directory 1077161748Scpercivaworkdir_init () { 1078161748Scperciva mkdir -p files 1079161748Scperciva touch tINDEX.present 1080161748Scperciva} 1081161748Scperciva 1082161748Scperciva# Check that we have a public key with an appropriate hash, or 1083161748Scperciva# fetch the key if it doesn't exist. Returns 1 if the key has 1084161748Scperciva# not yet been fetched. 1085161748Scpercivafetch_key () { 1086161748Scperciva if [ -r pub.ssl ] && [ `${SHA256} -q pub.ssl` = ${KEYPRINT} ]; then 1087161748Scperciva return 0 1088161748Scperciva fi 1089161748Scperciva 1090161748Scperciva echo -n "Fetching public key from ${SERVERNAME}... " 1091161748Scperciva rm -f pub.ssl 1092161748Scperciva fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/pub.ssl \ 1093161748Scperciva 2>${QUIETREDIR} || true 1094161748Scperciva if ! [ -r pub.ssl ]; then 1095161748Scperciva echo "failed." 1096161748Scperciva return 1 1097161748Scperciva fi 1098161748Scperciva if ! [ `${SHA256} -q pub.ssl` = ${KEYPRINT} ]; then 1099161748Scperciva echo "key has incorrect hash." 1100161748Scperciva rm -f pub.ssl 1101161748Scperciva return 1 1102161748Scperciva fi 1103161748Scperciva echo "done." 1104161748Scperciva} 1105161748Scperciva 1106161748Scperciva# Fetch metadata signature, aka "tag". 1107161748Scpercivafetch_tag () { 1108173564Scperciva echo -n "Fetching metadata signature " 1109173564Scperciva echo ${NDEBUG} "for ${RELNUM} from ${SERVERNAME}... " 1110161748Scperciva rm -f latest.ssl 1111161748Scperciva fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/latest.ssl \ 1112161748Scperciva 2>${QUIETREDIR} || true 1113161748Scperciva if ! [ -r latest.ssl ]; then 1114161748Scperciva echo "failed." 1115161748Scperciva return 1 1116161748Scperciva fi 1117161748Scperciva 1118161748Scperciva openssl rsautl -pubin -inkey pub.ssl -verify \ 1119161748Scperciva < latest.ssl > tag.new 2>${QUIETREDIR} || true 1120161748Scperciva rm latest.ssl 1121161748Scperciva 1122161748Scperciva if ! [ `wc -l < tag.new` = 1 ] || 1123161748Scperciva ! grep -qE \ 1124161748Scperciva "^freebsd-update\|${ARCH}\|${RELNUM}\|[0-9]+\|[0-9a-f]{64}\|[0-9]{10}" \ 1125161748Scperciva tag.new; then 1126161748Scperciva echo "invalid signature." 1127161748Scperciva return 1 1128161748Scperciva fi 1129161748Scperciva 1130161748Scperciva echo "done." 1131161748Scperciva 1132161748Scperciva RELPATCHNUM=`cut -f 4 -d '|' < tag.new` 1133161748Scperciva TINDEXHASH=`cut -f 5 -d '|' < tag.new` 1134161748Scperciva EOLTIME=`cut -f 6 -d '|' < tag.new` 1135161748Scperciva} 1136161748Scperciva 1137161748Scperciva# Sanity-check the patch number in a tag, to make sure that we're not 1138161748Scperciva# going to "update" backwards and to prevent replay attacks. 1139161748Scpercivafetch_tagsanity () { 1140161748Scperciva # Check that we're not going to move from -pX to -pY with Y < X. 1141161748Scperciva RELPX=`uname -r | sed -E 's,.*-,,'` 1142161748Scperciva if echo ${RELPX} | grep -qE '^p[0-9]+$'; then 1143161748Scperciva RELPX=`echo ${RELPX} | cut -c 2-` 1144161748Scperciva else 1145161748Scperciva RELPX=0 1146161748Scperciva fi 1147161748Scperciva if [ "${RELPATCHNUM}" -lt "${RELPX}" ]; then 1148161748Scperciva echo 1149161748Scperciva echo -n "Files on mirror (${RELNUM}-p${RELPATCHNUM})" 1150161748Scperciva echo " appear older than what" 1151161748Scperciva echo "we are currently running (`uname -r`)!" 1152161748Scperciva echo "Cowardly refusing to proceed any further." 1153161748Scperciva return 1 1154161748Scperciva fi 1155161748Scperciva 1156161748Scperciva # If "tag" exists and corresponds to ${RELNUM}, make sure that 1157161748Scperciva # it contains a patch number <= RELPATCHNUM, in order to protect 1158161748Scperciva # against rollback (replay) attacks. 1159161748Scperciva if [ -f tag ] && 1160161748Scperciva grep -qE \ 1161161748Scperciva "^freebsd-update\|${ARCH}\|${RELNUM}\|[0-9]+\|[0-9a-f]{64}\|[0-9]{10}" \ 1162161748Scperciva tag; then 1163161748Scperciva LASTRELPATCHNUM=`cut -f 4 -d '|' < tag` 1164161748Scperciva 1165161748Scperciva if [ "${RELPATCHNUM}" -lt "${LASTRELPATCHNUM}" ]; then 1166161748Scperciva echo 1167161748Scperciva echo -n "Files on mirror (${RELNUM}-p${RELPATCHNUM})" 1168161748Scperciva echo " are older than the" 1169161748Scperciva echo -n "most recently seen updates" 1170161748Scperciva echo " (${RELNUM}-p${LASTRELPATCHNUM})." 1171161748Scperciva echo "Cowardly refusing to proceed any further." 1172161748Scperciva return 1 1173161748Scperciva fi 1174161748Scperciva fi 1175161748Scperciva} 1176161748Scperciva 1177161748Scperciva# Fetch metadata index file 1178161748Scpercivafetch_metadata_index () { 1179161748Scperciva echo ${NDEBUG} "Fetching metadata index... " 1180161748Scperciva rm -f ${TINDEXHASH} 1181161748Scperciva fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/t/${TINDEXHASH} 1182161748Scperciva 2>${QUIETREDIR} 1183161748Scperciva if ! [ -f ${TINDEXHASH} ]; then 1184161748Scperciva echo "failed." 1185161748Scperciva return 1 1186161748Scperciva fi 1187161748Scperciva if [ `${SHA256} -q ${TINDEXHASH}` != ${TINDEXHASH} ]; then 1188161748Scperciva echo "update metadata index corrupt." 1189161748Scperciva return 1 1190161748Scperciva fi 1191161748Scperciva echo "done." 1192161748Scperciva} 1193161748Scperciva 1194161748Scperciva# Print an error message about signed metadata being bogus. 1195161748Scpercivafetch_metadata_bogus () { 1196161748Scperciva echo 1197161748Scperciva echo "The update metadata$1 is correctly signed, but" 1198161748Scperciva echo "failed an integrity check." 1199161748Scperciva echo "Cowardly refusing to proceed any further." 1200161748Scperciva return 1 1201161748Scperciva} 1202161748Scperciva 1203161748Scperciva# Construct tINDEX.new by merging the lines named in $1 from ${TINDEXHASH} 1204161748Scperciva# with the lines not named in $@ from tINDEX.present (if that file exists). 1205161748Scpercivafetch_metadata_index_merge () { 1206161748Scperciva for METAFILE in $@; do 1207161748Scperciva if [ `grep -E "^${METAFILE}\|" ${TINDEXHASH} | wc -l` \ 1208161748Scperciva -ne 1 ]; then 1209161748Scperciva fetch_metadata_bogus " index" 1210161748Scperciva return 1 1211161748Scperciva fi 1212161748Scperciva 1213161748Scperciva grep -E "${METAFILE}\|" ${TINDEXHASH} 1214161748Scperciva done | 1215161748Scperciva sort > tINDEX.wanted 1216161748Scperciva 1217161748Scperciva if [ -f tINDEX.present ]; then 1218161748Scperciva join -t '|' -v 2 tINDEX.wanted tINDEX.present | 1219161748Scperciva sort -m - tINDEX.wanted > tINDEX.new 1220161748Scperciva rm tINDEX.wanted 1221161748Scperciva else 1222161748Scperciva mv tINDEX.wanted tINDEX.new 1223161748Scperciva fi 1224161748Scperciva} 1225161748Scperciva 1226161748Scperciva# Sanity check all the lines of tINDEX.new. Even if more metadata lines 1227161748Scperciva# are added by future versions of the server, this won't cause problems, 1228161748Scperciva# since the only lines which appear in tINDEX.new are the ones which we 1229161748Scperciva# specifically grepped out of ${TINDEXHASH}. 1230161748Scpercivafetch_metadata_index_sanity () { 1231161748Scperciva if grep -qvE '^[0-9A-Z.-]+\|[0-9a-f]{64}$' tINDEX.new; then 1232161748Scperciva fetch_metadata_bogus " index" 1233161748Scperciva return 1 1234161748Scperciva fi 1235161748Scperciva} 1236161748Scperciva 1237161748Scperciva# Sanity check the metadata file $1. 1238161748Scpercivafetch_metadata_sanity () { 1239161748Scperciva # Some aliases to save space later: ${P} is a character which can 1240161748Scperciva # appear in a path; ${M} is the four numeric metadata fields; and 1241161748Scperciva # ${H} is a sha256 hash. 1242284940Sdelphij P="[-+./:=,%@_[~[:alnum:]]" 1243161748Scperciva M="[0-9]+\|[0-9]+\|[0-9]+\|[0-9]+" 1244161748Scperciva H="[0-9a-f]{64}" 1245161748Scperciva 1246161748Scperciva # Check that the first four fields make sense. 1247161748Scperciva if gunzip -c < files/$1.gz | 1248303304Sdelphij grep -qvE "^[a-z]+\|[0-9a-z-]+\|${P}+\|[fdL-]\|"; then 1249161748Scperciva fetch_metadata_bogus "" 1250161748Scperciva return 1 1251161748Scperciva fi 1252161748Scperciva 1253161748Scperciva # Remove the first three fields. 1254161748Scperciva gunzip -c < files/$1.gz | 1255161748Scperciva cut -f 4- -d '|' > sanitycheck.tmp 1256161748Scperciva 1257161748Scperciva # Sanity check entries with type 'f' 1258161748Scperciva if grep -E '^f' sanitycheck.tmp | 1259161748Scperciva grep -qvE "^f\|${M}\|${H}\|${P}*\$"; then 1260161748Scperciva fetch_metadata_bogus "" 1261161748Scperciva return 1 1262161748Scperciva fi 1263161748Scperciva 1264161748Scperciva # Sanity check entries with type 'd' 1265161748Scperciva if grep -E '^d' sanitycheck.tmp | 1266161748Scperciva grep -qvE "^d\|${M}\|\|\$"; then 1267161748Scperciva fetch_metadata_bogus "" 1268161748Scperciva return 1 1269161748Scperciva fi 1270161748Scperciva 1271161748Scperciva # Sanity check entries with type 'L' 1272161748Scperciva if grep -E '^L' sanitycheck.tmp | 1273161748Scperciva grep -qvE "^L\|${M}\|${P}*\|\$"; then 1274161748Scperciva fetch_metadata_bogus "" 1275161748Scperciva return 1 1276161748Scperciva fi 1277161748Scperciva 1278161748Scperciva # Sanity check entries with type '-' 1279161748Scperciva if grep -E '^-' sanitycheck.tmp | 1280161748Scperciva grep -qvE "^-\|\|\|\|\|\|"; then 1281161748Scperciva fetch_metadata_bogus "" 1282161748Scperciva return 1 1283161748Scperciva fi 1284161748Scperciva 1285161748Scperciva # Clean up 1286161748Scperciva rm sanitycheck.tmp 1287161748Scperciva} 1288161748Scperciva 1289161748Scperciva# Fetch the metadata index and metadata files listed in $@, 1290161748Scperciva# taking advantage of metadata patches where possible. 1291161748Scpercivafetch_metadata () { 1292161748Scperciva fetch_metadata_index || return 1 1293161748Scperciva fetch_metadata_index_merge $@ || return 1 1294161748Scperciva fetch_metadata_index_sanity || return 1 1295161748Scperciva 1296161748Scperciva # Generate a list of wanted metadata patches 1297161748Scperciva join -t '|' -o 1.2,2.2 tINDEX.present tINDEX.new | 1298161748Scperciva fetch_make_patchlist > patchlist 1299161748Scperciva 1300161748Scperciva if [ -s patchlist ]; then 1301161748Scperciva # Attempt to fetch metadata patches 1302161748Scperciva echo -n "Fetching `wc -l < patchlist | tr -d ' '` " 1303161748Scperciva echo ${NDEBUG} "metadata patches.${DDSTATS}" 1304161748Scperciva tr '|' '-' < patchlist | 1305161748Scperciva lam -s "${FETCHDIR}/tp/" - -s ".gz" | 1306161748Scperciva xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ 1307161748Scperciva 2>${STATSREDIR} | fetch_progress 1308161748Scperciva echo "done." 1309161748Scperciva 1310161748Scperciva # Attempt to apply metadata patches 1311161748Scperciva echo -n "Applying metadata patches... " 1312161748Scperciva tr '|' ' ' < patchlist | 1313161748Scperciva while read X Y; do 1314161748Scperciva if [ ! -f "${X}-${Y}.gz" ]; then continue; fi 1315161748Scperciva gunzip -c < ${X}-${Y}.gz > diff 1316161748Scperciva gunzip -c < files/${X}.gz > diff-OLD 1317161748Scperciva 1318161748Scperciva # Figure out which lines are being added and removed 1319161748Scperciva grep -E '^-' diff | 1320161748Scperciva cut -c 2- | 1321161748Scperciva while read PREFIX; do 1322161748Scperciva look "${PREFIX}" diff-OLD 1323161748Scperciva done | 1324161748Scperciva sort > diff-rm 1325161748Scperciva grep -E '^\+' diff | 1326161748Scperciva cut -c 2- > diff-add 1327161748Scperciva 1328161748Scperciva # Generate the new file 1329161748Scperciva comm -23 diff-OLD diff-rm | 1330161748Scperciva sort - diff-add > diff-NEW 1331161748Scperciva 1332161748Scperciva if [ `${SHA256} -q diff-NEW` = ${Y} ]; then 1333161748Scperciva mv diff-NEW files/${Y} 1334161748Scperciva gzip -n files/${Y} 1335161748Scperciva else 1336161748Scperciva mv diff-NEW ${Y}.bad 1337161748Scperciva fi 1338161748Scperciva rm -f ${X}-${Y}.gz diff 1339161748Scperciva rm -f diff-OLD diff-NEW diff-add diff-rm 1340161748Scperciva done 2>${QUIETREDIR} 1341161748Scperciva echo "done." 1342161748Scperciva fi 1343161748Scperciva 1344161748Scperciva # Update metadata without patches 1345161748Scperciva cut -f 2 -d '|' < tINDEX.new | 1346161748Scperciva while read Y; do 1347161748Scperciva if [ ! -f "files/${Y}.gz" ]; then 1348161748Scperciva echo ${Y}; 1349161748Scperciva fi 1350164600Scperciva done | 1351164600Scperciva sort -u > filelist 1352161748Scperciva 1353161748Scperciva if [ -s filelist ]; then 1354161748Scperciva echo -n "Fetching `wc -l < filelist | tr -d ' '` " 1355161748Scperciva echo ${NDEBUG} "metadata files... " 1356161748Scperciva lam -s "${FETCHDIR}/m/" - -s ".gz" < filelist | 1357161748Scperciva xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ 1358161748Scperciva 2>${QUIETREDIR} 1359161748Scperciva 1360161748Scperciva while read Y; do 1361161748Scperciva if ! [ -f ${Y}.gz ]; then 1362161748Scperciva echo "failed." 1363161748Scperciva return 1 1364161748Scperciva fi 1365161748Scperciva if [ `gunzip -c < ${Y}.gz | 1366161748Scperciva ${SHA256} -q` = ${Y} ]; then 1367161748Scperciva mv ${Y}.gz files/${Y}.gz 1368161748Scperciva else 1369161748Scperciva echo "metadata is corrupt." 1370161748Scperciva return 1 1371161748Scperciva fi 1372161748Scperciva done < filelist 1373161748Scperciva echo "done." 1374161748Scperciva fi 1375161748Scperciva 1376161748Scperciva# Sanity-check the metadata files. 1377161748Scperciva cut -f 2 -d '|' tINDEX.new > filelist 1378161748Scperciva while read X; do 1379161748Scperciva fetch_metadata_sanity ${X} || return 1 1380161748Scperciva done < filelist 1381161748Scperciva 1382161748Scperciva# Remove files which are no longer needed 1383161748Scperciva cut -f 2 -d '|' tINDEX.present | 1384161748Scperciva sort > oldfiles 1385161748Scperciva cut -f 2 -d '|' tINDEX.new | 1386161748Scperciva sort | 1387161748Scperciva comm -13 - oldfiles | 1388161748Scperciva lam -s "files/" - -s ".gz" | 1389161748Scperciva xargs rm -f 1390161748Scperciva rm patchlist filelist oldfiles 1391161748Scperciva rm ${TINDEXHASH} 1392161748Scperciva 1393161748Scperciva# We're done! 1394161748Scperciva mv tINDEX.new tINDEX.present 1395161748Scperciva mv tag.new tag 1396161748Scperciva 1397161748Scperciva return 0 1398161748Scperciva} 1399161748Scperciva 1400173564Scperciva# Extract a subset of a downloaded metadata file containing only the parts 1401173564Scperciva# which are listed in COMPONENTS. 1402173564Scpercivafetch_filter_metadata_components () { 1403173564Scperciva METAHASH=`look "$1|" tINDEX.present | cut -f 2 -d '|'` 1404173564Scperciva gunzip -c < files/${METAHASH}.gz > $1.all 1405173564Scperciva 1406173564Scperciva # Fish out the lines belonging to components we care about. 1407173564Scperciva for C in ${COMPONENTS}; do 1408173564Scperciva look "`echo ${C} | tr '/' '|'`|" $1.all 1409173564Scperciva done > $1 1410173564Scperciva 1411173564Scperciva # Remove temporary file. 1412173564Scperciva rm $1.all 1413173564Scperciva} 1414173564Scperciva 1415161869Scperciva# Generate a filtered version of the metadata file $1 from the downloaded 1416161748Scperciva# file, by fishing out the lines corresponding to components we're trying 1417161748Scperciva# to keep updated, and then removing lines corresponding to paths we want 1418161748Scperciva# to ignore. 1419161748Scpercivafetch_filter_metadata () { 1420173564Scperciva # Fish out the lines belonging to components we care about. 1421173564Scperciva fetch_filter_metadata_components $1 1422161748Scperciva 1423161748Scperciva # Canonicalize directory names by removing any trailing / in 1424161748Scperciva # order to avoid listing directories multiple times if they 1425161748Scperciva # belong to multiple components. Turning "/" into "" doesn't 1426161748Scperciva # matter, since we add a leading "/" when we use paths later. 1427173564Scperciva cut -f 3- -d '|' $1 | 1428161748Scperciva sed -e 's,/|d|,|d|,' | 1429276088Sdes sed -e 's,/|-|,|-|,' | 1430161748Scperciva sort -u > $1.tmp 1431161748Scperciva 1432161748Scperciva # Figure out which lines to ignore and remove them. 1433161748Scperciva for X in ${IGNOREPATHS}; do 1434161748Scperciva grep -E "^${X}" $1.tmp 1435161748Scperciva done | 1436161748Scperciva sort -u | 1437161748Scperciva comm -13 - $1.tmp > $1 1438161748Scperciva 1439161748Scperciva # Remove temporary files. 1440173564Scperciva rm $1.tmp 1441161748Scperciva} 1442161748Scperciva 1443173564Scperciva# Filter the metadata file $1 by adding lines with "/boot/$2" 1444164600Scperciva# replaced by ${KERNELDIR} (which is `sysctl -n kern.bootfile` minus the 1445173564Scperciva# trailing "/kernel"); and if "/boot/$2" does not exist, remove 1446164600Scperciva# the original lines which start with that. 1447164600Scperciva# Put another way: Deal with the fact that the FOO kernel is sometimes 1448164600Scperciva# installed in /boot/FOO/ and is sometimes installed elsewhere. 1449161748Scpercivafetch_filter_kernel_names () { 1450173564Scperciva grep ^/boot/$2 $1 | 1451173564Scperciva sed -e "s,/boot/$2,${KERNELDIR},g" | 1452161748Scperciva sort - $1 > $1.tmp 1453161748Scperciva mv $1.tmp $1 1454164600Scperciva 1455173564Scperciva if ! [ -d /boot/$2 ]; then 1456173564Scperciva grep -v ^/boot/$2 $1 > $1.tmp 1457164600Scperciva mv $1.tmp $1 1458164600Scperciva fi 1459161748Scperciva} 1460161748Scperciva 1461161748Scperciva# For all paths appearing in $1 or $3, inspect the system 1462161748Scperciva# and generate $2 describing what is currently installed. 1463161748Scpercivafetch_inspect_system () { 1464161748Scperciva # No errors yet... 1465161748Scperciva rm -f .err 1466161748Scperciva 1467161748Scperciva # Tell the user why his disk is suddenly making lots of noise 1468161748Scperciva echo -n "Inspecting system... " 1469161748Scperciva 1470161748Scperciva # Generate list of files to inspect 1471161748Scperciva cat $1 $3 | 1472161748Scperciva cut -f 1 -d '|' | 1473161748Scperciva sort -u > filelist 1474161748Scperciva 1475161748Scperciva # Examine each file and output lines of the form 1476161748Scperciva # /path/to/file|type|device-inum|user|group|perm|flags|value 1477161748Scperciva # sorted by device and inode number. 1478161748Scperciva while read F; do 1479161748Scperciva # If the symlink/file/directory does not exist, record this. 1480161748Scperciva if ! [ -e ${BASEDIR}/${F} ]; then 1481161748Scperciva echo "${F}|-||||||" 1482161748Scperciva continue 1483161748Scperciva fi 1484161748Scperciva if ! [ -r ${BASEDIR}/${F} ]; then 1485161748Scperciva echo "Cannot read file: ${BASEDIR}/${F}" \ 1486161748Scperciva >/dev/stderr 1487161748Scperciva touch .err 1488161748Scperciva return 1 1489161748Scperciva fi 1490161748Scperciva 1491161748Scperciva # Otherwise, output an index line. 1492161748Scperciva if [ -L ${BASEDIR}/${F} ]; then 1493161748Scperciva echo -n "${F}|L|" 1494161748Scperciva stat -n -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F}; 1495161748Scperciva readlink ${BASEDIR}/${F}; 1496161748Scperciva elif [ -f ${BASEDIR}/${F} ]; then 1497161748Scperciva echo -n "${F}|f|" 1498161748Scperciva stat -n -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F}; 1499161748Scperciva sha256 -q ${BASEDIR}/${F}; 1500161748Scperciva elif [ -d ${BASEDIR}/${F} ]; then 1501161748Scperciva echo -n "${F}|d|" 1502161748Scperciva stat -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F}; 1503161748Scperciva else 1504161748Scperciva echo "Unknown file type: ${BASEDIR}/${F}" \ 1505161748Scperciva >/dev/stderr 1506161748Scperciva touch .err 1507161748Scperciva return 1 1508161748Scperciva fi 1509161748Scperciva done < filelist | 1510161748Scperciva sort -k 3,3 -t '|' > $2.tmp 1511161748Scperciva rm filelist 1512161748Scperciva 1513215087Sbcr # Check if an error occurred during system inspection 1514161748Scperciva if [ -f .err ]; then 1515161748Scperciva return 1 1516161748Scperciva fi 1517161748Scperciva 1518161748Scperciva # Convert to the form 1519161748Scperciva # /path/to/file|type|user|group|perm|flags|value|hlink 1520161748Scperciva # by resolving identical device and inode numbers into hard links. 1521161748Scperciva cut -f 1,3 -d '|' $2.tmp | 1522161748Scperciva sort -k 1,1 -t '|' | 1523161748Scperciva sort -s -u -k 2,2 -t '|' | 1524161748Scperciva join -1 2 -2 3 -t '|' - $2.tmp | 1525161748Scperciva awk -F \| -v OFS=\| \ 1526161748Scperciva '{ 1527161748Scperciva if (($2 == $3) || ($4 == "-")) 1528161748Scperciva print $3,$4,$5,$6,$7,$8,$9,"" 1529161748Scperciva else 1530161748Scperciva print $3,$4,$5,$6,$7,$8,$9,$2 1531161748Scperciva }' | 1532161748Scperciva sort > $2 1533161748Scperciva rm $2.tmp 1534161748Scperciva 1535161748Scperciva # We're finished looking around 1536161748Scperciva echo "done." 1537161748Scperciva} 1538161748Scperciva 1539173564Scperciva# For any paths matching ${MERGECHANGES}, compare $1 and $2 and find any 1540173564Scperciva# files which differ; generate $3 containing these paths and the old hashes. 1541173564Scpercivafetch_filter_mergechanges () { 1542173564Scperciva # Pull out the paths and hashes of the files matching ${MERGECHANGES}. 1543173564Scperciva for F in $1 $2; do 1544173564Scperciva for X in ${MERGECHANGES}; do 1545173564Scperciva grep -E "^${X}" ${F} 1546173564Scperciva done | 1547173564Scperciva cut -f 1,2,7 -d '|' | 1548173564Scperciva sort > ${F}-values 1549173564Scperciva done 1550173564Scperciva 1551173564Scperciva # Any line in $2-values which doesn't appear in $1-values and is a 1552173564Scperciva # file means that we should list the path in $3. 1553173564Scperciva comm -13 $1-values $2-values | 1554173564Scperciva fgrep '|f|' | 1555173564Scperciva cut -f 1 -d '|' > $2-paths 1556173564Scperciva 1557173564Scperciva # For each path, pull out one (and only one!) entry from $1-values. 1558173564Scperciva # Note that we cannot distinguish which "old" version the user made 1559173564Scperciva # changes to; but hopefully any changes which occur due to security 1560173564Scperciva # updates will exist in both the "new" version and the version which 1561173564Scperciva # the user has installed, so the merging will still work. 1562173564Scperciva while read X; do 1563173564Scperciva look "${X}|" $1-values | 1564173564Scperciva head -1 1565173564Scperciva done < $2-paths > $3 1566173564Scperciva 1567173564Scperciva # Clean up 1568173564Scperciva rm $1-values $2-values $2-paths 1569173564Scperciva} 1570173564Scperciva 1571161748Scperciva# For any paths matching ${UPDATEIFUNMODIFIED}, remove lines from $[123] 1572173564Scperciva# which correspond to lines in $2 with hashes not matching $1 or $3, unless 1573173564Scperciva# the paths are listed in $4. For entries in $2 marked "not present" 1574173564Scperciva# (aka. type -), remove lines from $[123] unless there is a corresponding 1575173564Scperciva# entry in $1. 1576161748Scpercivafetch_filter_unmodified_notpresent () { 1577161748Scperciva # Figure out which lines of $1 and $3 correspond to bits which 1578161748Scperciva # should only be updated if they haven't changed, and fish out 1579161748Scperciva # the (path, type, value) tuples. 1580161748Scperciva # NOTE: We don't consider a file to be "modified" if it matches 1581161748Scperciva # the hash from $3. 1582161748Scperciva for X in ${UPDATEIFUNMODIFIED}; do 1583161748Scperciva grep -E "^${X}" $1 1584161748Scperciva grep -E "^${X}" $3 1585161748Scperciva done | 1586161748Scperciva cut -f 1,2,7 -d '|' | 1587161748Scperciva sort > $1-values 1588161748Scperciva 1589161748Scperciva # Do the same for $2. 1590161748Scperciva for X in ${UPDATEIFUNMODIFIED}; do 1591161748Scperciva grep -E "^${X}" $2 1592161748Scperciva done | 1593161748Scperciva cut -f 1,2,7 -d '|' | 1594161748Scperciva sort > $2-values 1595161748Scperciva 1596161748Scperciva # Any entry in $2-values which is not in $1-values corresponds to 1597173564Scperciva # a path which we need to remove from $1, $2, and $3, unless it 1598173564Scperciva # that path appears in $4. 1599173564Scperciva comm -13 $1-values $2-values | 1600173564Scperciva sort -t '|' -k 1,1 > mlines.tmp 1601173564Scperciva cut -f 1 -d '|' $4 | 1602173564Scperciva sort | 1603173564Scperciva join -v 2 -t '|' - mlines.tmp | 1604173564Scperciva sort > mlines 1605173564Scperciva rm $1-values $2-values mlines.tmp 1606161748Scperciva 1607161748Scperciva # Any lines in $2 which are not in $1 AND are "not present" lines 1608161748Scperciva # also belong in mlines. 1609161748Scperciva comm -13 $1 $2 | 1610161748Scperciva cut -f 1,2,7 -d '|' | 1611161748Scperciva fgrep '|-|' >> mlines 1612161748Scperciva 1613161748Scperciva # Remove lines from $1, $2, and $3 1614161748Scperciva for X in $1 $2 $3; do 1615161748Scperciva sort -t '|' -k 1,1 ${X} > ${X}.tmp 1616161748Scperciva cut -f 1 -d '|' < mlines | 1617161748Scperciva sort | 1618161748Scperciva join -v 2 -t '|' - ${X}.tmp | 1619161748Scperciva sort > ${X} 1620161748Scperciva rm ${X}.tmp 1621161748Scperciva done 1622161748Scperciva 1623161748Scperciva # Store a list of the modified files, for future reference 1624161748Scperciva fgrep -v '|-|' mlines | 1625161748Scperciva cut -f 1 -d '|' > modifiedfiles 1626161748Scperciva rm mlines 1627161748Scperciva} 1628161748Scperciva 1629161748Scperciva# For each entry in $1 of type -, remove any corresponding 1630161748Scperciva# entry from $2 if ${ALLOWADD} != "yes". Remove all entries 1631161748Scperciva# of type - from $1. 1632161748Scpercivafetch_filter_allowadd () { 1633161748Scperciva cut -f 1,2 -d '|' < $1 | 1634161748Scperciva fgrep '|-' | 1635161748Scperciva cut -f 1 -d '|' > filesnotpresent 1636161748Scperciva 1637161748Scperciva if [ ${ALLOWADD} != "yes" ]; then 1638161748Scperciva sort < $2 | 1639161748Scperciva join -v 1 -t '|' - filesnotpresent | 1640161748Scperciva sort > $2.tmp 1641161748Scperciva mv $2.tmp $2 1642161748Scperciva fi 1643161748Scperciva 1644161748Scperciva sort < $1 | 1645161748Scperciva join -v 1 -t '|' - filesnotpresent | 1646161748Scperciva sort > $1.tmp 1647161748Scperciva mv $1.tmp $1 1648161748Scperciva rm filesnotpresent 1649161748Scperciva} 1650161748Scperciva 1651161748Scperciva# If ${ALLOWDELETE} != "yes", then remove any entries from $1 1652161748Scperciva# which don't correspond to entries in $2. 1653161748Scpercivafetch_filter_allowdelete () { 1654161748Scperciva # Produce a lists ${PATH}|${TYPE} 1655161748Scperciva for X in $1 $2; do 1656161748Scperciva cut -f 1-2 -d '|' < ${X} | 1657161748Scperciva sort -u > ${X}.nodes 1658161748Scperciva done 1659161748Scperciva 1660161748Scperciva # Figure out which lines need to be removed from $1. 1661161748Scperciva if [ ${ALLOWDELETE} != "yes" ]; then 1662161748Scperciva comm -23 $1.nodes $2.nodes > $1.badnodes 1663161748Scperciva else 1664161748Scperciva : > $1.badnodes 1665161748Scperciva fi 1666161748Scperciva 1667161748Scperciva # Remove the relevant lines from $1 1668161748Scperciva while read X; do 1669161748Scperciva look "${X}|" $1 1670161748Scperciva done < $1.badnodes | 1671161748Scperciva comm -13 - $1 > $1.tmp 1672161748Scperciva mv $1.tmp $1 1673161748Scperciva 1674161748Scperciva rm $1.badnodes $1.nodes $2.nodes 1675161748Scperciva} 1676161748Scperciva 1677161748Scperciva# If ${KEEPMODIFIEDMETADATA} == "yes", then for each entry in $2 1678161748Scperciva# with metadata not matching any entry in $1, replace the corresponding 1679161748Scperciva# line of $3 with one having the same metadata as the entry in $2. 1680161748Scpercivafetch_filter_modified_metadata () { 1681161748Scperciva # Fish out the metadata from $1 and $2 1682161748Scperciva for X in $1 $2; do 1683161748Scperciva cut -f 1-6 -d '|' < ${X} > ${X}.metadata 1684161748Scperciva done 1685161748Scperciva 1686161748Scperciva # Find the metadata we need to keep 1687161748Scperciva if [ ${KEEPMODIFIEDMETADATA} = "yes" ]; then 1688161748Scperciva comm -13 $1.metadata $2.metadata > keepmeta 1689161748Scperciva else 1690161748Scperciva : > keepmeta 1691161748Scperciva fi 1692161748Scperciva 1693161748Scperciva # Extract the lines which we need to remove from $3, and 1694161748Scperciva # construct the lines which we need to add to $3. 1695161748Scperciva : > $3.remove 1696161748Scperciva : > $3.add 1697161748Scperciva while read LINE; do 1698161748Scperciva NODE=`echo "${LINE}" | cut -f 1-2 -d '|'` 1699161748Scperciva look "${NODE}|" $3 >> $3.remove 1700161748Scperciva look "${NODE}|" $3 | 1701161748Scperciva cut -f 7- -d '|' | 1702161748Scperciva lam -s "${LINE}|" - >> $3.add 1703161748Scperciva done < keepmeta 1704161748Scperciva 1705161748Scperciva # Remove the specified lines and add the new lines. 1706161748Scperciva sort $3.remove | 1707161748Scperciva comm -13 - $3 | 1708161748Scperciva sort -u - $3.add > $3.tmp 1709161748Scperciva mv $3.tmp $3 1710161748Scperciva 1711161748Scperciva rm keepmeta $1.metadata $2.metadata $3.add $3.remove 1712161748Scperciva} 1713161748Scperciva 1714161748Scperciva# Remove lines from $1 and $2 which are identical; 1715161748Scperciva# no need to update a file if it isn't changing. 1716161748Scpercivafetch_filter_uptodate () { 1717161748Scperciva comm -23 $1 $2 > $1.tmp 1718161748Scperciva comm -13 $1 $2 > $2.tmp 1719161748Scperciva 1720161748Scperciva mv $1.tmp $1 1721161748Scperciva mv $2.tmp $2 1722161748Scperciva} 1723161748Scperciva 1724173564Scperciva# Fetch any "clean" old versions of files we need for merging changes. 1725173564Scpercivafetch_files_premerge () { 1726173564Scperciva # We only need to do anything if $1 is non-empty. 1727173564Scperciva if [ -s $1 ]; then 1728173564Scperciva # Tell the user what we're doing 1729173564Scperciva echo -n "Fetching files from ${OLDRELNUM} for merging... " 1730173564Scperciva 1731173564Scperciva # List of files wanted 1732173564Scperciva fgrep '|f|' < $1 | 1733173564Scperciva cut -f 3 -d '|' | 1734173564Scperciva sort -u > files.wanted 1735173564Scperciva 1736173564Scperciva # Only fetch the files we don't already have 1737173564Scperciva while read Y; do 1738173564Scperciva if [ ! -f "files/${Y}.gz" ]; then 1739173564Scperciva echo ${Y}; 1740173564Scperciva fi 1741173564Scperciva done < files.wanted > filelist 1742173564Scperciva 1743173564Scperciva # Actually fetch them 1744173564Scperciva lam -s "${OLDFETCHDIR}/f/" - -s ".gz" < filelist | 1745173564Scperciva xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ 1746173564Scperciva 2>${QUIETREDIR} 1747173564Scperciva 1748173564Scperciva # Make sure we got them all, and move them into /files/ 1749173564Scperciva while read Y; do 1750173564Scperciva if ! [ -f ${Y}.gz ]; then 1751173564Scperciva echo "failed." 1752173564Scperciva return 1 1753173564Scperciva fi 1754173564Scperciva if [ `gunzip -c < ${Y}.gz | 1755173564Scperciva ${SHA256} -q` = ${Y} ]; then 1756173564Scperciva mv ${Y}.gz files/${Y}.gz 1757173564Scperciva else 1758173564Scperciva echo "${Y} has incorrect hash." 1759173564Scperciva return 1 1760173564Scperciva fi 1761173564Scperciva done < filelist 1762173564Scperciva echo "done." 1763173564Scperciva 1764173564Scperciva # Clean up 1765173564Scperciva rm filelist files.wanted 1766173564Scperciva fi 1767173564Scperciva} 1768173564Scperciva 1769161748Scperciva# Prepare to fetch files: Generate a list of the files we need, 1770161748Scperciva# copy the unmodified files we have into /files/, and generate 1771161748Scperciva# a list of patches to download. 1772161748Scpercivafetch_files_prepare () { 1773161748Scperciva # Tell the user why his disk is suddenly making lots of noise 1774161748Scperciva echo -n "Preparing to download files... " 1775161748Scperciva 1776161748Scperciva # Reduce indices to ${PATH}|${HASH} pairs 1777161748Scperciva for X in $1 $2 $3; do 1778161748Scperciva cut -f 1,2,7 -d '|' < ${X} | 1779161748Scperciva fgrep '|f|' | 1780161748Scperciva cut -f 1,3 -d '|' | 1781161748Scperciva sort > ${X}.hashes 1782161748Scperciva done 1783161748Scperciva 1784161748Scperciva # List of files wanted 1785161748Scperciva cut -f 2 -d '|' < $3.hashes | 1786173441Scperciva sort -u | 1787173441Scperciva while read HASH; do 1788173441Scperciva if ! [ -f files/${HASH}.gz ]; then 1789173441Scperciva echo ${HASH} 1790173441Scperciva fi 1791173441Scperciva done > files.wanted 1792161748Scperciva 1793161748Scperciva # Generate a list of unmodified files 1794161748Scperciva comm -12 $1.hashes $2.hashes | 1795161748Scperciva sort -k 1,1 -t '|' > unmodified.files 1796161748Scperciva 1797161748Scperciva # Copy all files into /files/. We only need the unmodified files 1798161748Scperciva # for use in patching; but we'll want all of them if the user asks 1799161748Scperciva # to rollback the updates later. 1800171784Scperciva while read LINE; do 1801171784Scperciva F=`echo "${LINE}" | cut -f 1 -d '|'` 1802171784Scperciva HASH=`echo "${LINE}" | cut -f 2 -d '|'` 1803171784Scperciva 1804171784Scperciva # Skip files we already have. 1805171784Scperciva if [ -f files/${HASH}.gz ]; then 1806171784Scperciva continue 1807171784Scperciva fi 1808171784Scperciva 1809171784Scperciva # Make sure the file hasn't changed. 1810161748Scperciva cp "${BASEDIR}/${F}" tmpfile 1811171784Scperciva if [ `sha256 -q tmpfile` != ${HASH} ]; then 1812171784Scperciva echo 1813171784Scperciva echo "File changed while FreeBSD Update running: ${F}" 1814171784Scperciva return 1 1815171784Scperciva fi 1816171784Scperciva 1817171784Scperciva # Place the file into storage. 1818171784Scperciva gzip -c < tmpfile > files/${HASH}.gz 1819161748Scperciva rm tmpfile 1820171784Scperciva done < $2.hashes 1821161748Scperciva 1822161748Scperciva # Produce a list of patches to download 1823161748Scperciva sort -k 1,1 -t '|' $3.hashes | 1824161748Scperciva join -t '|' -o 2.2,1.2 - unmodified.files | 1825161748Scperciva fetch_make_patchlist > patchlist 1826161748Scperciva 1827161748Scperciva # Garbage collect 1828161748Scperciva rm unmodified.files $1.hashes $2.hashes $3.hashes 1829161748Scperciva 1830161748Scperciva # We don't need the list of possible old files any more. 1831161748Scperciva rm $1 1832161748Scperciva 1833161748Scperciva # We're finished making noise 1834161748Scperciva echo "done." 1835161748Scperciva} 1836161748Scperciva 1837161748Scperciva# Fetch files. 1838161748Scpercivafetch_files () { 1839161748Scperciva # Attempt to fetch patches 1840161748Scperciva if [ -s patchlist ]; then 1841161748Scperciva echo -n "Fetching `wc -l < patchlist | tr -d ' '` " 1842161748Scperciva echo ${NDEBUG} "patches.${DDSTATS}" 1843161748Scperciva tr '|' '-' < patchlist | 1844173564Scperciva lam -s "${PATCHDIR}/" - | 1845161748Scperciva xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ 1846161748Scperciva 2>${STATSREDIR} | fetch_progress 1847161748Scperciva echo "done." 1848161748Scperciva 1849161748Scperciva # Attempt to apply patches 1850161748Scperciva echo -n "Applying patches... " 1851161748Scperciva tr '|' ' ' < patchlist | 1852161748Scperciva while read X Y; do 1853161748Scperciva if [ ! -f "${X}-${Y}" ]; then continue; fi 1854161748Scperciva gunzip -c < files/${X}.gz > OLD 1855161748Scperciva 1856161748Scperciva bspatch OLD NEW ${X}-${Y} 1857161748Scperciva 1858161748Scperciva if [ `${SHA256} -q NEW` = ${Y} ]; then 1859161748Scperciva mv NEW files/${Y} 1860161748Scperciva gzip -n files/${Y} 1861161748Scperciva fi 1862161748Scperciva rm -f diff OLD NEW ${X}-${Y} 1863161748Scperciva done 2>${QUIETREDIR} 1864161748Scperciva echo "done." 1865161748Scperciva fi 1866161748Scperciva 1867161748Scperciva # Download files which couldn't be generate via patching 1868161748Scperciva while read Y; do 1869161748Scperciva if [ ! -f "files/${Y}.gz" ]; then 1870161748Scperciva echo ${Y}; 1871161748Scperciva fi 1872161748Scperciva done < files.wanted > filelist 1873161748Scperciva 1874161748Scperciva if [ -s filelist ]; then 1875161748Scperciva echo -n "Fetching `wc -l < filelist | tr -d ' '` " 1876161748Scperciva echo ${NDEBUG} "files... " 1877161748Scperciva lam -s "${FETCHDIR}/f/" - -s ".gz" < filelist | 1878161748Scperciva xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ 1879161748Scperciva 2>${QUIETREDIR} 1880161748Scperciva 1881161748Scperciva while read Y; do 1882161748Scperciva if ! [ -f ${Y}.gz ]; then 1883161748Scperciva echo "failed." 1884161748Scperciva return 1 1885161748Scperciva fi 1886161748Scperciva if [ `gunzip -c < ${Y}.gz | 1887161748Scperciva ${SHA256} -q` = ${Y} ]; then 1888161748Scperciva mv ${Y}.gz files/${Y}.gz 1889161748Scperciva else 1890161748Scperciva echo "${Y} has incorrect hash." 1891161748Scperciva return 1 1892161748Scperciva fi 1893161748Scperciva done < filelist 1894161748Scperciva echo "done." 1895161748Scperciva fi 1896161748Scperciva 1897161748Scperciva # Clean up 1898161748Scperciva rm files.wanted filelist patchlist 1899161748Scperciva} 1900161748Scperciva 1901161748Scperciva# Create and populate install manifest directory; and report what updates 1902161748Scperciva# are available. 1903161748Scpercivafetch_create_manifest () { 1904161748Scperciva # If we have an existing install manifest, nuke it. 1905161748Scperciva if [ -L "${BDHASH}-install" ]; then 1906161748Scperciva rm -r ${BDHASH}-install/ 1907161748Scperciva rm ${BDHASH}-install 1908161748Scperciva fi 1909161748Scperciva 1910161748Scperciva # Report to the user if any updates were avoided due to local changes 1911161748Scperciva if [ -s modifiedfiles ]; then 1912161748Scperciva echo 1913161748Scperciva echo -n "The following files are affected by updates, " 1914161748Scperciva echo "but no changes have" 1915161748Scperciva echo -n "been downloaded because the files have been " 1916161748Scperciva echo "modified locally:" 1917161748Scperciva cat modifiedfiles 1918217767Sgordon fi | $PAGER 1919161748Scperciva rm modifiedfiles 1920161748Scperciva 1921161748Scperciva # If no files will be updated, tell the user and exit 1922161748Scperciva if ! [ -s INDEX-PRESENT ] && 1923161748Scperciva ! [ -s INDEX-NEW ]; then 1924161748Scperciva rm INDEX-PRESENT INDEX-NEW 1925161748Scperciva echo 1926161748Scperciva echo -n "No updates needed to update system to " 1927161748Scperciva echo "${RELNUM}-p${RELPATCHNUM}." 1928161748Scperciva return 1929161748Scperciva fi 1930161748Scperciva 1931161748Scperciva # Divide files into (a) removed files, (b) added files, and 1932161748Scperciva # (c) updated files. 1933161748Scperciva cut -f 1 -d '|' < INDEX-PRESENT | 1934161748Scperciva sort > INDEX-PRESENT.flist 1935161748Scperciva cut -f 1 -d '|' < INDEX-NEW | 1936161748Scperciva sort > INDEX-NEW.flist 1937161748Scperciva comm -23 INDEX-PRESENT.flist INDEX-NEW.flist > files.removed 1938161748Scperciva comm -13 INDEX-PRESENT.flist INDEX-NEW.flist > files.added 1939161748Scperciva comm -12 INDEX-PRESENT.flist INDEX-NEW.flist > files.updated 1940161748Scperciva rm INDEX-PRESENT.flist INDEX-NEW.flist 1941161748Scperciva 1942161748Scperciva # Report removed files, if any 1943161748Scperciva if [ -s files.removed ]; then 1944161748Scperciva echo 1945161748Scperciva echo -n "The following files will be removed " 1946161748Scperciva echo "as part of updating to ${RELNUM}-p${RELPATCHNUM}:" 1947161748Scperciva cat files.removed 1948217767Sgordon fi | $PAGER 1949161748Scperciva rm files.removed 1950161748Scperciva 1951161748Scperciva # Report added files, if any 1952161748Scperciva if [ -s files.added ]; then 1953161748Scperciva echo 1954161748Scperciva echo -n "The following files will be added " 1955161748Scperciva echo "as part of updating to ${RELNUM}-p${RELPATCHNUM}:" 1956161748Scperciva cat files.added 1957217767Sgordon fi | $PAGER 1958161748Scperciva rm files.added 1959161748Scperciva 1960161748Scperciva # Report updated files, if any 1961161748Scperciva if [ -s files.updated ]; then 1962161748Scperciva echo 1963161748Scperciva echo -n "The following files will be updated " 1964161748Scperciva echo "as part of updating to ${RELNUM}-p${RELPATCHNUM}:" 1965161748Scperciva 1966161748Scperciva cat files.updated 1967217767Sgordon fi | $PAGER 1968161748Scperciva rm files.updated 1969161748Scperciva 1970161748Scperciva # Create a directory for the install manifest. 1971161748Scperciva MDIR=`mktemp -d install.XXXXXX` || return 1 1972161748Scperciva 1973161748Scperciva # Populate it 1974161748Scperciva mv INDEX-PRESENT ${MDIR}/INDEX-OLD 1975161748Scperciva mv INDEX-NEW ${MDIR}/INDEX-NEW 1976161748Scperciva 1977161748Scperciva # Link it into place 1978161748Scperciva ln -s ${MDIR} ${BDHASH}-install 1979161748Scperciva} 1980161748Scperciva 1981161748Scperciva# Warn about any upcoming EoL 1982161748Scpercivafetch_warn_eol () { 1983161748Scperciva # What's the current time? 1984161748Scperciva NOWTIME=`date "+%s"` 1985161748Scperciva 1986161748Scperciva # When did we last warn about the EoL date? 1987161748Scperciva if [ -f lasteolwarn ]; then 1988161748Scperciva LASTWARN=`cat lasteolwarn` 1989161748Scperciva else 1990161748Scperciva LASTWARN=`expr ${NOWTIME} - 63072000` 1991161748Scperciva fi 1992161748Scperciva 1993161748Scperciva # If the EoL time is past, warn. 1994161748Scperciva if [ ${EOLTIME} -lt ${NOWTIME} ]; then 1995161748Scperciva echo 1996161748Scperciva cat <<-EOF 1997161869Scperciva WARNING: `uname -sr` HAS PASSED ITS END-OF-LIFE DATE. 1998161748Scperciva Any security issues discovered after `date -r ${EOLTIME}` 1999161748Scperciva will not have been corrected. 2000161748Scperciva EOF 2001161748Scperciva return 1 2002161748Scperciva fi 2003161748Scperciva 2004161748Scperciva # Figure out how long it has been since we last warned about the 2005161748Scperciva # upcoming EoL, and how much longer we have left. 2006161748Scperciva SINCEWARN=`expr ${NOWTIME} - ${LASTWARN}` 2007161748Scperciva TIMELEFT=`expr ${EOLTIME} - ${NOWTIME}` 2008161748Scperciva 2009171838Scperciva # Don't warn if the EoL is more than 3 months away 2010171838Scperciva if [ ${TIMELEFT} -gt 7884000 ]; then 2011161748Scperciva return 0 2012161748Scperciva fi 2013161748Scperciva 2014161748Scperciva # Don't warn if the time remaining is more than 3 times the time 2015161748Scperciva # since the last warning. 2016161748Scperciva if [ ${TIMELEFT} -gt `expr ${SINCEWARN} \* 3` ]; then 2017161748Scperciva return 0 2018161748Scperciva fi 2019161748Scperciva 2020161748Scperciva # Figure out what time units to use. 2021161748Scperciva if [ ${TIMELEFT} -lt 604800 ]; then 2022161748Scperciva UNIT="day" 2023161748Scperciva SIZE=86400 2024161748Scperciva elif [ ${TIMELEFT} -lt 2678400 ]; then 2025161748Scperciva UNIT="week" 2026161748Scperciva SIZE=604800 2027161748Scperciva else 2028161748Scperciva UNIT="month" 2029161748Scperciva SIZE=2678400 2030161748Scperciva fi 2031161748Scperciva 2032161748Scperciva # Compute the right number of units 2033161748Scperciva NUM=`expr ${TIMELEFT} / ${SIZE}` 2034161748Scperciva if [ ${NUM} != 1 ]; then 2035161748Scperciva UNIT="${UNIT}s" 2036161748Scperciva fi 2037161748Scperciva 2038161748Scperciva # Print the warning 2039161748Scperciva echo 2040161748Scperciva cat <<-EOF 2041161748Scperciva WARNING: `uname -sr` is approaching its End-of-Life date. 2042161748Scperciva It is strongly recommended that you upgrade to a newer 2043161748Scperciva release within the next ${NUM} ${UNIT}. 2044161748Scperciva EOF 2045161748Scperciva 2046161748Scperciva # Update the stored time of last warning 2047161748Scperciva echo ${NOWTIME} > lasteolwarn 2048161748Scperciva} 2049161748Scperciva 2050161748Scperciva# Do the actual work involved in "fetch" / "cron". 2051161748Scpercivafetch_run () { 2052161748Scperciva workdir_init || return 1 2053161748Scperciva 2054161748Scperciva # Prepare the mirror list. 2055161748Scperciva fetch_pick_server_init && fetch_pick_server 2056161748Scperciva 2057161748Scperciva # Try to fetch the public key until we run out of servers. 2058161748Scperciva while ! fetch_key; do 2059161748Scperciva fetch_pick_server || return 1 2060161748Scperciva done 2061161748Scperciva 2062161748Scperciva # Try to fetch the metadata index signature ("tag") until we run 2063161748Scperciva # out of available servers; and sanity check the downloaded tag. 2064161748Scperciva while ! fetch_tag; do 2065161748Scperciva fetch_pick_server || return 1 2066161748Scperciva done 2067161748Scperciva fetch_tagsanity || return 1 2068161748Scperciva 2069161748Scperciva # Fetch the latest INDEX-NEW and INDEX-OLD files. 2070161748Scperciva fetch_metadata INDEX-NEW INDEX-OLD || return 1 2071161748Scperciva 2072161748Scperciva # Generate filtered INDEX-NEW and INDEX-OLD files containing only 2073161748Scperciva # the lines which (a) belong to components we care about, and (b) 2074161748Scperciva # don't correspond to paths we're explicitly ignoring. 2075161748Scperciva fetch_filter_metadata INDEX-NEW || return 1 2076161748Scperciva fetch_filter_metadata INDEX-OLD || return 1 2077161748Scperciva 2078173564Scperciva # Translate /boot/${KERNCONF} into ${KERNELDIR} 2079173564Scperciva fetch_filter_kernel_names INDEX-NEW ${KERNCONF} 2080173564Scperciva fetch_filter_kernel_names INDEX-OLD ${KERNCONF} 2081161748Scperciva 2082161748Scperciva # For all paths appearing in INDEX-OLD or INDEX-NEW, inspect the 2083161748Scperciva # system and generate an INDEX-PRESENT file. 2084161748Scperciva fetch_inspect_system INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1 2085161748Scperciva 2086161748Scperciva # Based on ${UPDATEIFUNMODIFIED}, remove lines from INDEX-* which 2087161748Scperciva # correspond to lines in INDEX-PRESENT with hashes not appearing 2088161748Scperciva # in INDEX-OLD or INDEX-NEW. Also remove lines where the entry in 2089161748Scperciva # INDEX-PRESENT has type - and there isn't a corresponding entry in 2090161748Scperciva # INDEX-OLD with type -. 2091173564Scperciva fetch_filter_unmodified_notpresent \ 2092173564Scperciva INDEX-OLD INDEX-PRESENT INDEX-NEW /dev/null 2093161748Scperciva 2094161748Scperciva # For each entry in INDEX-PRESENT of type -, remove any corresponding 2095161748Scperciva # entry from INDEX-NEW if ${ALLOWADD} != "yes". Remove all entries 2096161748Scperciva # of type - from INDEX-PRESENT. 2097161748Scperciva fetch_filter_allowadd INDEX-PRESENT INDEX-NEW 2098161748Scperciva 2099161748Scperciva # If ${ALLOWDELETE} != "yes", then remove any entries from 2100161748Scperciva # INDEX-PRESENT which don't correspond to entries in INDEX-NEW. 2101161748Scperciva fetch_filter_allowdelete INDEX-PRESENT INDEX-NEW 2102161748Scperciva 2103161748Scperciva # If ${KEEPMODIFIEDMETADATA} == "yes", then for each entry in 2104161748Scperciva # INDEX-PRESENT with metadata not matching any entry in INDEX-OLD, 2105161748Scperciva # replace the corresponding line of INDEX-NEW with one having the 2106161748Scperciva # same metadata as the entry in INDEX-PRESENT. 2107161748Scperciva fetch_filter_modified_metadata INDEX-OLD INDEX-PRESENT INDEX-NEW 2108161748Scperciva 2109161748Scperciva # Remove lines from INDEX-PRESENT and INDEX-NEW which are identical; 2110161748Scperciva # no need to update a file if it isn't changing. 2111161748Scperciva fetch_filter_uptodate INDEX-PRESENT INDEX-NEW 2112161748Scperciva 2113161748Scperciva # Prepare to fetch files: Generate a list of the files we need, 2114161748Scperciva # copy the unmodified files we have into /files/, and generate 2115161748Scperciva # a list of patches to download. 2116171784Scperciva fetch_files_prepare INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1 2117161748Scperciva 2118161748Scperciva # Fetch files. 2119161748Scperciva fetch_files || return 1 2120161748Scperciva 2121161748Scperciva # Create and populate install manifest directory; and report what 2122161748Scperciva # updates are available. 2123161748Scperciva fetch_create_manifest || return 1 2124161748Scperciva 2125161748Scperciva # Warn about any upcoming EoL 2126161748Scperciva fetch_warn_eol || return 1 2127161748Scperciva} 2128161748Scperciva 2129173564Scperciva# If StrictComponents is not "yes", generate a new components list 2130173564Scperciva# with only the components which appear to be installed. 2131173564Scpercivaupgrade_guess_components () { 2132173564Scperciva if [ "${STRICTCOMPONENTS}" = "no" ]; then 2133173564Scperciva # Generate filtered INDEX-ALL with only the components listed 2134173564Scperciva # in COMPONENTS. 2135173564Scperciva fetch_filter_metadata_components $1 || return 1 2136173564Scperciva 2137173564Scperciva # Tell the user why his disk is suddenly making lots of noise 2138173564Scperciva echo -n "Inspecting system... " 2139173564Scperciva 2140173564Scperciva # Look at the files on disk, and assume that a component is 2141173564Scperciva # supposed to be present if it is more than half-present. 2142173564Scperciva cut -f 1-3 -d '|' < INDEX-ALL | 2143173564Scperciva tr '|' ' ' | 2144173564Scperciva while read C S F; do 2145173564Scperciva if [ -e ${BASEDIR}/${F} ]; then 2146173564Scperciva echo "+ ${C}|${S}" 2147173564Scperciva fi 2148173564Scperciva echo "= ${C}|${S}" 2149173564Scperciva done | 2150173564Scperciva sort | 2151173564Scperciva uniq -c | 2152173564Scperciva sed -E 's,^ +,,' > compfreq 2153173564Scperciva grep ' = ' compfreq | 2154173564Scperciva cut -f 1,3 -d ' ' | 2155173564Scperciva sort -k 2,2 -t ' ' > compfreq.total 2156173564Scperciva grep ' + ' compfreq | 2157173564Scperciva cut -f 1,3 -d ' ' | 2158173564Scperciva sort -k 2,2 -t ' ' > compfreq.present 2159173564Scperciva join -t ' ' -1 2 -2 2 compfreq.present compfreq.total | 2160173564Scperciva while read S P T; do 2161173564Scperciva if [ ${P} -gt `expr ${T} / 2` ]; then 2162173564Scperciva echo ${S} 2163173564Scperciva fi 2164173564Scperciva done > comp.present 2165173564Scperciva cut -f 2 -d ' ' < compfreq.total > comp.total 2166173564Scperciva rm INDEX-ALL compfreq compfreq.total compfreq.present 2167173564Scperciva 2168173564Scperciva # We're done making noise. 2169173564Scperciva echo "done." 2170173564Scperciva 2171173564Scperciva # Sometimes the kernel isn't installed where INDEX-ALL 2172173564Scperciva # thinks that it should be: In particular, it is often in 2173173564Scperciva # /boot/kernel instead of /boot/GENERIC or /boot/SMP. To 2174173564Scperciva # deal with this, if "kernel|X" is listed in comp.total 2175173564Scperciva # (i.e., is a component which would be upgraded if it is 2176173564Scperciva # found to be present) we will add it to comp.present. 2177173564Scperciva # If "kernel|<anything>" is in comp.total but "kernel|X" is 2178173564Scperciva # not, we print a warning -- the user is running a kernel 2179173564Scperciva # which isn't part of the release. 2180173564Scperciva KCOMP=`echo ${KERNCONF} | tr 'A-Z' 'a-z'` 2181173564Scperciva grep -E "^kernel\|${KCOMP}\$" comp.total >> comp.present 2182173564Scperciva 2183173564Scperciva if grep -qE "^kernel\|" comp.total && 2184173564Scperciva ! grep -qE "^kernel\|${KCOMP}\$" comp.total; then 2185173564Scperciva cat <<-EOF 2186173564Scperciva 2187173564ScpercivaWARNING: This system is running a "${KCOMP}" kernel, which is not a 2188173564Scpercivakernel configuration distributed as part of FreeBSD ${RELNUM}. 2189173564ScpercivaThis kernel will not be updated: you MUST update the kernel manually 2190173564Scpercivabefore running "$0 install". 2191173564Scperciva EOF 2192173564Scperciva fi 2193173564Scperciva 2194173564Scperciva # Re-sort the list of installed components and generate 2195173564Scperciva # the list of non-installed components. 2196173564Scperciva sort -u < comp.present > comp.present.tmp 2197173564Scperciva mv comp.present.tmp comp.present 2198173564Scperciva comm -13 comp.present comp.total > comp.absent 2199173564Scperciva 2200173564Scperciva # Ask the user to confirm that what we have is correct. To 2201173564Scperciva # reduce user confusion, translate "X|Y" back to "X/Y" (as 2202173564Scperciva # subcomponents must be listed in the configuration file). 2203173564Scperciva echo 2204173564Scperciva echo -n "The following components of FreeBSD " 2205173564Scperciva echo "seem to be installed:" 2206173564Scperciva tr '|' '/' < comp.present | 2207173564Scperciva fmt -72 2208173564Scperciva echo 2209173564Scperciva echo -n "The following components of FreeBSD " 2210173564Scperciva echo "do not seem to be installed:" 2211173564Scperciva tr '|' '/' < comp.absent | 2212173564Scperciva fmt -72 2213173564Scperciva echo 2214173564Scperciva continuep || return 1 2215173564Scperciva echo 2216173564Scperciva 2217173564Scperciva # Suck the generated list of components into ${COMPONENTS}. 2218173564Scperciva # Note that comp.present.tmp is used due to issues with 2219173564Scperciva # pipelines and setting variables. 2220173564Scperciva COMPONENTS="" 2221173564Scperciva tr '|' '/' < comp.present > comp.present.tmp 2222173564Scperciva while read C; do 2223173564Scperciva COMPONENTS="${COMPONENTS} ${C}" 2224173564Scperciva done < comp.present.tmp 2225173564Scperciva 2226173564Scperciva # Delete temporary files 2227173564Scperciva rm comp.present comp.present.tmp comp.absent comp.total 2228173564Scperciva fi 2229173564Scperciva} 2230173564Scperciva 2231173564Scperciva# If StrictComponents is not "yes", COMPONENTS contains an entry 2232173564Scperciva# corresponding to the currently running kernel, and said kernel 2233173564Scperciva# does not exist in the new release, add "kernel/generic" to the 2234173564Scperciva# list of components. 2235173564Scpercivaupgrade_guess_new_kernel () { 2236173564Scperciva if [ "${STRICTCOMPONENTS}" = "no" ]; then 2237173564Scperciva # Grab the unfiltered metadata file. 2238173564Scperciva METAHASH=`look "$1|" tINDEX.present | cut -f 2 -d '|'` 2239173564Scperciva gunzip -c < files/${METAHASH}.gz > $1.all 2240173564Scperciva 2241173564Scperciva # If "kernel/${KCOMP}" is in ${COMPONENTS} and that component 2242173564Scperciva # isn't in $1.all, we need to add kernel/generic. 2243173564Scperciva for C in ${COMPONENTS}; do 2244173564Scperciva if [ ${C} = "kernel/${KCOMP}" ] && 2245173564Scperciva ! grep -qE "^kernel\|${KCOMP}\|" $1.all; then 2246173564Scperciva COMPONENTS="${COMPONENTS} kernel/generic" 2247173564Scperciva NKERNCONF="GENERIC" 2248173564Scperciva cat <<-EOF 2249173564Scperciva 2250173564ScpercivaWARNING: This system is running a "${KCOMP}" kernel, which is not a 2251173564Scpercivakernel configuration distributed as part of FreeBSD ${RELNUM}. 2252173564ScpercivaAs part of upgrading to FreeBSD ${RELNUM}, this kernel will be 2253173564Scpercivareplaced with a "generic" kernel. 2254173564Scperciva EOF 2255173564Scperciva continuep || return 1 2256173564Scperciva fi 2257173564Scperciva done 2258173564Scperciva 2259173564Scperciva # Don't need this any more... 2260173564Scperciva rm $1.all 2261173564Scperciva fi 2262173564Scperciva} 2263173564Scperciva 2264173564Scperciva# Convert INDEX-OLD (last release) and INDEX-ALL (new release) into 2265173564Scperciva# INDEX-OLD and INDEX-NEW files (in the sense of normal upgrades). 2266173564Scpercivaupgrade_oldall_to_oldnew () { 2267173564Scperciva # For each ${F}|... which appears in INDEX-ALL but does not appear 2268173564Scperciva # in INDEX-OLD, add ${F}|-|||||| to INDEX-OLD. 2269173564Scperciva cut -f 1 -d '|' < $1 | 2270173564Scperciva sort -u > $1.paths 2271173564Scperciva cut -f 1 -d '|' < $2 | 2272173564Scperciva sort -u | 2273173564Scperciva comm -13 $1.paths - | 2274173564Scperciva lam - -s "|-||||||" | 2275173564Scperciva sort - $1 > $1.tmp 2276173564Scperciva mv $1.tmp $1 2277173564Scperciva 2278173564Scperciva # Remove lines from INDEX-OLD which also appear in INDEX-ALL 2279173564Scperciva comm -23 $1 $2 > $1.tmp 2280173564Scperciva mv $1.tmp $1 2281173564Scperciva 2282173564Scperciva # Remove lines from INDEX-ALL which have a file name not appearing 2283173564Scperciva # anywhere in INDEX-OLD (since these must be files which haven't 2284173564Scperciva # changed -- if they were new, there would be an entry of type "-"). 2285173564Scperciva cut -f 1 -d '|' < $1 | 2286173564Scperciva sort -u > $1.paths 2287173564Scperciva sort -k 1,1 -t '|' < $2 | 2288173564Scperciva join -t '|' - $1.paths | 2289173564Scperciva sort > $2.tmp 2290173564Scperciva rm $1.paths 2291173564Scperciva mv $2.tmp $2 2292173564Scperciva 2293173564Scperciva # Rename INDEX-ALL to INDEX-NEW. 2294173564Scperciva mv $2 $3 2295173564Scperciva} 2296173564Scperciva 2297221780Scperciva# Helper for upgrade_merge: Return zero true iff the two files differ only 2298284937Sdelphij# in the contents of their RCS tags. 2299221780Scpercivasamef () { 2300221780Scperciva X=`sed -E 's/\\$FreeBSD.*\\$/\$FreeBSD\$/' < $1 | ${SHA256}` 2301221780Scperciva Y=`sed -E 's/\\$FreeBSD.*\\$/\$FreeBSD\$/' < $2 | ${SHA256}` 2302221780Scperciva 2303221780Scperciva if [ $X = $Y ]; then 2304221780Scperciva return 0; 2305221780Scperciva else 2306221780Scperciva return 1; 2307221780Scperciva fi 2308221780Scperciva} 2309221780Scperciva 2310173564Scperciva# From the list of "old" files in $1, merge changes in $2 with those in $3, 2311173564Scperciva# and update $3 to reflect the hashes of merged files. 2312173564Scpercivaupgrade_merge () { 2313173564Scperciva # We only need to do anything if $1 is non-empty. 2314173564Scperciva if [ -s $1 ]; then 2315173564Scperciva cut -f 1 -d '|' $1 | 2316173564Scperciva sort > $1-paths 2317173564Scperciva 2318173564Scperciva # Create staging area for merging files 2319173564Scperciva rm -rf merge/ 2320173564Scperciva while read F; do 2321173564Scperciva D=`dirname ${F}` 2322173564Scperciva mkdir -p merge/old/${D} 2323173564Scperciva mkdir -p merge/${OLDRELNUM}/${D} 2324173564Scperciva mkdir -p merge/${RELNUM}/${D} 2325173564Scperciva mkdir -p merge/new/${D} 2326173564Scperciva done < $1-paths 2327173564Scperciva 2328173564Scperciva # Copy in files 2329173564Scperciva while read F; do 2330173564Scperciva # Currently installed file 2331173564Scperciva V=`look "${F}|" $2 | cut -f 7 -d '|'` 2332173564Scperciva gunzip < files/${V}.gz > merge/old/${F} 2333173564Scperciva 2334173564Scperciva # Old release 2335173564Scperciva if look "${F}|" $1 | fgrep -q "|f|"; then 2336173564Scperciva V=`look "${F}|" $1 | cut -f 3 -d '|'` 2337173564Scperciva gunzip < files/${V}.gz \ 2338173564Scperciva > merge/${OLDRELNUM}/${F} 2339173564Scperciva fi 2340173564Scperciva 2341173564Scperciva # New release 2342173564Scperciva if look "${F}|" $3 | cut -f 1,2,7 -d '|' | 2343173564Scperciva fgrep -q "|f|"; then 2344173564Scperciva V=`look "${F}|" $3 | cut -f 7 -d '|'` 2345173564Scperciva gunzip < files/${V}.gz \ 2346173564Scperciva > merge/${RELNUM}/${F} 2347173564Scperciva fi 2348173564Scperciva done < $1-paths 2349173564Scperciva 2350173564Scperciva # Attempt to automatically merge changes 2351173564Scperciva echo -n "Attempting to automatically merge " 2352173564Scperciva echo -n "changes in files..." 2353173564Scperciva : > failed.merges 2354173564Scperciva while read F; do 2355173564Scperciva # If the file doesn't exist in the new release, 2356173564Scperciva # the result of "merging changes" is having the file 2357173564Scperciva # not exist. 2358173564Scperciva if ! [ -f merge/${RELNUM}/${F} ]; then 2359173564Scperciva continue 2360173564Scperciva fi 2361173564Scperciva 2362173564Scperciva # If the file didn't exist in the old release, we're 2363173564Scperciva # going to throw away the existing file and hope that 2364173564Scperciva # the version from the new release is what we want. 2365173564Scperciva if ! [ -f merge/${OLDRELNUM}/${F} ]; then 2366173564Scperciva cp merge/${RELNUM}/${F} merge/new/${F} 2367173564Scperciva continue 2368173564Scperciva fi 2369173564Scperciva 2370173564Scperciva # Some files need special treatment. 2371173564Scperciva case ${F} in 2372173564Scperciva /etc/spwd.db | /etc/pwd.db | /etc/login.conf.db) 2373173564Scperciva # Don't merge these -- we're rebuild them 2374173564Scperciva # after updates are installed. 2375173564Scperciva cp merge/old/${F} merge/new/${F} 2376173564Scperciva ;; 2377173564Scperciva *) 2378173564Scperciva if ! merge -p -L "current version" \ 2379173564Scperciva -L "${OLDRELNUM}" -L "${RELNUM}" \ 2380173564Scperciva merge/old/${F} \ 2381173564Scperciva merge/${OLDRELNUM}/${F} \ 2382173564Scperciva merge/${RELNUM}/${F} \ 2383173564Scperciva > merge/new/${F} 2>/dev/null; then 2384173564Scperciva echo ${F} >> failed.merges 2385173564Scperciva fi 2386173564Scperciva ;; 2387173564Scperciva esac 2388173564Scperciva done < $1-paths 2389173564Scperciva echo " done." 2390173564Scperciva 2391173564Scperciva # Ask the user to handle any files which didn't merge. 2392173564Scperciva while read F; do 2393221780Scperciva # If the installed file differs from the version in 2394284937Sdelphij # the old release only due to RCS tag expansion 2395221780Scperciva # then just use the version in the new release. 2396221780Scperciva if samef merge/old/${F} merge/${OLDRELNUM}/${F}; then 2397221780Scperciva cp merge/${RELNUM}/${F} merge/new/${F} 2398221780Scperciva continue 2399221780Scperciva fi 2400221780Scperciva 2401173564Scperciva cat <<-EOF 2402173564Scperciva 2403173564ScpercivaThe following file could not be merged automatically: ${F} 2404173564ScpercivaPress Enter to edit this file in ${EDITOR} and resolve the conflicts 2405173564Scpercivamanually... 2406173564Scperciva EOF 2407173564Scperciva read dummy </dev/tty 2408173564Scperciva ${EDITOR} `pwd`/merge/new/${F} < /dev/tty 2409173564Scperciva done < failed.merges 2410173564Scperciva rm failed.merges 2411173564Scperciva 2412173564Scperciva # Ask the user to confirm that he likes how the result 2413173564Scperciva # of merging files. 2414173564Scperciva while read F; do 2415221780Scperciva # Skip files which haven't changed except possibly 2416284937Sdelphij # in their RCS tags. 2417221780Scperciva if [ -f merge/old/${F} ] && [ -f merge/new/${F} ] && 2418221780Scperciva samef merge/old/${F} merge/new/${F}; then 2419173564Scperciva continue 2420173564Scperciva fi 2421173564Scperciva 2422221780Scperciva # Skip files where the installed file differs from 2423284937Sdelphij # the old file only due to RCS tags. 2424221780Scperciva if [ -f merge/old/${F} ] && 2425221780Scperciva [ -f merge/${OLDRELNUM}/${F} ] && 2426221780Scperciva samef merge/old/${F} merge/${OLDRELNUM}/${F}; then 2427221780Scperciva continue 2428221780Scperciva fi 2429221780Scperciva 2430173564Scperciva # Warn about files which are ceasing to exist. 2431173564Scperciva if ! [ -f merge/new/${F} ]; then 2432173564Scperciva cat <<-EOF 2433173564Scperciva 2434173564ScpercivaThe following file will be removed, as it no longer exists in 2435173564ScpercivaFreeBSD ${RELNUM}: ${F} 2436173564Scperciva EOF 2437173564Scperciva continuep < /dev/tty || return 1 2438173564Scperciva continue 2439173564Scperciva fi 2440173564Scperciva 2441173564Scperciva # Print changes for the user's approval. 2442173564Scperciva cat <<-EOF 2443173564Scperciva 2444173564ScpercivaThe following changes, which occurred between FreeBSD ${OLDRELNUM} and 2445173564ScpercivaFreeBSD ${RELNUM} have been merged into ${F}: 2446173564ScpercivaEOF 2447173564Scperciva diff -U 5 -L "current version" -L "new version" \ 2448173564Scperciva merge/old/${F} merge/new/${F} || true 2449173564Scperciva continuep < /dev/tty || return 1 2450173564Scperciva done < $1-paths 2451173564Scperciva 2452173564Scperciva # Store merged files. 2453173564Scperciva while read F; do 2454177527Scperciva if [ -f merge/new/${F} ]; then 2455177527Scperciva V=`${SHA256} -q merge/new/${F}` 2456173564Scperciva 2457173564Scperciva gzip -c < merge/new/${F} > files/${V}.gz 2458173564Scperciva echo "${F}|${V}" 2459173564Scperciva fi 2460173564Scperciva done < $1-paths > newhashes 2461173564Scperciva 2462173564Scperciva # Pull lines out from $3 which need to be updated to 2463173564Scperciva # reflect merged files. 2464173564Scperciva while read F; do 2465173564Scperciva look "${F}|" $3 2466173564Scperciva done < $1-paths > $3-oldlines 2467173564Scperciva 2468173564Scperciva # Update lines to reflect merged files 2469173564Scperciva join -t '|' -o 1.1,1.2,1.3,1.4,1.5,1.6,2.2,1.8 \ 2470173564Scperciva $3-oldlines newhashes > $3-newlines 2471173564Scperciva 2472173564Scperciva # Remove old lines from $3 and add new lines. 2473173564Scperciva sort $3-oldlines | 2474173564Scperciva comm -13 - $3 | 2475173564Scperciva sort - $3-newlines > $3.tmp 2476173564Scperciva mv $3.tmp $3 2477173564Scperciva 2478173564Scperciva # Clean up 2479173564Scperciva rm $1-paths newhashes $3-oldlines $3-newlines 2480173564Scperciva rm -rf merge/ 2481173564Scperciva fi 2482173564Scperciva 2483173564Scperciva # We're done with merging files. 2484173564Scperciva rm $1 2485173564Scperciva} 2486173564Scperciva 2487173564Scperciva# Do the work involved in fetching upgrades to a new release 2488173564Scpercivaupgrade_run () { 2489173564Scperciva workdir_init || return 1 2490173564Scperciva 2491173564Scperciva # Prepare the mirror list. 2492173564Scperciva fetch_pick_server_init && fetch_pick_server 2493173564Scperciva 2494173564Scperciva # Try to fetch the public key until we run out of servers. 2495173564Scperciva while ! fetch_key; do 2496173564Scperciva fetch_pick_server || return 1 2497173564Scperciva done 2498173564Scperciva 2499173564Scperciva # Try to fetch the metadata index signature ("tag") until we run 2500173564Scperciva # out of available servers; and sanity check the downloaded tag. 2501173564Scperciva while ! fetch_tag; do 2502173564Scperciva fetch_pick_server || return 1 2503173564Scperciva done 2504173564Scperciva fetch_tagsanity || return 1 2505173564Scperciva 2506173564Scperciva # Fetch the INDEX-OLD and INDEX-ALL. 2507173564Scperciva fetch_metadata INDEX-OLD INDEX-ALL || return 1 2508173564Scperciva 2509173564Scperciva # If StrictComponents is not "yes", generate a new components list 2510173564Scperciva # with only the components which appear to be installed. 2511173564Scperciva upgrade_guess_components INDEX-ALL || return 1 2512173564Scperciva 2513173564Scperciva # Generate filtered INDEX-OLD and INDEX-ALL files containing only 2514173564Scperciva # the components we want and without anything marked as "Ignore". 2515173564Scperciva fetch_filter_metadata INDEX-OLD || return 1 2516173564Scperciva fetch_filter_metadata INDEX-ALL || return 1 2517173564Scperciva 2518173564Scperciva # Merge the INDEX-OLD and INDEX-ALL files into INDEX-OLD. 2519173564Scperciva sort INDEX-OLD INDEX-ALL > INDEX-OLD.tmp 2520173564Scperciva mv INDEX-OLD.tmp INDEX-OLD 2521173564Scperciva rm INDEX-ALL 2522173564Scperciva 2523173564Scperciva # Adjust variables for fetching files from the new release. 2524173564Scperciva OLDRELNUM=${RELNUM} 2525173564Scperciva RELNUM=${TARGETRELEASE} 2526173564Scperciva OLDFETCHDIR=${FETCHDIR} 2527173564Scperciva FETCHDIR=${RELNUM}/${ARCH} 2528173564Scperciva 2529173564Scperciva # Try to fetch the NEW metadata index signature ("tag") until we run 2530173564Scperciva # out of available servers; and sanity check the downloaded tag. 2531173564Scperciva while ! fetch_tag; do 2532173564Scperciva fetch_pick_server || return 1 2533173564Scperciva done 2534173564Scperciva 2535173564Scperciva # Fetch the new INDEX-ALL. 2536173564Scperciva fetch_metadata INDEX-ALL || return 1 2537173564Scperciva 2538173564Scperciva # If StrictComponents is not "yes", COMPONENTS contains an entry 2539173564Scperciva # corresponding to the currently running kernel, and said kernel 2540173564Scperciva # does not exist in the new release, add "kernel/generic" to the 2541173564Scperciva # list of components. 2542173564Scperciva upgrade_guess_new_kernel INDEX-ALL || return 1 2543173564Scperciva 2544173564Scperciva # Filter INDEX-ALL to contain only the components we want and without 2545173564Scperciva # anything marked as "Ignore". 2546173564Scperciva fetch_filter_metadata INDEX-ALL || return 1 2547173564Scperciva 2548173564Scperciva # Convert INDEX-OLD (last release) and INDEX-ALL (new release) into 2549173564Scperciva # INDEX-OLD and INDEX-NEW files (in the sense of normal upgrades). 2550173564Scperciva upgrade_oldall_to_oldnew INDEX-OLD INDEX-ALL INDEX-NEW 2551173564Scperciva 2552173564Scperciva # Translate /boot/${KERNCONF} or /boot/${NKERNCONF} into ${KERNELDIR} 2553173564Scperciva fetch_filter_kernel_names INDEX-NEW ${NKERNCONF} 2554173564Scperciva fetch_filter_kernel_names INDEX-OLD ${KERNCONF} 2555173564Scperciva 2556173564Scperciva # For all paths appearing in INDEX-OLD or INDEX-NEW, inspect the 2557173564Scperciva # system and generate an INDEX-PRESENT file. 2558173564Scperciva fetch_inspect_system INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1 2559173564Scperciva 2560173564Scperciva # Based on ${MERGECHANGES}, generate a file tomerge-old with the 2561173564Scperciva # paths and hashes of old versions of files to merge. 2562173564Scperciva fetch_filter_mergechanges INDEX-OLD INDEX-PRESENT tomerge-old 2563173564Scperciva 2564173564Scperciva # Based on ${UPDATEIFUNMODIFIED}, remove lines from INDEX-* which 2565173564Scperciva # correspond to lines in INDEX-PRESENT with hashes not appearing 2566173564Scperciva # in INDEX-OLD or INDEX-NEW. Also remove lines where the entry in 2567173564Scperciva # INDEX-PRESENT has type - and there isn't a corresponding entry in 2568173564Scperciva # INDEX-OLD with type -. 2569173564Scperciva fetch_filter_unmodified_notpresent \ 2570173564Scperciva INDEX-OLD INDEX-PRESENT INDEX-NEW tomerge-old 2571173564Scperciva 2572173564Scperciva # For each entry in INDEX-PRESENT of type -, remove any corresponding 2573173564Scperciva # entry from INDEX-NEW if ${ALLOWADD} != "yes". Remove all entries 2574173564Scperciva # of type - from INDEX-PRESENT. 2575173564Scperciva fetch_filter_allowadd INDEX-PRESENT INDEX-NEW 2576173564Scperciva 2577173564Scperciva # If ${ALLOWDELETE} != "yes", then remove any entries from 2578173564Scperciva # INDEX-PRESENT which don't correspond to entries in INDEX-NEW. 2579173564Scperciva fetch_filter_allowdelete INDEX-PRESENT INDEX-NEW 2580173564Scperciva 2581173564Scperciva # If ${KEEPMODIFIEDMETADATA} == "yes", then for each entry in 2582173564Scperciva # INDEX-PRESENT with metadata not matching any entry in INDEX-OLD, 2583173564Scperciva # replace the corresponding line of INDEX-NEW with one having the 2584173564Scperciva # same metadata as the entry in INDEX-PRESENT. 2585173564Scperciva fetch_filter_modified_metadata INDEX-OLD INDEX-PRESENT INDEX-NEW 2586173564Scperciva 2587173564Scperciva # Remove lines from INDEX-PRESENT and INDEX-NEW which are identical; 2588173564Scperciva # no need to update a file if it isn't changing. 2589173564Scperciva fetch_filter_uptodate INDEX-PRESENT INDEX-NEW 2590173564Scperciva 2591173564Scperciva # Fetch "clean" files from the old release for merging changes. 2592173564Scperciva fetch_files_premerge tomerge-old 2593173564Scperciva 2594173564Scperciva # Prepare to fetch files: Generate a list of the files we need, 2595173564Scperciva # copy the unmodified files we have into /files/, and generate 2596173564Scperciva # a list of patches to download. 2597173564Scperciva fetch_files_prepare INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1 2598173564Scperciva 2599173564Scperciva # Fetch patches from to-${RELNUM}/${ARCH}/bp/ 2600173564Scperciva PATCHDIR=to-${RELNUM}/${ARCH}/bp 2601173564Scperciva fetch_files || return 1 2602173564Scperciva 2603173564Scperciva # Merge configuration file changes. 2604173564Scperciva upgrade_merge tomerge-old INDEX-PRESENT INDEX-NEW || return 1 2605173564Scperciva 2606173564Scperciva # Create and populate install manifest directory; and report what 2607173564Scperciva # updates are available. 2608173564Scperciva fetch_create_manifest || return 1 2609173564Scperciva 2610173564Scperciva # Leave a note behind to tell the "install" command that the kernel 2611173564Scperciva # needs to be installed before the world. 2612173564Scperciva touch ${BDHASH}-install/kernelfirst 2613212431Scperciva 2614212431Scperciva # Remind the user that they need to run "freebsd-update install" 2615212431Scperciva # to install the downloaded bits, in case they didn't RTFM. 2616212431Scperciva echo "To install the downloaded upgrades, run \"$0 install\"." 2617173564Scperciva} 2618173564Scperciva 2619161748Scperciva# Make sure that all the file hashes mentioned in $@ have corresponding 2620161748Scperciva# gzipped files stored in /files/. 2621161748Scpercivainstall_verify () { 2622161748Scperciva # Generate a list of hashes 2623161748Scperciva cat $@ | 2624161748Scperciva cut -f 2,7 -d '|' | 2625161748Scperciva grep -E '^f' | 2626161748Scperciva cut -f 2 -d '|' | 2627161748Scperciva sort -u > filelist 2628161748Scperciva 2629161748Scperciva # Make sure all the hashes exist 2630161748Scperciva while read HASH; do 2631161748Scperciva if ! [ -f files/${HASH}.gz ]; then 2632161748Scperciva echo -n "Update files missing -- " 2633161748Scperciva echo "this should never happen." 2634161748Scperciva echo "Re-run '$0 fetch'." 2635161748Scperciva return 1 2636161748Scperciva fi 2637161748Scperciva done < filelist 2638161748Scperciva 2639161748Scperciva # Clean up 2640161748Scperciva rm filelist 2641161748Scperciva} 2642161748Scperciva 2643161748Scperciva# Remove the system immutable flag from files 2644161748Scpercivainstall_unschg () { 2645161748Scperciva # Generate file list 2646161748Scperciva cat $@ | 2647161748Scperciva cut -f 1 -d '|' > filelist 2648161748Scperciva 2649161748Scperciva # Remove flags 2650161748Scperciva while read F; do 2651169603Scperciva if ! [ -e ${BASEDIR}/${F} ]; then 2652161748Scperciva continue 2653284936Sdelphij else 2654284936Sdelphij echo ${BASEDIR}/${F} 2655161748Scperciva fi 2656284936Sdelphij done < filelist | xargs chflags noschg || return 1 2657161748Scperciva 2658161748Scperciva # Clean up 2659161748Scperciva rm filelist 2660161748Scperciva} 2661161748Scperciva 2662196392Ssimon# Decide which directory name to use for kernel backups. 2663196392Ssimonbackup_kernel_finddir () { 2664196392Ssimon CNT=0 2665196392Ssimon while true ; do 2666196392Ssimon # Pathname does not exist, so it is OK use that name 2667196392Ssimon # for backup directory. 2668279556Sthomas if [ ! -e $BASEDIR/$BACKUPKERNELDIR ]; then 2669196392Ssimon return 0 2670196392Ssimon fi 2671196392Ssimon 2672196392Ssimon # If directory do exist, we only use if it has our 2673196392Ssimon # marker file. 2674279556Sthomas if [ -d $BASEDIR/$BACKUPKERNELDIR -a \ 2675279556Sthomas -e $BASEDIR/$BACKUPKERNELDIR/.freebsd-update ]; then 2676196392Ssimon return 0 2677196392Ssimon fi 2678196392Ssimon 2679196392Ssimon # We could not use current directory name, so add counter to 2680196392Ssimon # the end and try again. 2681196392Ssimon CNT=$((CNT + 1)) 2682196392Ssimon if [ $CNT -gt 9 ]; then 2683279556Sthomas echo "Could not find valid backup dir ($BASEDIR/$BACKUPKERNELDIR)" 2684196392Ssimon exit 1 2685196392Ssimon fi 2686196392Ssimon BACKUPKERNELDIR="`echo $BACKUPKERNELDIR | sed -Ee 's/[0-9]\$//'`" 2687196392Ssimon BACKUPKERNELDIR="${BACKUPKERNELDIR}${CNT}" 2688196392Ssimon done 2689196392Ssimon} 2690196392Ssimon 2691196392Ssimon# Backup the current kernel using hardlinks, if not disabled by user. 2692196392Ssimon# Since we delete all files in the directory used for previous backups 2693196392Ssimon# we create a marker file called ".freebsd-update" in the directory so 2694196392Ssimon# we can determine on the next run that the directory was created by 2695196392Ssimon# freebsd-update and we then do not accidentally remove user files in 2696196392Ssimon# the unlikely case that the user has created a directory with a 2697196392Ssimon# conflicting name. 2698196392Ssimonbackup_kernel () { 2699196392Ssimon # Only make kernel backup is so configured. 2700196392Ssimon if [ $BACKUPKERNEL != yes ]; then 2701196392Ssimon return 0 2702196392Ssimon fi 2703196392Ssimon 2704196392Ssimon # Decide which directory name to use for kernel backups. 2705196392Ssimon backup_kernel_finddir 2706196392Ssimon 2707196392Ssimon # Remove old kernel backup files. If $BACKUPKERNELDIR was 2708196392Ssimon # "not ours", backup_kernel_finddir would have exited, so 2709196392Ssimon # deleting the directory content is as safe as we can make it. 2710279556Sthomas if [ -d $BASEDIR/$BACKUPKERNELDIR ]; then 2711279556Sthomas rm -fr $BASEDIR/$BACKUPKERNELDIR 2712196392Ssimon fi 2713196392Ssimon 2714212505Sjh # Create directories for backup. 2715279556Sthomas mkdir -p $BASEDIR/$BACKUPKERNELDIR 2716279556Sthomas mtree -cdn -p "${BASEDIR}/${KERNELDIR}" | \ 2717279556Sthomas mtree -Ue -p "${BASEDIR}/${BACKUPKERNELDIR}" > /dev/null 2718196392Ssimon 2719196392Ssimon # Mark the directory as having been created by freebsd-update. 2720279556Sthomas touch $BASEDIR/$BACKUPKERNELDIR/.freebsd-update 2721196392Ssimon if [ $? -ne 0 ]; then 2722196392Ssimon echo "Could not create kernel backup directory" 2723196392Ssimon exit 1 2724196392Ssimon fi 2725196392Ssimon 2726196392Ssimon # Disable pathname expansion to be sure *.symbols is not 2727196392Ssimon # expanded. 2728196392Ssimon set -f 2729196392Ssimon 2730196392Ssimon # Use find to ignore symbol files, unless disabled by user. 2731196392Ssimon if [ $BACKUPKERNELSYMBOLFILES = yes ]; then 2732196392Ssimon FINDFILTER="" 2733196392Ssimon else 2734196392Ssimon FINDFILTER=-"a ! -name *.symbols" 2735196392Ssimon fi 2736196392Ssimon 2737196392Ssimon # Backup all the kernel files using hardlinks. 2738279556Sthomas (cd ${BASEDIR}/${KERNELDIR} && find . -type f $FINDFILTER -exec \ 2739279556Sthomas cp -pl '{}' ${BASEDIR}/${BACKUPKERNELDIR}/'{}' \;) 2740196392Ssimon 2741196392Ssimon # Re-enable patchname expansion. 2742196392Ssimon set +f 2743196392Ssimon} 2744196392Ssimon 2745161748Scperciva# Install new files 2746161748Scpercivainstall_from_index () { 2747161748Scperciva # First pass: Do everything apart from setting file flags. We 2748161748Scperciva # can't set flags yet, because schg inhibits hard linking. 2749161748Scperciva sort -k 1,1 -t '|' $1 | 2750161748Scperciva tr '|' ' ' | 2751161748Scperciva while read FPATH TYPE OWNER GROUP PERM FLAGS HASH LINK; do 2752161748Scperciva case ${TYPE} in 2753161748Scperciva d) 2754161748Scperciva # Create a directory 2755161748Scperciva install -d -o ${OWNER} -g ${GROUP} \ 2756161748Scperciva -m ${PERM} ${BASEDIR}/${FPATH} 2757161748Scperciva ;; 2758161748Scperciva f) 2759161748Scperciva if [ -z "${LINK}" ]; then 2760161748Scperciva # Create a file, without setting flags. 2761161748Scperciva gunzip < files/${HASH}.gz > ${HASH} 2762161748Scperciva install -S -o ${OWNER} -g ${GROUP} \ 2763161748Scperciva -m ${PERM} ${HASH} ${BASEDIR}/${FPATH} 2764161748Scperciva rm ${HASH} 2765161748Scperciva else 2766161748Scperciva # Create a hard link. 2767169603Scperciva ln -f ${BASEDIR}/${LINK} ${BASEDIR}/${FPATH} 2768161748Scperciva fi 2769161748Scperciva ;; 2770161748Scperciva L) 2771161748Scperciva # Create a symlink 2772161748Scperciva ln -sfh ${HASH} ${BASEDIR}/${FPATH} 2773161748Scperciva ;; 2774161748Scperciva esac 2775161748Scperciva done 2776161748Scperciva 2777161748Scperciva # Perform a second pass, adding file flags. 2778161748Scperciva tr '|' ' ' < $1 | 2779161748Scperciva while read FPATH TYPE OWNER GROUP PERM FLAGS HASH LINK; do 2780161748Scperciva if [ ${TYPE} = "f" ] && 2781161748Scperciva ! [ ${FLAGS} = "0" ]; then 2782161748Scperciva chflags ${FLAGS} ${BASEDIR}/${FPATH} 2783161748Scperciva fi 2784161748Scperciva done 2785161748Scperciva} 2786161748Scperciva 2787161748Scperciva# Remove files which we want to delete 2788161748Scpercivainstall_delete () { 2789161748Scperciva # Generate list of new files 2790161748Scperciva cut -f 1 -d '|' < $2 | 2791161748Scperciva sort > newfiles 2792161748Scperciva 2793161748Scperciva # Generate subindex of old files we want to nuke 2794161748Scperciva sort -k 1,1 -t '|' $1 | 2795161748Scperciva join -t '|' -v 1 - newfiles | 2796164600Scperciva sort -r -k 1,1 -t '|' | 2797161748Scperciva cut -f 1,2 -d '|' | 2798161748Scperciva tr '|' ' ' > killfiles 2799161748Scperciva 2800161748Scperciva # Remove the offending bits 2801161748Scperciva while read FPATH TYPE; do 2802161748Scperciva case ${TYPE} in 2803161748Scperciva d) 2804161748Scperciva rmdir ${BASEDIR}/${FPATH} 2805161748Scperciva ;; 2806161748Scperciva f) 2807161748Scperciva rm ${BASEDIR}/${FPATH} 2808161748Scperciva ;; 2809161748Scperciva L) 2810161748Scperciva rm ${BASEDIR}/${FPATH} 2811161748Scperciva ;; 2812161748Scperciva esac 2813161748Scperciva done < killfiles 2814161748Scperciva 2815161748Scperciva # Clean up 2816161748Scperciva rm newfiles killfiles 2817161748Scperciva} 2818161748Scperciva 2819173564Scperciva# Install new files, delete old files, and update linker.hints 2820173564Scpercivainstall_files () { 2821173564Scperciva # If we haven't already dealt with the kernel, deal with it. 2822173564Scperciva if ! [ -f $1/kerneldone ]; then 2823173564Scperciva grep -E '^/boot/' $1/INDEX-OLD > INDEX-OLD 2824173564Scperciva grep -E '^/boot/' $1/INDEX-NEW > INDEX-NEW 2825173564Scperciva 2826196392Ssimon # Backup current kernel before installing a new one 2827196392Ssimon backup_kernel || return 1 2828196392Ssimon 2829173564Scperciva # Install new files 2830173564Scperciva install_from_index INDEX-NEW || return 1 2831173564Scperciva 2832173564Scperciva # Remove files which need to be deleted 2833173564Scperciva install_delete INDEX-OLD INDEX-NEW || return 1 2834173564Scperciva 2835173564Scperciva # Update linker.hints if necessary 2836173564Scperciva if [ -s INDEX-OLD -o -s INDEX-NEW ]; then 2837279556Sthomas kldxref -R ${BASEDIR}/boot/ 2>/dev/null 2838173564Scperciva fi 2839173564Scperciva 2840173564Scperciva # We've finished updating the kernel. 2841173564Scperciva touch $1/kerneldone 2842173564Scperciva 2843173564Scperciva # Do we need to ask for a reboot now? 2844173564Scperciva if [ -f $1/kernelfirst ] && 2845173564Scperciva [ -s INDEX-OLD -o -s INDEX-NEW ]; then 2846173564Scperciva cat <<-EOF 2847173564Scperciva 2848173564ScpercivaKernel updates have been installed. Please reboot and run 2849173564Scperciva"$0 install" again to finish installing updates. 2850173564Scperciva EOF 2851173564Scperciva exit 0 2852173564Scperciva fi 2853161748Scperciva fi 2854173564Scperciva 2855173564Scperciva # If we haven't already dealt with the world, deal with it. 2856173564Scperciva if ! [ -f $1/worlddone ]; then 2857257153Scperciva # Create any necessary directories first 2858257153Scperciva grep -vE '^/boot/' $1/INDEX-NEW | 2859257153Scperciva grep -E '^[^|]+\|d\|' > INDEX-NEW 2860257153Scperciva install_from_index INDEX-NEW || return 1 2861257153Scperciva 2862278443Sbrooks # Install new runtime linker 2863278443Sbrooks grep -vE '^/boot/' $1/INDEX-NEW | 2864278443Sbrooks grep -vE '^[^|]+\|d\|' | 2865278443Sbrooks grep -E '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' > INDEX-NEW 2866278443Sbrooks install_from_index INDEX-NEW || return 1 2867278443Sbrooks 2868173564Scperciva # Install new shared libraries next 2869173564Scperciva grep -vE '^/boot/' $1/INDEX-NEW | 2870257153Scperciva grep -vE '^[^|]+\|d\|' | 2871278443Sbrooks grep -vE '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' | 2872257153Scperciva grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-NEW 2873173564Scperciva install_from_index INDEX-NEW || return 1 2874173564Scperciva 2875173564Scperciva # Deal with everything else 2876173564Scperciva grep -vE '^/boot/' $1/INDEX-OLD | 2877257153Scperciva grep -vE '^[^|]+\|d\|' | 2878278443Sbrooks grep -vE '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' | 2879257153Scperciva grep -vE '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-OLD 2880173564Scperciva grep -vE '^/boot/' $1/INDEX-NEW | 2881257153Scperciva grep -vE '^[^|]+\|d\|' | 2882278443Sbrooks grep -vE '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' | 2883257153Scperciva grep -vE '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-NEW 2884173564Scperciva install_from_index INDEX-NEW || return 1 2885173564Scperciva install_delete INDEX-OLD INDEX-NEW || return 1 2886173564Scperciva 2887173564Scperciva # Rebuild /etc/spwd.db and /etc/pwd.db if necessary. 2888279556Sthomas if [ ${BASEDIR}/etc/master.passwd -nt ${BASEDIR}/etc/spwd.db ] || 2889279556Sthomas [ ${BASEDIR}/etc/master.passwd -nt ${BASEDIR}/etc/pwd.db ]; then 2890279556Sthomas pwd_mkdb -d ${BASEDIR}/etc ${BASEDIR}/etc/master.passwd 2891173564Scperciva fi 2892173564Scperciva 2893173564Scperciva # Rebuild /etc/login.conf.db if necessary. 2894279556Sthomas if [ ${BASEDIR}/etc/login.conf -nt ${BASEDIR}/etc/login.conf.db ]; then 2895279556Sthomas cap_mkdb ${BASEDIR}/etc/login.conf 2896173564Scperciva fi 2897173564Scperciva 2898173564Scperciva # We've finished installing the world and deleting old files 2899173564Scperciva # which are not shared libraries. 2900173564Scperciva touch $1/worlddone 2901173564Scperciva 2902173564Scperciva # Do we need to ask the user to portupgrade now? 2903173564Scperciva grep -vE '^/boot/' $1/INDEX-NEW | 2904257153Scperciva grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' | 2905173564Scperciva cut -f 1 -d '|' | 2906173564Scperciva sort > newfiles 2907173564Scperciva if grep -vE '^/boot/' $1/INDEX-OLD | 2908257153Scperciva grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' | 2909173564Scperciva cut -f 1 -d '|' | 2910173564Scperciva sort | 2911173564Scperciva join -v 1 - newfiles | 2912173564Scperciva grep -q .; then 2913173564Scperciva cat <<-EOF 2914173564Scperciva 2915173564ScpercivaCompleting this upgrade requires removing old shared object files. 2916173564ScpercivaPlease rebuild all installed 3rd party software (e.g., programs 2917173564Scpercivainstalled from the ports tree) and then run "$0 install" 2918173564Scpercivaagain to finish installing updates. 2919173564Scperciva EOF 2920173564Scperciva rm newfiles 2921173564Scperciva exit 0 2922173564Scperciva fi 2923173564Scperciva rm newfiles 2924173564Scperciva fi 2925173564Scperciva 2926173564Scperciva # Remove old shared libraries 2927173564Scperciva grep -vE '^/boot/' $1/INDEX-NEW | 2928257153Scperciva grep -vE '^[^|]+\|d\|' | 2929257153Scperciva grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-NEW 2930173564Scperciva grep -vE '^/boot/' $1/INDEX-OLD | 2931257153Scperciva grep -vE '^[^|]+\|d\|' | 2932257153Scperciva grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-OLD 2933173564Scperciva install_delete INDEX-OLD INDEX-NEW || return 1 2934173564Scperciva 2935257153Scperciva # Remove old directories 2936258723Sdelphij grep -vE '^/boot/' $1/INDEX-NEW | 2937258723Sdelphij grep -E '^[^|]+\|d\|' > INDEX-NEW 2938257153Scperciva grep -vE '^/boot/' $1/INDEX-OLD | 2939257153Scperciva grep -E '^[^|]+\|d\|' > INDEX-OLD 2940257153Scperciva install_delete INDEX-OLD INDEX-NEW || return 1 2941257153Scperciva 2942173564Scperciva # Remove temporary files 2943173564Scperciva rm INDEX-OLD INDEX-NEW 2944161748Scperciva} 2945161748Scperciva 2946161748Scperciva# Rearrange bits to allow the installed updates to be rolled back 2947161748Scpercivainstall_setup_rollback () { 2948173564Scperciva # Remove the "reboot after installing kernel", "kernel updated", and 2949173564Scperciva # "finished installing the world" flags if present -- they are 2950173564Scperciva # irrelevant when rolling back updates. 2951173564Scperciva if [ -f ${BDHASH}-install/kernelfirst ]; then 2952173564Scperciva rm ${BDHASH}-install/kernelfirst 2953173564Scperciva rm ${BDHASH}-install/kerneldone 2954173564Scperciva fi 2955173564Scperciva if [ -f ${BDHASH}-install/worlddone ]; then 2956173564Scperciva rm ${BDHASH}-install/worlddone 2957173564Scperciva fi 2958173564Scperciva 2959161748Scperciva if [ -L ${BDHASH}-rollback ]; then 2960161748Scperciva mv ${BDHASH}-rollback ${BDHASH}-install/rollback 2961161748Scperciva fi 2962161748Scperciva 2963161748Scperciva mv ${BDHASH}-install ${BDHASH}-rollback 2964161748Scperciva} 2965161748Scperciva 2966161748Scperciva# Actually install updates 2967161748Scpercivainstall_run () { 2968161748Scperciva echo -n "Installing updates..." 2969161748Scperciva 2970161748Scperciva # Make sure we have all the files we should have 2971161748Scperciva install_verify ${BDHASH}-install/INDEX-OLD \ 2972161748Scperciva ${BDHASH}-install/INDEX-NEW || return 1 2973161748Scperciva 2974161748Scperciva # Remove system immutable flag from files 2975161748Scperciva install_unschg ${BDHASH}-install/INDEX-OLD \ 2976161748Scperciva ${BDHASH}-install/INDEX-NEW || return 1 2977161748Scperciva 2978173564Scperciva # Install new files, delete old files, and update linker.hints 2979173564Scperciva install_files ${BDHASH}-install || return 1 2980161748Scperciva 2981161748Scperciva # Rearrange bits to allow the installed updates to be rolled back 2982161748Scperciva install_setup_rollback 2983161748Scperciva 2984161748Scperciva echo " done." 2985161748Scperciva} 2986161748Scperciva 2987161748Scperciva# Rearrange bits to allow the previous set of updates to be rolled back next. 2988161748Scpercivarollback_setup_rollback () { 2989161748Scperciva if [ -L ${BDHASH}-rollback/rollback ]; then 2990161748Scperciva mv ${BDHASH}-rollback/rollback rollback-tmp 2991161748Scperciva rm -r ${BDHASH}-rollback/ 2992161748Scperciva rm ${BDHASH}-rollback 2993161748Scperciva mv rollback-tmp ${BDHASH}-rollback 2994161748Scperciva else 2995161748Scperciva rm -r ${BDHASH}-rollback/ 2996161748Scperciva rm ${BDHASH}-rollback 2997161748Scperciva fi 2998161748Scperciva} 2999161748Scperciva 3000173564Scperciva# Install old files, delete new files, and update linker.hints 3001173564Scpercivarollback_files () { 3002173671Scperciva # Install old shared library files which don't have the same path as 3003173671Scperciva # a new shared library file. 3004173671Scperciva grep -vE '^/boot/' $1/INDEX-NEW | 3005177601Scperciva grep -E '/lib/.*\.so\.[0-9]+\|' | 3006173671Scperciva cut -f 1 -d '|' | 3007173671Scperciva sort > INDEX-NEW.libs.flist 3008173564Scperciva grep -vE '^/boot/' $1/INDEX-OLD | 3009177601Scperciva grep -E '/lib/.*\.so\.[0-9]+\|' | 3010173671Scperciva sort -k 1,1 -t '|' - | 3011173671Scperciva join -t '|' -v 1 - INDEX-NEW.libs.flist > INDEX-OLD 3012173564Scperciva install_from_index INDEX-OLD || return 1 3013173564Scperciva 3014173564Scperciva # Deal with files which are neither kernel nor shared library 3015173564Scperciva grep -vE '^/boot/' $1/INDEX-OLD | 3016177601Scperciva grep -vE '/lib/.*\.so\.[0-9]+\|' > INDEX-OLD 3017173564Scperciva grep -vE '^/boot/' $1/INDEX-NEW | 3018177601Scperciva grep -vE '/lib/.*\.so\.[0-9]+\|' > INDEX-NEW 3019173564Scperciva install_from_index INDEX-OLD || return 1 3020173564Scperciva install_delete INDEX-NEW INDEX-OLD || return 1 3021173564Scperciva 3022173671Scperciva # Install any old shared library files which we didn't install above. 3023173671Scperciva grep -vE '^/boot/' $1/INDEX-OLD | 3024177601Scperciva grep -E '/lib/.*\.so\.[0-9]+\|' | 3025173671Scperciva sort -k 1,1 -t '|' - | 3026173671Scperciva join -t '|' - INDEX-NEW.libs.flist > INDEX-OLD 3027173671Scperciva install_from_index INDEX-OLD || return 1 3028173671Scperciva 3029173564Scperciva # Delete unneeded shared library files 3030173564Scperciva grep -vE '^/boot/' $1/INDEX-OLD | 3031177601Scperciva grep -E '/lib/.*\.so\.[0-9]+\|' > INDEX-OLD 3032173564Scperciva grep -vE '^/boot/' $1/INDEX-NEW | 3033177601Scperciva grep -E '/lib/.*\.so\.[0-9]+\|' > INDEX-NEW 3034173564Scperciva install_delete INDEX-NEW INDEX-OLD || return 1 3035173564Scperciva 3036173564Scperciva # Deal with kernel files 3037173564Scperciva grep -E '^/boot/' $1/INDEX-OLD > INDEX-OLD 3038173564Scperciva grep -E '^/boot/' $1/INDEX-NEW > INDEX-NEW 3039173564Scperciva install_from_index INDEX-OLD || return 1 3040173564Scperciva install_delete INDEX-NEW INDEX-OLD || return 1 3041173564Scperciva if [ -s INDEX-OLD -o -s INDEX-NEW ]; then 3042173564Scperciva kldxref -R /boot/ 2>/dev/null 3043173564Scperciva fi 3044173564Scperciva 3045173564Scperciva # Remove temporary files 3046173672Scperciva rm INDEX-OLD INDEX-NEW INDEX-NEW.libs.flist 3047173564Scperciva} 3048173564Scperciva 3049161748Scperciva# Actually rollback updates 3050161748Scpercivarollback_run () { 3051161748Scperciva echo -n "Uninstalling updates..." 3052161748Scperciva 3053161748Scperciva # If there are updates waiting to be installed, remove them; we 3054161748Scperciva # want the user to re-run 'fetch' after rolling back updates. 3055161748Scperciva if [ -L ${BDHASH}-install ]; then 3056161748Scperciva rm -r ${BDHASH}-install/ 3057161748Scperciva rm ${BDHASH}-install 3058161748Scperciva fi 3059161748Scperciva 3060161748Scperciva # Make sure we have all the files we should have 3061161748Scperciva install_verify ${BDHASH}-rollback/INDEX-NEW \ 3062161748Scperciva ${BDHASH}-rollback/INDEX-OLD || return 1 3063161748Scperciva 3064161748Scperciva # Remove system immutable flag from files 3065161748Scperciva install_unschg ${BDHASH}-rollback/INDEX-NEW \ 3066161748Scperciva ${BDHASH}-rollback/INDEX-OLD || return 1 3067161748Scperciva 3068173564Scperciva # Install old files, delete new files, and update linker.hints 3069173564Scperciva rollback_files ${BDHASH}-rollback || return 1 3070161748Scperciva 3071161748Scperciva # Remove the rollback directory and the symlink pointing to it; and 3072161748Scperciva # rearrange bits to allow the previous set of updates to be rolled 3073161748Scperciva # back next. 3074161748Scperciva rollback_setup_rollback 3075161748Scperciva 3076161748Scperciva echo " done." 3077161748Scperciva} 3078161748Scperciva 3079181142Scperciva# Compare INDEX-ALL and INDEX-PRESENT and print warnings about differences. 3080181142ScpercivaIDS_compare () { 3081181425Scperciva # Get all the lines which mismatch in something other than file 3082181425Scperciva # flags. We ignore file flags because sysinstall doesn't seem to 3083181425Scperciva # set them when it installs FreeBSD; warning about these adds a 3084181425Scperciva # very large amount of noise. 3085181425Scperciva cut -f 1-5,7-8 -d '|' $1 > $1.noflags 3086181425Scperciva sort -k 1,1 -t '|' $1.noflags > $1.sorted 3087181425Scperciva cut -f 1-5,7-8 -d '|' $2 | 3088181425Scperciva comm -13 $1.noflags - | 3089181425Scperciva fgrep -v '|-|||||' | 3090181142Scperciva sort -k 1,1 -t '|' | 3091181142Scperciva join -t '|' $1.sorted - > INDEX-NOTMATCHING 3092181142Scperciva 3093181142Scperciva # Ignore files which match IDSIGNOREPATHS. 3094181142Scperciva for X in ${IDSIGNOREPATHS}; do 3095181142Scperciva grep -E "^${X}" INDEX-NOTMATCHING 3096181142Scperciva done | 3097181142Scperciva sort -u | 3098181142Scperciva comm -13 - INDEX-NOTMATCHING > INDEX-NOTMATCHING.tmp 3099181142Scperciva mv INDEX-NOTMATCHING.tmp INDEX-NOTMATCHING 3100181142Scperciva 3101181142Scperciva # Go through the lines and print warnings. 3102284939Sdelphij local IFS='|' 3103284939Sdelphij while read FPATH TYPE OWNER GROUP PERM HASH LINK P_TYPE P_OWNER P_GROUP P_PERM P_HASH P_LINK; do 3104181142Scperciva # Warn about different object types. 3105181142Scperciva if ! [ "${TYPE}" = "${P_TYPE}" ]; then 3106181142Scperciva echo -n "${FPATH} is a " 3107181142Scperciva case "${P_TYPE}" in 3108181142Scperciva f) echo -n "regular file, " 3109181142Scperciva ;; 3110181142Scperciva d) echo -n "directory, " 3111181142Scperciva ;; 3112181142Scperciva L) echo -n "symlink, " 3113181142Scperciva ;; 3114181142Scperciva esac 3115181142Scperciva echo -n "but should be a " 3116181142Scperciva case "${TYPE}" in 3117181142Scperciva f) echo -n "regular file." 3118181142Scperciva ;; 3119181142Scperciva d) echo -n "directory." 3120181142Scperciva ;; 3121181142Scperciva L) echo -n "symlink." 3122181142Scperciva ;; 3123181142Scperciva esac 3124181142Scperciva echo 3125181142Scperciva 3126181142Scperciva # Skip other tests, since they don't make sense if 3127181142Scperciva # we're comparing different object types. 3128181142Scperciva continue 3129181142Scperciva fi 3130181142Scperciva 3131181142Scperciva # Warn about different owners. 3132181142Scperciva if ! [ "${OWNER}" = "${P_OWNER}" ]; then 3133181142Scperciva echo -n "${FPATH} is owned by user id ${P_OWNER}, " 3134181142Scperciva echo "but should be owned by user id ${OWNER}." 3135181142Scperciva fi 3136181142Scperciva 3137181142Scperciva # Warn about different groups. 3138181142Scperciva if ! [ "${GROUP}" = "${P_GROUP}" ]; then 3139181142Scperciva echo -n "${FPATH} is owned by group id ${P_GROUP}, " 3140181142Scperciva echo "but should be owned by group id ${GROUP}." 3141181142Scperciva fi 3142181142Scperciva 3143181142Scperciva # Warn about different permissions. We do not warn about 3144181142Scperciva # different permissions on symlinks, since some archivers 3145181142Scperciva # don't extract symlink permissions correctly and they are 3146181142Scperciva # ignored anyway. 3147181142Scperciva if ! [ "${PERM}" = "${P_PERM}" ] && 3148181142Scperciva ! [ "${TYPE}" = "L" ]; then 3149181142Scperciva echo -n "${FPATH} has ${P_PERM} permissions, " 3150181142Scperciva echo "but should have ${PERM} permissions." 3151181142Scperciva fi 3152181142Scperciva 3153181142Scperciva # Warn about different file hashes / symlink destinations. 3154181142Scperciva if ! [ "${HASH}" = "${P_HASH}" ]; then 3155181142Scperciva if [ "${TYPE}" = "L" ]; then 3156181142Scperciva echo -n "${FPATH} is a symlink to ${P_HASH}, " 3157181142Scperciva echo "but should be a symlink to ${HASH}." 3158181142Scperciva fi 3159181142Scperciva if [ "${TYPE}" = "f" ]; then 3160181142Scperciva echo -n "${FPATH} has SHA256 hash ${P_HASH}, " 3161181142Scperciva echo "but should have SHA256 hash ${HASH}." 3162181142Scperciva fi 3163181142Scperciva fi 3164181142Scperciva 3165181142Scperciva # We don't warn about different hard links, since some 3166181142Scperciva # some archivers break hard links, and as long as the 3167181142Scperciva # underlying data is correct they really don't matter. 3168181142Scperciva done < INDEX-NOTMATCHING 3169181142Scperciva 3170181142Scperciva # Clean up 3171181425Scperciva rm $1 $1.noflags $1.sorted $2 INDEX-NOTMATCHING 3172181142Scperciva} 3173181142Scperciva 3174181142Scperciva# Do the work involved in comparing the system to a "known good" index 3175181142ScpercivaIDS_run () { 3176181142Scperciva workdir_init || return 1 3177181142Scperciva 3178181142Scperciva # Prepare the mirror list. 3179181142Scperciva fetch_pick_server_init && fetch_pick_server 3180181142Scperciva 3181181142Scperciva # Try to fetch the public key until we run out of servers. 3182181142Scperciva while ! fetch_key; do 3183181142Scperciva fetch_pick_server || return 1 3184181142Scperciva done 3185181142Scperciva 3186181142Scperciva # Try to fetch the metadata index signature ("tag") until we run 3187181142Scperciva # out of available servers; and sanity check the downloaded tag. 3188181142Scperciva while ! fetch_tag; do 3189181142Scperciva fetch_pick_server || return 1 3190181142Scperciva done 3191181142Scperciva fetch_tagsanity || return 1 3192181142Scperciva 3193181142Scperciva # Fetch INDEX-OLD and INDEX-ALL. 3194181142Scperciva fetch_metadata INDEX-OLD INDEX-ALL || return 1 3195181142Scperciva 3196181142Scperciva # Generate filtered INDEX-OLD and INDEX-ALL files containing only 3197181142Scperciva # the components we want and without anything marked as "Ignore". 3198181142Scperciva fetch_filter_metadata INDEX-OLD || return 1 3199181142Scperciva fetch_filter_metadata INDEX-ALL || return 1 3200181142Scperciva 3201181142Scperciva # Merge the INDEX-OLD and INDEX-ALL files into INDEX-ALL. 3202181142Scperciva sort INDEX-OLD INDEX-ALL > INDEX-ALL.tmp 3203181142Scperciva mv INDEX-ALL.tmp INDEX-ALL 3204181142Scperciva rm INDEX-OLD 3205181142Scperciva 3206181142Scperciva # Translate /boot/${KERNCONF} to ${KERNELDIR} 3207181142Scperciva fetch_filter_kernel_names INDEX-ALL ${KERNCONF} 3208181142Scperciva 3209181142Scperciva # Inspect the system and generate an INDEX-PRESENT file. 3210181142Scperciva fetch_inspect_system INDEX-ALL INDEX-PRESENT /dev/null || return 1 3211181142Scperciva 3212181142Scperciva # Compare INDEX-ALL and INDEX-PRESENT and print warnings about any 3213181142Scperciva # differences. 3214181142Scperciva IDS_compare INDEX-ALL INDEX-PRESENT 3215181142Scperciva} 3216181142Scperciva 3217161748Scperciva#### Main functions -- call parameter-handling and core functions 3218161748Scperciva 3219161748Scperciva# Using the command line, configuration file, and defaults, 3220161748Scperciva# set all the parameters which are needed later. 3221161748Scpercivaget_params () { 3222161748Scperciva init_params 3223161748Scperciva parse_cmdline $@ 3224161748Scperciva parse_conffile 3225161748Scperciva default_params 3226161748Scperciva} 3227161748Scperciva 3228161748Scperciva# Fetch command. Make sure that we're being called 3229161748Scperciva# interactively, then run fetch_check_params and fetch_run 3230161748Scpercivacmd_fetch () { 3231282870Sdelphij if [ ! -t 0 -a $NOTTYOK -eq 0 ]; then 3232161748Scperciva echo -n "`basename $0` fetch should not " 3233161748Scperciva echo "be run non-interactively." 3234161748Scperciva echo "Run `basename $0` cron instead." 3235161748Scperciva exit 1 3236161748Scperciva fi 3237161748Scperciva fetch_check_params 3238161748Scperciva fetch_run || exit 1 3239161748Scperciva} 3240161748Scperciva 3241161748Scperciva# Cron command. Make sure the parameters are sensible; wait 3242161748Scperciva# rand(3600) seconds; then fetch updates. While fetching updates, 3243161748Scperciva# send output to a temporary file; only print that file if the 3244161748Scperciva# fetching failed. 3245161748Scpercivacmd_cron () { 3246161748Scperciva fetch_check_params 3247161748Scperciva sleep `jot -r 1 0 3600` 3248161748Scperciva 3249161748Scperciva TMPFILE=`mktemp /tmp/freebsd-update.XXXXXX` || exit 1 3250161748Scperciva if ! fetch_run >> ${TMPFILE} || 3251161748Scperciva ! grep -q "No updates needed" ${TMPFILE} || 3252161748Scperciva [ ${VERBOSELEVEL} = "debug" ]; then 3253161748Scperciva mail -s "`hostname` security updates" ${MAILTO} < ${TMPFILE} 3254161748Scperciva fi 3255161748Scperciva 3256161748Scperciva rm ${TMPFILE} 3257161748Scperciva} 3258161748Scperciva 3259173564Scperciva# Fetch files for upgrading to a new release. 3260173564Scpercivacmd_upgrade () { 3261173564Scperciva upgrade_check_params 3262173564Scperciva upgrade_run || exit 1 3263173564Scperciva} 3264173564Scperciva 3265161748Scperciva# Install downloaded updates. 3266161748Scpercivacmd_install () { 3267161748Scperciva install_check_params 3268161748Scperciva install_run || exit 1 3269161748Scperciva} 3270161748Scperciva 3271161748Scperciva# Rollback most recently installed updates. 3272161748Scpercivacmd_rollback () { 3273161748Scperciva rollback_check_params 3274161748Scperciva rollback_run || exit 1 3275161748Scperciva} 3276161748Scperciva 3277181142Scperciva# Compare system against a "known good" index. 3278181142Scpercivacmd_IDS () { 3279181142Scperciva IDS_check_params 3280181142Scperciva IDS_run || exit 1 3281181142Scperciva} 3282181142Scperciva 3283161748Scperciva#### Entry point 3284161748Scperciva 3285161748Scperciva# Make sure we find utilities from the base system 3286161748Scpercivaexport PATH=/sbin:/bin:/usr/sbin:/usr/bin:${PATH} 3287161748Scperciva 3288217767Sgordon# Set a pager if the user doesn't 3289217767Sgordonif [ -z "$PAGER" ]; then 3290217767Sgordon PAGER=/usr/bin/more 3291217767Sgordonfi 3292217767Sgordon 3293163564Scperciva# Set LC_ALL in order to avoid problems with character ranges like [A-Z]. 3294163564Scpercivaexport LC_ALL=C 3295163564Scperciva 3296161748Scpercivaget_params $@ 3297161748Scpercivafor COMMAND in ${COMMANDS}; do 3298161748Scperciva cmd_${COMMAND} 3299161748Scpercivadone 3300