tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Two improvements to etcupdate(8)



Should this go to tech-install?

I wrote two improvements (or so I think) to etcupdate(8) for which I attach
two separate patches. I must admit I did't test them too hard yet.

1. I never used automatic (-a) mode because I never used it before.
The problem is that unless you used -a last time, you lack the reference 
checksums in /var/etcupdate.
So I added a ``bootstrap'' mode (-A) that only builds the checksums from its 
-s arguments and doesn't do anything else.
The idea is that you first etcupdate -A -s /path/to/old/etc.tgz and then 
etcupdate -a -s /path/to/new/etc.tgz afterwards.

2. I regularily update a whole set of machines. I usually did this by 
running etcupdate on a development machine, noted the per-file decisions 
I made (on paper) and then used that list to know what to type to further 
etcupdate invocations on the production machines.
I think computers are better at recording and playback than humans, so I added 
two switches, -W and -R, that record the (hand-made) keep/overwrite/merge 
decisions to a file resp. use that file to follow the same decisions again.
The file doesn't record the details of a merge operations, only the fact,
but manually re-merging three files is an improvement over typing d/i/m 
for a hundred files. Or so I think.

Comments/suggestions/improvements (and better names than ``bootstrap'', 
``read'' and ``write'') welcome.
--- etcupdate	2016-01-27 11:26:42.000000000 +0100
+++ etcupdate-A	2016-01-27 16:12:36.000000000 +0100
@@ -63,6 +63,7 @@
 SRC_ARGLIST=		# quoted list of one or more "-s" args
 N_SRC_ARGS=0		# number of "-s" args
 AUTOMATIC=false
+BOOT_AUTOMATIC=false
 LOCALSKIP=false
 MACHINE="${MACHINE:="$(uname -m)"}"
 export MACHINE
@@ -96,6 +97,8 @@
   -t temproot  Where to store temporary files  (default: /tmp/temproot)
   -w width     Screen width                    (default: 80)
   -a           Automatically update unmodified files
+  -A           Bootstrap automatic mode: Initialize reference checksums
+               from -s arguments
   -l           Automatically skip files with strictly local changes
                (this option has no effect on files lacking RCS Ids)
   -h           This help text
@@ -412,12 +415,15 @@
 [ -r ${USERRC} ] && . ${USERRC}
 
 # Read command line arguments
-while getopts ahlp:s:t:vw: i
+while getopts aAhlp:s:t:vw: i
 do
 	case "${i}" in
 	a)
 		AUTOMATIC=true
 		;;
+	A)
+		BOOT_AUTOMATIC=true
+		;;
 	h)
 		usage
 		;;
@@ -520,6 +526,13 @@
 	exit 1
 fi
 if [ -r "${TEMPROOT}" ]; then
+	if ${BOOT_AUTOMATIC}; then
+		echo ""
+		echo "*** ERROR: ${TEMPROOT} already exists"
+		echo ""
+		exit 1
+	else
+	#>indent
 	echo ""
 	echo "*** WARNING: ${TEMPROOT} already exists"
 	echo ""
@@ -529,6 +542,8 @@
 		echo "*** Removing ${TEMPROOT}"
 		rm -rf "${TEMPROOT}"
 	fi
+	#<indent
+	fi
 fi
 
 if ! ${CONTINUE}; then
@@ -599,6 +614,19 @@
 		done
 	fi
 
+	if ${BOOT_AUTOMATIC}; then
+		echo "*** Initializing checksums"
+		find "${TEMPROOT}" -type f  -a ! -name \*.etcupdate.\* | \
+		while read i; do
+			D="${i#"${TEMPROOT}"}"
+			AUTOMATIC=true install_checksum "${D}"
+		done
+		echo "*** Removing ${TEMPROOT}"
+		rm -rf "${TEMPROOT}"
+		echo "*** Done"
+		exit 0
+	fi
+
 	# Are there any new directories?
 	echo "*** Checking for new directories"
 	exec 3<&0
--- etcupdate.8	2016-01-27 11:51:48.000000000 +0100
+++ etcupdate-A.8	2016-01-27 15:56:55.000000000 +0100
@@ -36,7 +36,7 @@
 .Pa /etc
 .Sh SYNOPSIS
 .Nm
-.Op Fl ahlv
+.Op Fl aAhlv
 .Op Fl p Ar pager
 .Op Fl s Brq Ar srcdir | Ar tgzdir | Ar tgzfile
 .Op Fl t Ar temproot
@@ -136,6 +136,23 @@
 .Pa /var/etcupdate
 and use these checksums to determine if there have been any
 local modifications.
+.It Fl A
+``bootstrap'' automatic
+.Pf ( Fl a )
+mode by initializing the checksums in
+.Pa /var/etcupdate
+from the reference files instead of updating anything.
+Use this if you never ran in
+.Fl a
+mode before or lost your
+.Pa /var/etcupdate
+directory. 
+Note that unless you just ran a normal
+.Nm
+before, in this mode, the
+.Fl s
+arguments must refer to the ``old'' configuration files, i.e.\&
+those the currently installed ones are based on.
 .It Fl h
 Prints a help text.
 .It Fl l
--- etcupdate	2016-01-27 11:26:42.000000000 +0100
+++ etcupdate-RW	2016-01-27 19:17:57.000000000 +0100
@@ -68,6 +68,11 @@
 export MACHINE
 MACHINE_ARCH="${MACHINE_ARCH:="$(uname -p)"}"
 export MACHINE_ARCH
+OUTFILE=		# file name argument to -W
+INFILE=			# file name argument to -R
+KEEP_FILES=" "		# files to keep (Don't install)
+OVERWRITE_FILES=" "	# files to overwrite (Install)
+MERGE_FILES=" "		# files to merge
 
 # Settings for post-installation procedures
 NEED_MAKEDEV=false
@@ -98,6 +103,8 @@
   -a           Automatically update unmodified files
   -l           Automatically skip files with strictly local changes
                (this option has no effect on files lacking RCS Ids)
+  -W file      Write per-file decisions taken to file
+  -R file      Read per-file decisions to be taken from file
   -h           This help text
   -v           Be more verbose
 
@@ -225,6 +232,12 @@
   scommand Show differences using the specified diff-like command"
 }
 
+record_action() {
+	# $1 = action, $2 = target file
+	test -n "${OUTFILE}" || return
+	printf "%c %s\n" "$1" "$2" >>${OUTFILE}
+}
+
 diff_and_merge_file() {
 	# $1 = target file
 
@@ -257,6 +270,28 @@
 		fi
 	fi
 
+	AUTOANSWER=""
+	case ${KEEP_FILES} in
+		*\ ${1}\ *) 
+			verbose "===> ${1} (KEEP)"
+			AUTOANSWER="d"
+			;;
+	esac
+	case ${OVERWRITE_FILES} in
+		*\ ${1}\ *) 
+			verbose "===> ${1} (OVERWRITE)"
+			AUTOANSWER="i"
+			;;
+	esac
+	case ${MERGE_FILES} in
+		*\ ${1}\ *) 
+			verbose "===> ${1} (MERGE)"
+			AUTOANSWER="m"
+			;;
+	esac
+
+	if [ -z "${AUTOANSWER}" ]; then
+	#>indent
 	clear
 	if [ ! -f "${1}" ]; then
 		verbose "===> ${1} (missing)"
@@ -267,6 +302,8 @@
 		DOES_EXIST=true
 		diff -u "${1}" "${TEMPROOT}${1}" | ${PAGER}
 	fi
+	#<indent
+	fi
 
 	STAY_HERE=true
 	ALREADY_MERGED=false
@@ -279,6 +316,10 @@
 
 	while ${STAY_HERE}; do
 
+		if [ -n "${AUTOANSWER}" ]; then
+			ANSWER="${AUTOANSWER}"
+		else
+		#>indent
 		# Ask the user if (s)he wants to install the new
 		# version or perform a more complicated manual work.
 		echo ""
@@ -323,17 +364,23 @@
 		fi
 		echo -n "What do you want to do? [Leave it for later] "
 		read ANSWER
+		#<indent
+		fi
 		case "${ANSWER}" in
 
 		[dD])
 			verbose "Removing ${TEMPROOT}${1}"
 			rm -f "${TEMPROOT}${1}"
+			record_action "d" "${1}"
 			STAY_HERE=false
 			;;
 		[iI])
 			install_file "${1}"
 			if ! ${ALREADY_MERGED}; then
+				record_action "i" "${1}"
 				install_checksum "${1}"
+			else
+				record_action "m" "${1}"
 			fi
 			STAY_HERE=false
 			;;
@@ -412,7 +459,7 @@
 [ -r ${USERRC} ] && . ${USERRC}
 
 # Read command line arguments
-while getopts ahlp:s:t:vw: i
+while getopts ahlp:s:t:vw:R:W: i
 do
 	case "${i}" in
 	a)
@@ -482,6 +529,12 @@
 	w)
 		WIDTH="${OPTARG}"
 		;;
+	R)
+		INFILE="${OPTARG}"
+		;;
+	W)
+		OUTFILE="${OPTARG}"
+		;;
 	*)
 		# getopts should already have printed an error message
 		usage
@@ -610,6 +663,22 @@
 	done
 fi
 
+if [ -n "${OUTFILE}" ]; then
+	echo "# $0 $(date)" >${OUTFILE}
+fi
+
+if [ -n "${INFILE}" ]; then
+	while read cmd file comment; do
+		case ${cmd} in
+			\#) ;;
+			d) KEEP_FILES="${KEEP_FILES}${file} " ;;
+			i) OVERWRITE_FILES="${OVERWRITE_FILES}${file} " ;;
+			m) MERGE_FILES="${MERGE_FILES}${file} " ;;
+			*) echo "*** ERROR: unknown command $cmd in ${INFILE}"; exit 1 ;;
+		esac
+	done <${INFILE}
+fi
+
 # Start the comparision
 echo "*** Checking for added/modified files"
 init_diff_extra_options
--- etcupdate.8	2016-01-27 11:51:48.000000000 +0100
+++ etcupdate-RW.8	2016-01-27 18:44:49.000000000 +0100
@@ -41,6 +41,8 @@
 .Op Fl s Brq Ar srcdir | Ar tgzdir | Ar tgzfile
 .Op Fl t Ar temproot
 .Op Fl w Ar width
+.Op Fl W Ar file
+.Op Fl R Ar file
 .Sh DESCRIPTION
 .Nm
 is a tool that lets the administrator update the configuration and
@@ -258,6 +260,36 @@
 This is useful for
 .Xr xterm 1
 users with wider shell windows.
+.It Fl W Ar file
+Write the per-file decisions taken to 
+.Pa file
+in a format suitable to be read by the
+.Fl R
+option.
+This can be used to record the decisions taken on a fully interactive run of
+.Nm
+and re-use that information on a subsequent invocation of
+.Nm
+on another machine.
+Note that in case of a merge,
+.Pa file
+only records the fact that a merge was performed, not the details of the merge
+operation.
+.It Fl R Ar file
+Read the per-file decisions to be taken drom
+.Pa file .
+The contents of
+.Pa file
+is typically the output from a
+.Nm Fl W Ar file
+run on another machine, but may also be crafted manually.
+The format is one line per file, starting with a single character
+#/d/i/m for comment, keep (``Don't install''), overwrite (``Install'') or merge,
+whitspace, file name and optionally a per-file comment starting with whitespace.
+Note that in case of a merge,
+.Pa file
+only gives the information that a file has to be merged,
+the merge itself has still be to performed interactively.
 .El
 .Sh ENVIRONMENT
 .Bl -tag -width IGNOREFILESXX


Home | Main Index | Thread Index | Old Index