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