mergemaster.sh revision 155309
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-2004 Douglas Barton
9# DougB@FreeBSD.org
10
11# $FreeBSD: head/usr.sbin/mergemaster/mergemaster.sh 155309 2006-02-04 18:24:06Z rwatson $
12
13PATH=/bin:/usr/bin:/usr/sbin
14
15display_usage () {
16  VERSION_NUMBER=`grep "[$]FreeBSD:" $0 | cut -d ' ' -f 4`
17  echo "mergemaster version ${VERSION_NUMBER}"
18  echo 'Usage: mergemaster [-scrvahipCP] [-m /path]'
19  echo '         [-t /path] [-d] [-u N] [-w N] [-D /path]'
20  echo "Options:"
21  echo "  -s  Strict comparison (diff every pair of files)"
22  echo "  -c  Use context diff instead of unified diff"
23  echo "  -r  Re-run on a previously cleaned directory (skip temproot creation)"
24  echo "  -v  Be more verbose about the process, include additional checks"
25  echo "  -a  Leave all files that differ to merge by hand"
26  echo "  -h  Display more complete help"
27  echo '  -i  Automatically install files that do not exist in destination directory'
28  echo '  -p  Pre-buildworld mode, only compares crucial files'
29  echo '  -C  Compare local rc.conf variables to the defaults'
30  echo '  -P  Preserve files that are overwritten'
31  echo "  -m /path/directory  Specify location of source to do the make in"
32  echo "  -t /path/directory  Specify temp root directory"
33  echo "  -d  Add date and time to directory name (e.g., /var/tmp/temproot.`date +%m%d.%H.%M`)"
34  echo "  -u N  Specify a numeric umask"
35  echo "  -w N  Specify a screen width in columns to sdiff"
36  echo "  -A architecture  Alternative architecture name to pass to make"
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:A:" COMMAND_LINE_ARGUMENT ; do
243  case "${COMMAND_LINE_ARGUMENT}" in
244  A)
245    ARCHSTRING='MACHINE_ARCH='${OPTARG}
246    ;;
247  s)
248    STRICT=yes
249    unset DIFF_OPTIONS
250    ;;
251  c)
252    DIFF_FLAG='-c'
253    ;;
254  r)
255    RERUN=yes
256    ;;
257  v)
258    case "${AUTO_RUN}" in
259    '') VERBOSE=yes ;;
260    esac
261    ;;
262  a)
263    AUTO_RUN=yes
264    unset VERBOSE
265    ;;
266  h)
267    display_usage
268    display_help
269    exit 0
270    ;;
271  i)
272    AUTO_INSTALL=yes
273    ;;
274  C)
275    COMP_CONFS=yes
276    ;;
277  P)
278    PRESERVE_FILES=yes
279    ;;
280  p)
281    PRE_WORLD=yes
282    unset COMP_CONFS
283    unset AUTO_RUN
284    ;;
285  m)
286    SOURCEDIR=${OPTARG}
287    ;;
288  t)
289    TEMPROOT=${OPTARG}
290    ;;
291  d)
292    TEMPROOT=${TEMPROOT}.`date +%m%d.%H.%M`
293    ;;
294  u)
295    NEW_UMASK=${OPTARG}
296    ;;
297  w)
298    SCREEN_WIDTH=${OPTARG}
299    ;;
300  D)
301    DESTDIR=${OPTARG}
302    ;;
303  *)
304    display_usage
305    exit 1
306    ;;
307  esac
308done
309
310# Don't force the user to set this in the mergemaster rc file
311if [ -n "${PRESERVE_FILES}" -a -z "${PRESERVE_FILES_DIR}" ]; then
312  PRESERVE_FILES_DIR=/var/tmp/mergemaster/preserved-files-`date +%y%m%d-%H%M%S`
313fi
314
315echo ''
316
317# If the user has a pager defined, make sure we can run it
318#
319case "${DONT_CHECK_PAGER}" in
320'')
321  while ! type "${PAGER%% *}" >/dev/null && [ -n "${PAGER}" ]; do
322    echo " *** Your PAGER environment variable specifies '${PAGER}', but"
323    echo "     due to the limited PATH that I use for security reasons,"
324    echo "     I cannot execute it.  So, what would you like to do?"
325    echo ''
326    echo "  Use 'e' to exit mergemaster and fix your PAGER variable"
327    if [ -x /usr/bin/less -o -x /usr/local/bin/less ]; then
328    echo "  Use 'l' to set PAGER to 'less' for this run"
329    fi
330    echo "  Use 'm' to use plain old 'more' as your PAGER for this run"
331    echo ''
332    echo "  Default is to use plain old 'more' "
333    echo ''
334    echo -n "What should I do? [Use 'more'] "
335    read FIXPAGER
336
337    case "${FIXPAGER}" in
338    [eE])
339       exit 0
340       ;;
341    [lL])
342       if [ -x /usr/bin/less ]; then
343         PAGER=/usr/bin/less
344       elif [ -x /usr/local/bin/less ]; then
345         PAGER=/usr/local/bin/less
346       else
347         echo ''
348         echo " *** Fatal Error:"
349         echo "     You asked to use 'less' as your pager, but I can't"
350         echo "     find it in /usr/bin or /usr/local/bin"
351         exit 1
352       fi
353       ;;
354    [mM]|'')
355       PAGER=more
356       ;;
357    *)
358       echo ''
359       echo "invalid choice: ${FIXPAGER}"
360    esac
361    echo ''
362  done
363  ;;
364esac
365
366# If user has a pager defined, or got assigned one above, use it.
367# If not, use more.
368#
369PAGER=${PAGER:-more}
370
371if [ -n "${VERBOSE}" -a ! "${PAGER}" = "more" ]; then
372  echo " *** You have ${PAGER} defined as your pager so we will use that"
373  echo ''
374  sleep 3
375fi
376
377# Assign the diff flag once so we will not have to keep testing it
378#
379DIFF_FLAG=${DIFF_FLAG:--u}
380
381# Assign the source directory
382#
383SOURCEDIR=${SOURCEDIR:-/usr/src/etc}
384
385# Check the width of the user's terminal
386#
387if [ -t 0 ]; then
388  w=`tput columns`
389  case "${w}" in
390  0|'') ;; # No-op, since the input is not valid
391  *)
392    case "${SCREEN_WIDTH}" in
393    '') SCREEN_WIDTH="${w}" ;;
394    "${w}") ;; # No-op, since they are the same
395    *)
396      echo -n "*** You entered ${SCREEN_WIDTH} as your screen width, but stty "
397      echo "thinks it is ${w}."
398      echo ''
399      echo -n "What would you like to use? [${w}] "
400      read SCREEN_WIDTH
401      case "${SCREEN_WIDTH}" in
402      '') SCREEN_WIDTH="${w}" ;;
403      esac
404      ;;
405    esac
406  esac
407fi
408
409# Define what CVS $Id tag to look for to aid portability.
410#
411CVS_ID_TAG=FreeBSD
412
413delete_temproot () {
414  rm -rf "${TEMPROOT}" 2>/dev/null
415  chflags -R 0 "${TEMPROOT}" 2>/dev/null
416  rm -rf "${TEMPROOT}" || exit 1
417}
418
419case "${RERUN}" in
420'')
421  # Set up the loop to test for the existence of the
422  # temp root directory.
423  #
424  TEST_TEMP_ROOT=yes
425  while [ "${TEST_TEMP_ROOT}" = "yes" ]; do
426    if [ -d "${TEMPROOT}" ]; then
427      echo "*** The directory specified for the temporary root environment,"
428      echo "    ${TEMPROOT}, exists.  This can be a security risk if untrusted"
429      echo "    users have access to the system."
430      echo ''
431      case "${AUTO_RUN}" in
432      '')
433        echo "  Use 'd' to delete the old ${TEMPROOT} and continue"
434        echo "  Use 't' to select a new temporary root directory"
435        echo "  Use 'e' to exit mergemaster"
436        echo ''
437        echo "  Default is to use ${TEMPROOT} as is"
438        echo ''
439        echo -n "How should I deal with this? [Use the existing ${TEMPROOT}] "
440        read DELORNOT
441
442        case "${DELORNOT}" in
443        [dD])
444          echo ''
445          echo "   *** Deleting the old ${TEMPROOT}"
446          echo ''
447          delete_temproot || exit 1
448          unset TEST_TEMP_ROOT
449          ;;
450        [tT])
451          echo "   *** Enter new directory name for temporary root environment"
452          read TEMPROOT
453          ;;
454        [eE])
455          exit 0
456          ;;
457        '')
458          echo ''
459          echo "   *** Leaving ${TEMPROOT} intact"
460          echo ''
461          unset TEST_TEMP_ROOT
462          ;;
463        *)
464          echo ''
465          echo "invalid choice: ${DELORNOT}"
466          echo ''
467          ;;
468        esac
469        ;;
470      *)
471        # If this is an auto-run, try a hopefully safe alternative then
472        # re-test anyway.
473        TEMPROOT=/var/tmp/temproot.`date +%m%d.%H.%M.%S`
474        ;;
475      esac
476    else
477      unset TEST_TEMP_ROOT
478    fi
479  done
480
481  echo "*** Creating the temporary root environment in ${TEMPROOT}"
482
483  if mkdir -p "${TEMPROOT}"; then
484    echo " *** ${TEMPROOT} ready for use"
485  fi
486
487  if [ ! -d "${TEMPROOT}" ]; then
488    echo ''
489    echo "  *** FATAL ERROR: Cannot create ${TEMPROOT}"
490    echo ''
491    exit 1
492  fi
493
494  echo " *** Creating and populating directory structure in ${TEMPROOT}"
495  echo ''
496
497  case "${VERBOSE}" in
498  '') ;;
499  *)
500    press_to_continue
501    ;;
502  esac
503
504  case "${PRE_WORLD}" in
505  '')
506    { cd ${SOURCEDIR} &&
507      case "${DESTDIR}" in
508      '') ;;
509      *)
510      make DESTDIR=${DESTDIR} ${ARCHSTRING} distrib-dirs
511        ;;
512      esac
513      make DESTDIR=${TEMPROOT} ${ARCHSTRING} distrib-dirs &&
514      MAKEOBJDIRPREFIX=${TEMPROOT}/usr/obj make ${ARCHSTRING} obj &&
515      MAKEOBJDIRPREFIX=${TEMPROOT}/usr/obj make ${ARCHSTRING} all &&
516      MAKEOBJDIRPREFIX=${TEMPROOT}/usr/obj make ${ARCHSTRING} \
517	  DESTDIR=${TEMPROOT} distribution;} ||
518    { echo '';
519     echo "  *** FATAL ERROR: Cannot 'cd' to ${SOURCEDIR} and install files to";
520      echo "      the temproot environment";
521      echo '';
522      exit 1;}
523    ;;
524  *)
525    # Only set up files that are crucial to {build|install}world
526    { mkdir -p ${TEMPROOT}/etc &&
527      cp -p ${SOURCEDIR}/master.passwd ${TEMPROOT}/etc &&
528      cp -p ${SOURCEDIR}/group ${TEMPROOT}/etc;} ||
529    { echo '';
530      echo '  *** FATAL ERROR: Cannot copy files to the temproot environment';
531      echo '';
532      exit 1;}
533    ;;
534  esac
535
536  # Doing the inventory and removing files that we don't want to compare only
537  # makes sense if we are not doing a rerun, since we have no way of knowing
538  # what happened to the files during previous incarnations.
539  case "${VERBOSE}" in
540  '') ;;
541  *)
542    echo ''
543    echo ' *** The following files exist only in the installed version of'
544    echo "     ${DESTDIR}/etc.  In the vast majority of cases these files"
545    echo '     are necessary parts of the system and should not be deleted.'
546    echo '     However because these files are not updated by this process you'
547    echo '     might want to verify their status before rebooting your system.'
548    echo ''
549    press_to_continue
550    diff -qr ${DESTDIR}/etc ${TEMPROOT}/etc | grep "^Only in ${DESTDIR}/etc" | ${PAGER}
551    echo ''
552    press_to_continue
553    ;;
554  esac
555
556  # Avoid comparing the motd if the user specifies it in .mergemasterrc
557  case "${IGNORE_MOTD}" in
558  '') ;;
559  *) rm -f ${TEMPROOT}/etc/motd
560     ;;
561  esac
562
563  # Avoid trying to update MAKEDEV if /dev is on a devfs
564  if /sbin/sysctl vfs.devfs.generation > /dev/null 2>&1 ; then
565    rm -f ${TEMPROOT}/dev/MAKEDEV ${TEMPROOT}/dev/MAKEDEV.local
566  fi
567
568  ;; # End of the "RERUN" test
569esac
570
571# We really don't want to have to deal with files like login.conf.db, pwd.db,
572# or spwd.db.  Instead, we want to compare the text versions, and run *_mkdb.
573# Prompt the user to do so below, as needed.
574#
575rm -f ${TEMPROOT}/etc/*.db ${TEMPROOT}/etc/passwd
576
577# We only need to compare things like freebsd.cf once
578find ${TEMPROOT}/usr/obj -type f -delete 2>/dev/null
579
580# Get ready to start comparing files
581
582# Check umask if not specified on the command line,
583# and we are not doing an autorun
584#
585if [ -z "${NEW_UMASK}" -a -z "${AUTO_RUN}" ]; then
586  USER_UMASK=`umask`
587  case "${USER_UMASK}" in
588  0022|022) ;;
589  *)
590    echo ''
591    echo " *** Your umask is currently set to ${USER_UMASK}.  By default, this script"
592    echo "     installs all files with the same user, group and modes that"
593    echo "     they are created with by ${SOURCEDIR}/Makefile, compared to"
594    echo "     a umask of 022.  This umask allows world read permission when"
595    echo "     the file's default permissions have it."
596    echo ''
597    echo "     No world permissions can sometimes cause problems.  A umask of"
598    echo "     022 will restore the default behavior, but is not mandatory."
599    echo "     /etc/master.passwd is a special case.  Its file permissions"
600    echo "     will be 600 (rw-------) if installed."
601    echo ''
602    echo -n "What umask should I use? [${USER_UMASK}] "
603    read NEW_UMASK
604
605    NEW_UMASK="${NEW_UMASK:-$USER_UMASK}"
606    ;;
607  esac
608  echo ''
609fi
610
611CONFIRMED_UMASK=${NEW_UMASK:-0022}
612
613#
614# Warn users who still have old rc files
615#
616for file in atm devfs diskless1 diskless2 isdn network network6 pccard \
617  serial syscons sysctl alpha amd64 i386 ia64 sparc64; do
618  if [ -f "${DESTDIR}/etc/rc.${file}" ]; then
619    OLD_RC_PRESENT=1
620    break
621  fi
622done
623
624case "${OLD_RC_PRESENT}" in
6251)
626  echo ''
627  echo " *** There are elements of the old rc system in ${DESTDIR}/etc/."
628  echo ''
629  echo '     While these scripts will not hurt anything, they are not'
630  echo '     functional on an up to date system, and can be removed.'
631  echo ''
632
633  case "${AUTO_RUN}" in
634  '')
635    echo -n 'Move these files to /var/tmp/mergemaster/old_rc? [yes] '
636    read MOVE_OLD_RC
637
638    case "${MOVE_OLD_RC}" in
639    [nN]*) ;;
640    *)
641      mkdir -p /var/tmp/mergemaster/old_rc
642        for file in atm devfs diskless1 diskless2 isdn network network6 pccard \
643          serial syscons sysctl alpha amd64 i386 ia64 sparc64; do
644          if [ -f "${DESTDIR}/etc/rc.${file}" ]; then
645            mv ${DESTDIR}/etc/rc.${file} /var/tmp/mergemaster/old_rc/
646          fi
647        done
648      echo '  The files have been moved'
649      press_to_continue
650      ;;
651    esac
652    ;;
653  *) ;;
654  esac
655esac
656
657# Use the umask/mode information to install the files
658# Create directories as needed
659#
660do_install_and_rm () {
661  case "${PRESERVE_FILES}" in
662  [Yy][Ee][Ss])
663    if [ -f "${3}/${2##*/}" ]; then
664      mkdir -p ${PRESERVE_FILES_DIR}/${2%/*}
665      cp ${3}/${2##*/} ${PRESERVE_FILES_DIR}/${2%/*}
666    fi
667    ;;
668  esac
669
670  install -m "${1}" "${2}" "${3}" &&
671  rm -f "${2}"
672}
673
674# 4095 = "obase=10;ibase=8;07777" | bc
675find_mode () {
676  local OCTAL
677  OCTAL=$(( ~$(echo "obase=10; ibase=8; ${CONFIRMED_UMASK}" | bc) & 4095 &
678    $(echo "obase=10; ibase=8; $(stat -f "%OMp%OLp" ${1})" | bc) ))
679  printf "%04o\n" ${OCTAL}
680}
681
682mm_install () {
683  local INSTALL_DIR
684  INSTALL_DIR=${1#.}
685  INSTALL_DIR=${INSTALL_DIR%/*}
686
687  case "${INSTALL_DIR}" in
688  '')
689    INSTALL_DIR=/
690    ;;
691  esac
692
693  if [ -n "${DESTDIR}${INSTALL_DIR}" -a ! -d "${DESTDIR}${INSTALL_DIR}" ]; then
694    DIR_MODE=`find_mode "${TEMPROOT}/${INSTALL_DIR}"`
695    install -d -o root -g wheel -m "${DIR_MODE}" "${DESTDIR}${INSTALL_DIR}"
696  fi
697
698  FILE_MODE=`find_mode "${1}"`
699
700  if [ ! -x "${1}" ]; then
701    case "${1#.}" in
702    /etc/mail/aliases)
703      NEED_NEWALIASES=yes
704      ;;
705    /etc/login.conf)
706      NEED_CAP_MKDB=yes
707      ;;
708    /etc/master.passwd)
709      do_install_and_rm 600 "${1}" "${DESTDIR}${INSTALL_DIR}"
710      NEED_PWD_MKDB=yes
711      DONT_INSTALL=yes
712      ;;
713    /.cshrc | /.profile)
714    case "${AUTO_INSTALL}" in
715    '')
716      case "${LINK_EXPLAINED}" in
717      '')
718        echo "   *** Historically BSD derived systems have had a"
719        echo "       hard link from /.cshrc and /.profile to"
720        echo "       their namesakes in /root.  Please indicate"
721        echo "       your preference below for bringing your"
722        echo "       installed files up to date."
723        echo ''
724        LINK_EXPLAINED=yes
725        ;;
726      esac
727
728      echo "   Use 'd' to delete the temporary ${COMPFILE}"
729      echo "   Use 'l' to delete the existing ${DESTDIR}${COMPFILE#.} and create the link"
730      echo ''
731      echo "   Default is to leave the temporary file to deal with by hand"
732      echo ''
733      echo -n "  How should I handle ${COMPFILE}? [Leave it to install later] "
734      read HANDLE_LINK
735      ;;
736    *)  # Part of AUTO_INSTALL
737      HANDLE_LINK=l
738      ;;
739    esac
740
741      case "${HANDLE_LINK}" in
742      [dD]*)
743        rm "${COMPFILE}"
744        echo ''
745        echo "   *** Deleting ${COMPFILE}"
746        ;;
747      [lL]*)
748        echo ''
749        rm -f "${DESTDIR}${COMPFILE#.}"
750        if ln "${DESTDIR}/root/${COMPFILE##*/}" "${DESTDIR}${COMPFILE#.}"; then
751          echo "   *** Link from ${DESTDIR}${COMPFILE#.} to ${DESTDIR}/root/${COMPFILE##*/} installed successfully"
752          rm "${COMPFILE}"
753        else
754          echo "   *** Error linking ${DESTDIR}${COMPFILE#.} to ${DESTDIR}/root/${COMPFILE##*/}, ${COMPFILE} will remain to install by hand"
755        fi
756        ;;
757      *)
758        echo "   *** ${COMPFILE} will remain for your consideration"
759        ;;
760      esac
761      DONT_INSTALL=yes
762      ;;
763    esac
764
765    case "${DONT_INSTALL}" in
766    '')
767      do_install_and_rm "${FILE_MODE}" "${1}" "${DESTDIR}${INSTALL_DIR}"
768      ;;
769    *)
770      unset DONT_INSTALL
771      ;;
772    esac
773  else	# File matched -x
774    case "${1#.}" in
775    /dev/MAKEDEV)
776      NEED_MAKEDEV=yes
777      ;;
778    esac
779    do_install_and_rm "${FILE_MODE}" "${1}" "${DESTDIR}${INSTALL_DIR}"
780  fi
781  return $?
782}
783
784echo ''
785echo "*** Beginning comparison"
786echo ''
787
788# Pre-world does not populate /etc/rc.d.
789# It is very possible that a previous run would have deleted files in
790# ${TEMPROOT}/etc/rc.d, thus creating a lot of false positives.
791if [ -z "${PRE_WORLD}" -a -z "${RERUN}" ]; then
792  echo "   *** Checking ${DESTDIR}/etc/rc.d for stale files"
793  echo ''
794  cd "${DESTDIR}/etc/rc.d" &&
795  for file in *; do
796    if [ ! -e "${TEMPROOT}/etc/rc.d/${file}" ]; then
797      STALE_RC_FILES="${STALE_RC_FILES} ${file}"
798    fi
799  done
800  case "${STALE_RC_FILES}" in
801  ''|' *')
802    echo '   *** No stale files found'
803    ;;
804  *)
805    echo "   *** The following files exist in ${DESTDIR}/etc/rc.d but not in"
806    echo "       ${TEMPROOT}/etc/rc.d/:"
807    echo ''
808    echo "${STALE_RC_FILES}"
809    echo ''
810    echo '       The presence of stale files in this directory can cause the'
811    echo '       dreaded unpredictable results, and therefore it is highly'
812    echo '       recommended that you delete them.'
813    case "${AUTO_RUN}" in
814    '')
815      echo ''
816      echo -n '   *** Delete them now? [n] '
817      read DELETE_STALE_RC_FILES
818      case "${DELETE_STALE_RC_FILES}" in
819      [yY])
820        echo '      *** Deleting ... '
821        rm ${STALE_RC_FILES}
822        echo '                       done.'
823        ;;
824      *)
825        echo '      *** Files will not be deleted'
826        ;;
827      esac
828      sleep 2
829      ;;
830    esac
831    ;;
832  esac
833  echo ''
834fi
835
836cd "${TEMPROOT}"
837
838if [ -r "${MM_PRE_COMPARE_SCRIPT}" ]; then
839  . "${MM_PRE_COMPARE_SCRIPT}"
840fi
841
842# Using -size +0 avoids uselessly checking the empty log files created
843# by ${SOURCEDIR}/Makefile and the device entries in ./dev, but does
844# check the scripts in ./dev, as we'd like (assuming no devfs of course).
845#
846for COMPFILE in `find . -type f -size +0`; do
847
848  # First, check to see if the file exists in DESTDIR.  If not, the
849  # diff_loop function knows how to handle it.
850  #
851  if [ ! -e "${DESTDIR}${COMPFILE#.}" ]; then
852    case "${AUTO_RUN}" in
853      '')
854        diff_loop
855        ;;
856      *)
857        case "${AUTO_INSTALL}" in
858        '')
859          # If this is an auto run, make it official
860          echo "   *** ${COMPFILE} will remain for your consideration"
861          ;;
862        *)
863          diff_loop
864          ;;
865        esac
866        ;;
867    esac # Auto run test
868    continue
869  fi
870
871  case "${STRICT}" in
872  '' | [Nn][Oo])
873    # Compare CVS $Id's first so if the file hasn't been modified
874    # local changes will be ignored.
875    # If the files have the same $Id, delete the one in temproot so the
876    # user will have less to wade through if files are left to merge by hand.
877    #
878    CVSID1=`grep "[$]${CVS_ID_TAG}:" ${DESTDIR}${COMPFILE#.} 2>/dev/null`
879    CVSID2=`grep "[$]${CVS_ID_TAG}:" ${COMPFILE} 2>/dev/null` || CVSID2=none
880
881    case "${CVSID2}" in
882    "${CVSID1}")
883      echo " *** Temp ${COMPFILE} and installed have the same CVS Id, deleting"
884      rm "${COMPFILE}"
885      ;;
886    esac
887    ;;
888  esac
889
890  # If the file is still here either because the $Ids are different, the
891  # file doesn't have an $Id, or we're using STRICT mode; look at the diff.
892  #
893  if [ -f "${COMPFILE}" ]; then
894
895    # Do an absolute diff first to see if the files are actually different.
896    # If they're not different, delete the one in temproot.
897    #
898    if diff -q ${DIFF_OPTIONS} "${DESTDIR}${COMPFILE#.}" "${COMPFILE}" > \
899      /dev/null 2>&1; then
900      echo " *** Temp ${COMPFILE} and installed are the same, deleting"
901      rm "${COMPFILE}"
902    else
903      # Ok, the files are different, so show the user where they differ.
904      # Use user's choice of diff methods; and user's pager if they have one.
905      # Use more if not.
906      # Use unified diffs by default.  Context diffs give me a headache. :)
907      #
908      case "${AUTO_RUN}" in
909      '')
910        # prompt user to install/delete/merge changes
911        diff_loop
912        ;;
913      *)
914        # If this is an auto run, make it official
915        echo "   *** ${COMPFILE} will remain for your consideration"
916        ;;
917      esac # Auto run test
918    fi # Yes, the files are different
919  fi # Yes, the file still remains to be checked
920done # This is for the do way up there at the beginning of the comparison
921
922echo ''
923echo "*** Comparison complete"
924echo ''
925
926TEST_FOR_FILES=`find ${TEMPROOT} -type f -size +0 2>/dev/null`
927if [ -n "${TEST_FOR_FILES}" ]; then
928  echo "*** Files that remain for you to merge by hand:"
929  find "${TEMPROOT}" -type f -size +0
930  echo ''
931fi
932
933case "${AUTO_RUN}" in
934'')
935  echo -n "Do you wish to delete what is left of ${TEMPROOT}? [no] "
936  read DEL_TEMPROOT
937
938  case "${DEL_TEMPROOT}" in
939  [yY]*)
940    if delete_temproot; then
941      echo " *** ${TEMPROOT} has been deleted"
942    else
943      echo " *** Unable to delete ${TEMPROOT}"
944    fi
945    ;;
946  *)
947    echo " *** ${TEMPROOT} will remain"
948    ;;
949  esac
950  ;;
951*) ;;
952esac
953
954case "${AUTO_INSTALLED_FILES}" in
955'') ;;
956*)
957  case "${AUTO_RUN}" in
958  '')
959    (
960      echo ''
961      echo '*** You chose the automatic install option for files that did not'
962      echo '    exist on your system.  The following were installed for you:'
963      echo "${AUTO_INSTALLED_FILES}"
964    ) | ${PAGER}
965    ;;
966  *)
967    echo ''
968    echo '*** You chose the automatic install option for files that did not'
969    echo '    exist on your system.  The following were installed for you:'
970    echo "${AUTO_INSTALLED_FILES}"
971    ;;
972  esac
973  ;;
974esac
975
976run_it_now () {
977  case "${AUTO_RUN}" in
978  '')
979    unset YES_OR_NO
980    echo ''
981    echo -n '    Would you like to run it now? y or n [n] '
982    read YES_OR_NO
983
984    case "${YES_OR_NO}" in
985    y)
986      echo "    Running ${1}"
987      echo ''
988      eval "${1}"
989      ;;
990    ''|n)
991      echo ''
992      echo "       *** Cancelled"
993      echo ''
994      echo "    Make sure to run ${1} yourself"
995      ;;
996    *)
997      echo ''
998      echo "       *** Sorry, I do not understand your answer (${YES_OR_NO})"
999      echo ''
1000      echo "    Make sure to run ${1} yourself"
1001    esac
1002    ;;
1003  *) ;;
1004  esac
1005}
1006
1007case "${NEED_MAKEDEV}" in
1008'') ;;
1009*)
1010  echo ''
1011  echo "*** You installed a new ${DESTDIR}/dev/MAKEDEV script, so make sure that you run"
1012  echo "    'cd ${DESTDIR}/dev && /bin/sh MAKEDEV all' to rebuild your devices"
1013  run_it_now "cd ${DESTDIR}/dev && /bin/sh MAKEDEV all"
1014  ;;
1015esac
1016
1017case "${NEED_NEWALIASES}" in
1018'') ;;
1019*)
1020  echo ''
1021  if [ -n "${DESTDIR}" ]; then
1022    echo "*** You installed a new aliases file into ${DESTDIR}/etc/mail, but"
1023    echo "    the newaliases command is limited to the directories configured"
1024    echo "    in sendmail.cf.  Make sure to create your aliases database by"
1025    echo "    hand when your sendmail configuration is done."
1026  else
1027    echo "*** You installed a new aliases file, so make sure that you run"
1028    echo "    '/usr/bin/newaliases' to rebuild your aliases database"
1029    run_it_now '/usr/bin/newaliases'
1030  fi
1031  ;;
1032esac
1033
1034case "${NEED_CAP_MKDB}" in
1035'') ;;
1036*)
1037  echo ''
1038  echo "*** You installed a login.conf file, so make sure that you run"
1039  echo "    '/usr/bin/cap_mkdb ${DESTDIR}/etc/login.conf'"
1040  echo "     to rebuild your login.conf database"
1041  run_it_now "/usr/bin/cap_mkdb ${DESTDIR}/etc/login.conf"
1042  ;;
1043esac
1044
1045case "${NEED_PWD_MKDB}" in
1046'') ;;
1047*)
1048  echo ''
1049  echo "*** You installed a new master.passwd file, so make sure that you run"
1050  if [ -n "${DESTDIR}" ]; then
1051    echo "    '/usr/sbin/pwd_mkdb -d ${DESTDIR}/etc -p ${DESTDIR}/etc/master.passwd'"
1052    echo "    to rebuild your password files"
1053    run_it_now "/usr/sbin/pwd_mkdb -d ${DESTDIR}/etc -p ${DESTDIR}/etc/master.passwd"
1054  else
1055    echo "    '/usr/sbin/pwd_mkdb -p /etc/master.passwd'"
1056    echo "     to rebuild your password files"
1057    run_it_now '/usr/sbin/pwd_mkdb -p /etc/master.passwd'
1058  fi
1059  ;;
1060esac
1061
1062echo ''
1063
1064if [ -r "${MM_EXIT_SCRIPT}" ]; then
1065  . "${MM_EXIT_SCRIPT}"
1066fi
1067
1068case "${COMP_CONFS}" in
1069'') ;;
1070*)
1071  . ${DESTDIR}/etc/defaults/rc.conf
1072
1073  (echo ''
1074  echo "*** Comparing conf files: ${rc_conf_files}"
1075
1076  for CONF_FILE in ${rc_conf_files}; do
1077    if [ -r "${DESTDIR}${CONF_FILE}" ]; then
1078      echo ''
1079      echo "*** From ${DESTDIR}${CONF_FILE}"
1080      echo "*** From ${DESTDIR}/etc/defaults/rc.conf"
1081
1082      for RC_CONF_VAR in `grep -i ^[a-z] ${DESTDIR}${CONF_FILE} |
1083        cut -d '=' -f 1`; do
1084        echo ''
1085        grep -w ^${RC_CONF_VAR} ${DESTDIR}${CONF_FILE}
1086        grep -w ^${RC_CONF_VAR} ${DESTDIR}/etc/defaults/rc.conf ||
1087          echo ' * No default variable with this name'
1088      done
1089    fi
1090  done) | ${PAGER}
1091  echo ''
1092  ;;
1093esac
1094
1095case "${PRE_WORLD}" in
1096'') ;;
1097*)
1098  MAKE_CONF="${SOURCEDIR%etc}share/examples/etc/make.conf"
1099
1100  (echo ''
1101  echo '*** Comparing make variables'
1102  echo ''
1103  echo "*** From ${DESTDIR}/etc/make.conf"
1104  echo "*** From ${MAKE_CONF}"
1105
1106  for MAKE_VAR in `grep -i ^[a-z] ${DESTDIR}/etc/make.conf | cut -d '=' -f 1`; do
1107    echo ''
1108    grep -w ^${MAKE_VAR} ${DESTDIR}/etc/make.conf
1109    grep -w ^#${MAKE_VAR} ${MAKE_CONF} ||
1110      echo ' * No example variable with this name'
1111  done) | ${PAGER}
1112  ;;
1113esac
1114
1115exit 0
1116
1117