4 # SPDX-License-Identifier: BSD-2-Clause
6 # Copyright 2004-2007 Colin Percival
9 # Redistribution and use in source and binary forms, with or without
10 # modification, are permitted providing that the following conditions
12 # 1. Redistributions of source code must retain the above copyright
13 # notice, this list of conditions and the following disclaimer.
14 # 2. Redistributions in binary form must reproduce the above copyright
15 # notice, this list of conditions and the following disclaimer in the
16 # documentation and/or other materials provided with the distribution.
18 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27 # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 # POSSIBILITY OF SUCH DAMAGE.
30 #### Usage function -- called from command-line handling code.
32 # Usage instructions. Options not listed:
33 # --debug -- don't filter output from utilities
34 # --no-stats -- don't show progress statistics while fetching files
37 usage: `basename $0` [options] command ...
40 -b basedir -- Operate on a system mounted at basedir
42 -d workdir -- Store working files in workdir
43 (default: /var/db/freebsd-update/)
44 -f conffile -- Read configuration options from conffile
45 (default: /etc/freebsd-update.conf)
46 -F -- Force a fetch operation to proceed in the
47 case of an unfinished upgrade
48 -j jail -- Operate on the given jail specified by jid or name
49 -k KEY -- Trust an RSA key with SHA256 hash of KEY
50 -r release -- Target for upgrade (e.g., 13.2-RELEASE)
51 -s server -- Server from which to fetch updates
52 (default: update.FreeBSD.org)
53 -t address -- Mail output of cron command, if any, to address
55 --not-running-from-cron
56 -- Run without a tty, for use by automated tools
57 --currently-running release
58 -- Update as if currently running this release
60 fetch -- Fetch updates from server
61 cron -- Sleep rand(3600) seconds, fetch updates, and send an
62 email if updates were found
63 upgrade -- Fetch upgrades to FreeBSD version specified via -r option
64 updatesready -- Check if there are fetched updates ready to install
65 install -- Install downloaded updates or upgrades
66 rollback -- Uninstall most recently installed updates
67 IDS -- Compare the system against an index of "known good" files
68 showconfig -- Show configuration
73 #### Configuration processing functions
76 # Configuration options are set in the following order of priority:
77 # 1. Command line options
78 # 2. Configuration file options
80 # In addition, certain options (e.g., IgnorePaths) can be specified multiple
81 # times and (as long as these are all in the same place, e.g., inside the
82 # configuration file) they will accumulate. Finally, because the path to the
83 # configuration file can be specified at the command line, the entire command
84 # line must be processed before we start reading the configuration file.
86 # Sound like a mess? It is. Here's how we handle this:
87 # 1. Initialize CONFFILE and all the options to "".
88 # 2. Process the command line. Throw an error if a non-accumulating option
90 # 3. If CONFFILE is "", set CONFFILE to /etc/freebsd-update.conf .
91 # 4. For all the configuration options X, set X_saved to X.
92 # 5. Initialize all the options to "".
93 # 6. Read CONFFILE line by line, parsing options.
94 # 7. For each configuration option X, set X to X_saved iff X_saved is not "".
95 # 8. Repeat steps 4-7, except setting options to their default values at (6).
97 CONFIGOPTIONS="KEYPRINT WORKDIR SERVERNAME MAILTO ALLOWADD ALLOWDELETE
98 KEEPMODIFIEDMETADATA COMPONENTS IGNOREPATHS UPDATEIFUNMODIFIED
99 BASEDIR VERBOSELEVEL TARGETRELEASE STRICTCOMPONENTS MERGECHANGES
100 IDSIGNOREPATHS BACKUPKERNEL BACKUPKERNELDIR BACKUPKERNELSYMBOLFILES"
102 # Set all the configuration options to "".
104 for X in ${CONFIGOPTIONS}; do
109 # For each configuration option X, set X_saved to X.
111 for X in ${CONFIGOPTIONS}; do
112 eval ${X}_saved=\$${X}
116 # For each configuration option X, set X to X_saved if X_saved is not "".
118 for X in ${CONFIGOPTIONS}; do
120 if ! [ -z "${_}" ]; then
121 eval ${X}=\$${X}_saved
126 # Set the trusted keyprint.
128 if [ -z ${KEYPRINT} ]; then
135 # Set the working directory.
137 if [ -z ${WORKDIR} ]; then
144 # Set the name of the server (pool) from which to fetch updates
145 config_ServerName () {
146 if [ -z ${SERVERNAME} ]; then
153 # Set the address to which 'cron' output will be mailed.
155 if [ -z ${MAILTO} ]; then
162 # Set whether FreeBSD Update is allowed to add files (or directories, or
163 # symlinks) which did not previously exist.
165 if [ -z ${ALLOWADD} ]; then
182 # Set whether FreeBSD Update is allowed to remove files/directories/symlinks.
183 config_AllowDelete () {
184 if [ -z ${ALLOWDELETE} ]; then
201 # Set whether FreeBSD Update should keep existing inode ownership,
202 # permissions, and flags, in the event that they have been modified locally
204 config_KeepModifiedMetadata () {
205 if [ -z ${KEEPMODIFIEDMETADATA} ]; then
208 KEEPMODIFIEDMETADATA=yes
211 KEEPMODIFIEDMETADATA=no
222 # Add to the list of components which should be kept updated.
223 config_Components () {
225 COMPONENTS="${COMPONENTS} ${C}"
229 # Remove src component from list if it isn't installed
230 finalize_components_config () {
233 if [ "$C" = "src" ]; then
234 if [ -e "${BASEDIR}/usr/src/COPYRIGHT" ]; then
235 COMPONENTS="${COMPONENTS} ${C}"
237 echo "src component not installed, skipped"
240 COMPONENTS="${COMPONENTS} ${C}"
245 # Add to the list of paths under which updates will be ignored.
246 config_IgnorePaths () {
248 IGNOREPATHS="${IGNOREPATHS} ${C}"
252 # Add to the list of paths which IDS should ignore.
253 config_IDSIgnorePaths () {
255 IDSIGNOREPATHS="${IDSIGNOREPATHS} ${C}"
259 # Add to the list of paths within which updates will be performed only if the
260 # file on disk has not been modified locally.
261 config_UpdateIfUnmodified () {
263 UPDATEIFUNMODIFIED="${UPDATEIFUNMODIFIED} ${C}"
267 # Add to the list of paths within which updates to text files will be merged
268 # instead of overwritten.
269 config_MergeChanges () {
271 MERGECHANGES="${MERGECHANGES} ${C}"
275 # Work on a FreeBSD installation mounted under $1
277 if [ -z ${BASEDIR} ]; then
284 # When fetching upgrades, should we assume the user wants exactly the
285 # components listed in COMPONENTS, rather than trying to guess based on
286 # what's currently installed?
287 config_StrictComponents () {
288 if [ -z ${STRICTCOMPONENTS} ]; then
305 # Upgrade to FreeBSD $1
306 config_TargetRelease () {
307 if [ -z ${TARGETRELEASE} ]; then
312 if echo ${TARGETRELEASE} | grep -qE '^[0-9.]+$'; then
313 TARGETRELEASE="${TARGETRELEASE}-RELEASE"
317 # Pretend current release is FreeBSD $1
318 config_SourceRelease () {
320 if echo ${UNAME_r} | grep -qE '^[0-9.]+$'; then
321 UNAME_r="${UNAME_r}-RELEASE"
326 # Get the Jail's path and the version of its installed userland
327 config_TargetJail () {
329 UNAME_r=$(freebsd-version -j ${JAIL})
330 BASEDIR=$(jls -j ${JAIL} -h path | awk 'NR == 2 {print}')
331 if [ -z ${BASEDIR} ] || [ -z ${UNAME_r} ]; then
332 echo "The specified jail either doesn't exist or" \
333 "does not have freebsd-version."
339 # Define what happens to output of utilities
340 config_VerboseLevel () {
341 if [ -z ${VERBOSELEVEL} ]; then
343 [Dd][Ee][Bb][Uu][Gg])
346 [Nn][Oo][Ss][Tt][Aa][Tt][Ss])
349 [Ss][Tt][Aa][Tt][Ss])
361 config_BackupKernel () {
362 if [ -z ${BACKUPKERNEL} ]; then
379 config_BackupKernelDir () {
380 if [ -z ${BACKUPKERNELDIR} ]; then
382 echo "BackupKernelDir set to empty dir"
386 # We check for some paths which would be extremely odd
387 # to use, but which could cause a lot of problems if
390 /|/bin|/boot|/etc|/lib|/libexec|/sbin|/usr|/var)
391 echo "BackupKernelDir set to invalid path $1"
398 echo "BackupKernelDir ($1) is not an absolute path"
407 config_BackupKernelSymbolFiles () {
408 if [ -z ${BACKUPKERNELSYMBOLFILES} ]; then
411 BACKUPKERNELSYMBOLFILES=yes
414 BACKUPKERNELSYMBOLFILES=no
425 config_CreateBootEnv () {
426 if [ -z ${BOOTENV} ]; then
442 # Handle one line of configuration
444 if [ $# -eq 0 ]; then
453 #### Parameter handling functions.
455 # Initialize parameters to null, just in case they're
456 # set in the environment.
458 # Configration settings
461 # No configuration file set yet
464 # No commands specified yet
467 # Force fetch to proceed
473 # Fetched first in a chain of commands
477 # Parse the command line
479 while [ $# -gt 0 ]; do
481 # Location of configuration file
483 if [ $# -eq 1 ]; then usage; fi
484 if [ ! -z "${CONFFILE}" ]; then usage; fi
490 --not-running-from-cron)
495 config_SourceRelease $1 || usage
498 # Configuration file equivalents
500 if [ $# -eq 1 ]; then usage; fi; shift
501 config_BaseDir $1 || usage
504 if [ $# -eq 1 ]; then usage; fi; shift
505 config_WorkDir $1 || usage
508 if [ $# -eq 1 ]; then usage; fi; shift
509 config_TargetJail $1 || usage
512 if [ $# -eq 1 ]; then usage; fi; shift
513 config_KeyPrint $1 || usage
516 if [ $# -eq 1 ]; then usage; fi; shift
517 config_ServerName $1 || usage
520 if [ $# -eq 1 ]; then usage; fi; shift
521 config_TargetRelease $1 || usage
524 if [ $# -eq 1 ]; then usage; fi; shift
525 config_MailTo $1 || usage
528 if [ $# -eq 1 ]; then usage; fi; shift
529 config_VerboseLevel $1 || usage
532 # Aliases for "-v debug" and "-v nostats"
534 config_VerboseLevel debug || usage
537 config_VerboseLevel nostats || usage
541 cron | fetch | upgrade | updatesready | install | rollback |\
543 COMMANDS="${COMMANDS} $1"
546 # Anything else is an error
554 # Make sure we have at least one command
555 if [ -z "${COMMANDS}" ]; then
560 # Parse the configuration file
562 # If a configuration file was specified on the command line, check
563 # that it exists and is readable.
564 if [ ! -z "${CONFFILE}" ] && [ ! -r "${CONFFILE}" ]; then
565 echo -n "File does not exist "
566 echo -n "or is not readable: "
571 # If a configuration file was not specified on the command line,
572 # use the default configuration file path. If that default does
573 # not exist, give up looking for any configuration.
574 if [ -z "${CONFFILE}" ]; then
575 CONFFILE="/etc/freebsd-update.conf"
576 if [ ! -r "${CONFFILE}" ]; then
581 # Save the configuration options specified on the command line, and
582 # clear all the options in preparation for reading the config file.
586 # Read the configuration file. Anything after the first '#' is
587 # ignored, and any blank lines are ignored.
591 LINEX=`echo "${LINE}" | cut -f 1 -d '#'`
592 if ! configline ${LINEX}; then
593 echo "Error processing configuration file, line $L:"
599 # Merge the settings read from the configuration file with those
600 # provided at the command line.
604 # Provide some default parameters
606 # Save any parameters already configured, and clear the slate
610 # Default configurations
611 config_WorkDir /var/db/freebsd-update
614 config_AllowDelete yes
615 config_KeepModifiedMetadata yes
617 config_VerboseLevel stats
618 config_StrictComponents no
619 config_BackupKernel yes
620 config_BackupKernelDir /boot/kernel.old
621 config_BackupKernelSymbolFiles no
622 config_CreateBootEnv yes
624 # Merge these defaults into the earlier-configured settings
628 # Set utility output filtering options, based on ${VERBOSELEVEL}
629 fetch_setup_verboselevel () {
630 case ${VERBOSELEVEL} in
632 QUIETREDIR="/dev/stderr"
634 STATSREDIR="/dev/stderr"
642 STATSREDIR="/dev/null"
648 QUIETREDIR="/dev/null"
650 STATSREDIR="/dev/stdout"
658 # Perform sanity checks and set some final parameters
659 # in preparation for fetching files. Figure out which
660 # set of updates should be downloaded: If the user is
661 # running *-p[0-9]+, strip off the last part; if the
662 # user is running -SECURITY, call it -RELEASE. Chdir
663 # into the working directory.
664 fetchupgrade_check_params () {
665 export HTTP_USER_AGENT="freebsd-update (${COMMAND}, `uname -r`)"
668 "SERVERNAME must be given via command line or configuration file."
669 _KEYPRINT_z="Key must be given via -k option or configuration file."
670 _KEYPRINT_bad="Invalid key fingerprint: "
671 _WORKDIR_bad="Directory does not exist or is not writable: "
672 _WORKDIR_bad2="Directory is not on a persistent filesystem: "
674 if [ -z "${SERVERNAME}" ]; then
675 echo -n "`basename $0`: "
676 echo "${_SERVERNAME_z}"
679 if [ -z "${KEYPRINT}" ]; then
680 echo -n "`basename $0`: "
681 echo "${_KEYPRINT_z}"
684 if ! echo "${KEYPRINT}" | grep -qE "^[0-9a-f]{64}$"; then
685 echo -n "`basename $0`: "
686 echo -n "${_KEYPRINT_bad}"
690 if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then
691 echo -n "`basename $0`: "
692 echo -n "${_WORKDIR_bad}"
696 case `df -T ${WORKDIR}` in */dev/md[0-9]* | *tmpfs*)
697 echo -n "`basename $0`: "
698 echo -n "${_WORKDIR_bad2}"
704 cd ${WORKDIR} || exit 1
706 # Generate release number. The s/SECURITY/RELEASE/ bit exists
707 # to provide an upgrade path for FreeBSD Update 1.x users, since
708 # the kernels provided by FreeBSD Update 1.x are always labelled
711 sed -E 's,-p[0-9]+,,' |
712 sed -E 's,-SECURITY,-RELEASE,'`
714 FETCHDIR=${RELNUM}/${ARCH}
715 PATCHDIR=${RELNUM}/${ARCH}/bp
717 # Disallow upgrade from a version that is not a release
719 *-RELEASE | *-ALPHA* | *-BETA* | *-RC*)
722 echo -n "`basename $0`: "
724 Cannot upgrade from a version that is not a release
725 (including alpha, beta and release candidates)
726 using `basename $0`. Instead, FreeBSD can be directly
727 upgraded by source or upgraded to a RELEASE/RELENG version
728 prior to running `basename $0`.
729 Currently running: ${RELNUM}
735 # Figure out what directory contains the running kernel
736 BOOTFILE=`sysctl -n kern.bootfile`
737 KERNELDIR=${BOOTFILE%/kernel}
738 if ! [ -d ${KERNELDIR} ]; then
739 echo "Cannot identify running kernel"
743 # Figure out what kernel configuration is running. We start with
744 # the output of `uname -i`, and then make the following adjustments:
745 # 1. Replace "SMP-GENERIC" with "SMP". Why the SMP kernel config
746 # file says "ident SMP-GENERIC", I don't know...
747 # 2. If the kernel claims to be GENERIC _and_ ${ARCH} is "amd64"
748 # _and_ `sysctl kern.version` contains a line which ends "/SMP", then
749 # we're running an SMP kernel. This mis-identification is a bug
750 # which was fixed in 6.2-STABLE.
752 if [ ${KERNCONF} = "SMP-GENERIC" ]; then
755 if [ ${KERNCONF} = "GENERIC" ] && [ ${ARCH} = "amd64" ]; then
756 if sysctl kern.version | grep -qE '/SMP$'; then
762 BSPATCH=/usr/bin/bspatch
764 PHTTPGET=/usr/libexec/phttpget
766 # Set up variables relating to VERBOSELEVEL
767 fetch_setup_verboselevel
769 # Construct a unique name from ${BASEDIR}
770 BDHASH=`echo ${BASEDIR} | sha256 -q`
773 # Perform sanity checks etc. before fetching updates.
774 fetch_check_params () {
775 fetchupgrade_check_params
777 if ! [ -z "${TARGETRELEASE}" ]; then
778 echo -n "`basename $0`: "
779 echo -n "-r option is meaningless with 'fetch' command. "
780 echo "(Did you mean 'upgrade' instead?)"
784 # Check that we have updates ready to install
785 if [ -f ${BDHASH}-install/kerneldone -a $FORCEFETCH -eq 0 ]; then
786 echo "You have a partially completed upgrade pending"
787 echo "Run '$0 install' first."
788 echo "Run '$0 fetch -F' to proceed anyway."
793 # Perform sanity checks etc. before fetching upgrades.
794 upgrade_check_params () {
795 fetchupgrade_check_params
797 # Unless set otherwise, we're upgrading to the same kernel config.
798 NKERNCONF=${KERNCONF}
800 # We need TARGETRELEASE set
801 _TARGETRELEASE_z="Release target must be specified via -r option."
802 if [ -z "${TARGETRELEASE}" ]; then
803 echo -n "`basename $0`: "
804 echo "${_TARGETRELEASE_z}"
808 # The target release should be != the current release.
809 if [ "${TARGETRELEASE}" = "${RELNUM}" ]; then
810 echo -n "`basename $0`: "
811 echo "Cannot upgrade from ${RELNUM} to itself"
815 # Turning off AllowAdd or AllowDelete is a bad idea for upgrades.
816 if [ "${ALLOWADD}" = "no" ]; then
817 echo -n "`basename $0`: "
818 echo -n "WARNING: \"AllowAdd no\" is a bad idea "
819 echo "when upgrading between releases."
822 if [ "${ALLOWDELETE}" = "no" ]; then
823 echo -n "`basename $0`: "
824 echo -n "WARNING: \"AllowDelete no\" is a bad idea "
825 echo "when upgrading between releases."
829 # Set EDITOR to /usr/bin/vi if it isn't already set
830 : ${EDITOR:='/usr/bin/vi'}
833 # Perform sanity checks and set some final parameters in
834 # preparation for installing updates.
835 install_check_params () {
836 # Check that we are root. All sorts of things won't work otherwise.
837 if [ `id -u` != 0 ]; then
838 echo "You must be root to run this."
842 # Check that securelevel <= 0. Otherwise we can't update schg files.
843 if [ `sysctl -n kern.securelevel` -gt 0 ]; then
844 echo "Updates cannot be installed when the system securelevel"
845 echo "is greater than zero."
849 # Check that we have a working directory
850 _WORKDIR_bad="Directory does not exist or is not writable: "
851 if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then
852 echo -n "`basename $0`: "
853 echo -n "${_WORKDIR_bad}"
857 cd ${WORKDIR} || exit 1
859 # Construct a unique name from ${BASEDIR}
860 BDHASH=`echo ${BASEDIR} | sha256 -q`
862 # Check that we have updates ready to install
863 if ! [ -L ${BDHASH}-install ]; then
864 echo "No updates are available to install."
865 if [ $ISFETCHED -eq 0 ]; then
866 echo "Run '$0 fetch' first."
871 if ! [ -f ${BDHASH}-install/INDEX-OLD ] ||
872 ! [ -f ${BDHASH}-install/INDEX-NEW ]; then
873 echo "Update manifest is corrupt -- this should never happen."
874 echo "Re-run '$0 fetch'."
878 # Figure out what directory contains the running kernel
879 BOOTFILE=`sysctl -n kern.bootfile`
880 KERNELDIR=${BOOTFILE%/kernel}
881 if ! [ -d ${KERNELDIR} ]; then
882 echo "Cannot identify running kernel"
887 # Creates a new boot environment
888 install_create_be () {
889 # Figure out if we're running in a jail and return if we are
890 if [ `sysctl -n security.jail.jailed` = 1 ]; then
893 # Operating on roots that aren't located at / will, more often than not,
894 # not touch the boot environment.
895 if [ "$BASEDIR" != "/" ]; then
898 # Create a boot environment if enabled
899 if [ ${BOOTENV} = yes ]; then
900 bectl check 2>/dev/null
903 # Boot environment are supported
907 # Boot environments are not supported
911 # If bectl returns an unexpected exit code, don't create a BE
915 if [ ${CREATEBE} = yes ]; then
916 echo -n "Creating snapshot of existing boot environment... "
917 VERSION=`freebsd-version -ku | sort -V | tail -n 1`
918 TIMESTAMP=`date +"%Y-%m-%d_%H%M%S"`
919 bectl create -r ${VERSION}_${TIMESTAMP}
920 if [ $? -eq 0 ]; then
930 # Perform sanity checks and set some final parameters in
931 # preparation for UNinstalling updates.
932 rollback_check_params () {
933 # Check that we are root. All sorts of things won't work otherwise.
934 if [ `id -u` != 0 ]; then
935 echo "You must be root to run this."
939 # Check that we have a working directory
940 _WORKDIR_bad="Directory does not exist or is not writable: "
941 if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then
942 echo -n "`basename $0`: "
943 echo -n "${_WORKDIR_bad}"
947 cd ${WORKDIR} || exit 1
949 # Construct a unique name from ${BASEDIR}
950 BDHASH=`echo ${BASEDIR} | sha256 -q`
952 # Check that we have updates ready to rollback
953 if ! [ -L ${BDHASH}-rollback ]; then
954 echo "No rollback directory found."
957 if ! [ -f ${BDHASH}-rollback/INDEX-OLD ] ||
958 ! [ -f ${BDHASH}-rollback/INDEX-NEW ]; then
959 echo "Update manifest is corrupt -- this should never happen."
964 # Perform sanity checks and set some final parameters
965 # in preparation for comparing the system against the
966 # published index. Figure out which index we should
967 # compare against: If the user is running *-p[0-9]+,
968 # strip off the last part; if the user is running
969 # -SECURITY, call it -RELEASE. Chdir into the working
971 IDS_check_params () {
972 export HTTP_USER_AGENT="freebsd-update (${COMMAND}, `uname -r`)"
975 "SERVERNAME must be given via command line or configuration file."
976 _KEYPRINT_z="Key must be given via -k option or configuration file."
977 _KEYPRINT_bad="Invalid key fingerprint: "
978 _WORKDIR_bad="Directory does not exist or is not writable: "
980 if [ -z "${SERVERNAME}" ]; then
981 echo -n "`basename $0`: "
982 echo "${_SERVERNAME_z}"
985 if [ -z "${KEYPRINT}" ]; then
986 echo -n "`basename $0`: "
987 echo "${_KEYPRINT_z}"
990 if ! echo "${KEYPRINT}" | grep -qE "^[0-9a-f]{64}$"; then
991 echo -n "`basename $0`: "
992 echo -n "${_KEYPRINT_bad}"
996 if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then
997 echo -n "`basename $0`: "
998 echo -n "${_WORKDIR_bad}"
1002 cd ${WORKDIR} || exit 1
1004 # Generate release number. The s/SECURITY/RELEASE/ bit exists
1005 # to provide an upgrade path for FreeBSD Update 1.x users, since
1006 # the kernels provided by FreeBSD Update 1.x are always labelled
1009 sed -E 's,-p[0-9]+,,' |
1010 sed -E 's,-SECURITY,-RELEASE,'`
1012 FETCHDIR=${RELNUM}/${ARCH}
1013 PATCHDIR=${RELNUM}/${ARCH}/bp
1015 # Figure out what directory contains the running kernel
1016 BOOTFILE=`sysctl -n kern.bootfile`
1017 KERNELDIR=${BOOTFILE%/kernel}
1018 if ! [ -d ${KERNELDIR} ]; then
1019 echo "Cannot identify running kernel"
1023 # Figure out what kernel configuration is running. We start with
1024 # the output of `uname -i`, and then make the following adjustments:
1025 # 1. Replace "SMP-GENERIC" with "SMP". Why the SMP kernel config
1026 # file says "ident SMP-GENERIC", I don't know...
1027 # 2. If the kernel claims to be GENERIC _and_ ${ARCH} is "amd64"
1028 # _and_ `sysctl kern.version` contains a line which ends "/SMP", then
1029 # we're running an SMP kernel. This mis-identification is a bug
1030 # which was fixed in 6.2-STABLE.
1032 if [ ${KERNCONF} = "SMP-GENERIC" ]; then
1035 if [ ${KERNCONF} = "GENERIC" ] && [ ${ARCH} = "amd64" ]; then
1036 if sysctl kern.version | grep -qE '/SMP$'; then
1043 PHTTPGET=/usr/libexec/phttpget
1045 # Set up variables relating to VERBOSELEVEL
1046 fetch_setup_verboselevel
1049 #### Core functionality -- the actual work gets done here
1051 # Use an SRV query to pick a server. If the SRV query doesn't provide
1052 # a useful answer, use the server name specified by the user.
1053 # Put another way... look up _http._tcp.${SERVERNAME} and pick a server
1054 # from that; or if no servers are returned, use ${SERVERNAME}.
1055 # This allows a user to specify "portsnap.freebsd.org" (in which case
1056 # portsnap will select one of the mirrors) or "portsnap5.tld.freebsd.org"
1057 # (in which case portsnap will use that particular server, since there
1058 # won't be an SRV entry for that name).
1060 # We ignore the Port field, since we are always going to use port 80.
1062 # Fetch the mirror list, but do not pick a mirror yet. Returns 1 if
1063 # no mirrors are available for any reason.
1064 fetch_pick_server_init () {
1065 : > serverlist_tried
1067 # Check that host(1) exists (i.e., that the system wasn't built with the
1068 # WITHOUT_BIND set) and don't try to find a mirror if it doesn't exist.
1069 if ! which -s host; then
1074 echo -n "Looking up ${SERVERNAME} mirrors... "
1076 # Issue the SRV query and pull out the Priority, Weight, and Target fields.
1077 # BIND 9 prints "$name has SRV record ..." while BIND 8 prints
1078 # "$name server selection ..."; we allow either format.
1079 MLIST="_http._tcp.${SERVERNAME}"
1080 host -t srv "${MLIST}" |
1081 sed -nE "s/${MLIST} (has SRV record|server selection) //Ip" |
1082 cut -f 1,2,4 -d ' ' |
1084 sort > serverlist_full
1086 # If no records, give up -- we'll just use the server name we were given.
1087 if [ `wc -l < serverlist_full` -eq 0 ]; then
1092 # Report how many mirrors we found.
1093 echo `wc -l < serverlist_full` "mirrors found."
1095 # Generate a random seed for use in picking mirrors. If HTTP_PROXY
1096 # is set, this will be used to generate the seed; otherwise, the seed
1098 if [ -n "${HTTP_PROXY}${http_proxy}" ]; then
1099 RANDVALUE=`sha256 -qs "${HTTP_PROXY}${http_proxy}" |
1103 RANDVALUE=`jot -r 1 0 999999999`
1107 # Pick a mirror. Returns 1 if we have run out of mirrors to try.
1108 fetch_pick_server () {
1109 # Generate a list of not-yet-tried mirrors
1110 sort serverlist_tried |
1111 comm -23 serverlist_full - > serverlist
1113 # Have we run out of mirrors?
1114 if [ `wc -l < serverlist` -eq 0 ]; then
1116 No mirrors remaining, giving up.
1118 This may be because upgrading from this platform (${ARCH})
1119 or release (${RELNUM}) is unsupported by `basename $0`. Only
1120 platforms with Tier 1 support can be upgraded by `basename $0`.
1121 See https://www.freebsd.org/platforms/ for more info.
1123 If unsupported, FreeBSD must be upgraded by source.
1128 # Find the highest priority level (lowest numeric value).
1129 SRV_PRIORITY=`cut -f 1 -d ' ' serverlist | sort -n | head -1`
1131 # Add up the weights of the response lines at that priority level.
1136 SRV_W=`echo $X | cut -f 2 -d ' '`
1137 SRV_WSUM=$(($SRV_WSUM + $SRV_W))
1142 # If all the weights are 0, pretend that they are all 1 instead.
1143 if [ ${SRV_WSUM} -eq 0 ]; then
1144 SRV_WSUM=`grep -E "^${SRV_PRIORITY} " serverlist | wc -l`
1150 # Pick a value between 0 and the sum of the weights - 1
1151 SRV_RND=`expr ${RANDVALUE} % ${SRV_WSUM}`
1153 # Read through the list of mirrors and set SERVERNAME. Write the line
1154 # corresponding to the mirror we selected into serverlist_tried so that
1155 # we won't try it again.
1159 SRV_W=`echo $X | cut -f 2 -d ' '`
1160 SRV_W=$(($SRV_W + $SRV_W_ADD))
1161 if [ $SRV_RND -lt $SRV_W ]; then
1162 SERVERNAME=`echo $X | cut -f 3 -d ' '`
1163 echo "$X" >> serverlist_tried
1166 SRV_RND=$(($SRV_RND - $SRV_W))
1173 # Take a list of ${oldhash}|${newhash} and output a list of needed patches,
1174 # i.e., those for which we have ${oldhash} and don't have ${newhash}.
1175 fetch_make_patchlist () {
1176 grep -vE "^([0-9a-f]{64})\|\1$" |
1179 if [ -f "files/${Y}.gz" ] ||
1180 [ ! -f "files/${X}.gz" ]; then
1187 # Print user-friendly progress statistics
1192 if [ $(($LNC % 10)) = 0 ]; then
1194 elif [ $(($LNC % 2)) = 0 ]; then
1201 # Function for asking the user if everything is ok
1203 while read -p "Does this look reasonable (y/n)? " CONTINUE; do
1204 case "${CONTINUE}" in
1215 # Initialize the working directory
1218 touch tINDEX.present
1221 # Check that we have a public key with an appropriate hash, or
1222 # fetch the key if it doesn't exist. Returns 1 if the key has
1223 # not yet been fetched.
1225 if [ -r pub.ssl ] && [ `${SHA256} -q pub.ssl` = ${KEYPRINT} ]; then
1229 echo -n "Fetching public key from ${SERVERNAME}... "
1231 fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/pub.ssl \
1232 2>${QUIETREDIR} || true
1233 if ! [ -r pub.ssl ]; then
1237 if ! [ `${SHA256} -q pub.ssl` = ${KEYPRINT} ]; then
1238 echo "key has incorrect hash."
1245 # Fetch metadata signature, aka "tag".
1247 echo -n "Fetching metadata signature "
1248 echo ${NDEBUG} "for ${RELNUM} from ${SERVERNAME}... "
1250 fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/latest.ssl \
1251 2>${QUIETREDIR} || true
1252 if ! [ -r latest.ssl ]; then
1257 openssl rsautl -pubin -inkey pub.ssl -verify \
1258 < latest.ssl > tag.new 2>${QUIETREDIR} || true
1261 if ! [ `wc -l < tag.new` = 1 ] ||
1263 "^freebsd-update\|${ARCH}\|${RELNUM}\|[0-9]+\|[0-9a-f]{64}\|[0-9]{10}" \
1265 echo "invalid signature."
1271 RELPATCHNUM=`cut -f 4 -d '|' < tag.new`
1272 TINDEXHASH=`cut -f 5 -d '|' < tag.new`
1273 EOLTIME=`cut -f 6 -d '|' < tag.new`
1276 # Sanity-check the patch number in a tag, to make sure that we're not
1277 # going to "update" backwards and to prevent replay attacks.
1278 fetch_tagsanity () {
1279 # Check that we're not going to move from -pX to -pY with Y < X.
1280 RELPX=`uname -r | sed -E 's,.*-,,'`
1281 if echo ${RELPX} | grep -qE '^p[0-9]+$'; then
1282 RELPX=`echo ${RELPX} | cut -c 2-`
1286 if [ "${RELPATCHNUM}" -lt "${RELPX}" ]; then
1288 echo -n "Files on mirror (${RELNUM}-p${RELPATCHNUM})"
1289 echo " appear older than what"
1290 echo "we are currently running (`uname -r`)!"
1291 echo "Cowardly refusing to proceed any further."
1295 # If "tag" exists and corresponds to ${RELNUM}, make sure that
1296 # it contains a patch number <= RELPATCHNUM, in order to protect
1297 # against rollback (replay) attacks.
1300 "^freebsd-update\|${ARCH}\|${RELNUM}\|[0-9]+\|[0-9a-f]{64}\|[0-9]{10}" \
1302 LASTRELPATCHNUM=`cut -f 4 -d '|' < tag`
1304 if [ "${RELPATCHNUM}" -lt "${LASTRELPATCHNUM}" ]; then
1306 echo -n "Files on mirror (${RELNUM}-p${RELPATCHNUM})"
1307 echo " are older than the"
1308 echo -n "most recently seen updates"
1309 echo " (${RELNUM}-p${LASTRELPATCHNUM})."
1310 echo "Cowardly refusing to proceed any further."
1316 # Fetch metadata index file
1317 fetch_metadata_index () {
1318 echo ${NDEBUG} "Fetching metadata index... "
1320 fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/t/${TINDEXHASH}
1322 if ! [ -f ${TINDEXHASH} ]; then
1326 if [ `${SHA256} -q ${TINDEXHASH}` != ${TINDEXHASH} ]; then
1327 echo "update metadata index corrupt."
1333 # Print an error message about signed metadata being bogus.
1334 fetch_metadata_bogus () {
1336 echo "The update metadata$1 is correctly signed, but"
1337 echo "failed an integrity check."
1338 echo "Cowardly refusing to proceed any further."
1342 # Construct tINDEX.new by merging the lines named in $1 from ${TINDEXHASH}
1343 # with the lines not named in $@ from tINDEX.present (if that file exists).
1344 fetch_metadata_index_merge () {
1345 for METAFILE in $@; do
1346 if [ `grep -E "^${METAFILE}\|" ${TINDEXHASH} | wc -l` \
1348 fetch_metadata_bogus " index"
1352 grep -E "${METAFILE}\|" ${TINDEXHASH}
1354 sort > tINDEX.wanted
1356 if [ -f tINDEX.present ]; then
1357 join -t '|' -v 2 tINDEX.wanted tINDEX.present |
1358 sort -m - tINDEX.wanted > tINDEX.new
1361 mv tINDEX.wanted tINDEX.new
1365 # Sanity check all the lines of tINDEX.new. Even if more metadata lines
1366 # are added by future versions of the server, this won't cause problems,
1367 # since the only lines which appear in tINDEX.new are the ones which we
1368 # specifically grepped out of ${TINDEXHASH}.
1369 fetch_metadata_index_sanity () {
1370 if grep -qvE '^[0-9A-Z.-]+\|[0-9a-f]{64}$' tINDEX.new; then
1371 fetch_metadata_bogus " index"
1376 # Sanity check the metadata file $1.
1377 fetch_metadata_sanity () {
1378 # Some aliases to save space later: ${P} is a character which can
1379 # appear in a path; ${M} is the four numeric metadata fields; and
1380 # ${H} is a sha256 hash.
1381 P="[-+./:=,%@_[~[:alnum:]]"
1382 M="[0-9]+\|[0-9]+\|[0-9]+\|[0-9]+"
1385 # Check that the first four fields make sense.
1386 if gunzip -c < files/$1.gz |
1387 grep -qvE "^[a-z]+\|[0-9a-z-]+\|${P}+\|[fdL-]\|"; then
1388 fetch_metadata_bogus ""
1392 # Remove the first three fields.
1393 gunzip -c < files/$1.gz |
1394 cut -f 4- -d '|' > sanitycheck.tmp
1396 # Sanity check entries with type 'f'
1397 if grep -E '^f' sanitycheck.tmp |
1398 grep -qvE "^f\|${M}\|${H}\|${P}*\$"; then
1399 fetch_metadata_bogus ""
1403 # Sanity check entries with type 'd'
1404 if grep -E '^d' sanitycheck.tmp |
1405 grep -qvE "^d\|${M}\|\|\$"; then
1406 fetch_metadata_bogus ""
1410 # Sanity check entries with type 'L'
1411 if grep -E '^L' sanitycheck.tmp |
1412 grep -qvE "^L\|${M}\|${P}*\|\$"; then
1413 fetch_metadata_bogus ""
1417 # Sanity check entries with type '-'
1418 if grep -E '^-' sanitycheck.tmp |
1419 grep -qvE "^-\|\|\|\|\|\|"; then
1420 fetch_metadata_bogus ""
1428 # Fetch the metadata index and metadata files listed in $@,
1429 # taking advantage of metadata patches where possible.
1431 fetch_metadata_index || return 1
1432 fetch_metadata_index_merge $@ || return 1
1433 fetch_metadata_index_sanity || return 1
1435 # Generate a list of wanted metadata patches
1436 join -t '|' -o 1.2,2.2 tINDEX.present tINDEX.new |
1437 fetch_make_patchlist > patchlist
1439 if [ -s patchlist ]; then
1440 # Attempt to fetch metadata patches
1441 echo -n "Fetching `wc -l < patchlist | tr -d ' '` "
1442 echo ${NDEBUG} "metadata patches.${DDSTATS}"
1443 tr '|' '-' < patchlist |
1444 lam -s "${FETCHDIR}/tp/" - -s ".gz" |
1445 xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \
1446 2>${STATSREDIR} | fetch_progress
1449 # Attempt to apply metadata patches
1450 echo -n "Applying metadata patches... "
1451 tr '|' ' ' < patchlist |
1453 if [ ! -f "${X}-${Y}.gz" ]; then continue; fi
1454 gunzip -c < ${X}-${Y}.gz > diff
1455 gunzip -c < files/${X}.gz > diff-OLD
1457 # Figure out which lines are being added and removed
1460 while read PREFIX; do
1461 look "${PREFIX}" diff-OLD
1464 grep -E '^\+' diff |
1465 cut -c 2- > diff-add
1467 # Generate the new file
1468 comm -23 diff-OLD diff-rm |
1469 sort - diff-add > diff-NEW
1471 if [ `${SHA256} -q diff-NEW` = ${Y} ]; then
1472 mv diff-NEW files/${Y}
1475 mv diff-NEW ${Y}.bad
1477 rm -f ${X}-${Y}.gz diff
1478 rm -f diff-OLD diff-NEW diff-add diff-rm
1479 done 2>${QUIETREDIR}
1483 # Update metadata without patches
1484 cut -f 2 -d '|' < tINDEX.new |
1486 if [ ! -f "files/${Y}.gz" ]; then
1492 if [ -s filelist ]; then
1493 echo -n "Fetching `wc -l < filelist | tr -d ' '` "
1494 echo ${NDEBUG} "metadata files... "
1495 lam -s "${FETCHDIR}/m/" - -s ".gz" < filelist |
1496 xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \
1500 if ! [ -f ${Y}.gz ]; then
1504 if [ `gunzip -c < ${Y}.gz |
1505 ${SHA256} -q` = ${Y} ]; then
1506 mv ${Y}.gz files/${Y}.gz
1508 echo "metadata is corrupt."
1515 # Sanity-check the metadata files.
1516 cut -f 2 -d '|' tINDEX.new > filelist
1518 fetch_metadata_sanity ${X} || return 1
1521 # Remove files which are no longer needed
1522 cut -f 2 -d '|' tINDEX.present |
1524 cut -f 2 -d '|' tINDEX.new |
1526 comm -13 - oldfiles |
1527 lam -s "files/" - -s ".gz" |
1529 rm patchlist filelist oldfiles
1533 mv tINDEX.new tINDEX.present
1539 # Extract a subset of a downloaded metadata file containing only the parts
1540 # which are listed in COMPONENTS.
1541 fetch_filter_metadata_components () {
1542 METAHASH=`look "$1|" tINDEX.present | cut -f 2 -d '|'`
1543 gunzip -c < files/${METAHASH}.gz > $1.all
1545 # Fish out the lines belonging to components we care about.
1546 for C in ${COMPONENTS}; do
1547 look "`echo ${C} | tr '/' '|'`|" $1.all
1550 # Remove temporary file.
1554 # Generate a filtered version of the metadata file $1 from the downloaded
1555 # file, by fishing out the lines corresponding to components we're trying
1556 # to keep updated, and then removing lines corresponding to paths we want
1558 fetch_filter_metadata () {
1559 # Fish out the lines belonging to components we care about.
1560 fetch_filter_metadata_components $1
1562 # Canonicalize directory names by removing any trailing / in
1563 # order to avoid listing directories multiple times if they
1564 # belong to multiple components. Turning "/" into "" doesn't
1565 # matter, since we add a leading "/" when we use paths later.
1566 cut -f 3- -d '|' $1 |
1567 sed -e 's,/|d|,|d|,' |
1568 sed -e 's,/|-|,|-|,' |
1571 # Figure out which lines to ignore and remove them.
1572 for X in ${IGNOREPATHS}; do
1573 grep -E "^${X}" $1.tmp
1576 comm -13 - $1.tmp > $1
1578 # Remove temporary files.
1582 # Filter the metadata file $1 by adding lines with "/boot/$2"
1583 # replaced by ${KERNELDIR} (which is `sysctl -n kern.bootfile` minus the
1584 # trailing "/kernel"); and if "/boot/$2" does not exist, remove
1585 # the original lines which start with that.
1586 # Put another way: Deal with the fact that the FOO kernel is sometimes
1587 # installed in /boot/FOO/ and is sometimes installed elsewhere.
1588 fetch_filter_kernel_names () {
1590 sed -e "s,/boot/$2,${KERNELDIR},g" |
1594 if ! [ -d /boot/$2 ]; then
1595 grep -v ^/boot/$2 $1 > $1.tmp
1600 # For all paths appearing in $1 or $3, inspect the system
1601 # and generate $2 describing what is currently installed.
1602 fetch_inspect_system () {
1606 # Tell the user why his disk is suddenly making lots of noise
1607 echo -n "Inspecting system... "
1609 # Generate list of files to inspect
1614 # Examine each file and output lines of the form
1615 # /path/to/file|type|device-inum|user|group|perm|flags|value
1616 # sorted by device and inode number.
1618 # If the symlink/file/directory does not exist, record this.
1619 if ! [ -e ${BASEDIR}/${F} ]; then
1623 if ! [ -r ${BASEDIR}/${F} ]; then
1624 echo "Cannot read file: ${BASEDIR}/${F}" \
1630 # Otherwise, output an index line.
1631 if [ -L ${BASEDIR}/${F} ]; then
1633 stat -n -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F};
1634 readlink ${BASEDIR}/${F};
1635 elif [ -f ${BASEDIR}/${F} ]; then
1637 stat -n -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F};
1638 sha256 -q ${BASEDIR}/${F};
1639 elif [ -d ${BASEDIR}/${F} ]; then
1641 stat -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F};
1643 echo "Unknown file type: ${BASEDIR}/${F}" \
1649 sort -k 3,3 -t '|' > $2.tmp
1652 # Check if an error occurred during system inspection
1653 if [ -f .err ]; then
1657 # Convert to the form
1658 # /path/to/file|type|user|group|perm|flags|value|hlink
1659 # by resolving identical device and inode numbers into hard links.
1660 cut -f 1,3 -d '|' $2.tmp |
1661 sort -k 1,1 -t '|' |
1662 sort -s -u -k 2,2 -t '|' |
1663 join -1 2 -2 3 -t '|' - $2.tmp |
1664 awk -F \| -v OFS=\| \
1666 if (($2 == $3) || ($4 == "-"))
1667 print $3,$4,$5,$6,$7,$8,$9,""
1669 print $3,$4,$5,$6,$7,$8,$9,$2
1674 # We're finished looking around
1678 # For any paths matching ${MERGECHANGES}, compare $2 against $1 and $3 and
1679 # find any files with values unique to $2; generate $4 containing these paths
1680 # and their corresponding hashes from $1.
1681 fetch_filter_mergechanges () {
1682 # Pull out the paths and hashes of the files matching ${MERGECHANGES}.
1683 for F in $1 $2 $3; do
1684 for X in ${MERGECHANGES}; do
1685 grep -E "^${X}" ${F}
1687 cut -f 1,2,7 -d '|' |
1691 # Any line in $2-values which doesn't appear in $1-values or $3-values
1692 # and is a file means that we should list the path in $3.
1693 sort $1-values $3-values |
1694 comm -13 - $2-values |
1696 cut -f 1 -d '|' > $2-paths
1698 # For each path, pull out one (and only one!) entry from $1-values.
1699 # Note that we cannot distinguish which "old" version the user made
1700 # changes to; but hopefully any changes which occur due to security
1701 # updates will exist in both the "new" version and the version which
1702 # the user has installed, so the merging will still work.
1704 look "${X}|" $1-values |
1706 done < $2-paths > $4
1709 rm $1-values $2-values $3-values $2-paths
1712 # For any paths matching ${UPDATEIFUNMODIFIED}, remove lines from $[123]
1713 # which correspond to lines in $2 with hashes not matching $1 or $3, unless
1714 # the paths are listed in $4. For entries in $2 marked "not present"
1715 # (aka. type -), remove lines from $[123] unless there is a corresponding
1717 fetch_filter_unmodified_notpresent () {
1718 # Figure out which lines of $1 and $3 correspond to bits which
1719 # should only be updated if they haven't changed, and fish out
1720 # the (path, type, value) tuples.
1721 # NOTE: We don't consider a file to be "modified" if it matches
1723 for X in ${UPDATEIFUNMODIFIED}; do
1727 cut -f 1,2,7 -d '|' |
1730 # Do the same for $2.
1731 for X in ${UPDATEIFUNMODIFIED}; do
1734 cut -f 1,2,7 -d '|' |
1737 # Any entry in $2-values which is not in $1-values corresponds to
1738 # a path which we need to remove from $1, $2, and $3, unless it
1739 # that path appears in $4.
1740 comm -13 $1-values $2-values |
1741 sort -t '|' -k 1,1 > mlines.tmp
1742 cut -f 1 -d '|' $4 |
1744 join -v 2 -t '|' - mlines.tmp |
1746 rm $1-values $2-values mlines.tmp
1748 # Any lines in $2 which are not in $1 AND are "not present" lines
1749 # also belong in mlines.
1751 cut -f 1,2,7 -d '|' |
1752 fgrep '|-|' >> mlines
1754 # Remove lines from $1, $2, and $3
1755 for X in $1 $2 $3; do
1756 sort -t '|' -k 1,1 ${X} > ${X}.tmp
1757 cut -f 1 -d '|' < mlines |
1759 join -v 2 -t '|' - ${X}.tmp |
1764 # Store a list of the modified files, for future reference
1765 fgrep -v '|-|' mlines |
1766 cut -f 1 -d '|' > modifiedfiles
1770 # For each entry in $1 of type -, remove any corresponding
1771 # entry from $2 if ${ALLOWADD} != "yes". Remove all entries
1772 # of type - from $1.
1773 fetch_filter_allowadd () {
1774 cut -f 1,2 -d '|' < $1 |
1776 cut -f 1 -d '|' > filesnotpresent
1778 if [ ${ALLOWADD} != "yes" ]; then
1780 join -v 1 -t '|' - filesnotpresent |
1786 join -v 1 -t '|' - filesnotpresent |
1792 # If ${ALLOWDELETE} != "yes", then remove any entries from $1
1793 # which don't correspond to entries in $2.
1794 fetch_filter_allowdelete () {
1795 # Produce a lists ${PATH}|${TYPE}
1797 cut -f 1-2 -d '|' < ${X} |
1798 sort -u > ${X}.nodes
1801 # Figure out which lines need to be removed from $1.
1802 if [ ${ALLOWDELETE} != "yes" ]; then
1803 comm -23 $1.nodes $2.nodes > $1.badnodes
1808 # Remove the relevant lines from $1
1811 done < $1.badnodes |
1812 comm -13 - $1 > $1.tmp
1815 rm $1.badnodes $1.nodes $2.nodes
1818 # If ${KEEPMODIFIEDMETADATA} == "yes", then for each entry in $2
1819 # with metadata not matching any entry in $1, replace the corresponding
1820 # line of $3 with one having the same metadata as the entry in $2.
1821 fetch_filter_modified_metadata () {
1822 # Fish out the metadata from $1 and $2
1824 cut -f 1-6 -d '|' < ${X} > ${X}.metadata
1827 # Find the metadata we need to keep
1828 if [ ${KEEPMODIFIEDMETADATA} = "yes" ]; then
1829 comm -13 $1.metadata $2.metadata > keepmeta
1834 # Extract the lines which we need to remove from $3, and
1835 # construct the lines which we need to add to $3.
1839 NODE=`echo "${LINE}" | cut -f 1-2 -d '|'`
1840 look "${NODE}|" $3 >> $3.remove
1841 look "${NODE}|" $3 |
1843 lam -s "${LINE}|" - >> $3.add
1846 # Remove the specified lines and add the new lines.
1849 sort -u - $3.add > $3.tmp
1852 rm keepmeta $1.metadata $2.metadata $3.add $3.remove
1855 # Remove lines from $1 and $2 which are identical;
1856 # no need to update a file if it isn't changing.
1857 fetch_filter_uptodate () {
1858 comm -23 $1 $2 > $1.tmp
1859 comm -13 $1 $2 > $2.tmp
1865 # Fetch any "clean" old versions of files we need for merging changes.
1866 fetch_files_premerge () {
1867 # We only need to do anything if $1 is non-empty.
1869 # Tell the user what we're doing
1870 echo -n "Fetching files from ${OLDRELNUM} for merging... "
1872 # List of files wanted
1875 sort -u > files.wanted
1877 # Only fetch the files we don't already have
1879 if [ ! -f "files/${Y}.gz" ]; then
1882 done < files.wanted > filelist
1884 # Actually fetch them
1885 lam -s "${OLDFETCHDIR}/f/" - -s ".gz" < filelist |
1886 xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \
1889 # Make sure we got them all, and move them into /files/
1891 if ! [ -f ${Y}.gz ]; then
1895 if [ `gunzip -c < ${Y}.gz |
1896 ${SHA256} -q` = ${Y} ]; then
1897 mv ${Y}.gz files/${Y}.gz
1899 echo "${Y} has incorrect hash."
1906 rm filelist files.wanted
1910 # Prepare to fetch files: Generate a list of the files we need,
1911 # copy the unmodified files we have into /files/, and generate
1912 # a list of patches to download.
1913 fetch_files_prepare () {
1914 # Tell the user why his disk is suddenly making lots of noise
1915 echo -n "Preparing to download files... "
1917 # Reduce indices to ${PATH}|${HASH} pairs
1918 for X in $1 $2 $3; do
1919 cut -f 1,2,7 -d '|' < ${X} |
1925 # List of files wanted
1926 cut -f 2 -d '|' < $3.hashes |
1929 if ! [ -f files/${HASH}.gz ]; then
1934 # Generate a list of unmodified files
1935 comm -12 $1.hashes $2.hashes |
1936 sort -k 1,1 -t '|' > unmodified.files
1938 # Copy all files into /files/. We only need the unmodified files
1939 # for use in patching; but we'll want all of them if the user asks
1940 # to rollback the updates later.
1942 F=`echo "${LINE}" | cut -f 1 -d '|'`
1943 HASH=`echo "${LINE}" | cut -f 2 -d '|'`
1945 # Skip files we already have.
1946 if [ -f files/${HASH}.gz ]; then
1950 # Make sure the file hasn't changed.
1951 cp "${BASEDIR}/${F}" tmpfile
1952 if [ `sha256 -q tmpfile` != ${HASH} ]; then
1954 echo "File changed while FreeBSD Update running: ${F}"
1958 # Place the file into storage.
1959 gzip -c < tmpfile > files/${HASH}.gz
1963 # Produce a list of patches to download
1964 sort -k 1,1 -t '|' $3.hashes |
1965 join -t '|' -o 2.2,1.2 - unmodified.files |
1966 fetch_make_patchlist > patchlist
1969 rm unmodified.files $1.hashes $2.hashes $3.hashes
1971 # We don't need the list of possible old files any more.
1974 # We're finished making noise
1980 # Attempt to fetch patches
1981 if [ -s patchlist ]; then
1982 echo -n "Fetching `wc -l < patchlist | tr -d ' '` "
1983 echo ${NDEBUG} "patches.${DDSTATS}"
1984 tr '|' '-' < patchlist |
1985 lam -s "${PATCHDIR}/" - |
1986 xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \
1987 2>${STATSREDIR} | fetch_progress
1990 # Attempt to apply patches
1991 echo -n "Applying patches... "
1992 tr '|' ' ' < patchlist |
1994 if [ ! -f "${X}-${Y}" ]; then continue; fi
1995 gunzip -c < files/${X}.gz > OLD
1997 bspatch OLD NEW ${X}-${Y}
1999 if [ `${SHA256} -q NEW` = ${Y} ]; then
2003 rm -f diff OLD NEW ${X}-${Y}
2004 done 2>${QUIETREDIR}
2008 # Download files which couldn't be generate via patching
2010 if [ ! -f "files/${Y}.gz" ]; then
2013 done < files.wanted > filelist
2015 if [ -s filelist ]; then
2016 echo -n "Fetching `wc -l < filelist | tr -d ' '` "
2017 echo ${NDEBUG} "files... "
2018 lam -s "${FETCHDIR}/f/" - -s ".gz" < filelist |
2019 xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \
2020 2>${STATSREDIR} | fetch_progress
2023 if ! [ -f ${Y}.gz ]; then
2027 if [ `gunzip -c < ${Y}.gz |
2028 ${SHA256} -q` = ${Y} ]; then
2029 mv ${Y}.gz files/${Y}.gz
2031 echo "${Y} has incorrect hash."
2039 rm files.wanted filelist patchlist
2042 # Create and populate install manifest directory; and report what updates
2044 fetch_create_manifest () {
2045 # If we have an existing install manifest, nuke it.
2046 if [ -L "${BDHASH}-install" ]; then
2047 rm -r ${BDHASH}-install/
2048 rm ${BDHASH}-install
2051 # Report to the user if any updates were avoided due to local changes
2052 if [ -s modifiedfiles ]; then
2053 cat - modifiedfiles <<- EOF | ${PAGER}
2054 The following files are affected by updates. No changes have
2055 been downloaded, however, because the files have been modified
2061 # If no files will be updated, tell the user and exit
2062 if ! [ -s INDEX-PRESENT ] &&
2063 ! [ -s INDEX-NEW ]; then
2064 rm INDEX-PRESENT INDEX-NEW
2066 echo -n "No updates needed to update system to "
2067 echo "${RELNUM}-p${RELPATCHNUM}."
2071 # Divide files into (a) removed files, (b) added files, and
2072 # (c) updated files.
2073 cut -f 1 -d '|' < INDEX-PRESENT |
2074 sort > INDEX-PRESENT.flist
2075 cut -f 1 -d '|' < INDEX-NEW |
2076 sort > INDEX-NEW.flist
2077 comm -23 INDEX-PRESENT.flist INDEX-NEW.flist > files.removed
2078 comm -13 INDEX-PRESENT.flist INDEX-NEW.flist > files.added
2079 comm -12 INDEX-PRESENT.flist INDEX-NEW.flist > files.updated
2080 rm INDEX-PRESENT.flist INDEX-NEW.flist
2082 # Report removed files, if any
2083 if [ -s files.removed ]; then
2084 cat - files.removed <<- EOF | ${PAGER}
2085 The following files will be removed as part of updating to
2086 ${RELNUM}-p${RELPATCHNUM}:
2091 # Report added files, if any
2092 if [ -s files.added ]; then
2093 cat - files.added <<- EOF | ${PAGER}
2094 The following files will be added as part of updating to
2095 ${RELNUM}-p${RELPATCHNUM}:
2100 # Report updated files, if any
2101 if [ -s files.updated ]; then
2102 cat - files.updated <<- EOF | ${PAGER}
2103 The following files will be updated as part of updating to
2104 ${RELNUM}-p${RELPATCHNUM}:
2109 # Create a directory for the install manifest.
2110 MDIR=`mktemp -d install.XXXXXX` || return 1
2113 mv INDEX-PRESENT ${MDIR}/INDEX-OLD
2114 mv INDEX-NEW ${MDIR}/INDEX-NEW
2116 # Link it into place
2117 ln -s ${MDIR} ${BDHASH}-install
2120 # Warn about any upcoming EoL
2122 # What's the current time?
2123 NOWTIME=`date "+%s"`
2125 # When did we last warn about the EoL date?
2126 if [ -f lasteolwarn ]; then
2127 LASTWARN=`cat lasteolwarn`
2129 LASTWARN=`expr ${NOWTIME} - 63072000`
2132 # If the EoL time is past, warn.
2133 if [ ${EOLTIME} -lt ${NOWTIME} ]; then
2136 WARNING: `uname -sr` HAS PASSED ITS END-OF-LIFE DATE.
2137 Any security issues discovered after `date -r ${EOLTIME}`
2138 will not have been corrected.
2143 # Figure out how long it has been since we last warned about the
2144 # upcoming EoL, and how much longer we have left.
2145 SINCEWARN=`expr ${NOWTIME} - ${LASTWARN}`
2146 TIMELEFT=`expr ${EOLTIME} - ${NOWTIME}`
2148 # Don't warn if the EoL is more than 3 months away
2149 if [ ${TIMELEFT} -gt 7884000 ]; then
2153 # Don't warn if the time remaining is more than 3 times the time
2154 # since the last warning.
2155 if [ ${TIMELEFT} -gt `expr ${SINCEWARN} \* 3` ]; then
2159 # Figure out what time units to use.
2160 if [ ${TIMELEFT} -lt 604800 ]; then
2163 elif [ ${TIMELEFT} -lt 2678400 ]; then
2171 # Compute the right number of units
2172 NUM=`expr ${TIMELEFT} / ${SIZE}`
2173 if [ ${NUM} != 1 ]; then
2180 WARNING: `uname -sr` is approaching its End-of-Life date.
2181 It is strongly recommended that you upgrade to a newer
2182 release within the next ${NUM} ${UNIT}.
2185 # Update the stored time of last warning
2186 echo ${NOWTIME} > lasteolwarn
2189 # Do the actual work involved in "fetch" / "cron".
2191 workdir_init || return 1
2193 # Prepare the mirror list.
2194 fetch_pick_server_init && fetch_pick_server
2196 # Try to fetch the public key until we run out of servers.
2197 while ! fetch_key; do
2198 fetch_pick_server || return 1
2201 # Try to fetch the metadata index signature ("tag") until we run
2202 # out of available servers; and sanity check the downloaded tag.
2203 while ! fetch_tag; do
2204 fetch_pick_server || return 1
2206 fetch_tagsanity || return 1
2208 # Fetch the latest INDEX-NEW and INDEX-OLD files.
2209 fetch_metadata INDEX-NEW INDEX-OLD || return 1
2211 # Generate filtered INDEX-NEW and INDEX-OLD files containing only
2212 # the lines which (a) belong to components we care about, and (b)
2213 # don't correspond to paths we're explicitly ignoring.
2214 fetch_filter_metadata INDEX-NEW || return 1
2215 fetch_filter_metadata INDEX-OLD || return 1
2217 # Translate /boot/${KERNCONF} into ${KERNELDIR}
2218 fetch_filter_kernel_names INDEX-NEW ${KERNCONF}
2219 fetch_filter_kernel_names INDEX-OLD ${KERNCONF}
2221 # For all paths appearing in INDEX-OLD or INDEX-NEW, inspect the
2222 # system and generate an INDEX-PRESENT file.
2223 fetch_inspect_system INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1
2225 # Based on ${UPDATEIFUNMODIFIED}, remove lines from INDEX-* which
2226 # correspond to lines in INDEX-PRESENT with hashes not appearing
2227 # in INDEX-OLD or INDEX-NEW. Also remove lines where the entry in
2228 # INDEX-PRESENT has type - and there isn't a corresponding entry in
2229 # INDEX-OLD with type -.
2230 fetch_filter_unmodified_notpresent \
2231 INDEX-OLD INDEX-PRESENT INDEX-NEW /dev/null
2233 # For each entry in INDEX-PRESENT of type -, remove any corresponding
2234 # entry from INDEX-NEW if ${ALLOWADD} != "yes". Remove all entries
2235 # of type - from INDEX-PRESENT.
2236 fetch_filter_allowadd INDEX-PRESENT INDEX-NEW
2238 # If ${ALLOWDELETE} != "yes", then remove any entries from
2239 # INDEX-PRESENT which don't correspond to entries in INDEX-NEW.
2240 fetch_filter_allowdelete INDEX-PRESENT INDEX-NEW
2242 # If ${KEEPMODIFIEDMETADATA} == "yes", then for each entry in
2243 # INDEX-PRESENT with metadata not matching any entry in INDEX-OLD,
2244 # replace the corresponding line of INDEX-NEW with one having the
2245 # same metadata as the entry in INDEX-PRESENT.
2246 fetch_filter_modified_metadata INDEX-OLD INDEX-PRESENT INDEX-NEW
2248 # Remove lines from INDEX-PRESENT and INDEX-NEW which are identical;
2249 # no need to update a file if it isn't changing.
2250 fetch_filter_uptodate INDEX-PRESENT INDEX-NEW
2252 # Prepare to fetch files: Generate a list of the files we need,
2253 # copy the unmodified files we have into /files/, and generate
2254 # a list of patches to download.
2255 fetch_files_prepare INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1
2258 fetch_files || return 1
2260 # Create and populate install manifest directory; and report what
2261 # updates are available.
2262 fetch_create_manifest || return 1
2264 # Warn about any upcoming EoL
2265 fetch_warn_eol || return 1
2268 # If StrictComponents is not "yes", generate a new components list
2269 # with only the components which appear to be installed.
2270 upgrade_guess_components () {
2271 if [ "${STRICTCOMPONENTS}" = "no" ]; then
2272 # Generate filtered INDEX-ALL with only the components listed
2274 fetch_filter_metadata_components $1 || return 1
2276 # Tell the user why his disk is suddenly making lots of noise
2277 echo -n "Inspecting system... "
2279 # Look at the files on disk, and assume that a component is
2280 # supposed to be present if it is more than half-present.
2281 cut -f 1-3 -d '|' < INDEX-ALL |
2283 while read C S F; do
2284 if [ -e ${BASEDIR}/${F} ]; then
2291 sed -E 's,^ +,,' > compfreq
2292 grep ' = ' compfreq |
2294 sort -k 2,2 -t ' ' > compfreq.total
2295 grep ' + ' compfreq |
2297 sort -k 2,2 -t ' ' > compfreq.present
2298 join -t ' ' -1 2 -2 2 compfreq.present compfreq.total |
2299 while read S P T; do
2300 if [ ${T} -ne 0 -a ${P} -gt `expr ${T} / 2` ]; then
2304 cut -f 2 -d ' ' < compfreq.total > comp.total
2305 rm INDEX-ALL compfreq compfreq.total compfreq.present
2307 # We're done making noise.
2310 # Sometimes the kernel isn't installed where INDEX-ALL
2311 # thinks that it should be: In particular, it is often in
2312 # /boot/kernel instead of /boot/GENERIC or /boot/SMP. To
2313 # deal with this, if "kernel|X" is listed in comp.total
2314 # (i.e., is a component which would be upgraded if it is
2315 # found to be present) we will add it to comp.present.
2316 # If "kernel|<anything>" is in comp.total but "kernel|X" is
2317 # not, we print a warning -- the user is running a kernel
2318 # which isn't part of the release.
2319 KCOMP=`echo ${KERNCONF} | tr 'A-Z' 'a-z'`
2320 grep -E "^kernel\|${KCOMP}\$" comp.total >> comp.present
2322 if grep -qE "^kernel\|" comp.total &&
2323 ! grep -qE "^kernel\|${KCOMP}\$" comp.total; then
2326 WARNING: This system is running a "${KCOMP}" kernel, which is not a
2327 kernel configuration distributed as part of FreeBSD ${RELNUM}.
2328 This kernel will not be updated: you MUST update the kernel manually
2329 before running "$0 install".
2333 # Re-sort the list of installed components and generate
2334 # the list of non-installed components.
2335 sort -u < comp.present > comp.present.tmp
2336 mv comp.present.tmp comp.present
2337 comm -13 comp.present comp.total > comp.absent
2339 # Ask the user to confirm that what we have is correct. To
2340 # reduce user confusion, translate "X|Y" back to "X/Y" (as
2341 # subcomponents must be listed in the configuration file).
2343 echo -n "The following components of FreeBSD "
2344 echo "seem to be installed:"
2345 tr '|' '/' < comp.present |
2348 echo -n "The following components of FreeBSD "
2349 echo "do not seem to be installed:"
2350 tr '|' '/' < comp.absent |
2353 continuep || return 1
2356 # Suck the generated list of components into ${COMPONENTS}.
2357 # Note that comp.present.tmp is used due to issues with
2358 # pipelines and setting variables.
2360 tr '|' '/' < comp.present > comp.present.tmp
2362 COMPONENTS="${COMPONENTS} ${C}"
2363 done < comp.present.tmp
2365 # Delete temporary files
2366 rm comp.present comp.present.tmp comp.absent comp.total
2370 # If StrictComponents is not "yes", COMPONENTS contains an entry
2371 # corresponding to the currently running kernel, and said kernel
2372 # does not exist in the new release, add "kernel/generic" to the
2373 # list of components.
2374 upgrade_guess_new_kernel () {
2375 if [ "${STRICTCOMPONENTS}" = "no" ]; then
2376 # Grab the unfiltered metadata file.
2377 METAHASH=`look "$1|" tINDEX.present | cut -f 2 -d '|'`
2378 gunzip -c < files/${METAHASH}.gz > $1.all
2380 # If "kernel/${KCOMP}" is in ${COMPONENTS} and that component
2381 # isn't in $1.all, we need to add kernel/generic.
2382 for C in ${COMPONENTS}; do
2383 if [ ${C} = "kernel/${KCOMP}" ] &&
2384 ! grep -qE "^kernel\|${KCOMP}\|" $1.all; then
2385 COMPONENTS="${COMPONENTS} kernel/generic"
2389 WARNING: This system is running a "${KCOMP}" kernel, which is not a
2390 kernel configuration distributed as part of FreeBSD ${RELNUM}.
2391 As part of upgrading to FreeBSD ${RELNUM}, this kernel will be
2392 replaced with a "generic" kernel.
2394 continuep || return 1
2398 # Don't need this any more...
2403 # Convert INDEX-OLD (last release) and INDEX-ALL (new release) into
2404 # INDEX-OLD and INDEX-NEW files (in the sense of normal upgrades).
2405 upgrade_oldall_to_oldnew () {
2406 # For each ${F}|... which appears in INDEX-ALL but does not appear
2407 # in INDEX-OLD, add ${F}|-|||||| to INDEX-OLD.
2408 cut -f 1 -d '|' < $1 |
2410 cut -f 1 -d '|' < $2 |
2412 comm -13 $1.paths - |
2413 lam - -s "|-||||||" |
2417 # Remove lines from INDEX-OLD which also appear in INDEX-ALL
2418 comm -23 $1 $2 > $1.tmp
2421 # Remove lines from INDEX-ALL which have a file name not appearing
2422 # anywhere in INDEX-OLD (since these must be files which haven't
2423 # changed -- if they were new, there would be an entry of type "-").
2424 cut -f 1 -d '|' < $1 |
2426 sort -k 1,1 -t '|' < $2 |
2427 join -t '|' - $1.paths |
2432 # Rename INDEX-ALL to INDEX-NEW.
2436 # Helper for upgrade_merge: Return zero true iff the two files differ only
2437 # in the contents of their RCS tags.
2439 X=`sed -E 's/\\$FreeBSD.*\\$/\$FreeBSD\$/' < $1 | ${SHA256}`
2440 Y=`sed -E 's/\\$FreeBSD.*\\$/\$FreeBSD\$/' < $2 | ${SHA256}`
2442 if [ $X = $Y ]; then
2449 # From the list of "old" files in $1, merge changes in $2 with those in $3,
2450 # and update $3 to reflect the hashes of merged files.
2452 # We only need to do anything if $1 is non-empty.
2454 cut -f 1 -d '|' $1 |
2457 # Create staging area for merging files
2461 mkdir -p merge/old/${D}
2462 mkdir -p merge/${OLDRELNUM}/${D}
2463 mkdir -p merge/${RELNUM}/${D}
2464 mkdir -p merge/new/${D}
2469 # Currently installed file
2470 V=`look "${F}|" $2 | cut -f 7 -d '|'`
2471 gunzip < files/${V}.gz > merge/old/${F}
2474 if look "${F}|" $1 | fgrep -q "|f|"; then
2475 V=`look "${F}|" $1 | cut -f 3 -d '|'`
2476 gunzip < files/${V}.gz \
2477 > merge/${OLDRELNUM}/${F}
2481 if look "${F}|" $3 | cut -f 1,2,7 -d '|' |
2482 fgrep -q "|f|"; then
2483 V=`look "${F}|" $3 | cut -f 7 -d '|'`
2484 gunzip < files/${V}.gz \
2485 > merge/${RELNUM}/${F}
2489 # Attempt to automatically merge changes
2490 echo -n "Attempting to automatically merge "
2491 echo -n "changes in files..."
2494 # If the file doesn't exist in the new release,
2495 # the result of "merging changes" is having the file
2497 if ! [ -f merge/${RELNUM}/${F} ]; then
2501 # If the file didn't exist in the old release, we're
2502 # going to throw away the existing file and hope that
2503 # the version from the new release is what we want.
2504 if ! [ -f merge/${OLDRELNUM}/${F} ]; then
2505 cp merge/${RELNUM}/${F} merge/new/${F}
2509 # Some files need special treatment.
2511 /etc/spwd.db | /etc/pwd.db | /etc/login.conf.db)
2512 # Don't merge these -- we're rebuild them
2513 # after updates are installed.
2514 cp merge/old/${F} merge/new/${F}
2517 if ! diff3 -E -m -L "current version" \
2518 -L "${OLDRELNUM}" -L "${RELNUM}" \
2520 merge/${OLDRELNUM}/${F} \
2521 merge/${RELNUM}/${F} \
2522 > merge/new/${F} 2>/dev/null; then
2523 echo ${F} >> failed.merges
2530 # Ask the user to handle any files which didn't merge.
2532 # If the installed file differs from the version in
2533 # the old release only due to RCS tag expansion
2534 # then just use the version in the new release.
2535 if samef merge/old/${F} merge/${OLDRELNUM}/${F}; then
2536 cp merge/${RELNUM}/${F} merge/new/${F}
2542 The following file could not be merged automatically: ${F}
2543 Press Enter to edit this file in ${EDITOR} and resolve the conflicts
2547 read response </dev/tty
2548 if expr "${response}" : '[Aa][Cc][Cc][Ee][Pp][Tt]' > /dev/null; then
2552 ${EDITOR} `pwd`/merge/new/${F} < /dev/tty
2554 if ! grep -qE '^(<<<<<<<|=======|>>>>>>>)([[:space:]].*)?$' $(pwd)/merge/new/${F} ; then
2559 Merge conflict markers remain in: ${F}
2560 These must be resolved for the system to be functional.
2562 Press Enter to return to editing this file, or type "ACCEPT" to carry on with
2563 these lines remaining in the file.
2566 done < failed.merges
2569 # Ask the user to confirm that he likes how the result
2572 # Skip files which haven't changed except possibly
2573 # in their RCS tags.
2574 if [ -f merge/old/${F} ] && [ -f merge/new/${F} ] &&
2575 samef merge/old/${F} merge/new/${F}; then
2579 # Skip files where the installed file differs from
2580 # the old file only due to RCS tags.
2581 if [ -f merge/old/${F} ] &&
2582 [ -f merge/${OLDRELNUM}/${F} ] &&
2583 samef merge/old/${F} merge/${OLDRELNUM}/${F}; then
2587 # Warn about files which are ceasing to exist.
2588 if ! [ -f merge/new/${F} ]; then
2591 The following file will be removed, as it no longer exists in
2592 FreeBSD ${RELNUM}: ${F}
2594 continuep < /dev/tty || return 1
2598 # Print changes for the user's approval.
2601 The following changes, which occurred between FreeBSD ${OLDRELNUM} and
2602 FreeBSD ${RELNUM} have been merged into ${F}:
2604 diff -U 5 -L "current version" -L "new version" \
2605 merge/old/${F} merge/new/${F} || true
2606 continuep < /dev/tty || return 1
2609 # Store merged files.
2611 if [ -f merge/new/${F} ]; then
2612 V=`${SHA256} -q merge/new/${F}`
2614 gzip -c < merge/new/${F} > files/${V}.gz
2617 done < $1-paths > newhashes
2619 # Pull lines out from $3 which need to be updated to
2620 # reflect merged files.
2623 done < $1-paths > $3-oldlines
2625 # Update lines to reflect merged files
2626 join -t '|' -o 1.1,1.2,1.3,1.4,1.5,1.6,2.2,1.8 \
2627 $3-oldlines newhashes > $3-newlines
2629 # Remove old lines from $3 and add new lines.
2632 sort - $3-newlines > $3.tmp
2636 rm $1-paths newhashes $3-oldlines $3-newlines
2640 # We're done with merging files.
2644 # Do the work involved in fetching upgrades to a new release
2646 workdir_init || return 1
2648 # Prepare the mirror list.
2649 fetch_pick_server_init && fetch_pick_server
2651 # Try to fetch the public key until we run out of servers.
2652 while ! fetch_key; do
2653 fetch_pick_server || return 1
2656 # Try to fetch the metadata index signature ("tag") until we run
2657 # out of available servers; and sanity check the downloaded tag.
2658 while ! fetch_tag; do
2659 fetch_pick_server || return 1
2661 fetch_tagsanity || return 1
2663 # Fetch the INDEX-OLD and INDEX-ALL.
2664 fetch_metadata INDEX-OLD INDEX-ALL || return 1
2666 # If StrictComponents is not "yes", generate a new components list
2667 # with only the components which appear to be installed.
2668 upgrade_guess_components INDEX-ALL || return 1
2670 # Generate filtered INDEX-OLD and INDEX-ALL files containing only
2671 # the components we want and without anything marked as "Ignore".
2672 fetch_filter_metadata INDEX-OLD || return 1
2673 fetch_filter_metadata INDEX-ALL || return 1
2675 # Merge the INDEX-OLD and INDEX-ALL files into INDEX-OLD.
2676 sort INDEX-OLD INDEX-ALL > INDEX-OLD.tmp
2677 mv INDEX-OLD.tmp INDEX-OLD
2680 # Adjust variables for fetching files from the new release.
2682 RELNUM=${TARGETRELEASE}
2683 OLDFETCHDIR=${FETCHDIR}
2684 FETCHDIR=${RELNUM}/${ARCH}
2686 # Try to fetch the NEW metadata index signature ("tag") until we run
2687 # out of available servers; and sanity check the downloaded tag.
2688 while ! fetch_tag; do
2689 fetch_pick_server || return 1
2692 # Fetch the new INDEX-ALL.
2693 fetch_metadata INDEX-ALL || return 1
2695 # If StrictComponents is not "yes", COMPONENTS contains an entry
2696 # corresponding to the currently running kernel, and said kernel
2697 # does not exist in the new release, add "kernel/generic" to the
2698 # list of components.
2699 upgrade_guess_new_kernel INDEX-ALL || return 1
2701 # Filter INDEX-ALL to contain only the components we want and without
2702 # anything marked as "Ignore".
2703 fetch_filter_metadata INDEX-ALL || return 1
2705 # Convert INDEX-OLD (last release) and INDEX-ALL (new release) into
2706 # INDEX-OLD and INDEX-NEW files (in the sense of normal upgrades).
2707 upgrade_oldall_to_oldnew INDEX-OLD INDEX-ALL INDEX-NEW
2709 # Translate /boot/${KERNCONF} or /boot/${NKERNCONF} into ${KERNELDIR}
2710 fetch_filter_kernel_names INDEX-NEW ${NKERNCONF}
2711 fetch_filter_kernel_names INDEX-OLD ${KERNCONF}
2713 # For all paths appearing in INDEX-OLD or INDEX-NEW, inspect the
2714 # system and generate an INDEX-PRESENT file.
2715 fetch_inspect_system INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1
2717 # Based on ${MERGECHANGES}, generate a file tomerge-old with the
2718 # paths and hashes of old versions of files to merge.
2719 fetch_filter_mergechanges INDEX-OLD INDEX-PRESENT INDEX-NEW tomerge-old
2721 # Based on ${UPDATEIFUNMODIFIED}, remove lines from INDEX-* which
2722 # correspond to lines in INDEX-PRESENT with hashes not appearing
2723 # in INDEX-OLD or INDEX-NEW. Also remove lines where the entry in
2724 # INDEX-PRESENT has type - and there isn't a corresponding entry in
2725 # INDEX-OLD with type -.
2726 fetch_filter_unmodified_notpresent \
2727 INDEX-OLD INDEX-PRESENT INDEX-NEW tomerge-old
2729 # For each entry in INDEX-PRESENT of type -, remove any corresponding
2730 # entry from INDEX-NEW if ${ALLOWADD} != "yes". Remove all entries
2731 # of type - from INDEX-PRESENT.
2732 fetch_filter_allowadd INDEX-PRESENT INDEX-NEW
2734 # If ${ALLOWDELETE} != "yes", then remove any entries from
2735 # INDEX-PRESENT which don't correspond to entries in INDEX-NEW.
2736 fetch_filter_allowdelete INDEX-PRESENT INDEX-NEW
2738 # If ${KEEPMODIFIEDMETADATA} == "yes", then for each entry in
2739 # INDEX-PRESENT with metadata not matching any entry in INDEX-OLD,
2740 # replace the corresponding line of INDEX-NEW with one having the
2741 # same metadata as the entry in INDEX-PRESENT.
2742 fetch_filter_modified_metadata INDEX-OLD INDEX-PRESENT INDEX-NEW
2744 # Remove lines from INDEX-PRESENT and INDEX-NEW which are identical;
2745 # no need to update a file if it isn't changing.
2746 fetch_filter_uptodate INDEX-PRESENT INDEX-NEW
2748 # Fetch "clean" files from the old release for merging changes.
2749 fetch_files_premerge tomerge-old
2751 # Prepare to fetch files: Generate a list of the files we need,
2752 # copy the unmodified files we have into /files/, and generate
2753 # a list of patches to download.
2754 fetch_files_prepare INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1
2756 # Fetch patches from to-${RELNUM}/${ARCH}/bp/
2757 PATCHDIR=to-${RELNUM}/${ARCH}/bp
2758 fetch_files || return 1
2760 # Merge configuration file changes.
2761 upgrade_merge tomerge-old INDEX-PRESENT INDEX-NEW || return 1
2763 # Create and populate install manifest directory; and report what
2764 # updates are available.
2765 fetch_create_manifest || return 1
2767 # Leave a note behind to tell the "install" command that the kernel
2768 # needs to be installed before the world.
2769 touch ${BDHASH}-install/kernelfirst
2771 # Remind the user that they need to run "freebsd-update install"
2772 # to install the downloaded bits, in case they didn't RTFM.
2773 echo "To install the downloaded upgrades, run \"$0 install\"."
2776 # Make sure that all the file hashes mentioned in $@ have corresponding
2777 # gzipped files stored in /files/.
2779 # Generate a list of hashes
2786 # Make sure all the hashes exist
2788 if ! [ -f files/${HASH}.gz ]; then
2789 echo -n "Update files missing -- "
2790 echo "this should never happen."
2791 echo "Re-run '$0 fetch'."
2800 # Remove the system immutable flag from files
2802 # Generate file list
2804 cut -f 1 -d '|' > filelist
2808 if ! [ -e ${BASEDIR}/${F} ]; then
2811 echo ${BASEDIR}/${F}
2813 done < filelist | xargs chflags noschg || return 1
2819 # Decide which directory name to use for kernel backups.
2820 backup_kernel_finddir () {
2823 # Pathname does not exist, so it is OK use that name
2824 # for backup directory.
2825 if [ ! -e $BASEDIR/$BACKUPKERNELDIR ]; then
2829 # If directory do exist, we only use if it has our
2831 if [ -d $BASEDIR/$BACKUPKERNELDIR -a \
2832 -e $BASEDIR/$BACKUPKERNELDIR/.freebsd-update ]; then
2836 # We could not use current directory name, so add counter to
2837 # the end and try again.
2839 if [ $CNT -gt 9 ]; then
2840 echo "Could not find valid backup dir ($BASEDIR/$BACKUPKERNELDIR)"
2843 BACKUPKERNELDIR="`echo $BACKUPKERNELDIR | sed -Ee 's/[0-9]\$//'`"
2844 BACKUPKERNELDIR="${BACKUPKERNELDIR}${CNT}"
2848 # Backup the current kernel using hardlinks, if not disabled by user.
2849 # Since we delete all files in the directory used for previous backups
2850 # we create a marker file called ".freebsd-update" in the directory so
2851 # we can determine on the next run that the directory was created by
2852 # freebsd-update and we then do not accidentally remove user files in
2853 # the unlikely case that the user has created a directory with a
2856 # Only make kernel backup is so configured.
2857 if [ $BACKUPKERNEL != yes ]; then
2861 # Decide which directory name to use for kernel backups.
2862 backup_kernel_finddir
2864 # Remove old kernel backup files. If $BACKUPKERNELDIR was
2865 # "not ours", backup_kernel_finddir would have exited, so
2866 # deleting the directory content is as safe as we can make it.
2867 if [ -d $BASEDIR/$BACKUPKERNELDIR ]; then
2868 rm -fr $BASEDIR/$BACKUPKERNELDIR
2871 # Create directories for backup.
2872 mkdir -p $BASEDIR/$BACKUPKERNELDIR
2873 mtree -cdn -p "${BASEDIR}/${KERNELDIR}" | \
2874 mtree -Ue -p "${BASEDIR}/${BACKUPKERNELDIR}" > /dev/null
2876 # Mark the directory as having been created by freebsd-update.
2877 touch $BASEDIR/$BACKUPKERNELDIR/.freebsd-update
2878 if [ $? -ne 0 ]; then
2879 echo "Could not create kernel backup directory"
2883 # Disable pathname expansion to be sure *.symbols is not
2887 # Use find to ignore symbol files, unless disabled by user.
2888 if [ $BACKUPKERNELSYMBOLFILES = yes ]; then
2891 FINDFILTER="-a ! -name *.debug -a ! -name *.symbols"
2894 # Backup all the kernel files using hardlinks.
2895 (cd ${BASEDIR}/${KERNELDIR} && find . -type f $FINDFILTER -exec \
2896 cp -pl '{}' ${BASEDIR}/${BACKUPKERNELDIR}/'{}' \;)
2898 # Re-enable patchname expansion.
2902 # Check for and remove an existing directory that conflicts with the file or
2903 # symlink that we are going to install.
2905 if [ -d "$1" ]; then
2906 echo "Removing conflicting directory $1"
2912 install_from_index () {
2913 # First pass: Do everything apart from setting file flags. We
2914 # can't set flags yet, because schg inhibits hard linking.
2915 sort -k 1,1 -t '|' $1 |
2917 while read FPATH TYPE OWNER GROUP PERM FLAGS HASH LINK; do
2920 # Create a directory. A file may change to a directory
2921 # on upgrade (PR273661). If that happens, remove the
2923 if [ -e "${BASEDIR}/${FPATH}" ] && \
2924 ! [ -d "${BASEDIR}/${FPATH}" ]; then
2925 rm -f -- "${BASEDIR}/${FPATH}"
2927 install -d -o ${OWNER} -g ${GROUP} \
2928 -m ${PERM} ${BASEDIR}/${FPATH}
2931 dir_conflict "${BASEDIR}/${FPATH}"
2932 if [ -z "${LINK}" ]; then
2933 # Create a file, without setting flags.
2934 gunzip < files/${HASH}.gz > ${HASH}
2935 install -S -o ${OWNER} -g ${GROUP} \
2936 -m ${PERM} ${HASH} ${BASEDIR}/${FPATH}
2939 # Create a hard link.
2940 ln -f ${BASEDIR}/${LINK} ${BASEDIR}/${FPATH}
2944 dir_conflict "${BASEDIR}/${FPATH}"
2946 ln -sfh ${HASH} ${BASEDIR}/${FPATH}
2951 # Perform a second pass, adding file flags.
2953 while read FPATH TYPE OWNER GROUP PERM FLAGS HASH LINK; do
2954 if [ ${TYPE} = "f" ] &&
2955 ! [ ${FLAGS} = "0" ]; then
2956 chflags ${FLAGS} ${BASEDIR}/${FPATH}
2961 # Remove files which we want to delete
2963 # Generate list of new files
2964 cut -f 1 -d '|' < $2 |
2967 # Generate subindex of old files we want to nuke
2968 sort -k 1,1 -t '|' $1 |
2969 join -t '|' -v 1 - newfiles |
2970 sort -r -k 1,1 -t '|' |
2972 tr '|' ' ' > killfiles
2974 # Remove the offending bits
2975 while read FPATH TYPE; do
2978 rmdir ${BASEDIR}/${FPATH}
2981 if [ -f "${BASEDIR}/${FPATH}" ]; then
2982 rm "${BASEDIR}/${FPATH}"
2986 if [ -L "${BASEDIR}/${FPATH}" ]; then
2987 rm "${BASEDIR}/${FPATH}"
2994 rm newfiles killfiles
2997 # Install new files, delete old files, and update generated files
2999 # If we haven't already dealt with the kernel, deal with it.
3000 if ! [ -f $1/kerneldone ]; then
3001 grep -E '^/boot/' $1/INDEX-OLD > INDEX-OLD
3002 grep -E '^/boot/' $1/INDEX-NEW > INDEX-NEW
3004 # Backup current kernel before installing a new one
3005 backup_kernel || return 1
3008 install_from_index INDEX-NEW || return 1
3010 # Remove files which need to be deleted
3011 install_delete INDEX-OLD INDEX-NEW || return 1
3013 # Update linker.hints if necessary
3014 if [ -s INDEX-OLD -o -s INDEX-NEW ]; then
3015 kldxref -R ${BASEDIR}/boot/ 2>/dev/null
3018 # We've finished updating the kernel.
3021 # Do we need to ask for a reboot now?
3022 if [ -f $1/kernelfirst ] &&
3023 [ -s INDEX-OLD -o -s INDEX-NEW ]; then
3026 Kernel updates have been installed. Please reboot and run
3027 "$0 install" again to finish installing updates.
3033 # If we haven't already dealt with the world, deal with it.
3034 if ! [ -f $1/worlddone ]; then
3035 # Create any necessary directories first
3036 grep -vE '^/boot/' $1/INDEX-NEW |
3037 grep -E '^[^|]+\|d\|' > INDEX-NEW
3038 install_from_index INDEX-NEW || return 1
3040 # Install new runtime linker
3041 grep -vE '^/boot/' $1/INDEX-NEW |
3042 grep -vE '^[^|]+\|d\|' |
3043 grep -E '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' > INDEX-NEW
3044 install_from_index INDEX-NEW || return 1
3046 # Install new shared libraries next
3047 grep -vE '^/boot/' $1/INDEX-NEW |
3048 grep -vE '^[^|]+\|d\|' |
3049 grep -vE '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' |
3050 grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-NEW
3051 install_from_index INDEX-NEW || return 1
3053 # Deal with everything else
3054 grep -vE '^/boot/' $1/INDEX-OLD |
3055 grep -vE '^[^|]+\|d\|' |
3056 grep -vE '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' |
3057 grep -vE '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-OLD
3058 grep -vE '^/boot/' $1/INDEX-NEW |
3059 grep -vE '^[^|]+\|d\|' |
3060 grep -vE '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' |
3061 grep -vE '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-NEW
3062 install_from_index INDEX-NEW || return 1
3063 install_delete INDEX-OLD INDEX-NEW || return 1
3065 # Restart host sshd if running (PR263489). Note that this does
3066 # not affect child sshd processes handling existing sessions.
3067 if [ "$BASEDIR" = / ] && \
3068 service sshd status >/dev/null 2>/dev/null; then
3070 echo "Restarting sshd after upgrade"
3071 service sshd restart
3074 # Rehash certs if we actually have certctl installed.
3075 if which certctl>/dev/null; then
3076 env DESTDIR=${BASEDIR} certctl rehash
3079 # Rebuild generated pwd files and /etc/login.conf.db.
3080 pwd_mkdb -d ${BASEDIR}/etc -p ${BASEDIR}/etc/master.passwd
3081 cap_mkdb ${BASEDIR}/etc/login.conf
3083 # Rebuild man page databases, if necessary.
3084 for D in /usr/share/man /usr/share/openssl/man; do
3085 if [ ! -d ${BASEDIR}/$D ]; then
3088 if [ -f ${BASEDIR}/$D/mandoc.db ] && \
3089 [ -z "$(find ${BASEDIR}/$D -type f -newer ${BASEDIR}/$D/mandoc.db)" ]; then
3092 makewhatis ${BASEDIR}/$D
3095 # We've finished installing the world and deleting old files
3096 # which are not shared libraries.
3099 # Do we need to ask the user to portupgrade now?
3100 grep -vE '^/boot/' $1/INDEX-NEW |
3101 grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' |
3104 if grep -vE '^/boot/' $1/INDEX-OLD |
3105 grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' |
3108 join -v 1 - newfiles |
3112 Completing this upgrade requires removing old shared object files.
3113 Please rebuild all installed 3rd party software (e.g., programs
3114 installed from the ports tree) and then run "$0 install"
3115 again to finish installing updates.
3123 # Remove old shared libraries
3124 grep -vE '^/boot/' $1/INDEX-NEW |
3125 grep -vE '^[^|]+\|d\|' |
3126 grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-NEW
3127 grep -vE '^/boot/' $1/INDEX-OLD |
3128 grep -vE '^[^|]+\|d\|' |
3129 grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-OLD
3130 install_delete INDEX-OLD INDEX-NEW || return 1
3132 # Remove old directories
3133 grep -vE '^/boot/' $1/INDEX-NEW |
3134 grep -E '^[^|]+\|d\|' > INDEX-NEW
3135 grep -vE '^/boot/' $1/INDEX-OLD |
3136 grep -E '^[^|]+\|d\|' > INDEX-OLD
3137 install_delete INDEX-OLD INDEX-NEW || return 1
3139 # Remove temporary files
3140 rm INDEX-OLD INDEX-NEW
3143 # Rearrange bits to allow the installed updates to be rolled back
3144 install_setup_rollback () {
3145 # Remove the "reboot after installing kernel", "kernel updated", and
3146 # "finished installing the world" flags if present -- they are
3147 # irrelevant when rolling back updates.
3148 if [ -f ${BDHASH}-install/kernelfirst ]; then
3149 rm ${BDHASH}-install/kernelfirst
3150 rm ${BDHASH}-install/kerneldone
3152 if [ -f ${BDHASH}-install/worlddone ]; then
3153 rm ${BDHASH}-install/worlddone
3156 if [ -L ${BDHASH}-rollback ]; then
3157 mv ${BDHASH}-rollback ${BDHASH}-install/rollback
3160 mv ${BDHASH}-install ${BDHASH}-rollback
3163 # Actually install updates
3165 echo -n "Installing updates..."
3167 # Make sure we have all the files we should have
3168 install_verify ${BDHASH}-install/INDEX-OLD \
3169 ${BDHASH}-install/INDEX-NEW || return 1
3171 # Remove system immutable flag from files
3172 install_unschg ${BDHASH}-install/INDEX-OLD \
3173 ${BDHASH}-install/INDEX-NEW || return 1
3175 # Install new files, delete old files, and update linker.hints
3176 install_files ${BDHASH}-install || return 1
3178 # Rearrange bits to allow the installed updates to be rolled back
3179 install_setup_rollback
3184 # Rearrange bits to allow the previous set of updates to be rolled back next.
3185 rollback_setup_rollback () {
3186 if [ -L ${BDHASH}-rollback/rollback ]; then
3187 mv ${BDHASH}-rollback/rollback rollback-tmp
3188 rm -r ${BDHASH}-rollback/
3189 rm ${BDHASH}-rollback
3190 mv rollback-tmp ${BDHASH}-rollback
3192 rm -r ${BDHASH}-rollback/
3193 rm ${BDHASH}-rollback
3197 # Install old files, delete new files, and update linker.hints
3199 # Create directories first. They may be needed by files we will
3200 # install in subsequent steps (PR273950).
3201 awk -F \| '{if ($2 == "d") print }' $1/INDEX-OLD > INDEX-OLD
3202 install_from_index INDEX-OLD || return 1
3204 # Install old shared library files which don't have the same path as
3205 # a new shared library file.
3206 grep -vE '^/boot/' $1/INDEX-NEW |
3207 grep -E '/lib/.*\.so\.[0-9]+\|' |
3209 sort > INDEX-NEW.libs.flist
3210 grep -vE '^/boot/' $1/INDEX-OLD |
3211 grep -E '/lib/.*\.so\.[0-9]+\|' |
3212 sort -k 1,1 -t '|' - |
3213 join -t '|' -v 1 - INDEX-NEW.libs.flist > INDEX-OLD
3214 install_from_index INDEX-OLD || return 1
3216 # Deal with files which are neither kernel nor shared library
3217 grep -vE '^/boot/' $1/INDEX-OLD |
3218 grep -vE '/lib/.*\.so\.[0-9]+\|' > INDEX-OLD
3219 grep -vE '^/boot/' $1/INDEX-NEW |
3220 grep -vE '/lib/.*\.so\.[0-9]+\|' > INDEX-NEW
3221 install_from_index INDEX-OLD || return 1
3222 install_delete INDEX-NEW INDEX-OLD || return 1
3224 # Install any old shared library files which we didn't install above.
3225 grep -vE '^/boot/' $1/INDEX-OLD |
3226 grep -E '/lib/.*\.so\.[0-9]+\|' |
3227 sort -k 1,1 -t '|' - |
3228 join -t '|' - INDEX-NEW.libs.flist > INDEX-OLD
3229 install_from_index INDEX-OLD || return 1
3231 # Delete unneeded shared library files
3232 grep -vE '^/boot/' $1/INDEX-OLD |
3233 grep -E '/lib/.*\.so\.[0-9]+\|' > INDEX-OLD
3234 grep -vE '^/boot/' $1/INDEX-NEW |
3235 grep -E '/lib/.*\.so\.[0-9]+\|' > INDEX-NEW
3236 install_delete INDEX-NEW INDEX-OLD || return 1
3238 # Deal with kernel files
3239 grep -E '^/boot/' $1/INDEX-OLD > INDEX-OLD
3240 grep -E '^/boot/' $1/INDEX-NEW > INDEX-NEW
3241 install_from_index INDEX-OLD || return 1
3242 install_delete INDEX-NEW INDEX-OLD || return 1
3243 if [ -s INDEX-OLD -o -s INDEX-NEW ]; then
3244 kldxref -R /boot/ 2>/dev/null
3247 # Remove temporary files
3248 rm INDEX-OLD INDEX-NEW INDEX-NEW.libs.flist
3251 # Actually rollback updates
3253 echo -n "Uninstalling updates..."
3255 # If there are updates waiting to be installed, remove them; we
3256 # want the user to re-run 'fetch' after rolling back updates.
3257 if [ -L ${BDHASH}-install ]; then
3258 rm -r ${BDHASH}-install/
3259 rm ${BDHASH}-install
3262 # Make sure we have all the files we should have
3263 install_verify ${BDHASH}-rollback/INDEX-NEW \
3264 ${BDHASH}-rollback/INDEX-OLD || return 1
3266 # Remove system immutable flag from files
3267 install_unschg ${BDHASH}-rollback/INDEX-NEW \
3268 ${BDHASH}-rollback/INDEX-OLD || return 1
3270 # Install old files, delete new files, and update linker.hints
3271 rollback_files ${BDHASH}-rollback || return 1
3273 # Remove the rollback directory and the symlink pointing to it; and
3274 # rearrange bits to allow the previous set of updates to be rolled
3276 rollback_setup_rollback
3281 # Compare INDEX-ALL and INDEX-PRESENT and print warnings about differences.
3283 # Get all the lines which mismatch in something other than file
3284 # flags. We ignore file flags because sysinstall doesn't seem to
3285 # set them when it installs FreeBSD; warning about these adds a
3286 # very large amount of noise.
3287 cut -f 1-5,7-8 -d '|' $1 > $1.noflags
3288 sort -k 1,1 -t '|' $1.noflags > $1.sorted
3289 cut -f 1-5,7-8 -d '|' $2 |
3290 comm -13 $1.noflags - |
3291 fgrep -v '|-|||||' |
3292 sort -k 1,1 -t '|' |
3293 join -t '|' $1.sorted - > INDEX-NOTMATCHING
3295 # Ignore files which match IDSIGNOREPATHS.
3296 for X in ${IDSIGNOREPATHS}; do
3297 grep -E "^${X}" INDEX-NOTMATCHING
3300 comm -13 - INDEX-NOTMATCHING > INDEX-NOTMATCHING.tmp
3301 mv INDEX-NOTMATCHING.tmp INDEX-NOTMATCHING
3303 # Go through the lines and print warnings.
3305 while read FPATH TYPE OWNER GROUP PERM HASH LINK P_TYPE P_OWNER P_GROUP P_PERM P_HASH P_LINK; do
3306 # Warn about different object types.
3307 if ! [ "${TYPE}" = "${P_TYPE}" ]; then
3308 echo -n "${FPATH} is a "
3310 f) echo -n "regular file, "
3312 d) echo -n "directory, "
3314 L) echo -n "symlink, "
3317 echo -n "but should be a "
3319 f) echo -n "regular file."
3321 d) echo -n "directory."
3323 L) echo -n "symlink."
3328 # Skip other tests, since they don't make sense if
3329 # we're comparing different object types.
3333 # Warn about different owners.
3334 if ! [ "${OWNER}" = "${P_OWNER}" ]; then
3335 echo -n "${FPATH} is owned by user id ${P_OWNER}, "
3336 echo "but should be owned by user id ${OWNER}."
3339 # Warn about different groups.
3340 if ! [ "${GROUP}" = "${P_GROUP}" ]; then
3341 echo -n "${FPATH} is owned by group id ${P_GROUP}, "
3342 echo "but should be owned by group id ${GROUP}."
3345 # Warn about different permissions. We do not warn about
3346 # different permissions on symlinks, since some archivers
3347 # don't extract symlink permissions correctly and they are
3349 if ! [ "${PERM}" = "${P_PERM}" ] &&
3350 ! [ "${TYPE}" = "L" ]; then
3351 echo -n "${FPATH} has ${P_PERM} permissions, "
3352 echo "but should have ${PERM} permissions."
3355 # Warn about different file hashes / symlink destinations.
3356 if ! [ "${HASH}" = "${P_HASH}" ]; then
3357 if [ "${TYPE}" = "L" ]; then
3358 echo -n "${FPATH} is a symlink to ${P_HASH}, "
3359 echo "but should be a symlink to ${HASH}."
3361 if [ "${TYPE}" = "f" ]; then
3362 echo -n "${FPATH} has SHA256 hash ${P_HASH}, "
3363 echo "but should have SHA256 hash ${HASH}."
3367 # We don't warn about different hard links, since some
3368 # some archivers break hard links, and as long as the
3369 # underlying data is correct they really don't matter.
3370 done < INDEX-NOTMATCHING
3373 rm $1 $1.noflags $1.sorted $2 INDEX-NOTMATCHING
3376 # Do the work involved in comparing the system to a "known good" index
3378 workdir_init || return 1
3380 # Prepare the mirror list.
3381 fetch_pick_server_init && fetch_pick_server
3383 # Try to fetch the public key until we run out of servers.
3384 while ! fetch_key; do
3385 fetch_pick_server || return 1
3388 # Try to fetch the metadata index signature ("tag") until we run
3389 # out of available servers; and sanity check the downloaded tag.
3390 while ! fetch_tag; do
3391 fetch_pick_server || return 1
3393 fetch_tagsanity || return 1
3395 # Fetch INDEX-OLD and INDEX-ALL.
3396 fetch_metadata INDEX-OLD INDEX-ALL || return 1
3398 # Generate filtered INDEX-OLD and INDEX-ALL files containing only
3399 # the components we want and without anything marked as "Ignore".
3400 fetch_filter_metadata INDEX-OLD || return 1
3401 fetch_filter_metadata INDEX-ALL || return 1
3403 # Merge the INDEX-OLD and INDEX-ALL files into INDEX-ALL.
3404 sort INDEX-OLD INDEX-ALL > INDEX-ALL.tmp
3405 mv INDEX-ALL.tmp INDEX-ALL
3408 # Translate /boot/${KERNCONF} to ${KERNELDIR}
3409 fetch_filter_kernel_names INDEX-ALL ${KERNCONF}
3411 # Inspect the system and generate an INDEX-PRESENT file.
3412 fetch_inspect_system INDEX-ALL INDEX-PRESENT /dev/null || return 1
3414 # Compare INDEX-ALL and INDEX-PRESENT and print warnings about any
3416 IDS_compare INDEX-ALL INDEX-PRESENT
3419 #### Main functions -- call parameter-handling and core functions
3421 # Using the command line, configuration file, and defaults,
3422 # set all the parameters which are needed later.
3430 # Fetch command. Make sure that we're being called
3431 # interactively, then run fetch_check_params and fetch_run
3433 finalize_components_config ${COMPONENTS}
3434 if [ ! -t 0 -a $NOTTYOK -eq 0 ]; then
3435 echo -n "`basename $0` fetch should not "
3436 echo "be run non-interactively."
3437 echo "Run `basename $0` cron instead."
3445 # Cron command. Make sure the parameters are sensible; wait
3446 # rand(3600) seconds; then fetch updates. While fetching updates,
3447 # send output to a temporary file; only print that file if the
3451 sleep `jot -r 1 0 3600`
3453 TMPFILE=`mktemp /tmp/freebsd-update.XXXXXX` || exit 1
3454 finalize_components_config ${COMPONENTS} >> ${TMPFILE}
3455 if ! fetch_run >> ${TMPFILE} ||
3456 ! grep -q "No updates needed" ${TMPFILE} ||
3457 [ ${VERBOSELEVEL} = "debug" ]; then
3458 mail -s "`hostname` security updates" ${MAILTO} < ${TMPFILE}
3464 # Fetch files for upgrading to a new release.
3466 finalize_components_config ${COMPONENTS}
3467 upgrade_check_params
3468 upgrade_run || exit 1
3471 # Check if there are fetched updates ready to install.
3472 # Chdir into the working directory.
3473 cmd_updatesready () {
3474 finalize_components_config ${COMPONENTS}
3475 # Check if working directory exists (if not, no updates pending)
3476 if ! [ -e "${WORKDIR}" ]; then
3477 echo "No updates are available to install."
3481 # Change into working directory (fail if no permission/directory etc.)
3482 cd ${WORKDIR} || exit 1
3484 # Construct a unique name from ${BASEDIR}
3485 BDHASH=`echo ${BASEDIR} | sha256 -q`
3487 # Check that we have updates ready to install
3488 if ! [ -L ${BDHASH}-install ]; then
3489 echo "No updates are available to install."
3493 echo "There are updates available to install."
3494 echo "Run '$0 install' to proceed."
3497 # Install downloaded updates.
3499 finalize_components_config ${COMPONENTS}
3500 install_check_params
3502 install_run || exit 1
3505 # Rollback most recently installed updates.
3507 finalize_components_config ${COMPONENTS}
3508 rollback_check_params
3509 rollback_run || exit 1
3512 # Compare system against a "known good" index.
3514 finalize_components_config ${COMPONENTS}
3519 # Output configuration.
3521 finalize_components_config ${COMPONENTS}
3522 for X in ${CONFIGOPTIONS}; do
3523 echo $X=$(eval echo \$${X})
3529 # Make sure we find utilities from the base system
3530 export PATH=/sbin:/bin:/usr/sbin:/usr/bin:${PATH}
3532 # Set a pager if the user doesn't
3533 if [ -z "$PAGER" ]; then
3537 # Set LC_ALL in order to avoid problems with character ranges like [A-Z].
3540 # Clear environment variables that may affect operation of tools that we use.
3544 for COMMAND in ${COMMANDS}; do