git: 866e5c6b3ce7 - stable/13 - freebsd-update: Fix merging already-updated files

From: Colin Percival <cperciva_at_FreeBSD.org>
Date: Tue, 16 May 2023 21:34:35 UTC
The branch stable/13 has been updated by cperciva:

URL: https://cgit.FreeBSD.org/src/commit/?id=866e5c6b3ce7ca3e15a24180fa1a0dcbda7c4b0f

commit 866e5c6b3ce7ca3e15a24180fa1a0dcbda7c4b0f
Author:     Colin Percival <cperciva@FreeBSD.org>
AuthorDate: 2023-05-05 03:00:58 +0000
Commit:     Colin Percival <cperciva@FreeBSD.org>
CommitDate: 2023-05-16 21:34:10 +0000

    freebsd-update: Fix merging already-updated files
    
    When performing an "upgrade" (moving between FreeBSD releases, as
    opposed to "update" which merely applies security/errata updates
    to the installed release) FreeBSD Update:
    
    1. Generates a list of "files needing to be merged", namely those
    files which don't match the version installed in the "old" release
    and have paths matching the MergeChanges configuration directive
    (by default, /boot/device.hints and everything under /etc/).
    
    and later on,
    
    2. Compares the currently-installed files to the versions in the
    "new" release, removing index entries for files which "don't need
    to be updated because they're not changing".
    
    Unfortunately if a file falls into both of these categories -- that
    is to say, if a file in /etc/ is the same as the version in the new
    release and not the same as the version in the old release -- the
    resulting "merge" step saw that the file was no longer listed as
    being part of the new release, resulting in the file being deleted.
    
    For the first 18 years of FreeBSD Update's existence, this never
    happened, since $FreeBSD$ tags resulted in "new release" files
    always being different from any files systems would already have
    installed.
    
    This commit fixes this behaviour by only placing a file into the
    "files needing to be merged" list if it does not match the version
    in the old release *or* the version in the new release.
    
    Reported by:    des
    Reviewed by:    delphij (earlier version), des, emaste
    MFC after:      7 days
    X-EN-Candidate: yes
    Differential Revision:  https://reviews.freebsd.org/D39973
    
    (cherry picked from commit c55b7e522629cb78adeb54bd9964304481d55eab)
---
 usr.sbin/freebsd-update/freebsd-update.sh | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/usr.sbin/freebsd-update/freebsd-update.sh b/usr.sbin/freebsd-update/freebsd-update.sh
index 4ef44d1ad000..4f779270926d 100644
--- a/usr.sbin/freebsd-update/freebsd-update.sh
+++ b/usr.sbin/freebsd-update/freebsd-update.sh
@@ -1677,11 +1677,12 @@ fetch_inspect_system () {
 	echo "done."
 }
 
-# For any paths matching ${MERGECHANGES}, compare $1 and $2 and find any
-# files which differ; generate $3 containing these paths and the old hashes.
+# For any paths matching ${MERGECHANGES}, compare $2 against $1 and $3 and
+# find any files with values unique to $2; generate $4 containing these paths
+# and their corresponding hashes from $1.
 fetch_filter_mergechanges () {
 	# Pull out the paths and hashes of the files matching ${MERGECHANGES}.
-	for F in $1 $2; do
+	for F in $1 $2 $3; do
 		for X in ${MERGECHANGES}; do
 			grep -E "^${X}" ${F}
 		done |
@@ -1689,9 +1690,10 @@ fetch_filter_mergechanges () {
 		    sort > ${F}-values
 	done
 
-	# Any line in $2-values which doesn't appear in $1-values and is a
-	# file means that we should list the path in $3.
-	comm -13 $1-values $2-values |
+	# Any line in $2-values which doesn't appear in $1-values or $3-values
+	# and is a file means that we should list the path in $3.
+	sort $1-values $3-values |
+	    comm -13 - $2-values |
 	    fgrep '|f|' |
 	    cut -f 1 -d '|' > $2-paths
 
@@ -1703,10 +1705,10 @@ fetch_filter_mergechanges () {
 	while read X; do
 		look "${X}|" $1-values |
 		    head -1
-	done < $2-paths > $3
+	done < $2-paths > $4
 
 	# Clean up
-	rm $1-values $2-values $2-paths
+	rm $1-values $2-values $3-values $2-paths
 }
 
 # For any paths matching ${UPDATEIFUNMODIFIED}, remove lines from $[123]
@@ -2711,7 +2713,7 @@ upgrade_run () {
 
 	# Based on ${MERGECHANGES}, generate a file tomerge-old with the
 	# paths and hashes of old versions of files to merge.
-	fetch_filter_mergechanges INDEX-OLD INDEX-PRESENT tomerge-old
+	fetch_filter_mergechanges INDEX-OLD INDEX-PRESENT INDEX-NEW tomerge-old
 
 	# Based on ${UPDATEIFUNMODIFIED}, remove lines from INDEX-* which
 	# correspond to lines in INDEX-PRESENT with hashes not appearing