1#!/bin/sh
2
3# mergemaster
4
5# Compare files created by /usr/src/etc/Makefile (or the directory
6# the user specifies) with the currently installed copies.
7
8# Copyright 1998-2003 Douglas Barton
9# DougB@FreeBSD.org
10
11# $FreeBSD: src/usr.sbin/mergemaster/mergemaster.sh,v 1.46 2003/05/03 06:35:19 dougb Exp $
12# $DragonFly: src/usr.sbin/mergemaster/mergemaster.sh,v 1.6 2004/03/14 13:47:12 eirikn Exp $
13
14PATH=/bin:/usr/bin:/usr/sbin
15
16display_usage () {
17  VERSION_NUMBER=`grep "[$]DragonFly:" $0 | cut -d ' ' -f 4`
18  echo "mergemaster version ${VERSION_NUMBER}"
19  echo 'Usage: mergemaster [-scrvahipCP] [-m /path]'
20  echo '         [-t /path] [-d] [-u N] [-w N] [-D /path]'
21  echo "Options:"
22  echo "  -s  Strict comparison (diff every pair of files)"
23  echo "  -c  Use context diff instead of unified diff"
24  echo "  -r  Re-run on a previously cleaned directory (skip temproot creation)"
25  echo "  -v  Be more verbose about the process, include additional checks"
26  echo "  -a  Leave all files that differ to merge by hand"
27  echo "  -h  Display more complete help"
28  echo '  -i  Automatically install files that do not exist in destination directory'
29  echo '  -p  Pre-buildworld mode, only compares crucial files'
30  echo '  -C  Compare local rc.conf variables to the defaults'
31  echo '  -P  Preserve files that are overwritten'
32  echo "  -m /path/directory  Specify location of source to do the make in"
33  echo "  -t /path/directory  Specify temp root directory"
34  echo "  -d  Add date and time to directory name (e.g., /var/tmp/temproot.`date +%m%d.%H.%M`)"
35  echo "  -u N  Specify a numeric umask"
36  echo "  -w N  Specify a screen width in columns to sdiff"
37  echo '  -D /path/directory  Specify the destination directory to install files to'
38  echo ''
39}
40
41display_help () {
42  echo "* To specify a directory other than /var/tmp/temproot for the"
43  echo "  temporary root environment, use -t /path/to/temp/root"
44  echo "* The -w option takes a number as an argument for the column width"
45  echo "  of the screen.  The default is 80."
46  echo '* The -a option causes mergemaster to run without prompting.'
47}
48
49# Loop allowing the user to use sdiff to merge files and display the merged
50# file.
51merge_loop () {
52  case "${VERBOSE}" in
53  '') ;;
54  *)
55      echo "   *** Type h at the sdiff prompt (%) to get usage help"
56      ;;
57  esac
58  echo ''
59  MERGE_AGAIN=yes
60  while [ "${MERGE_AGAIN}" = "yes" ]; do
61    # Prime file.merged so we don't blat the owner/group id's
62    cp -p "${COMPFILE}" "${COMPFILE}.merged"
63    sdiff -o "${COMPFILE}.merged" --text --suppress-common-lines \
64      --width=${SCREEN_WIDTH:-80} "${DESTDIR}${COMPFILE#.}" "${COMPFILE}"
65    INSTALL_MERGED=V
66    while [ "${INSTALL_MERGED}" = "v" -o "${INSTALL_MERGED}" = "V" ]; do
67      echo ''
68      echo "  Use 'i' to install merged file"
69      echo "  Use 'r' to re-do the merge"
70      echo "  Use 'v' to view the merged file"
71      echo "  Default is to leave the temporary file to deal with by hand"
72      echo ''
73      echo -n "    *** How should I deal with the merged file? [Leave it for later] "
74      read INSTALL_MERGED
75
76      case "${INSTALL_MERGED}" in
77      [iI])
78        mv "${COMPFILE}.merged" "${COMPFILE}"
79        echo ''
80        if mm_install "${COMPFILE}"; then
81          echo "     *** Merged version of ${COMPFILE} installed successfully"
82        else
83          echo "     *** Problem installing ${COMPFILE}, it will remain to merge by hand later"
84        fi
85        unset MERGE_AGAIN
86        ;;
87      [rR])
88        rm "${COMPFILE}.merged"
89        ;;
90      [vV])
91        ${PAGER} "${COMPFILE}.merged"
92        ;;
93      '')
94        echo "   *** ${COMPFILE} will remain for your consideration"
95        unset MERGE_AGAIN
96        ;;
97      *)
98        echo "invalid choice: ${INSTALL_MERGED}"
99        INSTALL_MERGED=V
100        ;;
101      esac
102    done
103  done
104}
105
106# Loop showing user differences between files, allow merge, skip or install
107# options
108diff_loop () {
109
110  HANDLE_COMPFILE=v
111
112  while [ "${HANDLE_COMPFILE}" = "v" -o "${HANDLE_COMPFILE}" = "V" -o \
113    "${HANDLE_COMPFILE}" = "NOT V" ]; do
114    if [ -f "${DESTDIR}${COMPFILE#.}" -a -f "${COMPFILE}" ]; then
115      if [ "${HANDLE_COMPFILE}" = "v" -o "${HANDLE_COMPFILE}" = "V" ]; then
116	echo ''
117	echo '   ======================================================================   '
118	echo ''
119        (
120          echo "  *** Displaying differences between ${COMPFILE} and installed version:"
121          echo ''
122          diff ${DIFF_FLAG} ${DIFF_OPTIONS} "${DESTDIR}${COMPFILE#.}" "${COMPFILE}"
123        ) | ${PAGER}
124        echo ''
125      fi
126    else
127      echo ''
128      echo "  *** There is no installed version of ${COMPFILE}"
129      echo ''
130      case "${AUTO_INSTALL}" in
131      [Yy][Ee][Ss])
132        echo ''
133        if mm_install "${COMPFILE}"; then
134          echo "   *** ${COMPFILE} installed successfully"
135          echo ''
136          # Make the list print one file per line
137          AUTO_INSTALLED_FILES="${AUTO_INSTALLED_FILES}      ${DESTDIR}${COMPFILE#.}
138"
139        else
140          echo "   *** Problem installing ${COMPFILE}, it will remain to merge by hand"
141        fi
142        return
143        ;;
144      *)
145        NO_INSTALLED=yes
146        ;;
147      esac
148    fi
149
150    echo "  Use 'd' to delete the temporary ${COMPFILE}"
151    echo "  Use 'i' to install the temporary ${COMPFILE}"
152    case "${NO_INSTALLED}" in
153    '')
154      echo "  Use 'm' to merge the temporary and installed versions"
155      echo "  Use 'v' to view the diff results again"
156      ;;
157    esac
158    echo ''
159    echo "  Default is to leave the temporary file to deal with by hand"
160    echo ''
161    echo -n "How should I deal with this? [Leave it for later] "
162    read HANDLE_COMPFILE
163
164    case "${HANDLE_COMPFILE}" in
165    [dD])
166      rm "${COMPFILE}"
167      echo ''
168      echo "   *** Deleting ${COMPFILE}"
169      ;;
170    [iI])
171      echo ''
172      if mm_install "${COMPFILE}"; then
173        echo "   *** ${COMPFILE} installed successfully"
174      else
175        echo "   *** Problem installing ${COMPFILE}, it will remain to merge by hand"
176      fi
177      ;;
178    [mM])
179      case "${NO_INSTALLED}" in
180      '')
181        # interact with user to merge files
182        merge_loop
183        ;;
184      *)
185        echo ''
186        echo "   *** There is no installed version of ${COMPFILE}"
187        echo ''
188        HANDLE_COMPFILE="NOT V"
189        ;;
190      esac # End of "No installed version of file but user selected merge" test
191      ;;
192    [vV])
193      continue
194      ;;
195    '')
196      echo ''
197      echo "   *** ${COMPFILE} will remain for your consideration"
198      ;;
199    *)
200      # invalid choice, show menu again.
201      echo "invalid choice: ${HANDLE_COMPFILE}"
202      echo ''
203      HANDLE_COMPFILE="NOT V"
204      continue
205      ;;
206    esac  # End of "How to handle files that are different"
207  done
208  unset NO_INSTALLED
209  echo ''
210  case "${VERBOSE}" in
211  '') ;;
212  *)
213    sleep 3
214    ;;
215  esac
216}
217
218press_to_continue () {
219  local DISCARD
220  echo -n ' *** Press the [Enter] or [Return] key to continue '
221  read DISCARD
222}
223
224# Set the default path for the temporary root environment
225#
226TEMPROOT='/var/tmp/temproot'
227
228# Read /etc/mergemaster.rc first so the one in $HOME can override
229#
230if [ -r /etc/mergemaster.rc ]; then
231  . /etc/mergemaster.rc
232fi
233
234# Read .mergemasterrc before command line so CLI can override
235#
236if [ -r "$HOME/.mergemasterrc" ]; then
237  . "$HOME/.mergemasterrc"
238fi
239
240# Check the command line options
241#
242while getopts ":ascrvhipCPm:t:du:w:D:" COMMAND_LINE_ARGUMENT ; do
243  case "${COMMAND_LINE_ARGUMENT}" in
244  s)
245    STRICT=yes
246    unset DIFF_OPTIONS
247    ;;
248  c)
249    DIFF_FLAG='-c'
250    ;;
251  r)
252    RERUN=yes
253    ;;
254  v)
255    case "${AUTO_RUN}" in
256    '') VERBOSE=yes ;;
257    esac
258    ;;
259  a)
260    AUTO_RUN=yes
261    unset VERBOSE
262    ;;
263  h)
264    display_usage
265    display_help
266    exit 0
267    ;;
268  i)
269    AUTO_INSTALL=yes
270    ;;
271  C)
272    COMP_CONFS=yes
273    ;;
274  P)
275    PRESERVE_FILES=yes
276    ;;
277  p)
278    PRE_WORLD=yes
279    unset COMP_CONFS
280    unset AUTO_RUN
281    ;;
282  m)
283    SOURCEDIR=${OPTARG}
284    ;;
285  t)
286    TEMPROOT=${OPTARG}
287    ;;
288  d)
289    TEMPROOT=${TEMPROOT}.`date +%m%d.%H.%M`
290    ;;
291  u)
292    NEW_UMASK=${OPTARG}
293    ;;
294  w)
295    SCREEN_WIDTH=${OPTARG}
296    ;;
297  D)
298    DESTDIR=${OPTARG}
299    ;;
300  *)
301    display_usage
302    exit 1
303    ;;
304  esac
305done
306
307# Don't force the user to set this in the mergemaster rc file
308if [ -n "${PRESERVE_FILES}" -a -z "${PRESERVE_FILES_DIR}" ]; then
309  PRESERVE_FILES_DIR=/var/tmp/mergemaster/preserved-files-`date +%y%m%d-%H%M%S`
310fi
311
312echo ''
313
314# If the user has a pager defined, make sure we can run it
315#
316case "${DONT_CHECK_PAGER}" in
317'')
318  while ! type "${PAGER%% *}" >/dev/null && [ -n "${PAGER}" ]; do
319    echo " *** Your PAGER environment variable specifies '${PAGER}', but"
320    echo "     due to the limited PATH that I use for security reasons,"
321    echo "     I cannot execute it.  So, what would you like to do?"
322    echo ''
323    echo "  Use 'e' to exit mergemaster and fix your PAGER variable"
324    if [ -x /usr/bin/less -o -x /usr/local/bin/less ]; then
325    echo "  Use 'l' to set PAGER to 'less' for this run"
326    fi
327    echo "  Use 'm' to use plain old 'more' as your PAGER for this run"
328    echo ''
329    echo "  Default is to use plain old 'more' "
330    echo ''
331    echo -n "What should I do? [Use 'more'] "
332    read FIXPAGER
333
334    case "${FIXPAGER}" in
335    [eE])
336       exit 0
337       ;;
338    [lL])
339       if [ -x /usr/bin/less ]; then
340         PAGER=/usr/bin/less
341       elif [ -x /usr/local/bin/less ]; then
342         PAGER=/usr/local/bin/less
343       else
344         echo ''
345         echo " *** Fatal Error:"
346         echo "     You asked to use 'less' as your pager, but I can't"
347         echo "     find it in /usr/bin or /usr/local/bin"
348         exit 1
349       fi
350       ;;
351    [mM]|'')
352       PAGER=more
353       ;;
354    *)
355       echo ''
356       echo "invalid choice: ${FIXPAGER}"
357    esac
358    echo ''
359  done
360  ;;
361esac
362
363# If user has a pager defined, or got assigned one above, use it.
364# If not, use less.
365#
366PAGER=${PAGER:-less}
367PAGER="${PAGER} -c"
368
369if [ -n "${VERBOSE}" -a ! "${PAGER}" = "more" ]; then
370  echo " *** You have ${PAGER} defined as your pager so we will use that"
371  echo ''
372  sleep 3
373fi
374
375# Assign the diff flag once so we will not have to keep testing it
376#
377DIFF_FLAG=${DIFF_FLAG:--u}
378
379# Assign the source directory
380#
381SOURCEDIR=${SOURCEDIR:-/usr/src/etc}
382
383# Check the width of the user's terminal
384#
385if [ -t 0 ]; then
386  w=`tput columns`
387  case "${w}" in
388  0|'') ;; # No-op, since the input is not valid
389  *)
390    case "${SCREEN_WIDTH}" in
391    '') SCREEN_WIDTH="${w}" ;;
392    "${w}") ;; # No-op, since they are the same
393    *)
394      echo -n "*** You entered ${SCREEN_WIDTH} as your screen width, but stty "
395      echo "thinks it is ${w}."
396      echo ''
397      echo -n "What would you like to use? [${w}] "
398      read SCREEN_WIDTH
399      case "${SCREEN_WIDTH}" in
400      '') SCREEN_WIDTH="${w}" ;;
401      esac
402      ;;
403    esac
404  esac
405fi
406
407# Define what CVS $Id tag to look for to aid portability.
408#
409CVS_ID_TAG=DragonFly
410
411delete_temproot () {
412  rm -rf "${TEMPROOT}" 2>/dev/null
413  chflags -R 0 "${TEMPROOT}" 2>/dev/null
414  rm -rf "${TEMPROOT}" || exit 1
415}
416
417case "${RERUN}" in
418'')
419  # Set up the loop to test for the existence of the
420  # temp root directory.
421  #
422  TEST_TEMP_ROOT=yes
423  while [ "${TEST_TEMP_ROOT}" = "yes" ]; do
424    if [ -d "${TEMPROOT}" ]; then
425      echo "*** The directory specified for the temporary root environment,"
426      echo "    ${TEMPROOT}, exists.  This can be a security risk if untrusted"
427      echo "    users have access to the system."
428      echo ''
429      case "${AUTO_RUN}" in
430      '')
431        echo "  Use 'd' to delete the old ${TEMPROOT} and continue"
432        echo "  Use 't' to select a new temporary root directory"
433        echo "  Use 'e' to exit mergemaster"
434        echo ''
435        echo "  Default is to use ${TEMPROOT} as is"
436        echo ''
437        echo -n "How should I deal with this? [Use the existing ${TEMPROOT}] "
438        read DELORNOT
439
440        case "${DELORNOT}" in
441        [dD])
442          echo ''
443          echo "   *** Deleting the old ${TEMPROOT}"
444          echo ''
445          delete_temproot || exit 1
446          unset TEST_TEMP_ROOT
447          ;;
448        [tT])
449          echo "   *** Enter new directory name for temporary root environment"
450          read TEMPROOT
451          ;;
452        [eE])
453          exit 0
454          ;;
455        '')
456          echo ''
457          echo "   *** Leaving ${TEMPROOT} intact"
458          echo ''
459          unset TEST_TEMP_ROOT
460          ;;
461        *)
462          echo ''
463          echo "invalid choice: ${DELORNOT}"
464          echo ''
465          ;;
466        esac
467        ;;
468      *)
469        # If this is an auto-run, try a hopefully safe alternative then
470        # re-test anyway.
471        TEMPROOT=/var/tmp/temproot.`date +%m%d.%H.%M.%S`
472        ;;
473      esac
474    else
475      unset TEST_TEMP_ROOT
476    fi
477  done
478
479  echo "*** Creating the temporary root environment in ${TEMPROOT}"
480
481  if mkdir -p "${TEMPROOT}"; then
482    echo " *** ${TEMPROOT} ready for use"
483  fi
484
485  if [ ! -d "${TEMPROOT}" ]; then
486    echo ''
487    echo "  *** FATAL ERROR: Cannot create ${TEMPROOT}"
488    echo ''
489    exit 1
490  fi
491
492  echo " *** Creating and populating directory structure in ${TEMPROOT}"
493  echo ''
494
495  case "${VERBOSE}" in
496  '') ;;
497  *)
498    press_to_continue
499    ;;
500  esac
501
502  case "${PRE_WORLD}" in
503  '')
504    { cd ${SOURCEDIR} &&
505      case "${DESTDIR}" in
506      '') ;;
507      *)
508      make DESTDIR=${DESTDIR} distrib-dirs
509        ;;
510      esac
511      make DESTDIR=${TEMPROOT} distrib-dirs &&
512      make MAKEOBJDIRPREFIX=${TEMPROOT}/usr/obj obj &&
513      make MAKEOBJDIRPREFIX=${TEMPROOT}/usr/obj DESTDIR=${TEMPROOT} \
514          -DNO_MAKEDEV_RUN distribution;} ||
515    { echo '';
516     echo "  *** FATAL ERROR: Cannot 'cd' to ${SOURCEDIR} and install files to";
517      echo "      the temproot environment";
518      echo '';
519      exit 1;}
520    ;;
521  *)
522    # Only set up files that are crucial to {build|install}world
523    { mkdir -p ${TEMPROOT}/etc &&
524      cp -p ${SOURCEDIR}/master.passwd ${TEMPROOT}/etc &&
525      cp -p ${SOURCEDIR}/group ${TEMPROOT}/etc;} ||
526    { echo '';
527      echo '  *** FATAL ERROR: Cannot copy files to the temproot environment';
528      echo '';
529      exit 1;}
530    ;;
531  esac
532
533  # Doing the inventory and removing files that we don't want to compare only
534  # makes sense if we are not doing a rerun, since we have no way of knowing
535  # what happened to the files during previous incarnations.
536  case "${VERBOSE}" in
537  '') ;;
538  *)
539    echo ''
540    echo ' *** The following files exist only in the installed version of'
541    echo "     ${DESTDIR}/etc.  In the vast majority of cases these files"
542    echo '     are necessary parts of the system and should not be deleted.'
543    echo '     However because these files are not updated by this process you'
544    echo '     might want to verify their status before rebooting your system.'
545    echo ''
546    press_to_continue
547    diff -qr ${DESTDIR}/etc ${TEMPROOT}/etc | grep "^Only in ${DESTDIR}/etc" | ${PAGER}
548    echo ''
549    press_to_continue
550    ;;
551  esac
552
553  # Avoid comparing the motd if the user specifies it in .mergemasterrc
554  case "${IGNORE_MOTD}" in
555  '') ;;
556  *) rm -f ${TEMPROOT}/etc/motd
557     ;;
558  esac
559
560  # Avoid trying to update MAKEDEV if /dev is on a devfs
561  if /sbin/sysctl vfs.devfs > /dev/null 2>&1 ; then
562    rm -f ${TEMPROOT}/dev/MAKEDEV ${TEMPROOT}/dev/MAKEDEV.local
563  fi
564
565  ;; # End of the "RERUN" test
566esac
567
568# We really don't want to have to deal with files like login.conf.db, pwd.db,
569# or spwd.db.  Instead, we want to compare the text versions, and run *_mkdb.
570# Prompt the user to do so below, as needed.
571#
572rm -f ${TEMPROOT}/etc/*.db ${TEMPROOT}/etc/passwd
573
574# We only need to compare things like freebsd.cf once
575find ${TEMPROOT}/usr/obj -type f -delete 2>/dev/null
576
577# Get ready to start comparing files
578
579# Check umask if not specified on the command line,
580# and we are not doing an autorun
581#
582if [ -z "${NEW_UMASK}" -a -z "${AUTO_RUN}" ]; then
583  USER_UMASK=`umask`
584  case "${USER_UMASK}" in
585  0022|022) ;;
586  *)
587    echo ''
588    echo " *** Your umask is currently set to ${USER_UMASK}.  By default, this script"
589    echo "     installs all files with the same user, group and modes that"
590    echo "     they are created with by ${SOURCEDIR}/Makefile, compared to"
591    echo "     a umask of 022.  This umask allows world read permission when"
592    echo "     the file's default permissions have it."
593    echo ''
594    echo "     No world permissions can sometimes cause problems.  A umask of"
595    echo "     022 will restore the default behavior, but is not mandatory."
596    echo "     /etc/master.passwd is a special case.  Its file permissions"
597    echo "     will be 600 (rw-------) if installed."
598    echo ''
599    echo -n "What umask should I use? [${USER_UMASK}] "
600    read NEW_UMASK
601
602    NEW_UMASK="${NEW_UMASK:-$USER_UMASK}"
603    ;;
604  esac
605  echo ''
606fi
607
608CONFIRMED_UMASK=${NEW_UMASK:-0022}
609
610#
611# Warn users who still have old rc files
612#
613for file in atm devfs diskless1 diskless2 isdn network network6 pccard \
614  serial syscons sysctl alpha x86_64 i386 ia64 sparc64; do
615  if [ -f "${DESTDIR}/etc/rc.${file}" ]; then
616    OLD_RC_PRESENT=1
617    break
618  fi
619done
620
621case "${OLD_RC_PRESENT}" in
6221)
623  echo ''
624  echo " *** There are elements of the old rc system in ${DESTDIR}/etc/."
625  echo ''
626  echo '     While these scripts will not hurt anything, they are not'
627  echo '     functional on an up to date system, and can be removed.'
628  echo ''
629
630  case "${AUTO_RUN}" in
631  '')
632    echo -n 'Move these files to /var/tmp/mergemaster/old_rc? [yes] '
633    read MOVE_OLD_RC
634
635    case "${MOVE_OLD_RC}" in
636    [nN]*) ;;
637    *)
638      mkdir -p /var/tmp/mergemaster/old_rc
639        for file in atm devfs diskless1 diskless2 isdn network network6 pccard \
640          serial syscons sysctl alpha x86_64 i386 ia64 sparc64; do
641          if [ -f "${DESTDIR}/etc/rc.${file}" ]; then
642            mv ${DESTDIR}/etc/rc.${file} /var/tmp/mergemaster/old_rc/
643          fi
644        done
645      echo '  The files have been moved'
646      press_to_continue
647      ;;
648    esac
649    ;;
650  *) ;;
651  esac
652esac
653
654# Use the umask/mode information to install the files
655# Create directories as needed
656#
657do_install_and_rm () {
658  case "${PRESERVE_FILES}" in
659  [Yy][Ee][Ss])
660    if [ -f "${3}/${2##*/}" ]; then
661      mkdir -p ${PRESERVE_FILES_DIR}/${2%/*}
662      cp ${3}/${2##*/} ${PRESERVE_FILES_DIR}/${2%/*}
663    fi
664    ;;
665  esac
666
667  install -m "${1}" "${2}" "${3}" &&
668  rm -f "${2}"
669}
670
671# 4095 = "obase=10;ibase=8;07777" | bc
672find_mode () {
673  local OCTAL
674  OCTAL=$(( ~$(echo "obase=10;ibase=8; ${CONFIRMED_UMASK}" | bc) & 4095 &
675          $(echo "obase=10; ibase=8; $(stat -f "%OMp%OLp" ${1})" | bc) ))
676  printf "%04o\n" ${OCTAL}
677}
678
679mm_install () {
680  local INSTALL_DIR
681  INSTALL_DIR=${1#.}
682  INSTALL_DIR=${INSTALL_DIR%/*}
683
684  case "${INSTALL_DIR}" in
685  '')
686    INSTALL_DIR=/
687    ;;
688  esac
689
690  if [ -n "${DESTDIR}${INSTALL_DIR}" -a ! -d "${DESTDIR}${INSTALL_DIR}" ]; then
691    DIR_MODE=`find_mode "${TEMPROOT}/${INSTALL_DIR}"`
692    install -d -o root -g wheel -m "${DIR_MODE}" "${DESTDIR}${INSTALL_DIR}"
693  fi
694
695  FILE_MODE=`find_mode "${1}"`
696
697  if [ ! -x "${1}" ]; then
698    case "${1#.}" in
699    /etc/mail/aliases)
700      NEED_NEWALIASES=yes
701      ;;
702    /etc/login.conf)
703      NEED_CAP_MKDB=yes
704      ;;
705    /etc/master.passwd)
706      do_install_and_rm 600 "${1}" "${DESTDIR}${INSTALL_DIR}"
707      NEED_PWD_MKDB=yes
708      DONT_INSTALL=yes
709      ;;
710    /.cshrc | /.profile)
711    case "${AUTO_INSTALL}" in
712    '')
713      case "${LINK_EXPLAINED}" in
714      '')
715        echo "   *** Historically BSD derived systems have had a"
716        echo "       hard link from /.cshrc and /.profile to"
717        echo "       their namesakes in /root.  Please indicate"
718        echo "       your preference below for bringing your"
719        echo "       installed files up to date."
720        echo ''
721        LINK_EXPLAINED=yes
722        ;;
723      esac
724
725      echo "   Use 'd' to delete the temporary ${COMPFILE}"
726      echo "   Use 'l' to delete the existing ${DESTDIR}${COMPFILE#.} and create the link"
727      echo ''
728      echo "   Default is to leave the temporary file to deal with by hand"
729      echo ''
730      echo -n "  How should I handle ${COMPFILE}? [Leave it to install later] "
731      read HANDLE_LINK
732      ;;
733    *)  # Part of AUTO_INSTALL
734      HANDLE_LINK=l
735      ;;
736    esac
737
738      case "${HANDLE_LINK}" in
739      [dD]*)
740        rm "${COMPFILE}"
741        echo ''
742        echo "   *** Deleting ${COMPFILE}"
743        ;;
744      [lL]*)
745        echo ''
746        rm -f "${DESTDIR}${COMPFILE#.}"
747        if ln "${DESTDIR}/root/${COMPFILE##*/}" "${DESTDIR}${COMPFILE#.}"; then
748          echo "   *** Link from ${DESTDIR}${COMPFILE#.} to ${DESTDIR}/root/${COMPFILE##*/} installed successfully"
749          rm "${COMPFILE}"
750        else
751          echo "   *** Error linking ${DESTDIR}${COMPFILE#.} to ${DESTDIR}/root/${COMPFILE##*/}, ${COMPFILE} will remain to install by hand"
752        fi
753        ;;
754      *)
755        echo "   *** ${COMPFILE} will remain for your consideration"
756        ;;
757      esac
758      DONT_INSTALL=yes
759      ;;
760    esac
761
762    case "${DONT_INSTALL}" in
763    '')
764      do_install_and_rm "${FILE_MODE}" "${1}" "${DESTDIR}${INSTALL_DIR}"
765      ;;
766    *)
767      unset DONT_INSTALL
768      ;;
769    esac
770  else	# File matched -x
771    case "${1#.}" in
772    /dev/MAKEDEV)
773      NEED_MAKEDEV=yes
774      ;;
775    esac
776    do_install_and_rm "${FILE_MODE}" "${1}" "${DESTDIR}${INSTALL_DIR}"
777  fi
778  return $?
779}
780
781echo ''
782echo "*** Beginning comparison"
783echo ''
784
785cd "${TEMPROOT}"
786
787if [ -r "${MM_PRE_COMPARE_SCRIPT}" ]; then
788  . "${MM_PRE_COMPARE_SCRIPT}"
789fi
790
791# Using -size +0 avoids uselessly checking the empty log files created
792# by ${SOURCEDIR}/Makefile and the device entries in ./dev, but does
793# check the scripts in ./dev, as we'd like (assuming no devfs of course).
794#
795for COMPFILE in `find . -type f -size +0`; do
796
797  # First, check to see if the file exists in DESTDIR.  If not, the
798  # diff_loop function knows how to handle it.
799  #
800  if [ ! -e "${DESTDIR}${COMPFILE#.}" ]; then
801    case "${AUTO_RUN}" in
802      '')
803        diff_loop
804        ;;
805      *)
806        case "${AUTO_INSTALL}" in
807        '')
808          # If this is an auto run, make it official
809          echo "   *** ${COMPFILE} will remain for your consideration"
810          ;;
811        *)
812          diff_loop
813          ;;
814        esac
815        ;;
816    esac # Auto run test
817    continue
818  fi
819
820  case "${STRICT}" in
821  '' | [Nn][Oo])
822    # Compare CVS $Id's first so if the file hasn't been modified
823    # local changes will be ignored.
824    # If the files have the same $Id, delete the one in temproot so the
825    # user will have less to wade through if files are left to merge by hand.
826    #
827    CVSID1=`grep "[$]${CVS_ID_TAG}:" ${DESTDIR}${COMPFILE#.} 2>/dev/null`
828    CVSID2=`grep "[$]${CVS_ID_TAG}:" ${COMPFILE} 2>/dev/null` || CVSID2=none
829
830    case "${CVSID2}" in
831    "${CVSID1}")
832      echo " *** Temp ${COMPFILE} and installed have the same CVS Id, deleting"
833      rm "${COMPFILE}"
834      ;;
835    esac
836    ;;
837  esac
838
839  # If the file is still here either because the $Ids are different, the
840  # file doesn't have an $Id, or we're using STRICT mode; look at the diff.
841  #
842  if [ -f "${COMPFILE}" ]; then
843
844    # Do an absolute diff first to see if the files are actually different.
845    # If they're not different, delete the one in temproot.
846    #
847    if diff -q ${DIFF_OPTIONS} "${DESTDIR}${COMPFILE#.}" "${COMPFILE}" > \
848      /dev/null 2>&1; then
849      echo " *** Temp ${COMPFILE} and installed are the same, deleting"
850      rm "${COMPFILE}"
851    else
852      # Ok, the files are different, so show the user where they differ.
853      # Use user's choice of diff methods; and user's pager if they have one.
854      # Use more if not.
855      # Use unified diffs by default.  Context diffs give me a headache. :)
856      #
857      case "${AUTO_RUN}" in
858      '')
859        # prompt user to install/delete/merge changes
860        diff_loop
861        ;;
862      *)
863        # If this is an auto run, make it official
864        echo "   *** ${COMPFILE} will remain for your consideration"
865        ;;
866      esac # Auto run test
867    fi # Yes, the files are different
868  fi # Yes, the file still remains to be checked
869done # This is for the do way up there at the beginning of the comparison
870
871echo ''
872echo "*** Comparison complete"
873echo ''
874
875TEST_FOR_FILES=`find ${TEMPROOT} -type f -size +0 2>/dev/null`
876if [ -n "${TEST_FOR_FILES}" ]; then
877  echo "*** Files that remain for you to merge by hand:"
878  find "${TEMPROOT}" -type f -size +0
879  echo ''
880fi
881
882case "${AUTO_RUN}" in
883'')
884  echo -n "Do you wish to delete what is left of ${TEMPROOT}? [no] "
885  read DEL_TEMPROOT
886
887  case "${DEL_TEMPROOT}" in
888  [yY]*)
889    if delete_temproot; then
890      echo " *** ${TEMPROOT} has been deleted"
891    else
892      echo " *** Unable to delete ${TEMPROOT}"
893    fi
894    ;;
895  *)
896    echo " *** ${TEMPROOT} will remain"
897    ;;
898  esac
899  ;;
900*) ;;
901esac
902
903case "${AUTO_INSTALLED_FILES}" in
904'') ;;
905*)
906  case "${AUTO_RUN}" in
907  '')
908    (
909      echo ''
910      echo '*** You chose the automatic install option for files that did not'
911      echo '    exist on your system.  The following were installed for you:'
912      echo "${AUTO_INSTALLED_FILES}"
913    ) | ${PAGER}
914    ;;
915  *)
916    echo ''
917    echo '*** You chose the automatic install option for files that did not'
918    echo '    exist on your system.  The following were installed for you:'
919    echo "${AUTO_INSTALLED_FILES}"
920    ;;
921  esac
922  ;;
923esac
924
925run_it_now () {
926  case "${AUTO_RUN}" in
927  '')
928    unset YES_OR_NO
929    echo ''
930    echo -n '    Would you like to run it now? y or n [n] '
931    read YES_OR_NO
932
933    case "${YES_OR_NO}" in
934    y)
935      echo "    Running ${1}"
936      echo ''
937      eval "${1}"
938      ;;
939    ''|n)
940      echo ''
941      echo "       *** Cancelled"
942      echo ''
943      echo "    Make sure to run ${1} yourself"
944      ;;
945    *)
946      echo ''
947      echo "       *** Sorry, I do not understand your answer (${YES_OR_NO})"
948      echo ''
949      echo "    Make sure to run ${1} yourself"
950    esac
951    ;;
952  *) ;;
953  esac
954}
955
956case "${NEED_MAKEDEV}" in
957'') ;;
958*)
959  echo ''
960  echo "*** You installed a new ${DESTDIR}/dev/MAKEDEV script, so make sure that you run"
961  echo "    'cd ${DESTDIR}/dev && /bin/sh MAKEDEV all' to rebuild your devices"
962  run_it_now "cd ${DESTDIR}/dev && /bin/sh MAKEDEV all"
963  ;;
964esac
965
966case "${NEED_NEWALIASES}" in
967'') ;;
968*)
969  echo ''
970  if [ -n "${DESTDIR}" ]; then
971    echo "*** You installed a new aliases file into ${DESTDIR}/etc/mail, but"
972    echo "    the newaliases command is limited to the directories configured"
973    echo "    in sendmail.cf.  Make sure to create your aliases database by"
974    echo "    hand when your sendmail configuration is done."
975  else
976    echo "*** You installed a new aliases file, so make sure that you run"
977    echo "    '/usr/bin/newaliases' to rebuild your aliases database"
978    run_it_now '/usr/bin/newaliases'
979  fi
980  ;;
981esac
982
983case "${NEED_CAP_MKDB}" in
984'') ;;
985*)
986  echo ''
987  echo "*** You installed a login.conf file, so make sure that you run"
988  echo "    '/usr/bin/cap_mkdb ${DESTDIR}/etc/login.conf'"
989  echo "     to rebuild your login.conf database"
990  run_it_now "/usr/bin/cap_mkdb ${DESTDIR}/etc/login.conf"
991  ;;
992esac
993
994case "${NEED_PWD_MKDB}" in
995'') ;;
996*)
997  echo ''
998  echo "*** You installed a new master.passwd file, so make sure that you run"
999  if [ -n "${DESTDIR}" ]; then
1000    echo "    '/usr/sbin/pwd_mkdb -d ${DESTDIR}/etc -p ${DESTDIR}/etc/master.passwd'"
1001    echo "    to rebuild your password files"
1002    run_it_now "/usr/sbin/pwd_mkdb -d ${DESTDIR}/etc -p ${DESTDIR}/etc/master.passwd"
1003  else
1004    echo "    '/usr/sbin/pwd_mkdb -p /etc/master.passwd'"
1005    echo "     to rebuild your password files"
1006    run_it_now '/usr/sbin/pwd_mkdb -p /etc/master.passwd'
1007  fi
1008  ;;
1009esac
1010
1011echo ''
1012
1013if [ -r "${MM_EXIT_SCRIPT}" ]; then
1014  . "${MM_EXIT_SCRIPT}"
1015fi
1016
1017case "${COMP_CONFS}" in
1018'') ;;
1019*)
1020  . ${DESTDIR}/etc/defaults/rc.conf
1021
1022  (echo ''
1023  echo "*** Comparing conf files: ${rc_conf_files}"
1024
1025  for CONF_FILE in ${rc_conf_files}; do
1026    if [ -r "${DESTDIR}${CONF_FILE}" ]; then
1027      echo ''
1028      echo "*** From ${DESTDIR}${CONF_FILE}"
1029      echo "*** From ${DESTDIR}/etc/defaults/rc.conf"
1030
1031      for RC_CONF_VAR in `grep -i ^[a-z] ${DESTDIR}${CONF_FILE} |
1032        cut -d '=' -f 1`; do
1033        echo ''
1034        grep -w ^${RC_CONF_VAR} ${DESTDIR}${CONF_FILE}
1035        grep -w ^${RC_CONF_VAR} ${DESTDIR}/etc/defaults/rc.conf ||
1036          echo ' * No default variable with this name'
1037      done
1038    fi
1039  done) | ${PAGER}
1040  echo ''
1041  ;;
1042esac
1043
1044case "${PRE_WORLD}" in
1045'') ;;
1046*)
1047  MAKE_CONF="${SOURCEDIR%etc}etc/defaults/make.conf"
1048
1049  (echo ''
1050  echo '*** Comparing make variables'
1051  echo ''
1052  echo "*** From ${DESTDIR}/etc/make.conf"
1053  echo "*** From ${MAKE_CONF}"
1054
1055  for MAKE_VAR in `grep -i ^[a-z] ${DESTDIR}/etc/make.conf | cut -d '=' -f 1`; do
1056    echo ''
1057    grep -w ^${MAKE_VAR} ${DESTDIR}/etc/make.conf
1058    grep -w ^#${MAKE_VAR} ${MAKE_CONF} ||
1059      echo ' * No example variable with this name'
1060  done) | ${PAGER}
1061  ;;
1062esac
1063
1064exit 0
1065
1066