2 ################################################
3 ### Managed by someone's ansible provisioner ###
4 ################################################
5 # Part of: https://git.somenet.org/root/pub/somesible.git
6 # 2017-2025 by someone <someone@somenet.org>
9 # make sure we exit on error
12 # Sanitise environment
13 while read -r env ; do
16 OPTIND) ;; # Dash croaks when unsetting OPTIND. See #985478
18 LANGUAGE|LANG|LC_*) ;;
19 DEB_*|DEBIAN_*|DEBCONF_*) ;;
25 $(awk 'BEGIN{for(v in ENVIRON) print v}')
28 # set the version and revision
29 progname="$(basename "$0")"
32 ######################################################################
34 ######## Utility functions #########
36 ######################################################################
37 for libdir in "$(dirname "$0")" /usr/share/ucf ; do
38 [ -f "${libdir}/ucf_library.sh" ] && \
39 . "${libdir}/ucf_library.sh" && \
43 # Usage: get_file_metadate file_name
47 # get file modification date without the nanoseconds and timezone info
48 moddate="$(date +"%F %T" --date "$(stat --format '@%Y' "$1")")"
49 # print file_name user.group permissions above_date
50 stat --format "%n %U.%G 0%a $moddate" "$1"
56 # Runs the diff command with approrpiate arguments
57 # Usage run_diff diff|sdiff diff_opts old_file new_file
60 local diff_cmd diff_opt old_file new_file old_file_label new_file_label out
66 old_file_label="$(get_file_metadata "$old_file")"
67 new_file_label="$(get_file_metadata "$new_file")"
69 [ -e "$old_file" ] || old_file=/dev/null
70 [ -e "$new_file" ] || new_file=/dev/null
72 if [ "$diff_cmd" = "diff" ] ; then
73 diff "$diff_opt" --label "$old_file_label" "$old_file" \
74 --label "$new_file_label" "$new_file" || true
75 elif [ "$diff_cmd" = "sdiff" ] ; then
76 # unfortunatelly the sdiff command does not support --label option
77 out="$(sdiff "$diff_opt" "$old_file" "$new_file")" || true
78 [ -z "$out" ] || printf "Old file: %s\nNew file: %s\n\n%s" \
79 "$old_file_label" "$new_file_label" "$out"
81 echo "Unknown diff command: $diff_cmd" >&2
86 # Use debconf to show the differences
87 # Usage: show_diff actual_file_differences file_stat_differences
90 DIFF="There are no non-white space differences in the files."
92 if [ 99999 -lt "$(echo "$1" | wc -c | awk '{print $1; }')" ]; then
93 DIFF="The differences between the files are too large to display."
95 # Try to convert non-breaking space to current locale
96 nbsp=$(printf '\302\240' | iconv -c --from-code=UTF-8 --to-code=//TRANSLIT)
97 DIFF="$(printf "%s" "$1" | sed "s/ /${nbsp:- }/g" | debconf-escape -e )"
100 if [ "$DEBCONF_OK" = "YES" ] && [ "$DEBIAN_HAS_FRONTEND" ]; then
103 db_subst $templ DIFF "$DIFF"
104 db_fset $templ seen false
105 db_input critical $templ || true
108 # may contain sensitive information, so clear
109 # immediatly after use so it is never written
111 db_subst $templ DIFF ""
115 if [ -z "$my_pager" ]; then
116 echo "$DIFF" | sensible-pager
118 echo "$DIFF" | $my_pager
125 Debian GNU/Linux $progname $pversion.
126 Copyright (C) 2002-2020 Manoj Srivastava.
127 Copyright (C) 2024- Mark Hindley.
128 This is free software; see the GNU General Public Licence for copying
129 conditions. There is NO warranty.
131 Usage: $progname [options] new_file destination
133 -h, --help print this message
134 -s foo, --src-dir foo Set the src dir (historical md5sums live here)
135 --sum-file bar Force the historical md5sums to be read from
136 this file. Overrides any setting of --src-dir.
137 -d[n], --debug=[n] Set the Debug level to N. Please note there must
138 be no spaces before the debug level
139 -n, --no-action Dry run. No action is actually taken.
140 -P foo, --package foo Don't follow dpkg-divert diversions by package foo.
141 -v, --verbose Make the script verbose
142 --three-way Register this file in the cache, and turn on the
143 diff3 option allowing the merging of maintainer
144 changes into a (potentially modified) local
145 configuration file. )
146 --state-dir bar Set the state directory to bar instead of the
147 default '/var/lib/ucf'. Used mostly for testing.
148 --debconf-ok Indicate that it is ok for ucf to use an already
149 running debconf instance for prompting.
150 --debconf-template bar
151 Specify an alternate, caller-provided debconf
152 template to use for prompting.
153 Usage: $progname -p destination
154 -p, --purge Remove any reference to destination from records
156 By default, the directory the new_file lives in is assumed to be the src-dir,
157 which is where we look for any historical md5sums.
163 ######################################################################
165 ######## file and hash save/restore functions #########
167 ######################################################################
169 for i in $(/usr/bin/seq 6 -1 0); do
170 if [ -e "${statedir}/hashfile.${i}" ]; then
171 if [ "$docmd" = "YES" ]; then
172 cp -pf "${statedir}/hashfile.${i}" \
173 "${statedir}/hashfile.$(($i+1))"
175 echo cp -pf "${statedir}/hashfile.${i}" \
176 "${statedir}/hashfile.$(($i+1))"
180 if [ -e "$statedir/hashfile" ]; then
181 if [ "$docmd" = "YES" ]; then
182 cp -pf "$statedir/hashfile" "$statedir/hashfile.0"
184 echo cp -pf "$statedir/hashfile" "$statedir/hashfile.0"
186 if [ "$docmd" = "YES" ]; then
187 if [ "$VERBOSE" ]; then
188 echo >&2 "grep -v ${dest_file_bre} $statedir/hashfile"
189 grep -v "${dest_file_bre}" "$statedir/hashfile" >&2 \
192 grep -v "${dest_file_bre}" "$statedir/hashfile" > \
193 "$statedir/hashfile.tmp" || true
194 mv -f "$statedir/hashfile.tmp" "$statedir/hashfile"
197 [ "$VERBOSE" ] && echo >&2 "The cache file is $cached_file"
198 if [ "$cached_file" ] && [ -f "$statedir/cache/$cached_file" ]; then
199 $action rm -f "$statedir/cache/$cached_file"
204 for i in $(/usr/bin/seq 6 -1 0); do
205 if [ -e "${statedir}/hashfile.${i}" ]; then
206 if [ "$docmd" = "YES" ]; then
207 cp -pf "${statedir}/hashfile.${i}" \
208 "${statedir}/hashfile.$(($i+1))"
210 echo cp -pf "${statedir}/hashfile.${i}" \
211 "${statedir}/hashfile.$(($i+1))"
215 if [ -e "$statedir/hashfile" ]; then
216 if [ "$docmd" = "YES" ]; then
217 cp -pf "$statedir/hashfile" "$statedir/hashfile.0"
219 echo cp -pf "$statedir/hashfile" "$statedir/hashfile.0"
221 if [ "$docmd" = "YES" ]; then
222 if [ "$VERBOSE" ]; then
223 echo >&2 "grep -v \"${dest_file_bre}\" \"$statedir/hashfile\""
224 grep -v "${dest_file_bre}" "$statedir/hashfile" >&2 || true
225 md5sum "$orig_new_file" | sed "s|$orig_new_file|$dest_file|" >&2
227 grep -v "${dest_file_bre}" "$statedir/hashfile" > \
228 "$statedir/hashfile.tmp" || true
229 md5sum "$orig_new_file" | sed "s|$orig_new_file|$dest_file|" >> \
230 "$statedir/hashfile.tmp"
231 mv -f "$statedir/hashfile.tmp" "$statedir/hashfile"
233 echo "(grep -v \"${dest_file_bre}\" \"$statedir/hashfile\""
234 echo " md5sum \"$orig_new_file\" | sed \"s|$orig_new_file|$dest_file|\"; "
235 echo ") | sort > \"$statedir/hashfile\""
238 if [ "$docmd" = "YES" ]; then
239 md5sum "$orig_new_file" | sed "s|$orig_new_file|$dest_file|" > \
242 echo " md5sum \"$orig_new_file\" | sed \"s|$orig_new_file|$dest_file|\" >" \
243 "\"$statedir/hashfile\""
246 file_size=$(stat -c '%s' "$orig_new_file")
247 if [ "$THREEWAY" ] || [ "$file_size" -lt 25600 ]; then
248 $action cp -pf "$orig_new_file" "$statedir/cache/$cached_file"
250 # cp -pf "$orig_new_file" "$dest_file.${DIST_SUFFIX}"
253 replace_conf_file () {
254 # do not mangle $dest_file since it's the one registered in the hashfile
255 # or we have been ask to register
256 real_file="$dest_file"
257 if [ -L "$dest_file" ]; then
258 real_file="$(readlink -nf "$dest_file" || :)"
259 if [ ! "$real_file" ]; then
260 echo >&2 "$dest_file is a broken symlink!"
261 $action rm -f "$dest_file"
262 real_file="$dest_file"
265 if [ -e "$real_file" ]; then
266 if [ -z "$RETAIN_OLD" ]; then
267 #echo "Saving ${real_file}.${OLD_SUFFIX}, in case."
269 echo >&2 "Not saving ${real_file}, since it was unmodified"
271 $action cp -pf $selinux "${real_file}" "${real_file}.${OLD_SUFFIX}"
274 if [ -e "${real_file}" ]; then
275 # Do not change the permissions and attributes of the destination
276 $action cp -f $selinux "$new_file" "${real_file}"
278 # No destination file exists
279 $action cp -pf $selinux "$new_file" "${real_file}"
284 ######################################################################
286 ######## Command line args #########
288 ######################################################################
290 # Long term variables
298 statedir='/var/lib/ucf'
300 DIST_SUFFIX="ucf-dist"
303 ERR_SUFFIX="merge-error"
306 if [ "$PURGE" = "YES" ]; then
307 if [ $# -ne 1 ]; then
308 echo >&2 "*** ERROR: Need exactly one file argument when purging, got $#"
314 if [ -e "$temp_dest_file" ]; then
315 dest_file=$(vset "$(readlink -q -m "$temp_dest_file")" "The Destination file")
317 dest_file=$(vset "$temp_dest_file" "The Destination file")
320 if [ $# -ne 2 ]; then
321 echo >&2 "*** ERROR: Need exactly two file arguments, got $#"
329 if [ ! -e "${temp_new_file}" ]; then
330 echo >&2 "Error: The new file ${temp_new_file} does not exist!"
333 new_file=$(vset "$(readlink -q -m "$temp_new_file")" "The new file")
334 if [ -e "$temp_dest_file" ]; then
335 dest_file=$(vset "$(readlink -q -m "$temp_dest_file")" "The Destination file")
337 dest_file=$(vset "$temp_dest_file" "The Destination file")
343 # Arguments are from getopt(1) in quoted mode.
345 while [ $# -gt 0 ] ; do
347 -h|--help) usageversion; exit 0 ;;
348 -n|--no-action) action='echo'; docmd='NO'; shift ;;
349 -v|--verbose) VERBOSE=1; shift ;;
351 opt_package="$2"; shift 2 ;;
353 opt_source_dir="$2"; shift 2 ;;
355 opt_old_mdsum_file="$2"; shift 2 ;;
357 opt_state_dir="$2"; shift 2 ;;
359 override_template="$2"; shift 2 ;;
360 -D|-d|--debug|--DEBUG)
361 # d has an optional argument. As we are in quoted mode,
362 # an empty parameter will be generated if its optional
363 # argument is not found.
365 "") DEBUG=$(vset 1 "The Debug value"); shift 2 ;;
366 *) DEBUG=$(vset "$2" "The Debug value"); shift 2 ;;
368 -p|--purge) PURGE=YES; shift ;;
369 --three-way) THREEWAY=YES; shift ;;
370 --debconf-ok) DEBCONF_OK=YES; shift ;;
371 -Z) selinux='-Z'; shift ;;
372 --) shift ; handle_file_args "$@"; return ;;
373 *) echo >&2 "Internal error!" ; exit 1 ;;
378 # A separate assignment is essential to ensure getopt(1) error status isn't
380 UCF_OPTS="$(getopt -a -o hs:d::D::npP:Zv -n "$progname" \
381 --long help,src-dir:,sum-file:,dest-dir:,debug::,DEBUG::,no-action,package:,purge,verbose,three-way,debconf-ok,debconf-template:,state-dir: \
384 handle_opts "$UCF_OPTS"
386 ######################################################################
388 ######## Sanity checking #########
390 ######################################################################
391 # Need to run as root, or else the
392 if test "$(id -u)" != 0; then
393 if [ "$docmd" = "YES" ]; then
394 echo "$progname: Need to be run as root." >&2
395 echo "$progname: Setting up no action mode." >&2
396 action='echo'; docmd='NO'
400 # Follow dpkg-divert as though we are installed as part of $opt_package
401 divert_line=$(dpkg-divert --listpackage "$dest_file")
402 if [ -n "$divert_line" ]; then
403 # name of the package or 'LOCAL' for a local diversion
404 divert_package="$divert_line"
406 if [ "$divert_package" != "$opt_package" ]; then
407 dest_file=$(dpkg-divert --truename "$dest_file")
410 dest_file_bre="[[:space:]]$(escape_bre "$dest_file")"'$'
412 ######################################################################
414 ######## Set Default Values #########
416 ######################################################################
417 # Load site defaults and overrides.
418 if [ -f /etc/ucf.conf ]; then
422 # Command line, env variable, config file, or default
423 if [ "$opt_source_dir" ]; then
424 source_dir=$(vset "$opt_source_dir" "The Source directory")
425 elif [ "$UCF_SOURCE_DIR" ]; then
426 source_dir=$(vset "$UCF_SOURCE_DIR" "The Source directory")
427 elif [ "$conf_source_dir" ]; then
428 source_dir=$(vset "$conf_source_dir" "The Source directory")
430 if [ "$new_file" ]; then
431 source_dir=$(vset "$(dirname "$new_file")" "The Source directory")
433 source_dir=$(vset "/tmp" "The Source directory")
438 if [ "$PAGER" ] && which "$PAGER" >/dev/null 2>&1 ; then
439 my_pager="$(which "$PAGER")"
440 elif [ -s /usr/bin/pager ] &&
441 [ "$(readlink -e /usr/bin/pager || :)" ]; then
442 my_pager=/usr/bin/pager
443 elif [ -x /usr/bin/sensible-pager ]; then
444 my_pager=/usr/bin/sensible-pager
445 elif [ -x /bin/more ]; then
451 # Command line, env variable, config file, or default
452 if [ "$opt_state_dir" ]; then
453 statedir=$(vset "$opt_state_dir" "The State directory")
454 elif [ "$UCF_STATE_DIR" ]; then
455 statedir=$(vset "$UCF_STATE_DIR" "The State directory")
456 elif [ "$conf_state_dir" ]; then
457 statedir=$(vset "$conf_state_dir" "The State directory")
459 statedir=$(vset '/var/lib/ucf' "The State directory")
462 # Handle conffold and conffnew together. See #980996
467 if [ "$conf_force_conffold" ]; then
468 if [ "$conf_force_conffnew" ]; then
469 echo >&2 "Error: Only one of conf_force_conffold and conf_force_conffnew should"
470 echo >&2 " be set in the config file"
473 force_conff=$(vset "old" "Force keep file")
474 elif [ "$conf_force_conffnew" ]; then
475 force_conff=$(vset "new" "Force keep file")
479 if [ "$UCF_FORCE_CONFFOLD" ]; then
480 if [ "$UCF_FORCE_CONFFNEW" ]; then
481 echo >&2 "Error: Only one of UCF_FORCE_CONFFOLD and UCF_FORCE_CONFFNEW should"
482 echo >&2 " be set in the environment"
485 force_conff=$(vset "old" "Force keep file")
486 elif [ "$UCF_FORCE_CONFFNEW" ]; then
487 force_conff=$(vset "new" "Force keep file")
490 # Env variable, config file, or default
491 if [ "$UCF_FORCE_CONFFMISS" ]; then
492 force_conffmiss=$(vset "$UCF_FORCE_CONFFMISS" "Replace any missing files")
493 elif [ "$conf_force_conffmiss" ]; then
494 force_conffmiss=$(vset "$conf_force_conffmiss" "Replace any missing files")
499 # DPKG_FORCE overrides all others: see #925375.
501 for f in $DPKG_FORCE ; do
503 confmiss) force_conffmiss=$(vset 1 "DPKG_FORCE replace missing files") ;;
504 confold) force_conff=$(vset "old" "DPKG_FORCE keep file") ;;
505 confnew) force_conff=$(vset "new" "DPKG_FORCE keep file") ;;
506 # The following override other settings, so break out of loop.
507 confdef) unset force_conff
508 [ "$VERBOSE" ] && echo >&2 "DPKG_FORCE keep file default"
510 confask) force_conff=$(vset "ask" "DPKG_FORCE keep file"); break ;;
515 if [ -n "$opt_old_mdsum_file" ]; then
516 old_mdsum_file=$(vset "$opt_old_mdsum_file" "The md5sum is found here")
517 elif [ "$UCF_OLD_MDSUM_FILE" ]; then
518 old_mdsum_file=$(vset "$UCF_OLD_MDSUM_FILE" "The md5sum is found here")
519 elif [ "$conf_old_mdsum_file" ]; then
520 old_mdsum_file=$(vset "$conf_old_mdsum_file" "Replace the old file")
521 elif [ "${new_file}" ]; then
522 old_mdsum_file="$source_dir/$(basename "${new_file}").md5sum"
527 ######################################################################
529 ######## More Sanity checking #########
531 ######################################################################
533 # VERBOSE of 0 is supposed to be the same as not setting VERBOSE
534 if [ "$VERBOSE" = "0" ]; then
538 if [ -e "$statedir/hashfile" ] && [ ! -w "$statedir/hashfile" ]; then
539 echo >&2 "ucf: do not have write privilege to the state data"
540 if [ "$docmd" = "YES" ]; then
545 if [ ! -d "$statedir/cache" ]; then
546 $action mkdir -p "$statedir/cache"
549 # test and see if this file exists in the database
550 if [ -e "$statedir/hashfile" ]; then
551 if [ "$VERBOSE" ]; then
552 echo >&2 "The hash file exists"
553 echo >&2 "grep ${dest_file_bre} $statedir/hashfile"
554 grep "${dest_file_bre}" "$statedir/hashfile" >&2 || true
556 lastsum=$(grep "${dest_file_bre}" "$statedir/hashfile" | \
560 if [ "${new_file}" ]; then
561 old_mdsum_dir="$source_dir/$(basename "${new_file}").md5sum.d"
566 cached_file="$(echo "$dest_file" | tr / :)"
567 ######################################################################
569 ######## Debugging dump #########
571 ######################################################################
573 if [ "$DEBUG" -gt 0 ]; then
575 The new start file is \`$new_file\'
576 The destination is \`$dest_file\' (\`$dest_file_bre\')
577 The history is kept under \'$source_dir\'
578 The file may be cached at \'$statedir/cache/$cached_file\'
580 if [ -s "$dest_file" ]; then
581 echo "The destination file exists, and has md5sum:"
584 echo "The destination file does not exist."
586 if [ "$lastsum" ]; then
587 echo "The old md5sum exists, and is:"
590 echo "The old md5sum does not exist."
591 if [ -d "$old_mdsum_dir" ] || [ -f "$old_mdsum_file" ]; then
592 echo "However, there are historical md5sums around."
595 if [ -e "$new_file" ]; then
596 echo "The new file exists, and has md5sum:"
599 echo "The new file does not exist."
601 if [ -d "$old_mdsum_dir" ]; then
602 echo "The historical md5sum dir $old_mdsum_dir exists"
603 elif [ -f "$old_mdsum_file" ]; then
604 echo "The historical md5sum file $old_mdsum_file exists"
606 echo "Historical md5sums are not available"
610 ######################################################################
612 ######## Short circuit if we are purging #########
614 ######################################################################
616 if [ "$PURGE" = "YES" ]; then
618 echo >&2 "Preparing to purge ${dest_file}"
623 ######################################################################
625 ######## DebConf stuff #########
627 ######################################################################
629 # Is debconf already running? Kinda tricky, because it will be after the
630 # confmodule is sourced, so only test before that.
631 if [ -z "$DEBCONF_ALREADY_RUNNING" ]; then
632 if [ "$DEBIAN_HAS_FRONTEND" ]; then
633 DEBCONF_ALREADY_RUNNING='YES'
635 DEBCONF_ALREADY_RUNNING='NO'
639 export DEBCONF_ALREADY_RUNNING
641 if [ -z "$DEBCONF_OK" ]; then
642 if [ "$DEBCONF_ALREADY_RUNNING" = 'YES' ]; then
649 # Time to start nagging the users who call ucf without debconf-ok
650 if [ "$DEBCONF_ALREADY_RUNNING" = 'YES' ] && [ "$DEBCONF_OK" = NO ]; then
651 # Commented out for now, uncomment after a while to begin nagging
652 # maintainers to fix their scripts.
655 *** WARNING: ucf was run from a maintainer script that uses debconf, but
656 the script did not pass --debconf-ok to ucf. The maintainer
657 script should be fixed to not stop debconf before calling ucf,
658 and pass it this parameter. For now, ucf will revert to using
659 old-style, non-debconf prompting. Ugh!
661 Please inform the package maintainer about this problem.
665 # Start up debconf or at least get the db_* commands available
666 # Don't check debconf with shellcheck.
667 # shellcheck source=/dev/null
668 if [ -e /usr/share/debconf/confmodule ]; then
669 if test "$(id -u)" = 0; then
670 . /usr/share/debconf/confmodule
672 # Load our templates, just in case our template has
673 # not been loaded or the Debconf DB lost or corrupted
674 # since then, but only if it is OK to use debconf.
675 if [ "$DEBCONF_OK" = 'YES' ]; then
676 db_x_loadtemplatefile "$(dpkg-query --control-path ucf templates)" ucf
679 echo >&2 "$progname: Not loading confmodule, since we are not running as root."
681 # Only set the title if debconf was not already running.
682 # If it was running, then we do not want to clobber the
683 # title used for configuring the whole package with debconf.
684 if [ "$DEBCONF_ALREADY_RUNNING" = 'NO' ]; then
685 if ! db_settitle ucf/title 2>/dev/null; then
686 # Older debconf that does not support that command.
687 if test "$(id -u)" = 0; then
688 db_title "Modified configuration file"
690 echo >&2 "$progname: Not changing title, since we are not running as root."
696 ######################################################################
698 ######## Start Processing #########
700 ######################################################################
702 orig_new_file="$new_file" # Since sometimes we replace the newfile below
703 newsum=$(md5sum "$new_file" | awk '{print $1}')
705 ######################################################################
707 ######## Do the replacement #########
709 ######################################################################
710 # Step 1: If we have no record of this file, and dest file
711 # does, We need to determine how to initialize the
712 # ${old_mdsum_prefix}.old file..
713 if [ -e "$dest_file" ]; then
714 destsum=$(md5sum "$dest_file" | awk '{print $1}')
715 if [ ! "$lastsum" ]; then
716 # a: If we have a directory containing historical md5sums of this
717 # file in question, we should look and see if the currently
718 # installed file matches any of the old md5sums; in which case
719 # it can be silently replaced.
720 if [ -d "$old_mdsum_dir" ] || [ -f "$old_mdsum_file" ]; then
721 if [ -d "$old_mdsum_dir" ]; then
722 for file in "${old_mdsum_dir}/"*; do
723 oldsum="$(awk '{print $1}' "$file")"
724 if [ "$oldsum" = "$destsum" ]; then
725 if [ "$force_conff" != "old" ]; then
726 # Bingo! replace, set the md5sum, and we are done
729 "Replacing config file $dest_file with new version"
734 cp -pf "$orig_new_file" "$dest_file.${DIST_SUFFIX}"
739 elif [ -f "$old_mdsum_file" ]; then
740 oldsum=$(grep -E "^${destsum}" "$old_mdsum_file" || true)
741 if [ "$oldsum" ]; then
743 if [ "$force_conff" != old ]; then
746 "Replacing config file $dest_file with new version"
751 cp -pf "$orig_new_file" "$dest_file.${DIST_SUFFIX}"
756 # Well, nothing matched. We now check to see if the
757 # maintainer has an opinion on how to set the ``md5sum of the
758 # previously installed version'', since we have no way of
759 # determining that automatically. Please note that unless
760 # there are limited number of previously released packages
761 # (like just one), the maintainer is also making a guess at
762 # this point by supplying a historical md5sum default file.
764 echo >&2 "Historical md5sums did not match."
765 if [ -d "$old_mdsum_dir" ]; then
766 if [ -e "${old_mdsum_dir}/default" ]; then
768 echo >&2 "However, a default entry exists, using it."
769 lastsum="$(awk '{print $1;}' "${old_mdsum_dir}"/default)"
772 elif [ -f "$old_mdsum_file" ]; then
773 oldsum=$(grep -E "[[:space:]]default$" "$old_mdsum_file" | \
775 if [ "$oldsum" ]; then
783 # At this point, we are almost certain that either the
784 # historical record of md5sums is not complete, or the user has
785 # changed the configuration file. Rather than guessing and
786 # chosing one of the historical md5sums, we fall through to the
787 # solution used if there had been no historical md5sums
789 if [ ! "$lastsum" ]; then
790 # b: We do not have a historical list of md5sums, or none
791 # matched, and we still need to initialize the
792 # ${old_mdsum_prefix}.old file. We can't determine whther or
793 # not they made any changes, so we err on the side of caution
796 echo >&2 "No match found, we shall ask."
797 lastsum='AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
798 fi # the old md5sum file does not exist, and the historical
800 fi # the old md5sum file does not exist (bug))
801 else # "$dest_file" does not exist
802 # Step 2: If destfile does not exist, create it, set the file
803 # "${old_mdsum_prefix}.old" to the md5sum of the new file, and we
805 if [ ! "$lastsum" ]; then
806 # Ok, so there is no indication that the package was ever
807 # installed on this machine.
808 echo >&2 "Creating config file $dest_file with new version"
811 elif [ "$lastsum" = "$newsum" ]; then
812 # OK, new version of the file is the same as the last version
813 # we saw. Since the user apparently has deleted the file,
814 # nothing needs be done, unless we have been told differently
815 if [ "$force_conffmiss" ]; then
816 echo >&2 "Recreating deleted config file $dest_file with new version, as asked"
820 echo >&2 "Not replacing deleted config file $dest_file"
824 # OK. New upstream version.
825 if [ "$force_conffmiss" ]; then
826 # User has said to replace missing files, so we do so, no
828 echo >&2 "Recreating deleted config file $dest_file with new version, as asked"
832 # Even though the user has deleted this file, they should
833 # be asked now, unless specified otherwise.
834 if [ "$force_conff" != "old" ]; then
835 destsum='AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
843 # Here, the destfile exists.
845 # step 3: If the old md5sum and the md5sum of the new file
846 # do not match, we need to take action.
847 if [ "$lastsum" = "$newsum" ]; then
848 if [ "$force_conff" = 'ask' ]; then
850 echo >&2 "Forced to ask even though md5sums match."
851 destsum='AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
854 echo >&2 "md5sums match, nothing needs be done."
855 if [ "$do_replace_md5sum" ]; then
858 exit 0; # Hah. Match. We are done.
861 # a: If the md5sum of the dest file is the same as lastsum, replace the
862 # destfile, saying we are replacing old config files
863 if [ "$destsum" = "$lastsum" ]; then
864 if [ "$force_conff" != old ]; then
865 echo >&2 "Replacing config file $dest_file with new version"
870 cp -pf "$orig_new_file" "$dest_file.${DIST_SUFFIX}"
874 # b: If the md5sum of the dest file differs from lastsum, we need to ask
875 # the user what action to take.
876 if [ "$force_conff" = "new" ]; then
877 echo >&2 "Replacing config file $dest_file with new version"
878 echo >&2 "since you asked for it."
879 if [ "$destsum" = "$newsum" ]; then
880 echo >&2 "The new and the old files are identical, AFAICS"
882 echo >&2 "The new and the old files are different"
887 if [ "$force_conff" = "old" ]; then
889 cp -pf "$orig_new_file" "$dest_file.${DIST_SUFFIX}"
892 # c: If the destination file is the same as the new maintianer provided one,
893 # we need do nothing.
894 if [ "$newsum" = "$destsum" ]; then
896 echo >&2 "md5sums of the file in place matches, nothing needs be done."
898 exit 0; # Hah. Match. We are done.
902 while [ "$done" = "NO" ]; do
903 if [ "$DEBCONF_OK" = "YES" ] && [ "$DEBIAN_HAS_FRONTEND" ]; then
904 # Use debconf to prompt.
905 if [ -e "$statedir/cache/$cached_file" ] && [ "$THREEWAY" ]; then
906 templ=ucf/changeprompt_threeway
908 templ=ucf/changeprompt
910 if [ "$override_template" ]; then
911 choices="$(db_metaget $templ Choices-C)"
912 choices2="$(db_metaget "$override_template" Choices-C)"
913 if [ "$choices" = "$choices2" ]; then
914 templ=$override_template
917 db_fset "$templ" seen false
919 db_subst "$templ" FILE "$dest_file"
920 db_subst "$templ" NEW "$new_file"
921 db_subst "$templ" BASENAME "$(basename "$dest_file")"
922 db_input critical "$templ" || true
924 # The current ucf interface does not provide a way for it
925 # to tell its caller that the user chose to back up.
926 # However, we could get here, if the caller turned on
927 # debconf's backup capb. The best thing to do seems to be
928 # to ignore requests to back up.
934 echo >&2 "Need debconf to interact"
940 echo >&2 "Replacing config file $dest_file with new version"
946 DIFF="$(run_diff diff -uBbwt "$dest_file" "$new_file")"
950 DIFF="$(run_diff sdiff -BbWt "$dest_file" "$new_file")"
954 if [ -e "$statedir/cache/$cached_file" ] && \
955 [ "$THREEWAY" ]; then
956 if [ -e "$dest_file" ]; then
957 DIFF="$(diff3 -L Current -L Older -L New -A \
958 "$dest_file" "$statedir/cache/$cached_file" \
959 "$new_file")" || true
961 DIFF="$(diff3 -L Current -L Older -L New -A \
962 /dev/null "$statedir/cache/$cached_file" \
963 "$new_file")" || true
967 DIFF="$(run_diff diff -uBbwt "$dest_file" "$new_file")"
972 echo >&2 "Merging changes into the new version"
973 if [ -e "$statedir/cache/$cached_file" ] && \
974 [ "$THREEWAY" ]; then
976 diff3 -L Current -L Older -L New -m \
977 "$dest_file" "$statedir/cache/$cached_file" \
978 "$new_file" > "$dest_file.${NEW_SUFFIX}" || ret=$?
981 new_file="$dest_file.${NEW_SUFFIX}"
984 rm -f "$dest_file.${NEW_SUFFIX}" # don't need this around no mo'
988 mv "$dest_file.${NEW_SUFFIX}" "$dest_file.${ERR_SUFFIX}"
989 db_subst ucf/conflicts_found dest_file "$dest_file"
990 db_subst ucf/conflicts_found ERR_SUFFIX "${ERR_SUFFIX}"
991 db_input critical ucf/conflicts_found || true
997 rm -f "$dest_file.${NEW_SUFFIX}" # don't need this around no mo'
1002 # We explicitly connect STDIN and STDOUT to the
1003 # script's controlling terminal, so even if STDIN is
1004 # fed by a pipe, as is the case when run from
1005 # /usr/bin/debconf, the shell should be fully
1006 # functional. However, the test for a controlling
1007 # terminal uses /usr/bin/tty, which consults only
1008 # STDIN. As far as I can tell, when run from debconf,
1009 # ucf will _never_ use the current terminal. If the
1010 # goal is to check for access to a terminal, the test
1011 # should be for foreground process group membership,
1012 # not a terminal connected to STDIN (tty -s), and not
1013 # a terminal it doesn't necessarily own (tty -s
1014 # </dev/tty). The easiest way do this from a shell is
1015 # probably with /bin/ps.
1016 if [ "$(ps -o tpgid= $$)" -eq "$(ps -o pgid= $$)" ]; then
1017 export UCF_CONFFILE_OLD="$dest_file"
1018 export UCF_CONFFILE_NEW="$new_file"
1019 bash >/dev/tty </dev/tty || true
1020 elif [ -n "$DISPLAY" ]; then
1021 x-terminal-emulator || true
1023 # Don't know what to do
1024 echo >&2 "No terminal, and no DISPLAY set, can't fork shell."
1028 keep_current|n|N|o|O|'')
1031 cp -pf "$orig_new_file" "$dest_file.${DIST_SUFFIX}"
1035 if [ "$DEBCONF_OK" = "YES" ]; then
1036 echo "Error: unknown response from debconf:'$RET'" >&2
1040 echo "Please answer with one of the single letters listed." >&2