--- /dev/null
+.\" Copyright (c) 1998-2003 Douglas Barton
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/usr.sbin/mergemaster/mergemaster.8,v 1.5.2.12 2003/03/02 02:45:01 dougb Exp $
+.\" $DragonFly: src/usr.sbin/mergemaster/mergemaster.8,v 1.5 2008/05/02 02:05:08 swildner Exp $
+.\"
+.Dd February 5, 2001
+.Dt MERGEMASTER 8
+.Os
+.Sh NAME
+.Nm mergemaster
+.Nd merge configuration files, et al during an upgrade
+.Sh SYNOPSIS
+.Nm
+.Op Fl scrvahipC
+.Op Fl m Ar /path/to/sources
+.Op Fl t Ar /path/to/temp/root
+.Op Fl d
+.Op Fl u Ar N
+.Op Fl w Ar N
+.Op Fl D Ar /path
+.Sh DESCRIPTION
+The
+.Nm
+utility is a Bourne shell script which is designed to aid you
+in updating the various configuration and other files
+associated with
+.Dx .
+It is
+.Sy HIGHLY
+recommended that you back up your
+.Pa /etc
+directory before beginning this process.
+.Pp
+The script uses
+.Pa /usr/src/etc/Makefile
+to build a temporary root environment from
+.Pa /
+down, populating that environment with the various
+files.
+You can specify a different source directory
+with the
+.Op Fl m
+command line option, or specify the destination
+directory with the
+.Op Fl D
+option.
+It then compares each file in that environment
+to its installed counterpart.
+When the script finds a
+change in the new file, or there is no installed
+version of the new file it gives you four options to
+deal with it.
+You can install the new file as is,
+delete the new file, merge the old and new
+files (as appropriate) using
+.Xr sdiff 1
+or leave the file in the temporary root environment to
+merge by hand later.
+.Pp
+By default it creates the temporary root in
+.Pa /var/tmp/temproot
+and compares the
+.Xr cvs 1
+version $Id/$DragonFly strings for files that have them, deleting
+the temporary file if the strings match.
+If there is
+no $Id string, or if the strings are different it
+compares the files themselves.
+You can
+also specify that the script ignore the $Id strings and
+compare every file.
+.Pp
+The
+.Nm
+utility checks your umask and issues a warning for anything
+other than 022. While it is not mandatory to grant
+world read permissions for most configuration files, you
+may run into problems without them.
+If you choose a
+umask other than 022 and experience trouble later this
+could be the cause.
+.Pa /etc/master.passwd
+is treated as a special case.
+If you choose to install
+this file or a merged version of it the file permissions
+are always 600 (rw-------) for security reasons.
+After
+installing an updated version of this file you should
+probably run
+.Xr pwd_mkdb 8
+with the -p option to rebuild your password databases
+and recreate
+.Pa /etc/passwd .
+.Pp
+The script uses the owner and group id's
+that the files are created with by
+.Pa /usr/src/etc/Makefile ,
+and file permissions as specified by the umask.
+Unified diffs are used by default to display any
+differences unless you choose context diffs.
+.Pp
+The
+.Nm
+utility will source scripts that you specify right before
+it starts the comparison, and after it's done running.
+The easiest way to handle this is to place the path
+to the script(s) in the appropriate variables in your
+.Pa .mergemasterrc
+file.
+The script sourced before comparison is named in
+.Ev MM_PRE_COMPARE_SCRIPT ,
+and the one sourced after the script is done is
+.Ev MM_EXIT_SCRIPT .
+This is the recommended way to specify local modifications,
+or files that you want to give special handling to.
+This includes files that you want to be deleted without
+being compared.
+Because the named scripts are sourced from within
+.Nm ,
+all of the script's variables are available for use in
+your custom script.
+You can also use
+.Pa /etc/mergemaster.rc
+which will be read before
+.Pa .mergemasterrc .
+Options specified on the command line are updated last,
+and therefore can override both files.
+.Pp
+The options are as follows:
+.Bl -tag -width Fl
+.It Fl s
+Perform a strict comparison, diff'ing every pair of files.
+This comparison is performed line by line,
+without regard to CVS $Id's.
+.It Fl c
+Use context diffs instead of unified diffs.
+.It Fl r
+Re-run
+.Nm
+on a previously cleaned directory, skipping the creation of
+the temporary root environment.
+This option is compatible
+with all other options.
+.It Fl v
+Be more verbose about the process.
+You should probably use
+this option the first time you run
+.Nm .
+This option also gives you a list of files that exist
+only in the installed version of
+.Pa /etc .
+.It Fl a
+Run automatically.
+This option will leave all the files that
+differ from the installed versions in the temporary directory
+to be dealt with by hand.
+If the
+.Pa temproot
+directory exists, it creates a new one in a previously
+non-existent directory.
+This option unsets the verbose flag,
+but is compatible with all other options.
+Setting -a makes
+-w superfluous.
+.It Fl h
+Display usage and help information.
+.It Fl i
+Automatically install any files that do not exist in the
+destination directory.
+.It Fl p
+Pre-buildworld mode.
+Compares only files known to be essential to the success of
+{build|install}world,
+including
+.Pa /etc/make.conf .
+.It Fl C
+After a standard
+.Nm
+run,
+compares your rc.conf[.local] options to the defaults.
+.It Fl m Ar /path/to/sources
+Specify the path to the directory where you want to do the
+.Xr make 1 .
+(In other words, where your sources are, but -s was already
+taken.)
+.It Fl t Ar /path/to/temp/root
+Create the temporary root environment in
+.Pa /path/to/temp/root
+instead of the default
+.Pa /var/tmp/temproot .
+.It Fl d
+Add the date and time to the name of the temporary
+root directory.
+If -t is specified, this option must
+follow it if you want the date added too.
+.It Fl u Ar N
+Specify a numeric umask.
+The default is 022.
+.It Fl w Ar N
+Supply an alternate screen width to the
+.Xr sdiff 1
+command in numbers of columns.
+The default is 80.
+.It Fl D Ar /path
+Specify the destination directory for the installed files.
+.El
+.Sh ENVIRONMENT
+The
+.Nm
+utility uses the
+.Ev PAGER
+environment variable if set.
+Otherwise it uses
+.Xr more 1 .
+If
+.Ev PAGER
+specifies a program outside
+its
+limited
+.Ev PATH
+without specifying the full path,
+.Nm
+prompts you with options on how to proceed.
+The
+.Ev MM_PRE_COMPARE_SCRIPT
+and
+.Ev MM_EXIT_SCRIPT
+variables are used as described above.
+Other variables that are used by the script internally
+can be specified in
+.Pa .mergemasterrc
+as described in more detail below.
+.Sh FILES
+.Bl -tag -width $HOME/.mergemasterrc -compact
+.It Pa /etc/mergemaster.rc
+.It Pa $HOME/.mergemasterrc
+.El
+.Pp
+The
+.Nm
+utility will . (source) these files if they exist.
+Command line options
+will override rc file options.
+.Pa $HOME/.mergemasterrc
+overrides
+.Pa /etc/mergemaster.rc .
+Here is an example
+with all values commented out:
+.Bd -literal
+# These are options for mergemaster, with their default values listed
+# The following options have command line overrides
+#
+# Directory to install the temporary root environment into
+#TEMPROOT='/var/tmp/temproot'
+#
+# Strict comparison bypasses the CVS $Id tests and compares every file
+#STRICT=no
+#
+# Type of diff, such as unified, context, etc.
+#DIFF_FLAG='-u'
+#
+# Additional options for diff. This will get unset when using -s.
+#DIFF_OPTIONS='-I$\&DragonFly:.*[$]' # Ignores CVS Id tags
+#
+# Verbose mode includes more details and additional checks
+#VERBOSE=
+#
+# Automatically install files that do not exist on the system already
+#AUTO_INSTALL=
+#
+# Compare /etc/rc.conf[.local] to /etc/defaults/rc.conf
+#COMP_CONFS=yes
+#
+# Sourcedir is the directory to do the 'make' in (where the new files are)
+#SOURCEDIR='/usr/src/etc'
+#
+# The umask for mergemaster to compare the default file's modes to
+#NEW_UMASK=022
+#
+# Specify the destination directory for the installed files
+#DESTDIR=
+#
+# The following options have no command line overrides
+# For those who just cannot stand including the full path to PAGER
+#DONT_CHECK_PAGER=
+#
+# If you set 'yes' above, make sure to include the PATH to your pager
+#PATH=/bin:/usr/bin:/usr/sbin
+#
+# Don't compare the old and new motd files
+#IGNORE_MOTD=yes
+#
+# Specify the path to scripts to run before the comparison starts,
+# and/or after the script has finished its work
+#MM_PRE_COMPARE_SCRIPT=
+#MM_EXIT_SCRIPT=
+.Ed
+.Sh EXAMPLES
+Typically all you will need to do is type
+.Nm
+at the prompt and the script will do all the work for you.
+.Pp
+To use context diff's and have
+.Nm
+explain more things as it goes along, use:
+.Pp
+.Dl # mergemaster -cv
+.Pp
+To specify that
+.Nm
+put the temporary root environment in
+.Pa /usr/tmp/root ,
+use:
+.Pp
+.Dl # mergemaster -t /usr/tmp/root
+.Pp
+To specify a 110 column screen with a strict
+comparison, use:
+.Pp
+.Dl # mergemaster -sw 110
+.Sh DIAGNOSTICS
+Exit status is 0 on successful completion, or if the user bails out
+manually at some point during execution.
+.Pp
+Exit status is 1 if it fails for one of the following reasons:
+.Pp
+Invalid command line option
+.Pp
+Failure to create the temporary root environment
+.Pp
+Failure to populate the temporary root
+.Sh SEE ALSO
+.Xr cvs 1 ,
+.Xr diff 1 ,
+.Xr make 1 ,
+.Xr more 1 ,
+.Xr sdiff 1 ,
+.Xr pwd_mkdb 8
+.Pp
+.Pa /usr/src/etc/Makefile
+.Rs
+.%O http://www.FreeBSD.org/doc/handbook/makeworld.html
+.%T The Cutting Edge (using make world)
+.%A Nik Clayton
+.Re
+.Sh HISTORY
+The
+.Nm
+utility was first publicly available on one of my
+web pages in a much simpler form under the name
+.Pa comproot
+on 13 March 1998. The idea for creating the
+temporary root environment comes from Nik Clayton's
+make world tutorial which is referenced above.
+.Sh AUTHORS
+This manual page and the script itself were written by
+.An Douglas Barton Aq DougB@FreeBSD.org .
+.Sh BUGS
+There are no known bugs.
+Please report any problems,
+comments or suggestions to the author.
+Several of the
+improvements to this program have come from user
+suggestions.
+Thank you.
--- /dev/null
+#!/bin/sh
+
+# mergemaster
+
+# Compare files created by /usr/src/etc/Makefile (or the directory
+# the user specifies) with the currently installed copies.
+
+# Copyright 1998-2003 Douglas Barton
+# DougB@FreeBSD.org
+
+# $FreeBSD: src/usr.sbin/mergemaster/mergemaster.sh,v 1.46 2003/05/03 06:35:19 dougb Exp $
+# $DragonFly: src/usr.sbin/mergemaster/mergemaster.sh,v 1.6 2004/03/14 13:47:12 eirikn Exp $
+
+PATH=/bin:/usr/bin:/usr/sbin
+
+display_usage () {
+ VERSION_NUMBER=`grep "[$]DragonFly:" $0 | cut -d ' ' -f 4`
+ echo "mergemaster version ${VERSION_NUMBER}"
+ echo 'Usage: mergemaster [-scrvahipCP] [-m /path]'
+ echo ' [-t /path] [-d] [-u N] [-w N] [-D /path]'
+ echo "Options:"
+ echo " -s Strict comparison (diff every pair of files)"
+ echo " -c Use context diff instead of unified diff"
+ echo " -r Re-run on a previously cleaned directory (skip temproot creation)"
+ echo " -v Be more verbose about the process, include additional checks"
+ echo " -a Leave all files that differ to merge by hand"
+ echo " -h Display more complete help"
+ echo ' -i Automatically install files that do not exist in destination directory'
+ echo ' -p Pre-buildworld mode, only compares crucial files'
+ echo ' -C Compare local rc.conf variables to the defaults'
+ echo ' -P Preserve files that are overwritten'
+ echo " -m /path/directory Specify location of source to do the make in"
+ echo " -t /path/directory Specify temp root directory"
+ echo " -d Add date and time to directory name (e.g., /var/tmp/temproot.`date +%m%d.%H.%M`)"
+ echo " -u N Specify a numeric umask"
+ echo " -w N Specify a screen width in columns to sdiff"
+ echo ' -D /path/directory Specify the destination directory to install files to'
+ echo ''
+}
+
+display_help () {
+ echo "* To specify a directory other than /var/tmp/temproot for the"
+ echo " temporary root environment, use -t /path/to/temp/root"
+ echo "* The -w option takes a number as an argument for the column width"
+ echo " of the screen. The default is 80."
+ echo '* The -a option causes mergemaster to run without prompting.'
+}
+
+# Loop allowing the user to use sdiff to merge files and display the merged
+# file.
+merge_loop () {
+ case "${VERBOSE}" in
+ '') ;;
+ *)
+ echo " *** Type h at the sdiff prompt (%) to get usage help"
+ ;;
+ esac
+ echo ''
+ MERGE_AGAIN=yes
+ while [ "${MERGE_AGAIN}" = "yes" ]; do
+ # Prime file.merged so we don't blat the owner/group id's
+ cp -p "${COMPFILE}" "${COMPFILE}.merged"
+ sdiff -o "${COMPFILE}.merged" --text --suppress-common-lines \
+ --width=${SCREEN_WIDTH:-80} "${DESTDIR}${COMPFILE#.}" "${COMPFILE}"
+ INSTALL_MERGED=V
+ while [ "${INSTALL_MERGED}" = "v" -o "${INSTALL_MERGED}" = "V" ]; do
+ echo ''
+ echo " Use 'i' to install merged file"
+ echo " Use 'r' to re-do the merge"
+ echo " Use 'v' to view the merged file"
+ echo " Default is to leave the temporary file to deal with by hand"
+ echo ''
+ echo -n " *** How should I deal with the merged file? [Leave it for later] "
+ read INSTALL_MERGED
+
+ case "${INSTALL_MERGED}" in
+ [iI])
+ mv "${COMPFILE}.merged" "${COMPFILE}"
+ echo ''
+ if mm_install "${COMPFILE}"; then
+ echo " *** Merged version of ${COMPFILE} installed successfully"
+ else
+ echo " *** Problem installing ${COMPFILE}, it will remain to merge by hand later"
+ fi
+ unset MERGE_AGAIN
+ ;;
+ [rR])
+ rm "${COMPFILE}.merged"
+ ;;
+ [vV])
+ ${PAGER} "${COMPFILE}.merged"
+ ;;
+ '')
+ echo " *** ${COMPFILE} will remain for your consideration"
+ unset MERGE_AGAIN
+ ;;
+ *)
+ echo "invalid choice: ${INSTALL_MERGED}"
+ INSTALL_MERGED=V
+ ;;
+ esac
+ done
+ done
+}
+
+# Loop showing user differences between files, allow merge, skip or install
+# options
+diff_loop () {
+
+ HANDLE_COMPFILE=v
+
+ while [ "${HANDLE_COMPFILE}" = "v" -o "${HANDLE_COMPFILE}" = "V" -o \
+ "${HANDLE_COMPFILE}" = "NOT V" ]; do
+ if [ -f "${DESTDIR}${COMPFILE#.}" -a -f "${COMPFILE}" ]; then
+ if [ "${HANDLE_COMPFILE}" = "v" -o "${HANDLE_COMPFILE}" = "V" ]; then
+ echo ''
+ echo ' ====================================================================== '
+ echo ''
+ (
+ echo " *** Displaying differences between ${COMPFILE} and installed version:"
+ echo ''
+ diff ${DIFF_FLAG} ${DIFF_OPTIONS} "${DESTDIR}${COMPFILE#.}" "${COMPFILE}"
+ ) | ${PAGER}
+ echo ''
+ fi
+ else
+ echo ''
+ echo " *** There is no installed version of ${COMPFILE}"
+ echo ''
+ case "${AUTO_INSTALL}" in
+ [Yy][Ee][Ss])
+ echo ''
+ if mm_install "${COMPFILE}"; then
+ echo " *** ${COMPFILE} installed successfully"
+ echo ''
+ # Make the list print one file per line
+ AUTO_INSTALLED_FILES="${AUTO_INSTALLED_FILES} ${DESTDIR}${COMPFILE#.}
+"
+ else
+ echo " *** Problem installing ${COMPFILE}, it will remain to merge by hand"
+ fi
+ return
+ ;;
+ *)
+ NO_INSTALLED=yes
+ ;;
+ esac
+ fi
+
+ echo " Use 'd' to delete the temporary ${COMPFILE}"
+ echo " Use 'i' to install the temporary ${COMPFILE}"
+ case "${NO_INSTALLED}" in
+ '')
+ echo " Use 'm' to merge the temporary and installed versions"
+ echo " Use 'v' to view the diff results again"
+ ;;
+ esac
+ echo ''
+ echo " Default is to leave the temporary file to deal with by hand"
+ echo ''
+ echo -n "How should I deal with this? [Leave it for later] "
+ read HANDLE_COMPFILE
+
+ case "${HANDLE_COMPFILE}" in
+ [dD])
+ rm "${COMPFILE}"
+ echo ''
+ echo " *** Deleting ${COMPFILE}"
+ ;;
+ [iI])
+ echo ''
+ if mm_install "${COMPFILE}"; then
+ echo " *** ${COMPFILE} installed successfully"
+ else
+ echo " *** Problem installing ${COMPFILE}, it will remain to merge by hand"
+ fi
+ ;;
+ [mM])
+ case "${NO_INSTALLED}" in
+ '')
+ # interact with user to merge files
+ merge_loop
+ ;;
+ *)
+ echo ''
+ echo " *** There is no installed version of ${COMPFILE}"
+ echo ''
+ HANDLE_COMPFILE="NOT V"
+ ;;
+ esac # End of "No installed version of file but user selected merge" test
+ ;;
+ [vV])
+ continue
+ ;;
+ '')
+ echo ''
+ echo " *** ${COMPFILE} will remain for your consideration"
+ ;;
+ *)
+ # invalid choice, show menu again.
+ echo "invalid choice: ${HANDLE_COMPFILE}"
+ echo ''
+ HANDLE_COMPFILE="NOT V"
+ continue
+ ;;
+ esac # End of "How to handle files that are different"
+ done
+ unset NO_INSTALLED
+ echo ''
+ case "${VERBOSE}" in
+ '') ;;
+ *)
+ sleep 3
+ ;;
+ esac
+}
+
+press_to_continue () {
+ local DISCARD
+ echo -n ' *** Press the [Enter] or [Return] key to continue '
+ read DISCARD
+}
+
+# Set the default path for the temporary root environment
+#
+TEMPROOT='/var/tmp/temproot'
+
+# Read /etc/mergemaster.rc first so the one in $HOME can override
+#
+if [ -r /etc/mergemaster.rc ]; then
+ . /etc/mergemaster.rc
+fi
+
+# Read .mergemasterrc before command line so CLI can override
+#
+if [ -r "$HOME/.mergemasterrc" ]; then
+ . "$HOME/.mergemasterrc"
+fi
+
+# Check the command line options
+#
+while getopts ":ascrvhipCPm:t:du:w:D:" COMMAND_LINE_ARGUMENT ; do
+ case "${COMMAND_LINE_ARGUMENT}" in
+ s)
+ STRICT=yes
+ unset DIFF_OPTIONS
+ ;;
+ c)
+ DIFF_FLAG='-c'
+ ;;
+ r)
+ RERUN=yes
+ ;;
+ v)
+ case "${AUTO_RUN}" in
+ '') VERBOSE=yes ;;
+ esac
+ ;;
+ a)
+ AUTO_RUN=yes
+ unset VERBOSE
+ ;;
+ h)
+ display_usage
+ display_help
+ exit 0
+ ;;
+ i)
+ AUTO_INSTALL=yes
+ ;;
+ C)
+ COMP_CONFS=yes
+ ;;
+ P)
+ PRESERVE_FILES=yes
+ ;;
+ p)
+ PRE_WORLD=yes
+ unset COMP_CONFS
+ unset AUTO_RUN
+ ;;
+ m)
+ SOURCEDIR=${OPTARG}
+ ;;
+ t)
+ TEMPROOT=${OPTARG}
+ ;;
+ d)
+ TEMPROOT=${TEMPROOT}.`date +%m%d.%H.%M`
+ ;;
+ u)
+ NEW_UMASK=${OPTARG}
+ ;;
+ w)
+ SCREEN_WIDTH=${OPTARG}
+ ;;
+ D)
+ DESTDIR=${OPTARG}
+ ;;
+ *)
+ display_usage
+ exit 1
+ ;;
+ esac
+done
+
+# Don't force the user to set this in the mergemaster rc file
+if [ -n "${PRESERVE_FILES}" -a -z "${PRESERVE_FILES_DIR}" ]; then
+ PRESERVE_FILES_DIR=/var/tmp/mergemaster/preserved-files-`date +%y%m%d-%H%M%S`
+fi
+
+echo ''
+
+# If the user has a pager defined, make sure we can run it
+#
+case "${DONT_CHECK_PAGER}" in
+'')
+ while ! type "${PAGER%% *}" >/dev/null && [ -n "${PAGER}" ]; do
+ echo " *** Your PAGER environment variable specifies '${PAGER}', but"
+ echo " due to the limited PATH that I use for security reasons,"
+ echo " I cannot execute it. So, what would you like to do?"
+ echo ''
+ echo " Use 'e' to exit mergemaster and fix your PAGER variable"
+ if [ -x /usr/bin/less -o -x /usr/local/bin/less ]; then
+ echo " Use 'l' to set PAGER to 'less' for this run"
+ fi
+ echo " Use 'm' to use plain old 'more' as your PAGER for this run"
+ echo ''
+ echo " Default is to use plain old 'more' "
+ echo ''
+ echo -n "What should I do? [Use 'more'] "
+ read FIXPAGER
+
+ case "${FIXPAGER}" in
+ [eE])
+ exit 0
+ ;;
+ [lL])
+ if [ -x /usr/bin/less ]; then
+ PAGER=/usr/bin/less
+ elif [ -x /usr/local/bin/less ]; then
+ PAGER=/usr/local/bin/less
+ else
+ echo ''
+ echo " *** Fatal Error:"
+ echo " You asked to use 'less' as your pager, but I can't"
+ echo " find it in /usr/bin or /usr/local/bin"
+ exit 1
+ fi
+ ;;
+ [mM]|'')
+ PAGER=more
+ ;;
+ *)
+ echo ''
+ echo "invalid choice: ${FIXPAGER}"
+ esac
+ echo ''
+ done
+ ;;
+esac
+
+# If user has a pager defined, or got assigned one above, use it.
+# If not, use less.
+#
+PAGER=${PAGER:-less}
+PAGER="${PAGER} -c"
+
+if [ -n "${VERBOSE}" -a ! "${PAGER}" = "more" ]; then
+ echo " *** You have ${PAGER} defined as your pager so we will use that"
+ echo ''
+ sleep 3
+fi
+
+# Assign the diff flag once so we will not have to keep testing it
+#
+DIFF_FLAG=${DIFF_FLAG:--u}
+
+# Assign the source directory
+#
+SOURCEDIR=${SOURCEDIR:-/usr/src/etc}
+
+# Check the width of the user's terminal
+#
+if [ -t 0 ]; then
+ w=`tput columns`
+ case "${w}" in
+ 0|'') ;; # No-op, since the input is not valid
+ *)
+ case "${SCREEN_WIDTH}" in
+ '') SCREEN_WIDTH="${w}" ;;
+ "${w}") ;; # No-op, since they are the same
+ *)
+ echo -n "*** You entered ${SCREEN_WIDTH} as your screen width, but stty "
+ echo "thinks it is ${w}."
+ echo ''
+ echo -n "What would you like to use? [${w}] "
+ read SCREEN_WIDTH
+ case "${SCREEN_WIDTH}" in
+ '') SCREEN_WIDTH="${w}" ;;
+ esac
+ ;;
+ esac
+ esac
+fi
+
+# Define what CVS $Id tag to look for to aid portability.
+#
+CVS_ID_TAG=DragonFly
+
+delete_temproot () {
+ rm -rf "${TEMPROOT}" 2>/dev/null
+ chflags -R 0 "${TEMPROOT}" 2>/dev/null
+ rm -rf "${TEMPROOT}" || exit 1
+}
+
+case "${RERUN}" in
+'')
+ # Set up the loop to test for the existence of the
+ # temp root directory.
+ #
+ TEST_TEMP_ROOT=yes
+ while [ "${TEST_TEMP_ROOT}" = "yes" ]; do
+ if [ -d "${TEMPROOT}" ]; then
+ echo "*** The directory specified for the temporary root environment,"
+ echo " ${TEMPROOT}, exists. This can be a security risk if untrusted"
+ echo " users have access to the system."
+ echo ''
+ case "${AUTO_RUN}" in
+ '')
+ echo " Use 'd' to delete the old ${TEMPROOT} and continue"
+ echo " Use 't' to select a new temporary root directory"
+ echo " Use 'e' to exit mergemaster"
+ echo ''
+ echo " Default is to use ${TEMPROOT} as is"
+ echo ''
+ echo -n "How should I deal with this? [Use the existing ${TEMPROOT}] "
+ read DELORNOT
+
+ case "${DELORNOT}" in
+ [dD])
+ echo ''
+ echo " *** Deleting the old ${TEMPROOT}"
+ echo ''
+ delete_temproot || exit 1
+ unset TEST_TEMP_ROOT
+ ;;
+ [tT])
+ echo " *** Enter new directory name for temporary root environment"
+ read TEMPROOT
+ ;;
+ [eE])
+ exit 0
+ ;;
+ '')
+ echo ''
+ echo " *** Leaving ${TEMPROOT} intact"
+ echo ''
+ unset TEST_TEMP_ROOT
+ ;;
+ *)
+ echo ''
+ echo "invalid choice: ${DELORNOT}"
+ echo ''
+ ;;
+ esac
+ ;;
+ *)
+ # If this is an auto-run, try a hopefully safe alternative then
+ # re-test anyway.
+ TEMPROOT=/var/tmp/temproot.`date +%m%d.%H.%M.%S`
+ ;;
+ esac
+ else
+ unset TEST_TEMP_ROOT
+ fi
+ done
+
+ echo "*** Creating the temporary root environment in ${TEMPROOT}"
+
+ if mkdir -p "${TEMPROOT}"; then
+ echo " *** ${TEMPROOT} ready for use"
+ fi
+
+ if [ ! -d "${TEMPROOT}" ]; then
+ echo ''
+ echo " *** FATAL ERROR: Cannot create ${TEMPROOT}"
+ echo ''
+ exit 1
+ fi
+
+ echo " *** Creating and populating directory structure in ${TEMPROOT}"
+ echo ''
+
+ case "${VERBOSE}" in
+ '') ;;
+ *)
+ press_to_continue
+ ;;
+ esac
+
+ case "${PRE_WORLD}" in
+ '')
+ { cd ${SOURCEDIR} &&
+ case "${DESTDIR}" in
+ '') ;;
+ *)
+ make DESTDIR=${DESTDIR} distrib-dirs
+ ;;
+ esac
+ make DESTDIR=${TEMPROOT} distrib-dirs &&
+ make MAKEOBJDIRPREFIX=${TEMPROOT}/usr/obj obj &&
+ make MAKEOBJDIRPREFIX=${TEMPROOT}/usr/obj DESTDIR=${TEMPROOT} \
+ -DNO_MAKEDEV_RUN distribution;} ||
+ { echo '';
+ echo " *** FATAL ERROR: Cannot 'cd' to ${SOURCEDIR} and install files to";
+ echo " the temproot environment";
+ echo '';
+ exit 1;}
+ ;;
+ *)
+ # Only set up files that are crucial to {build|install}world
+ { mkdir -p ${TEMPROOT}/etc &&
+ cp -p ${SOURCEDIR}/master.passwd ${TEMPROOT}/etc &&
+ cp -p ${SOURCEDIR}/group ${TEMPROOT}/etc;} ||
+ { echo '';
+ echo ' *** FATAL ERROR: Cannot copy files to the temproot environment';
+ echo '';
+ exit 1;}
+ ;;
+ esac
+
+ # Doing the inventory and removing files that we don't want to compare only
+ # makes sense if we are not doing a rerun, since we have no way of knowing
+ # what happened to the files during previous incarnations.
+ case "${VERBOSE}" in
+ '') ;;
+ *)
+ echo ''
+ echo ' *** The following files exist only in the installed version of'
+ echo " ${DESTDIR}/etc. In the vast majority of cases these files"
+ echo ' are necessary parts of the system and should not be deleted.'
+ echo ' However because these files are not updated by this process you'
+ echo ' might want to verify their status before rebooting your system.'
+ echo ''
+ press_to_continue
+ diff -qr ${DESTDIR}/etc ${TEMPROOT}/etc | grep "^Only in ${DESTDIR}/etc" | ${PAGER}
+ echo ''
+ press_to_continue
+ ;;
+ esac
+
+ # Avoid comparing the motd if the user specifies it in .mergemasterrc
+ case "${IGNORE_MOTD}" in
+ '') ;;
+ *) rm -f ${TEMPROOT}/etc/motd
+ ;;
+ esac
+
+ # Avoid trying to update MAKEDEV if /dev is on a devfs
+ if /sbin/sysctl vfs.devfs > /dev/null 2>&1 ; then
+ rm -f ${TEMPROOT}/dev/MAKEDEV ${TEMPROOT}/dev/MAKEDEV.local
+ fi
+
+ ;; # End of the "RERUN" test
+esac
+
+# We really don't want to have to deal with files like login.conf.db, pwd.db,
+# or spwd.db. Instead, we want to compare the text versions, and run *_mkdb.
+# Prompt the user to do so below, as needed.
+#
+rm -f ${TEMPROOT}/etc/*.db ${TEMPROOT}/etc/passwd
+
+# We only need to compare things like freebsd.cf once
+find ${TEMPROOT}/usr/obj -type f -delete 2>/dev/null
+
+# Get ready to start comparing files
+
+# Check umask if not specified on the command line,
+# and we are not doing an autorun
+#
+if [ -z "${NEW_UMASK}" -a -z "${AUTO_RUN}" ]; then
+ USER_UMASK=`umask`
+ case "${USER_UMASK}" in
+ 0022|022) ;;
+ *)
+ echo ''
+ echo " *** Your umask is currently set to ${USER_UMASK}. By default, this script"
+ echo " installs all files with the same user, group and modes that"
+ echo " they are created with by ${SOURCEDIR}/Makefile, compared to"
+ echo " a umask of 022. This umask allows world read permission when"
+ echo " the file's default permissions have it."
+ echo ''
+ echo " No world permissions can sometimes cause problems. A umask of"
+ echo " 022 will restore the default behavior, but is not mandatory."
+ echo " /etc/master.passwd is a special case. Its file permissions"
+ echo " will be 600 (rw-------) if installed."
+ echo ''
+ echo -n "What umask should I use? [${USER_UMASK}] "
+ read NEW_UMASK
+
+ NEW_UMASK="${NEW_UMASK:-$USER_UMASK}"
+ ;;
+ esac
+ echo ''
+fi
+
+CONFIRMED_UMASK=${NEW_UMASK:-0022}
+
+#
+# Warn users who still have old rc files
+#
+for file in atm devfs diskless1 diskless2 isdn network network6 pccard \
+ serial syscons sysctl alpha x86_64 i386 ia64 sparc64; do
+ if [ -f "${DESTDIR}/etc/rc.${file}" ]; then
+ OLD_RC_PRESENT=1
+ break
+ fi
+done
+
+case "${OLD_RC_PRESENT}" in
+1)
+ echo ''
+ echo " *** There are elements of the old rc system in ${DESTDIR}/etc/."
+ echo ''
+ echo ' While these scripts will not hurt anything, they are not'
+ echo ' functional on an up to date system, and can be removed.'
+ echo ''
+
+ case "${AUTO_RUN}" in
+ '')
+ echo -n 'Move these files to /var/tmp/mergemaster/old_rc? [yes] '
+ read MOVE_OLD_RC
+
+ case "${MOVE_OLD_RC}" in
+ [nN]*) ;;
+ *)
+ mkdir -p /var/tmp/mergemaster/old_rc
+ for file in atm devfs diskless1 diskless2 isdn network network6 pccard \
+ serial syscons sysctl alpha x86_64 i386 ia64 sparc64; do
+ if [ -f "${DESTDIR}/etc/rc.${file}" ]; then
+ mv ${DESTDIR}/etc/rc.${file} /var/tmp/mergemaster/old_rc/
+ fi
+ done
+ echo ' The files have been moved'
+ press_to_continue
+ ;;
+ esac
+ ;;
+ *) ;;
+ esac
+esac
+
+# Use the umask/mode information to install the files
+# Create directories as needed
+#
+do_install_and_rm () {
+ case "${PRESERVE_FILES}" in
+ [Yy][Ee][Ss])
+ if [ -f "${3}/${2##*/}" ]; then
+ mkdir -p ${PRESERVE_FILES_DIR}/${2%/*}
+ cp ${3}/${2##*/} ${PRESERVE_FILES_DIR}/${2%/*}
+ fi
+ ;;
+ esac
+
+ install -m "${1}" "${2}" "${3}" &&
+ rm -f "${2}"
+}
+
+# 4095 = "obase=10;ibase=8;07777" | bc
+find_mode () {
+ local OCTAL
+ OCTAL=$(( ~$(echo "obase=10;ibase=8; ${CONFIRMED_UMASK}" | bc) & 4095 &
+ $(echo "obase=10; ibase=8; $(stat -f "%OMp%OLp" ${1})" | bc) ))
+ printf "%04o\n" ${OCTAL}
+}
+
+mm_install () {
+ local INSTALL_DIR
+ INSTALL_DIR=${1#.}
+ INSTALL_DIR=${INSTALL_DIR%/*}
+
+ case "${INSTALL_DIR}" in
+ '')
+ INSTALL_DIR=/
+ ;;
+ esac
+
+ if [ -n "${DESTDIR}${INSTALL_DIR}" -a ! -d "${DESTDIR}${INSTALL_DIR}" ]; then
+ DIR_MODE=`find_mode "${TEMPROOT}/${INSTALL_DIR}"`
+ install -d -o root -g wheel -m "${DIR_MODE}" "${DESTDIR}${INSTALL_DIR}"
+ fi
+
+ FILE_MODE=`find_mode "${1}"`
+
+ if [ ! -x "${1}" ]; then
+ case "${1#.}" in
+ /etc/mail/aliases)
+ NEED_NEWALIASES=yes
+ ;;
+ /etc/login.conf)
+ NEED_CAP_MKDB=yes
+ ;;
+ /etc/master.passwd)
+ do_install_and_rm 600 "${1}" "${DESTDIR}${INSTALL_DIR}"
+ NEED_PWD_MKDB=yes
+ DONT_INSTALL=yes
+ ;;
+ /.cshrc | /.profile)
+ case "${AUTO_INSTALL}" in
+ '')
+ case "${LINK_EXPLAINED}" in
+ '')
+ echo " *** Historically BSD derived systems have had a"
+ echo " hard link from /.cshrc and /.profile to"
+ echo " their namesakes in /root. Please indicate"
+ echo " your preference below for bringing your"
+ echo " installed files up to date."
+ echo ''
+ LINK_EXPLAINED=yes
+ ;;
+ esac
+
+ echo " Use 'd' to delete the temporary ${COMPFILE}"
+ echo " Use 'l' to delete the existing ${DESTDIR}${COMPFILE#.} and create the link"
+ echo ''
+ echo " Default is to leave the temporary file to deal with by hand"
+ echo ''
+ echo -n " How should I handle ${COMPFILE}? [Leave it to install later] "
+ read HANDLE_LINK
+ ;;
+ *) # Part of AUTO_INSTALL
+ HANDLE_LINK=l
+ ;;
+ esac
+
+ case "${HANDLE_LINK}" in
+ [dD]*)
+ rm "${COMPFILE}"
+ echo ''
+ echo " *** Deleting ${COMPFILE}"
+ ;;
+ [lL]*)
+ echo ''
+ rm -f "${DESTDIR}${COMPFILE#.}"
+ if ln "${DESTDIR}/root/${COMPFILE##*/}" "${DESTDIR}${COMPFILE#.}"; then
+ echo " *** Link from ${DESTDIR}${COMPFILE#.} to ${DESTDIR}/root/${COMPFILE##*/} installed successfully"
+ rm "${COMPFILE}"
+ else
+ echo " *** Error linking ${DESTDIR}${COMPFILE#.} to ${DESTDIR}/root/${COMPFILE##*/}, ${COMPFILE} will remain to install by hand"
+ fi
+ ;;
+ *)
+ echo " *** ${COMPFILE} will remain for your consideration"
+ ;;
+ esac
+ DONT_INSTALL=yes
+ ;;
+ esac
+
+ case "${DONT_INSTALL}" in
+ '')
+ do_install_and_rm "${FILE_MODE}" "${1}" "${DESTDIR}${INSTALL_DIR}"
+ ;;
+ *)
+ unset DONT_INSTALL
+ ;;
+ esac
+ else # File matched -x
+ case "${1#.}" in
+ /dev/MAKEDEV)
+ NEED_MAKEDEV=yes
+ ;;
+ esac
+ do_install_and_rm "${FILE_MODE}" "${1}" "${DESTDIR}${INSTALL_DIR}"
+ fi
+ return $?
+}
+
+echo ''
+echo "*** Beginning comparison"
+echo ''
+
+cd "${TEMPROOT}"
+
+if [ -r "${MM_PRE_COMPARE_SCRIPT}" ]; then
+ . "${MM_PRE_COMPARE_SCRIPT}"
+fi
+
+# Using -size +0 avoids uselessly checking the empty log files created
+# by ${SOURCEDIR}/Makefile and the device entries in ./dev, but does
+# check the scripts in ./dev, as we'd like (assuming no devfs of course).
+#
+for COMPFILE in `find . -type f -size +0`; do
+
+ # First, check to see if the file exists in DESTDIR. If not, the
+ # diff_loop function knows how to handle it.
+ #
+ if [ ! -e "${DESTDIR}${COMPFILE#.}" ]; then
+ case "${AUTO_RUN}" in
+ '')
+ diff_loop
+ ;;
+ *)
+ case "${AUTO_INSTALL}" in
+ '')
+ # If this is an auto run, make it official
+ echo " *** ${COMPFILE} will remain for your consideration"
+ ;;
+ *)
+ diff_loop
+ ;;
+ esac
+ ;;
+ esac # Auto run test
+ continue
+ fi
+
+ case "${STRICT}" in
+ '' | [Nn][Oo])
+ # Compare CVS $Id's first so if the file hasn't been modified
+ # local changes will be ignored.
+ # If the files have the same $Id, delete the one in temproot so the
+ # user will have less to wade through if files are left to merge by hand.
+ #
+ CVSID1=`grep "[$]${CVS_ID_TAG}:" ${DESTDIR}${COMPFILE#.} 2>/dev/null`
+ CVSID2=`grep "[$]${CVS_ID_TAG}:" ${COMPFILE} 2>/dev/null` || CVSID2=none
+
+ case "${CVSID2}" in
+ "${CVSID1}")
+ echo " *** Temp ${COMPFILE} and installed have the same CVS Id, deleting"
+ rm "${COMPFILE}"
+ ;;
+ esac
+ ;;
+ esac
+
+ # If the file is still here either because the $Ids are different, the
+ # file doesn't have an $Id, or we're using STRICT mode; look at the diff.
+ #
+ if [ -f "${COMPFILE}" ]; then
+
+ # Do an absolute diff first to see if the files are actually different.
+ # If they're not different, delete the one in temproot.
+ #
+ if diff -q ${DIFF_OPTIONS} "${DESTDIR}${COMPFILE#.}" "${COMPFILE}" > \
+ /dev/null 2>&1; then
+ echo " *** Temp ${COMPFILE} and installed are the same, deleting"
+ rm "${COMPFILE}"
+ else
+ # Ok, the files are different, so show the user where they differ.
+ # Use user's choice of diff methods; and user's pager if they have one.
+ # Use more if not.
+ # Use unified diffs by default. Context diffs give me a headache. :)
+ #
+ case "${AUTO_RUN}" in
+ '')
+ # prompt user to install/delete/merge changes
+ diff_loop
+ ;;
+ *)
+ # If this is an auto run, make it official
+ echo " *** ${COMPFILE} will remain for your consideration"
+ ;;
+ esac # Auto run test
+ fi # Yes, the files are different
+ fi # Yes, the file still remains to be checked
+done # This is for the do way up there at the beginning of the comparison
+
+echo ''
+echo "*** Comparison complete"
+echo ''
+
+TEST_FOR_FILES=`find ${TEMPROOT} -type f -size +0 2>/dev/null`
+if [ -n "${TEST_FOR_FILES}" ]; then
+ echo "*** Files that remain for you to merge by hand:"
+ find "${TEMPROOT}" -type f -size +0
+ echo ''
+fi
+
+case "${AUTO_RUN}" in
+'')
+ echo -n "Do you wish to delete what is left of ${TEMPROOT}? [no] "
+ read DEL_TEMPROOT
+
+ case "${DEL_TEMPROOT}" in
+ [yY]*)
+ if delete_temproot; then
+ echo " *** ${TEMPROOT} has been deleted"
+ else
+ echo " *** Unable to delete ${TEMPROOT}"
+ fi
+ ;;
+ *)
+ echo " *** ${TEMPROOT} will remain"
+ ;;
+ esac
+ ;;
+*) ;;
+esac
+
+case "${AUTO_INSTALLED_FILES}" in
+'') ;;
+*)
+ case "${AUTO_RUN}" in
+ '')
+ (
+ echo ''
+ echo '*** You chose the automatic install option for files that did not'
+ echo ' exist on your system. The following were installed for you:'
+ echo "${AUTO_INSTALLED_FILES}"
+ ) | ${PAGER}
+ ;;
+ *)
+ echo ''
+ echo '*** You chose the automatic install option for files that did not'
+ echo ' exist on your system. The following were installed for you:'
+ echo "${AUTO_INSTALLED_FILES}"
+ ;;
+ esac
+ ;;
+esac
+
+run_it_now () {
+ case "${AUTO_RUN}" in
+ '')
+ unset YES_OR_NO
+ echo ''
+ echo -n ' Would you like to run it now? y or n [n] '
+ read YES_OR_NO
+
+ case "${YES_OR_NO}" in
+ y)
+ echo " Running ${1}"
+ echo ''
+ eval "${1}"
+ ;;
+ ''|n)
+ echo ''
+ echo " *** Cancelled"
+ echo ''
+ echo " Make sure to run ${1} yourself"
+ ;;
+ *)
+ echo ''
+ echo " *** Sorry, I do not understand your answer (${YES_OR_NO})"
+ echo ''
+ echo " Make sure to run ${1} yourself"
+ esac
+ ;;
+ *) ;;
+ esac
+}
+
+case "${NEED_MAKEDEV}" in
+'') ;;
+*)
+ echo ''
+ echo "*** You installed a new ${DESTDIR}/dev/MAKEDEV script, so make sure that you run"
+ echo " 'cd ${DESTDIR}/dev && /bin/sh MAKEDEV all' to rebuild your devices"
+ run_it_now "cd ${DESTDIR}/dev && /bin/sh MAKEDEV all"
+ ;;
+esac
+
+case "${NEED_NEWALIASES}" in
+'') ;;
+*)
+ echo ''
+ if [ -n "${DESTDIR}" ]; then
+ echo "*** You installed a new aliases file into ${DESTDIR}/etc/mail, but"
+ echo " the newaliases command is limited to the directories configured"
+ echo " in sendmail.cf. Make sure to create your aliases database by"
+ echo " hand when your sendmail configuration is done."
+ else
+ echo "*** You installed a new aliases file, so make sure that you run"
+ echo " '/usr/bin/newaliases' to rebuild your aliases database"
+ run_it_now '/usr/bin/newaliases'
+ fi
+ ;;
+esac
+
+case "${NEED_CAP_MKDB}" in
+'') ;;
+*)
+ echo ''
+ echo "*** You installed a login.conf file, so make sure that you run"
+ echo " '/usr/bin/cap_mkdb ${DESTDIR}/etc/login.conf'"
+ echo " to rebuild your login.conf database"
+ run_it_now "/usr/bin/cap_mkdb ${DESTDIR}/etc/login.conf"
+ ;;
+esac
+
+case "${NEED_PWD_MKDB}" in
+'') ;;
+*)
+ echo ''
+ echo "*** You installed a new master.passwd file, so make sure that you run"
+ if [ -n "${DESTDIR}" ]; then
+ echo " '/usr/sbin/pwd_mkdb -d ${DESTDIR}/etc -p ${DESTDIR}/etc/master.passwd'"
+ echo " to rebuild your password files"
+ run_it_now "/usr/sbin/pwd_mkdb -d ${DESTDIR}/etc -p ${DESTDIR}/etc/master.passwd"
+ else
+ echo " '/usr/sbin/pwd_mkdb -p /etc/master.passwd'"
+ echo " to rebuild your password files"
+ run_it_now '/usr/sbin/pwd_mkdb -p /etc/master.passwd'
+ fi
+ ;;
+esac
+
+echo ''
+
+if [ -r "${MM_EXIT_SCRIPT}" ]; then
+ . "${MM_EXIT_SCRIPT}"
+fi
+
+case "${COMP_CONFS}" in
+'') ;;
+*)
+ . ${DESTDIR}/etc/defaults/rc.conf
+
+ (echo ''
+ echo "*** Comparing conf files: ${rc_conf_files}"
+
+ for CONF_FILE in ${rc_conf_files}; do
+ if [ -r "${DESTDIR}${CONF_FILE}" ]; then
+ echo ''
+ echo "*** From ${DESTDIR}${CONF_FILE}"
+ echo "*** From ${DESTDIR}/etc/defaults/rc.conf"
+
+ for RC_CONF_VAR in `grep -i ^[a-z] ${DESTDIR}${CONF_FILE} |
+ cut -d '=' -f 1`; do
+ echo ''
+ grep -w ^${RC_CONF_VAR} ${DESTDIR}${CONF_FILE}
+ grep -w ^${RC_CONF_VAR} ${DESTDIR}/etc/defaults/rc.conf ||
+ echo ' * No default variable with this name'
+ done
+ fi
+ done) | ${PAGER}
+ echo ''
+ ;;
+esac
+
+case "${PRE_WORLD}" in
+'') ;;
+*)
+ MAKE_CONF="${SOURCEDIR%etc}etc/defaults/make.conf"
+
+ (echo ''
+ echo '*** Comparing make variables'
+ echo ''
+ echo "*** From ${DESTDIR}/etc/make.conf"
+ echo "*** From ${MAKE_CONF}"
+
+ for MAKE_VAR in `grep -i ^[a-z] ${DESTDIR}/etc/make.conf | cut -d '=' -f 1`; do
+ echo ''
+ grep -w ^${MAKE_VAR} ${DESTDIR}/etc/make.conf
+ grep -w ^#${MAKE_VAR} ${MAKE_CONF} ||
+ echo ' * No example variable with this name'
+ done) | ${PAGER}
+ ;;
+esac
+
+exit 0
+