diff options
-rw-r--r-- | usr.sbin/mergemaster/mergemaster.8 | 64 | ||||
-rwxr-xr-x | usr.sbin/mergemaster/mergemaster.sh | 227 |
2 files changed, 194 insertions, 97 deletions
diff --git a/usr.sbin/mergemaster/mergemaster.8 b/usr.sbin/mergemaster/mergemaster.8 index e733c7c..65d22ae 100644 --- a/usr.sbin/mergemaster/mergemaster.8 +++ b/usr.sbin/mergemaster/mergemaster.8 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 10, 1999 +.Dd October 30, 2000 .Dt MERGEMASTER 8 .Os FreeBSD .Sh NAME @@ -32,12 +32,13 @@ .Nd Merge configuration files, et al during an upgrade .Sh SYNOPSIS .Nm -.Op Fl scrvah +.Op Fl scrvahi .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 .Nm is a Bourne shell script which is designed to aid you @@ -58,7 +59,10 @@ files. You can specify a different source directory with the .Op Fl m -command line option. +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 @@ -113,6 +117,26 @@ and file permissions as specified by the umask. Unified diffs are used by default to display any differences unless you choose context diffs. .Pp +.Nm +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. +.Pp The options are as follows: .Bl -tag -width Fl .It Fl s @@ -149,6 +173,9 @@ 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 m Ar /path/to/sources Specify the path to the directory where you want to do the .Xr make 1 . @@ -172,6 +199,8 @@ 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 @@ -190,6 +219,15 @@ limited 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 EXAMPLES Typically all you will need to do is type .Nm @@ -240,19 +278,33 @@ with all values commented out: # Verbose mode includes more details and additional checks #VERBOSE= # +# Automatically install files that do not exist on the system already +#AUTO_INSTALL= +# # Sourcedir is the directory to do the 'make' in (where the new files are) -#SOURCEDIR=/usr/src/etc +#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 +#PATH=/bin:/usr/bin:/usr/sbin:/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 SEE ALSO .Xr cvs 1 , @@ -291,7 +343,7 @@ make world tutorial which is referenced above. .Pp .Sh AUTHOR This manual page and the script itself were written by -.An Douglas Barton Aq Doug@gorean.org . +.An Douglas Barton Aq DougB@FreeBSD.org . .Sh BUGS There are no known bugs. Please report any problems, diff --git a/usr.sbin/mergemaster/mergemaster.sh b/usr.sbin/mergemaster/mergemaster.sh index 4900d12..8b38a55 100755 --- a/usr.sbin/mergemaster/mergemaster.sh +++ b/usr.sbin/mergemaster/mergemaster.sh @@ -15,7 +15,8 @@ PATH=/bin:/usr/bin:/usr/sbin:/sbin display_usage () { VERSION_NUMBER=`grep "[$]FreeBSD:" $0 | cut -d ' ' -f 4` echo "mergemaster version ${VERSION_NUMBER}" - echo "Usage: mergemaster [-scrvah] [-m /path] [-t /path] [-d] [-u N] [-w N]" + echo 'Usage: mergemaster [-scrvahi] [-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" @@ -23,26 +24,24 @@ display_usage () { 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 " -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 create a temporary root environment, compare CVS revision \$Ids" - echo " for files that have them, and compare diffs for files that do not," - echo " or have different ones, just type, mergemaster" 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" + 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 () { @@ -58,7 +57,7 @@ merge_loop () { # 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} "${COMPFILE#.}" "${COMPFILE}" + --width=${SCREEN_WIDTH:-80} "${DESTDIR}${COMPFILE#.}" "${COMPFILE}" INSTALL_MERGED=V while [ "${INSTALL_MERGED}" = "v" -o "${INSTALL_MERGED}" = "V" ]; do echo '' @@ -107,18 +106,36 @@ diff_loop () { HANDLE_COMPFILE=v while [ "${HANDLE_COMPFILE}" = "v" -o "${HANDLE_COMPFILE}" = "V" -o "${HANDLE_COMPFILE}" = "NOT V" ]; do - if [ -f "${COMPFILE#.}" -a -f "${COMPFILE}" ]; then + if [ -f "${DESTDIR}${COMPFILE#.}" -a -f "${COMPFILE}" ]; then if [ "${HANDLE_COMPFILE}" = "v" -o "${HANDLE_COMPFILE}" = "V" ]; then ( + echo '' echo " *** Displaying differences between ${COMPFILE} and installed version:" echo '' - diff "${DIFF_FLAG}" "${COMPFILE#.}" "${COMPFILE}" + diff "${DIFF_FLAG}" "${DESTDIR}${COMPFILE#.}" "${COMPFILE}" ) | ${PAGER} echo '' fi else + echo '' echo " *** There is no installed version of ${COMPFILE}" - NO_INSTALLED=yes + case "${AUTO_INSTALL}" in + [Yy][Ee][Ss]) + echo '' + if mm_install "${COMPFILE}"; then + echo " *** ${COMPFILE} installed successfully" + # 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}" @@ -179,7 +196,6 @@ diff_loop () { ;; esac # End of "How to handle files that are different" done - echo '' unset NO_INSTALLED echo '' case "${VERBOSE}" in @@ -196,13 +212,13 @@ TEMPROOT='/var/tmp/temproot' # Read .mergemasterrc before command line so CLI can override # -if [ -f "$HOME/.mergemasterrc" ]; then +if [ -r "$HOME/.mergemasterrc" ]; then . "$HOME/.mergemasterrc" fi # Check the command line options # -while getopts ":ascrvhm:t:du:w:" COMMAND_LINE_ARGUMENT ; do +while getopts ":ascrvhim:t:du:w:D:" COMMAND_LINE_ARGUMENT ; do case "${COMMAND_LINE_ARGUMENT}" in s) STRICT=yes @@ -227,6 +243,9 @@ while getopts ":ascrvhm:t:du:w:" COMMAND_LINE_ARGUMENT ; do display_help exit 0 ;; + i) + AUTO_INSTALL=yes + ;; m) SOURCEDIR=${OPTARG} ;; @@ -242,6 +261,9 @@ while getopts ":ascrvhm:t:du:w:" COMMAND_LINE_ARGUMENT ; do w) SCREEN_WIDTH=${OPTARG} ;; + D) + DESTDIR=${OPTARG} + ;; *) display_usage exit 1 @@ -406,6 +428,7 @@ case "${RERUN}" in esac { cd ${SOURCEDIR} && + make DESTDIR=${DESTDIR} distrib-dirs && make DESTDIR=${TEMPROOT} distrib-dirs && make DESTDIR=${TEMPROOT} -DNO_MAKEDEV distribution;} || { echo ''; @@ -414,11 +437,33 @@ case "${RERUN}" in echo ''; exit 1;} + # 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 '' + echo ' *** Press [Enter] or [Return] key to continue' + read ANY_KEY + unset ANY_KEY + diff -qr ${DESTDIR}/etc ${TEMPROOT}/etc | grep "^Only in /etc" | ${PAGER} + echo '' + echo ' *** Press [Enter] or [Return] key to continue' + read ANY_KEY + unset ANY_KEY + ;; + esac + # We really don't want to have to deal with these files, since # master.passwd is the real file that should be compared, then # the user should run pwd_mkdb if necessary. - # Only do this if we are not rerun'ing, since if we are the - # files will not be there. # rm ${TEMPROOT}/etc/spwd.db ${TEMPROOT}/etc/passwd ${TEMPROOT}/etc/pwd.db @@ -439,27 +484,6 @@ esac # Get ready to start comparing files -case "${VERBOSE}" in -'') ;; -*) - echo '' - echo " *** The following files exist only in the installed version" - echo " of /etc. In the far majority of cases these files are" - echo " necessary parts of the system and should not be deleted," - echo " however because these files are not updated by this process" - echo " you might want to verify their status before rebooting your system." - echo '' - echo " *** Press [Enter] or [Return] key to continue" - read ANY_KEY - unset ANY_KEY - diff -qr /etc ${TEMPROOT}/etc | grep "^Only in /etc" | ${PAGER} - echo '' - echo " *** Press [Enter] or [Return] key to continue" - read ANY_KEY - unset ANY_KEY - ;; -esac - # Check umask if not specified on the command line, # and we are not doing an autorun # @@ -490,15 +514,18 @@ fi CONFIRMED_UMASK=${NEW_UMASK:-0022} -# Warn users who have an /etc/sysconfig file +# Warn users who still have ${DESTDIR}/etc/sysconfig # -if [ -f /etc/sysconfig ]; then - echo " *** There is an /etc/sysconfig file on this system. Starting with" - echo " FreeBSD version 2.2.2 those settings have moved from /etc/sysconfig" - echo " to /etc/rc.conf. If you are upgrading an older system make sure" - echo " that you transfer your settings by hand from sysconfig to rc.conf and" - echo " install the rc.conf file. If you have already made this transition," - echo " you should consider renaming or deleting the /etc/sysconfig file." +if [ -e "${DESTDIR}/etc/sysconfig" ]; then + echo '' + echo " *** There is a sysconfig file on this system in ${DESTDIR}/etc/." + echo '' + echo ' Starting with FreeBSD version 2.2.2 those settings moved from' + echo ' /etc/sysconfig to /etc/rc.conf. If you are upgrading an older' + echo ' system make sure that you transfer your settings by hand from' + echo ' sysconfig to rc.conf and install the rc.conf file. If you' + echo ' have already made this transition, you should consider' + echo ' renaming or deleting the sysconfig file.' echo '' case "${AUTO_RUN}" in '') @@ -519,12 +546,6 @@ if [ -f /etc/sysconfig ]; then esac fi -echo '' -echo "*** Beginning comparison" -echo '' - -cd "${TEMPROOT}" - # Use the umask/mode information to install the files # Create directories as needed # @@ -532,24 +553,22 @@ mm_install () { local INSTALL_DIR INSTALL_DIR=${1#.} INSTALL_DIR=${INSTALL_DIR%/*} + case "${INSTALL_DIR}" in '') INSTALL_DIR=/ ;; esac - if [ -n "${INSTALL_DIR}" -a ! -d "${INSTALL_DIR}" ]; then + if [ -n "${DESTDIR}${INSTALL_DIR}" -a ! -d "${DESTDIR}${INSTALL_DIR}" ]; then DIR_MODE=`perl -e 'printf "%04o\n", (((stat("$ARGV[0]"))[2] & 07777) &~ oct("$ARGV[1]"))' "${TEMPROOT}/${INSTALL_DIR}" "${CONFIRMED_UMASK}"` - install -d -o root -g wheel -m "${DIR_MODE}" "${INSTALL_DIR}" + install -d -o root -g wheel -m "${DIR_MODE}" "${DESTDIR}${INSTALL_DIR}" fi FILE_MODE=`perl -e 'printf "%04o\n", (((stat("$ARGV[0]"))[2] & 07777) &~ oct("$ARGV[1]"))' "${1}" "${CONFIRMED_UMASK}"` if [ ! -x "${1}" ]; then case "${1#.}" in - /dev/MAKEDEV) - NEED_MAKEDEV=yes - ;; /etc/mail/aliases) NEED_NEWALIASES=yes ;; @@ -557,7 +576,7 @@ mm_install () { NEED_CAP_MKDB=yes ;; /etc/master.passwd) - install -m 600 "${1}" "${INSTALL_DIR}" + install -m 600 "${1}" "${DESTDIR}${INSTALL_DIR}" NEED_PWD_MKDB=yes DONT_INSTALL=yes ;; @@ -575,7 +594,7 @@ mm_install () { esac echo " Use 'd' to delete the temporary ${COMPFILE}" - echo " Use 'l' to delete the existing ${COMPFILE#.} and create the link" + 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 '' @@ -590,14 +609,12 @@ mm_install () { ;; [lL]*) echo '' - if [ -e "${COMPFILE#.}" ]; then - rm "${COMPFILE#.}" - fi - if ln "/root/${COMPFILE##*/}" "${COMPFILE#.}"; then - echo " *** Link from ${COMPFILE#.} to /root/${COMPFILE##*/} installed successfully" + 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 ${COMPFILE#.} to /root/${COMPFILE##*/}, ${COMPFILE} will remain to install by hand" + echo " *** Error linking ${DESTDIR}${COMPFILE#.} to ${DESTDIR}/root/${COMPFILE##*/}, ${COMPFILE} will remain to install by hand" fi ;; *) @@ -610,56 +627,68 @@ mm_install () { case "${DONT_INSTALL}" in '') - install -m "${FILE_MODE}" "${1}" "${INSTALL_DIR}" + install -m "${FILE_MODE}" "${1}" "${DESTDIR}${INSTALL_DIR}" ;; *) unset DONT_INSTALL ;; esac - else - install -m "${FILE_MODE}" "${1}" "${INSTALL_DIR}" + case "${1#.}" in + /dev/MAKEDEV) + NEED_MAKEDEV=yes + ;; + esac + install -m "${FILE_MODE}" "${1}" "${DESTDIR}${INSTALL_DIR}" fi return $? } -compare_ids () { - case "${1}" in - "${2}") - echo " *** Temp ${COMPFILE} and installed have the same ${IDTAG}, deleting" - rm "${COMPFILE}" - ;; - esac -} +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. +# 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 + diff_loop + 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. - # Take the $Id -> $FreeBSD tag change into account # - FREEBSDID1=`grep "[$]FreeBSD:" ${COMPFILE#.} 2>/dev/null` - FREEBSDID2=`grep "[$]FreeBSD:" ${COMPFILE} 2>/dev/null` - - if [ -n "${FREEBSDID1}" -a -n "${FREEBSDID2}" ]; then - IDTAG='$FreeBSD' - compare_ids "${FREEBSDID1}" "${FREEBSDID2}" - else - CVSID1=`grep "[$]Id:" ${COMPFILE#.} 2>/dev/null` - CVSID2=`grep "[$]Id:" ${COMPFILE} 2>/dev/null` + # Reduce complexity and improve portability by using ident + # + CVSID1=`ident ${DESTDIR}${COMPFILE#.} 2>&1` + CVSID1="${CVSID1#${DESTDIR}}" + CVSID2=`ident ${COMPFILE} 2>&1` - if [ -n "${CVSID1}" -a -n "${CVSID2}" ]; then - IDTAG='$Id' - compare_ids "${CVSID1}" "${CVSID2}" - fi - fi + case "${CVSID2}" in + *'no id keywords'*) + ;; + ."${CVSID1}") + echo " *** Temp ${COMPFILE} and installed have the same CVS Id, deleting" + rm "${COMPFILE}" + ;; + esac ;; esac @@ -671,7 +700,7 @@ for COMPFILE in `find . -type f -size +0`; do # 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 "${COMPFILE#.}" "${COMPFILE}" > /dev/null 2>&1; then + if diff -q "${DESTDIR}${COMPFILE#.}" "${COMPFILE}" > /dev/null 2>&1; then echo " *** Temp ${COMPFILE} and installed are the same, deleting" rm "${COMPFILE}" else @@ -761,7 +790,23 @@ case "${NEED_PWD_MKDB}" in ;; esac +case "${AUTO_INSTALLED_FILES}" in +'') ;; +*) + ( + echo '' + echo '*** You chose the automatic install option for files that did not exist' + echo ' on your system. The following files were installed for you:' + echo "${AUTO_INSTALLED_FILES}" + ) | ${PAGER} + ;; +esac + echo '' +if [ -r "${MM_EXIT_SCRIPT}" ]; then + . "${MM_EXIT_SCRIPT}" +fi + exit 0 |