Date: Tue, 12 Nov 2013 19:44:19 +0000 (UTC) From: John Baldwin <jhb@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r258066 - in head: tools/regression/usr.sbin/etcupdate usr.sbin/etcupdate Message-ID: <201311121944.rACJiJnS079510@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: jhb Date: Tue Nov 12 19:44:18 2013 New Revision: 258066 URL: http://svnweb.freebsd.org/changeset/base/258066 Log: Add a pre-world mode of updating similar to the -p option that can be passed to mergemaster. In this mode, only changes to /etc/master.passwd and /etc/group are merged to /etc. In addition, it uses a temporary tree to stage these changes rather than overwriting the existing 'current' and 'previous' trees so that a full update can be run after a normal installworld has completed. MFC after: 2 weeks Added: head/tools/regression/usr.sbin/etcupdate/preworld.sh (contents, props changed) Modified: head/usr.sbin/etcupdate/etcupdate.8 head/usr.sbin/etcupdate/etcupdate.sh Added: head/tools/regression/usr.sbin/etcupdate/preworld.sh ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/tools/regression/usr.sbin/etcupdate/preworld.sh Tue Nov 12 19:44:18 2013 (r258066) @@ -0,0 +1,238 @@ +#!/bin/sh +# +# Copyright (c) 2013 Advanced Computing Technologies LLC +# Written by: John H. Baldwin <jhb@FreeBSD.org> +# 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$ + +# Regression tests for the pre-world (-p) mode + +WORKDIR=work + +usage() +{ + echo "Usage: preworld.sh [-s script] [-w workdir]" + exit 1 +} + +# Allow the user to specify an alternate work directory or script. +COMMAND=etcupdate +while getopts "s:w:" option; do + case $option in + s) + COMMAND="sh $OPTARG" + ;; + w) + WORKDIR=$OPTARG + ;; + *) + echo + usage + ;; + esac +done +shift $((OPTIND - 1)) +if [ $# -ne 0 ]; then + usage +fi + +CONFLICTS=$WORKDIR/conflicts +SRC=$WORKDIR/src +OLD=$WORKDIR/current +TEST=$WORKDIR/test + +build_trees() +{ + + # Populate trees with pre-world files and an additional file + # that should not be touched. + + rm -rf $SRC $OLD $TEST $CONFLICTS + + # Create the "old" source tree as the starting point + mkdir -p $OLD/etc + cat >> $OLD/etc/master.passwd <<EOF +# +root::0:0::0:0:Charlie &:/root:/bin/csh +toor:*:0:0::0:0:Bourne-again Superuser:/root: +daemon:*:1:1::0:0:Owner of many system processes:/root:/usr/sbin/nologin +operator:*:2:5::0:0:System &:/:/usr/sbin/nologin +_dhcp:*:65:65::0:0:dhcp programs:/var/empty:/usr/sbin/nologin +uucp:*:66:66::0:0:UUCP pseudo-user:/var/spool/uucppublic:/usr/local/libexec/uucp/uucico +pop:*:68:6::0:0:Post Office Owner:/nonexistent:/usr/sbin/nologin +www:*:80:80::0:0:World Wide Web Owner:/nonexistent:/usr/sbin/nologin +hast:*:845:845::0:0:HAST unprivileged user:/var/empty:/usr/sbin/nologin +nobody:*:65534:65534::0:0:Unprivileged user:/nonexistent:/usr/sbin/nologin +EOF + cat >> $OLD/etc/group <<EOF +# +wheel:*:0:root +daemon:*:1: +kmem:*:2: +sys:*:3: +tty:*:4: +operator:*:5:root +_dhcp:*:65: +uucp:*:66: +dialer:*:68: +network:*:69: +www:*:80: +hast:*:845: +nogroup:*:65533: +nobody:*:65534: +EOF + cat >> $OLD/etc/inetd.conf <<EOF +# Yet another file +EOF + + # Copy the "old" source tree to the test tree and make local + # modifications. + cp -R $OLD $TEST + sed -I "" -e 's/root::/root:<rpass>:/' $TEST/etc/master.passwd + cat >> $TEST/etc/master.passwd <<EOF +john:<password>:1001:1001::0:0:John Baldwin:/home/john:/bin/tcsh +messagebus:*:556:556::0:0:D-BUS Daemon User:/nonexistent:/usr/sbin/nologin +polkit:*:562:562::0:0:PolicyKit User:/nonexistent:/usr/sbin/nologin +haldaemon:*:560:560::0:0:HAL Daemon User:/nonexistent:/usr/sbin/nologin +EOF + awk '/wheel/ { printf "%s,john\n", $0; next } // { print }' \ + $OLD/etc/group > $TEST/etc/group + cat >> $TEST/etc/group <<EOF +john:*:1001: +messagebus:*:556: +polkit:*:562: +haldaemon:*:560: +EOF + rm $TEST/etc/inetd.conf + + # Copy the "old" source tree to the new source tree and + # make upstream modifications. + cp -R $OLD $SRC + sed -I "" -e '/:80:/i\ +auditdistd:*:78:77::0:0:Auditdistd unprivileged user:/var/empty:/usr/sbin/nologin' \ + $SRC/etc/master.passwd + sed -I "" -e '/:80:/i\ +audit:*:77:' \ + $SRC/etc/group + cat >> $SRC/etc/inetd.conf <<EOF +# Making this larger +EOF +} + +# $1 - relative path to file that should be missing from TEST +missing() +{ + if [ -e $TEST/$1 -o -L $TEST/$1 ]; then + echo "File $1 should be missing" + fi +} + +# $1 - relative path to file that should be present in TEST +present() +{ + if ! [ -e $TEST/$1 -o -L $TEST/$1 ]; then + echo "File $1 should be present" + fi +} + +# $1 - relative path to regular file that should be present in TEST +# $2 - optional string that should match file contents +# $3 - optional MD5 of the flie contents, overrides $2 if present +file() +{ + local contents sum + + if ! [ -f $TEST/$1 ]; then + echo "File $1 should be a regular file" + elif [ $# -eq 2 ]; then + contents=`cat $TEST/$1` + if [ "$contents" != "$2" ]; then + echo "File $1 has wrong contents" + fi + elif [ $# -eq 3 ]; then + sum=`md5 -q $TEST/$1` + if [ "$sum" != "$3" ]; then + echo "File $1 has wrong contents" + fi + fi +} + +# $1 - relative path to a regular file that should have a conflict +# $2 - optional MD5 of the conflict file contents +conflict() +{ + local sum + + if ! [ -f $CONFLICTS/$1 ]; then + echo "File $1 missing conflict" + elif [ $# -gt 1 ]; then + sum=`md5 -q $CONFLICTS/$1` + if [ "$sum" != "$2" ]; then + echo "Conflict $1 has wrong contents" + fi + fi +} + +check_trees() +{ + + echo "Checking tree for correct results:" + + file /etc/master.passwd "" 1385366e8b424d33d59b7d8a2bdb15d3 + file /etc/group "" 21273f845f6ec0cda9188c4ddac9ed47 + missing /etc/inetd.conf + + # These should be auto-generated by pwd_mkdb + file /etc/passwd "" 9831537874bdc99adccaa2b0293248a1 + file /etc/pwd.db + file /etc/spwd.db +} + +if [ `id -u` -ne 0 ]; then + echo "must be root" +fi + +if [ -r /etc/etcupdate.conf ]; then + echo "WARNING: /etc/etcupdate.conf settings may break some tests." +fi + +build_trees + +$COMMAND -np -s $SRC -d $WORKDIR -D $TEST > $WORKDIR/testn.out + +cat > $WORKDIR/correct.out <<EOF + M /etc/group + M /etc/master.passwd +EOF + +echo "Differences for -n:" +diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/testn.out + +$COMMAND -p -s $SRC -d $WORKDIR -D $TEST > $WORKDIR/test.out + +echo "Differences for real:" +diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out + +check_trees Modified: head/usr.sbin/etcupdate/etcupdate.8 ============================================================================== --- head/usr.sbin/etcupdate/etcupdate.8 Tue Nov 12 19:39:14 2013 (r258065) +++ head/usr.sbin/etcupdate/etcupdate.8 Tue Nov 12 19:44:18 2013 (r258066) @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 16, 2012 +.Dd November 12, 2013 .Dt ETCUPDATE 8 .Os .Sh NAME @@ -33,7 +33,7 @@ .Nd "manage updates to system files not updated by installworld" .Sh SYNOPSIS .Nm -.Op Fl nBF +.Op Fl npBF .Op Fl d Ar workdir .Op Fl r | Fl s Ar source | Fl t Ar tarball .Op Fl A Ar patterns @@ -64,6 +64,7 @@ .Op Fl M Ar options .Nm .Cm resolve +.Op Fl p .Op Fl d Ar workdir .Op Fl D Ar destdir .Op Fl L Ar logfile @@ -481,6 +482,33 @@ option is not specified, then a temporary .Dq current tree will be extracted to perform the comparison. +.It Fl p +Enable +.Dq pre-world +mode. +Only merge changes to files that are necessary to successfully run +.Sq make installworld +or +.Sq make installkernel . +When this flag is enabled, +the existing +.Dq current +and +.Dq previous +trees are left alone. +Instead, +a temporary tree is populated with the necessary files. +This temporary tree is compared against the +.Dq current +tree. +This allows a normal update to be run after +.Sq make installworld +has completed. +Any conflicts generated during a +.Dq pre-world +update should be resolved by a +.Dq pre-world +.Cm resolve . .It Fl r Do not update the .Dq current Modified: head/usr.sbin/etcupdate/etcupdate.sh ============================================================================== --- head/usr.sbin/etcupdate/etcupdate.sh Tue Nov 12 19:39:14 2013 (r258065) +++ head/usr.sbin/etcupdate/etcupdate.sh Tue Nov 12 19:44:18 2013 (r258066) @@ -61,14 +61,15 @@ usage() { cat <<EOF -usage: etcupdate [-nBF] [-d workdir] [-r | -s source | -t tarball] [-A patterns] - [-D destdir] [-I patterns] [-L logfile] [-M options] +usage: etcupdate [-npBF] [-d workdir] [-r | -s source | -t tarball] + [-A patterns] [-D destdir] [-I patterns] [-L logfile] + [-M options] etcupdate build [-B] [-d workdir] [-s source] [-L logfile] [-M options] <tarball> etcupdate diff [-d workdir] [-D destdir] [-I patterns] [-L logfile] etcupdate extract [-B] [-d workdir] [-s source | -t tarball] [-L logfile] [-M options] - etcupdate resolve [-d workdir] [-D destdir] [-L logfile] + etcupdate resolve [-p] [-d workdir] [-D destdir] [-L logfile] etcupdate status [-d workdir] [-D destdir] EOF exit 1 @@ -181,22 +182,31 @@ always_install() # $1 - directory to store new tree in build_tree() { - local make + local destdir dir file make make="make $MAKE_OPTIONS" log "Building tree at $1 with $make" mkdir -p $1/usr/obj >&3 2>&1 - (cd $SRCDIR; $make DESTDIR=$1 distrib-dirs) >&3 2>&1 || return 1 + destdir=`realpath $1` - if ! [ -n "$nobuild" ]; then - (cd $SRCDIR; \ - MAKEOBJDIRPREFIX=$1/usr/obj $make _obj SUBDIR_OVERRIDE=etc && - MAKEOBJDIRPREFIX=$1/usr/obj $make everything SUBDIR_OVERRIDE=etc && - MAKEOBJDIRPREFIX=$1/usr/obj $make DESTDIR=$1 distribution) \ + if [ -n "$preworld" ]; then + # Build a limited tree that only contains files that are + # crucial to installworld. + for file in $PREWORLD_FILES; do + dir=`dirname /$file` + mkdir -p $1/$dir >&3 2>&1 || return 1 + cp -p $SRCDIR/$file $1/$file || return 1 + done + elif ! [ -n "$nobuild" ]; then + (cd $SRCDIR; $make DESTDIR=$destdir distrib-dirs && + MAKEOBJDIRPREFIX=$destdir/usr/obj $make _obj SUBDIR_OVERRIDE=etc && + MAKEOBJDIRPREFIX=$destdir/usr/obj $make everything SUBDIR_OVERRIDE=etc && + MAKEOBJDIRPREFIX=$destdir/usr/obj $make DESTDIR=$destdir distribution) \ >&3 2>&1 || return 1 else - (cd $SRCDIR; $make DESTDIR=$1 distribution) >&3 2>&1 || return 1 + (cd $SRCDIR; $make DESTDIR=$destdir distrib-dirs && + $make DESTDIR=$destdir distribution) >&3 2>&1 || return 1 fi chflags -R noschg $1 >&3 2>&1 || return 1 rm -rf $1/usr/obj >&3 2>&1 || return 1 @@ -218,9 +228,15 @@ build_tree() # source tree. extract_tree() { + local files + # If we have a tarball, extract that into the new directory. if [ -n "$tarball" ]; then - if ! (mkdir -p $NEWTREE && tar xf $tarball -C $NEWTREE) \ + files= + if [ -n "$preworld" ]; then + files="$PREWORLD_FILES" + fi + if ! (mkdir -p $NEWTREE && tar xf $tarball -C $NEWTREE $files) \ >&3 2>&1; then echo "Failed to extract new tree." remove_tree $NEWTREE @@ -1298,6 +1314,11 @@ resolve_cmd() return fi + if ! [ -d $NEWTREE ]; then + echo "The current tree is not present to resolve conflicts." + exit 1 + fi + conflicts=`(cd $CONFLICTS; find . ! -type d) | sed -e 's/^\.//'` for file in $conflicts; do resolve_conflict $file @@ -1343,7 +1364,7 @@ update_cmd() usage fi - log "update command: rerun=$rerun tarball=$tarball" + log "update command: rerun=$rerun tarball=$tarball preworld=$preworld" if [ `id -u` -ne 0 ]; then echo "Must be root to update a tree." @@ -1376,9 +1397,22 @@ update_cmd() echo "Unable to create temporary directory." exit 1 fi - OLDTREE=$NEWTREE + + # A pre-world dryrun has already set OLDTREE to + # point to the current stock tree. + if [ -z "$preworld" ]; then + OLDTREE=$NEWTREE + fi NEWTREE=$dir + # For a pre-world update, blow away any pre-existing + # NEWTREE. + elif [ -n "$preworld" ]; then + if ! remove_tree $NEWTREE; then + echo "Unable to remove pre-world tree." + exit 1 + fi + # Rotate the existing stock tree to the old tree. elif [ -d $NEWTREE ]; then # First, delete the previous old tree if it exists. @@ -1421,6 +1455,12 @@ EOF # Initialize conflicts and warnings handling. rm -f $WARNINGS mkdir -p $CONFLICTS + + # Ignore removed files for the pre-world case. A pre-world + # update uses a stripped-down tree. + if [ -n "$preworld" ]; then + > $WORKDIR/removed.files + fi # The order for the following sections is important. In the # odd case that a directory is converted into a file, the @@ -1535,7 +1575,8 @@ always= dryrun= ignore= nobuild= -while getopts "d:nrs:t:A:BD:FI:L:M:" option; do +preworld= +while getopts "d:nprs:t:A:BD:FI:L:M:" option; do case "$option" in d) WORKDIR=$OPTARG @@ -1543,6 +1584,9 @@ while getopts "d:nrs:t:A:BD:FI:L:M:" opt n) dryrun=YES ;; + p) + preworld=YES + ;; r) rerun=YES ;; @@ -1633,6 +1677,9 @@ WARNINGS=$WORKDIR/warnings # Use $EDITOR for resolving conflicts. If it is not set, default to vi. EDITOR=${EDITOR:-/usr/bin/vi} +# Files that need to be updated before installworld. +PREWORLD_FILES="etc/master.passwd etc/group" + # Handle command-specific argument processing such as complaining # about unsupported options. Since the configuration file is always # included, do not complain about extra command line arguments that @@ -1644,19 +1691,39 @@ case $command in echo usage fi + if [ -n "$rerun" -a -n "$preworld" ]; then + echo "Only one of -p or -r can be specified." + echo + usage + fi + ;; + build|diff|status) + if [ -n "$dryrun" -o -n "$rerun" -o -n "$tarball" -o + -n "$preworld" ]; then + usage + fi ;; - build|diff|resolve|status) + resolve) if [ -n "$dryrun" -o -n "$rerun" -o -n "$tarball" ]; then usage fi ;; extract) - if [ -n "$dryrun" -o -n "$rerun" ]; then + if [ -n "$dryrun" -o -n "$rerun" -o -n "$preworld" ]; then usage fi ;; esac +# Pre-world mode uses a different set of trees. It leaves the current +# tree as-is so it is still present for a full etcupdate run after the +# world install is complete. Instead, it installs a few critical files +# into a separate tree. +if [ -n "$preworld" ]; then + OLDTREE=$NEWTREE + NEWTREE=$WORKDIR/preworld +fi + # Open the log file. Don't truncate it if doing a minor operation so # that a minor operation doesn't lose log info from a major operation. if ! mkdir -p $WORKDIR 2>/dev/null; then
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201311121944.rACJiJnS079510>