summaryrefslogtreecommitdiffstats
path: root/usr.sbin
diff options
context:
space:
mode:
authorjmmv <jmmv@FreeBSD.org>2014-03-16 04:09:22 +0000
committerjmmv <jmmv@FreeBSD.org>2014-03-16 04:09:22 +0000
commitb2e51e38a88412c17ce1160c247a6d673c0b2147 (patch)
tree22c8956efd4de8b6e41a15566111321ba8fdfde0 /usr.sbin
parenta8cf290e9bcfb637ddde7dcc7345006c194c7ec8 (diff)
downloadFreeBSD-src-b2e51e38a88412c17ce1160c247a6d673c0b2147.zip
FreeBSD-src-b2e51e38a88412c17ce1160c247a6d673c0b2147.tar.gz
Migrate tools/regression/{usr.bin/lastcomm,usr.sbin}/ to the new tests layout.
This change was originally going to only migrate the usr.sbin tests but, as it turns out, the usr.sbin/sa/ tests require files from usr.bin/lastcomm/ so it's better to just also migrate the latter at the same time. The other usr.bin tests will be moved separately. To make these tests work within the test suite, some of them have required changes to prevent modifying the source directory and instead just rely on the current directory for file manipulation.
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/Makefile4
-rw-r--r--usr.sbin/etcupdate/Makefile6
-rw-r--r--usr.sbin/etcupdate/tests/Makefile17
-rw-r--r--usr.sbin/etcupdate/tests/always_test.sh630
-rw-r--r--usr.sbin/etcupdate/tests/conflicts_test.sh294
-rw-r--r--usr.sbin/etcupdate/tests/fbsdid_test.sh394
-rw-r--r--usr.sbin/etcupdate/tests/ignore_test.sh276
-rw-r--r--usr.sbin/etcupdate/tests/preworld_test.sh252
-rw-r--r--usr.sbin/etcupdate/tests/tests_test.sh1021
-rw-r--r--usr.sbin/etcupdate/tests/tzsetup_test.sh239
-rw-r--r--usr.sbin/newsyslog/Makefile6
-rw-r--r--usr.sbin/newsyslog/tests/Makefile7
-rw-r--r--usr.sbin/newsyslog/tests/legacy_test.sh444
-rw-r--r--usr.sbin/sa/Makefile6
-rw-r--r--usr.sbin/sa/tests/Makefile33
-rw-r--r--usr.sbin/sa/tests/legacy_test.sh78
-rwxr-xr-xusr.sbin/sa/tests/prime.sh37
-rw-r--r--usr.sbin/sa/tests/v1-amd64-sav.inbin0 -> 8192 bytes
-rw-r--r--usr.sbin/sa/tests/v1-amd64-sav.out5
-rw-r--r--usr.sbin/sa/tests/v1-amd64-u.out28
-rw-r--r--usr.sbin/sa/tests/v1-amd64-usr.inbin0 -> 8192 bytes
-rw-r--r--usr.sbin/sa/tests/v1-amd64-usr.out1
-rw-r--r--usr.sbin/sa/tests/v1-i386-sav.inbin0 -> 8192 bytes
-rw-r--r--usr.sbin/sa/tests/v1-i386-sav.out5
-rw-r--r--usr.sbin/sa/tests/v1-i386-u.out28
-rw-r--r--usr.sbin/sa/tests/v1-i386-usr.inbin0 -> 8192 bytes
-rw-r--r--usr.sbin/sa/tests/v1-i386-usr.out1
-rw-r--r--usr.sbin/sa/tests/v1-sparc64-sav.inbin0 -> 16384 bytes
-rw-r--r--usr.sbin/sa/tests/v1-sparc64-sav.out5
-rw-r--r--usr.sbin/sa/tests/v1-sparc64-u.out28
-rw-r--r--usr.sbin/sa/tests/v1-sparc64-usr.inbin0 -> 16384 bytes
-rw-r--r--usr.sbin/sa/tests/v1-sparc64-usr.out1
-rw-r--r--usr.sbin/sa/tests/v2-amd64-sav.inbin0 -> 8192 bytes
-rw-r--r--usr.sbin/sa/tests/v2-amd64-u.out28
-rw-r--r--usr.sbin/sa/tests/v2-amd64-usr.inbin0 -> 8192 bytes
-rw-r--r--usr.sbin/sa/tests/v2-i386-sav.inbin0 -> 8192 bytes
-rw-r--r--usr.sbin/sa/tests/v2-i386-u.out28
-rw-r--r--usr.sbin/sa/tests/v2-i386-usr.inbin0 -> 8192 bytes
-rw-r--r--usr.sbin/sa/tests/v2-sparc64-sav.inbin0 -> 16384 bytes
-rw-r--r--usr.sbin/sa/tests/v2-sparc64-u.out36
-rw-r--r--usr.sbin/sa/tests/v2-sparc64-usr.inbin0 -> 16384 bytes
-rw-r--r--usr.sbin/tests/Makefile10
42 files changed, 3948 insertions, 0 deletions
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile
index 61d91b9..b709be5 100644
--- a/usr.sbin/Makefile
+++ b/usr.sbin/Makefile
@@ -284,6 +284,10 @@ SUBDIR+= praliases
SUBDIR+= sendmail
.endif
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
.if ${MK_TOOLCHAIN} != "no"
SUBDIR+= config
SUBDIR+= crunch
diff --git a/usr.sbin/etcupdate/Makefile b/usr.sbin/etcupdate/Makefile
index 9f6d17e..765533a 100644
--- a/usr.sbin/etcupdate/Makefile
+++ b/usr.sbin/etcupdate/Makefile
@@ -1,6 +1,12 @@
# $FreeBSD$
+.include <bsd.own.mk>
+
SCRIPTS=etcupdate.sh
MAN= etcupdate.8
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
.include <bsd.prog.mk>
diff --git a/usr.sbin/etcupdate/tests/Makefile b/usr.sbin/etcupdate/tests/Makefile
new file mode 100644
index 0000000..da83397
--- /dev/null
+++ b/usr.sbin/etcupdate/tests/Makefile
@@ -0,0 +1,17 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/usr.sbin/etcupdate
+
+PLAIN_TESTS_SH=
+.for test in always_test \
+ conflicts_test \
+ fbsdid_test \
+ ignore_test \
+ preworld_test \
+ tests_test \
+ tzsetup_test
+PLAIN_TESTS_SH+= ${test}
+TEST_METADATA.${test}+= required_user="root"
+.endfor
+
+.include <bsd.test.mk>
diff --git a/usr.sbin/etcupdate/tests/always_test.sh b/usr.sbin/etcupdate/tests/always_test.sh
new file mode 100644
index 0000000..514481e
--- /dev/null
+++ b/usr.sbin/etcupdate/tests/always_test.sh
@@ -0,0 +1,630 @@
+#!/bin/sh
+#
+# Copyright (c) 2010 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$
+
+# Various regression tests to test the -A flag to the 'update' command.
+
+FAILED=no
+WORKDIR=work
+
+usage()
+{
+ echo "Usage: always.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
+OLD=$WORKDIR/old
+NEW=$WORKDIR/current
+TEST=$WORKDIR/test
+
+# The various states of the comparison of a file between two trees.
+states="equal first second difftype difflinks difffiles"
+
+# These tests deal with ignoring certain patterns of files. We run
+# the test multiple times forcing the install of different patterns.
+build_trees()
+{
+ local i
+
+ rm -rf $OLD $NEW $TEST $CONFLICTS
+
+ for i in $states; do
+ for j in $states; do
+ for k in $states; do
+ mkdir -p $OLD/$i/$j/$k $NEW/$i/$j/$k \
+ $TEST/$i/$j/$k
+ done
+ done
+ done
+
+ # What follows are the various warning/conflict cases from the
+ # larger regression tests. These results of many of these
+ # tests should be changed when installation is forced. The
+ # cases when these updates should still fail even when forced
+ # are: 1) it should not force the removal of a modified file
+ # and 2) it should not remove a subdirectory that contains a
+ # modified or added file.
+
+ # /first/difftype/second: File with different local type
+ # removed. Should generate a warning.
+ mkfifo $OLD/first/difftype/second/fifo
+ mkdir $TEST/first/difftype/second/fifo
+
+ # /first/difflinks/second: Modified link removed. Should
+ # generate a warning.
+ ln -s "old link" $OLD/first/difflinks/second/link
+ ln -s "test link" $TEST/first/difflinks/second/link
+
+ # /first/difffiles/second: Modified file removed. Should
+ # generate a warning.
+ echo "foo" > $OLD/first/difffiles/second/file
+ echo "bar" > $TEST/first/difffiles/second/file
+
+ # /second/second/difftype: Newly added file conflicts with
+ # existing file in test tree of a different type. Should
+ # generate a warning.
+ mkdir $NEW/second/second/difftype/dir
+ mkfifo $TEST/second/second/difftype/dir
+
+ # /second/second/difflinks: Newly added link conflicts with
+ # existing link in test tree. Should generate a warning.
+ ln -s "new link" $NEW/second/second/difflinks/link
+ ln -s "test link" $TEST/second/second/difflinks/link
+
+ # /second/second/difffiles: Newly added file conflicts with
+ # existing file in test tree. Should generate a warning.
+ echo "new" > $NEW/second/second/difffiles/file
+ echo "test" > $TEST/second/second/difffiles/file
+
+ # /difftype/first/first: A removed file has changed type.
+ # This should generate a warning.
+ mkfifo $OLD/difftype/first/first/fifo
+ mkdir $NEW/difftype/first/first/fifo
+
+ # /difftype/difftype/difftype: All three files (old, new, and
+ # test) are different types from each other. This should
+ # generate a warning.
+ mkfifo $OLD/difftype/difftype/difftype/one
+ mkdir $NEW/difftype/difftype/difftype/one
+ echo "foo" > $TEST/difftype/difftype/difftype/one
+ mkdir $OLD/difftype/difftype/difftype/two
+ echo "baz" > $NEW/difftype/difftype/difftype/two
+ ln -s "bar" $TEST/difftype/difftype/difftype/two
+
+ # /difftype/difftype/difflinks: A file has changed from a
+ # non-link to a link in both the new and test trees, but the
+ # target of the new and test links differ. This should
+ # generate a new link conflict.
+ mkfifo $OLD/difftype/difftype/difflinks/link
+ ln -s "new" $NEW/difftype/difftype/difflinks/link
+ ln -s "test" $TEST/difftype/difftype/difflinks/link
+
+ # /difftype/difftype/difffile: A file has changed from a
+ # non-regular file to a regular file in both the new and test
+ # trees, but the contents in the new and test files differ.
+ # This should generate a new file conflict.
+ ln -s "old" $OLD/difftype/difftype/difffiles/file
+ echo "foo" > $NEW/difftype/difftype/difffiles/file
+ echo "bar" > $TEST/difftype/difftype/difffiles/file
+
+ # /difflinks/first/first: A modified link is missing in the
+ # test tree. This should generate a warning.
+ ln -s "old" $OLD/difflinks/first/first/link
+ ln -s "new" $NEW/difflinks/first/first/link
+
+ # /difflinks/difftype/difftype: An updated link has been
+ # changed to a different file type in the test tree. This
+ # should generate a warning.
+ ln -s "old" $OLD/difflinks/difftype/difftype/link
+ ln -s "new" $NEW/difflinks/difftype/difftype/link
+ echo "test" > $TEST/difflinks/difftype/difftype/link
+
+ # /difflinks/difflinks/difflinks: An updated link has been
+ # modified in the test tree and doesn't match either the old
+ # or new links. This should generate a warning.
+ ln -s "old" $OLD/difflinks/difflinks/difflinks/link
+ ln -s "new" $NEW/difflinks/difflinks/difflinks/link
+ ln -s "test" $TEST/difflinks/difflinks/difflinks/link
+
+ # /difffiles/first/first: A removed file has been changed in
+ # the new tree. This should generate a warning.
+ echo "foo" > $OLD/difffiles/first/first/file
+ echo "bar" > $NEW/difffiles/first/first/file
+
+ # /difffiles/difftype/difftype: An updated regular file has
+ # been changed to a different file type in the test tree.
+ # This should generate a warning.
+ echo "old" > $OLD/difffiles/difftype/difftype/file
+ echo "new" > $NEW/difffiles/difftype/difftype/file
+ mkfifo $TEST/difffiles/difftype/difftype/file
+
+ # /difffiles/difffiles/difffiles: A modified regular file was
+ # updated in the new tree. The changes should be merged into
+ # to the new file if possible. If the merge fails, a conflict
+ # should be generated. For this test we just include the
+ # conflict case.
+ cat > $OLD/difffiles/difffiles/difffiles/conflict <<EOF
+this is an old file
+EOF
+ cat > $NEW/difffiles/difffiles/difffiles/conflict <<EOF
+this is a new file
+EOF
+ cat > $TEST/difffiles/difffiles/difffiles/conflict <<EOF
+this is a test file
+EOF
+
+ ## Tests for adding directories
+ mkdir -p $OLD/adddir $NEW/adddir $TEST/adddir
+
+ # /adddir/conflict: Add a new file in a directory that already
+ # exists as a file. This should generate two warnings.
+ mkdir $NEW/adddir/conflict
+ touch $NEW/adddir/conflict/newfile
+ touch $TEST/adddir/conflict
+
+ ## Tests for removing directories
+ mkdir -p $OLD/rmdir $NEW/rmdir $TEST/rmdir
+
+ # /rmdir/extra: Do not remove a directory with an extra local file.
+ # This should generate a warning.
+ for i in $OLD $TEST; do
+ mkdir $i/rmdir/extra
+ done
+ echo "foo" > $TEST/rmdir/extra/localfile.txt
+
+ # /rmdir/conflict: Do not remove a directory with a conflicted
+ # remove file. This should generate a warning.
+ for i in $OLD $TEST; do
+ mkdir $i/rmdir/conflict
+ done
+ mkfifo $OLD/rmdir/conflict/difftype
+ mkdir $TEST/rmdir/conflict/difftype
+
+ ## Tests for converting files to directories and vice versa
+ for i in $OLD $NEW $TEST; do
+ for j in already old fromdir todir; do
+ mkdir -p $i/dirchange/$j
+ done
+ done
+
+ # /dirchange/fromdir/extradir: Convert a directory tree to a
+ # file. The test tree includes an extra file in the directory
+ # that is not present in the old tree. This should generate a
+ # warning.
+ for i in $OLD $TEST; do
+ mkdir $i/dirchange/fromdir/extradir
+ echo "foo" > $i/dirchange/fromdir/extradir/file
+ done
+ mkfifo $TEST/dirchange/fromdir/extradir/fifo
+ ln -s "bar" $NEW/dirchange/fromdir/extradir
+
+ # /dirchange/fromdir/conflict: Convert a directory tree to a
+ # file. The test tree includes a local change that generates
+ # a warning and prevents the removal of the directory.
+ for i in $OLD $TEST; do
+ mkdir $i/dirchange/fromdir/conflict
+ done
+ echo "foo" > $OLD/dirchange/fromdir/conflict/somefile
+ echo "bar" > $TEST/dirchange/fromdir/conflict/somefile
+ mkfifo $NEW/dirchange/fromdir/conflict
+
+ # /dirchange/todir/difffile: Convert a file to a directory
+ # tree. The test tree has a locally modified version of the
+ # file so that the conversion fails with a warning.
+ echo "foo" > $OLD/dirchange/todir/difffile
+ mkdir $NEW/dirchange/todir/difffile
+ echo "baz" > $NEW/dirchange/todir/difffile/file
+ echo "bar" > $TEST/dirchange/todir/difffile
+
+ # /dirchange/todir/difftype: Similar to the previous test, but
+ # the conflict is due to a change in the file type.
+ echo "foo" > $OLD/dirchange/todir/difftype
+ mkdir $NEW/dirchange/todir/difftype
+ echo "baz" > $NEW/dirchange/todir/difftype/file
+ mkfifo $TEST/dirchange/todir/difftype
+}
+
+# $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"
+ FAILED=yes
+ 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"
+ FAILED=yes
+ fi
+}
+
+# $1 - relative path to file that should be a fifo in TEST
+fifo()
+{
+ if ! [ -p $TEST/$1 ]; then
+ echo "File $1 should be a FIFO"
+ FAILED=yes
+ fi
+}
+
+# $1 - relative path to file that should be a directory in TEST
+dir()
+{
+ if ! [ -d $TEST/$1 ]; then
+ echo "File $1 should be a directory"
+ FAILED=yes
+ fi
+}
+
+# $1 - relative path to file that should be a symlink in TEST
+# $2 - optional value of the link
+link()
+{
+ local val
+
+ if ! [ -L $TEST/$1 ]; then
+ echo "File $1 should be a link"
+ FAILED=yes
+ elif [ $# -gt 1 ]; then
+ val=`readlink $TEST/$1`
+ if [ "$val" != "$2" ]; then
+ echo "Link $1 should link to \"$2\""
+ FAILED=yes
+ fi
+ 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"
+ FAILED=yes
+ elif [ $# -eq 2 ]; then
+ contents=`cat $TEST/$1`
+ if [ "$contents" != "$2" ]; then
+ echo "File $1 has wrong contents"
+ FAILED=yes
+ fi
+ elif [ $# -eq 3 ]; then
+ sum=`md5 -q $TEST/$1`
+ if [ "$sum" != "$3" ]; then
+ echo "File $1 has wrong contents"
+ FAILED=yes
+ 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"
+ FAILED=yes
+ elif [ $# -gt 1 ]; then
+ sum=`md5 -q $CONFLICTS/$1`
+ if [ "$sum" != "$2" ]; then
+ echo "Conflict $1 has wrong contents"
+ FAILED=yes
+ fi
+ fi
+}
+
+# $1 - relative path to a regular file that should not have a conflict
+noconflict()
+{
+ if [ -f $CONFLICTS/$1 ]; then
+ echo "File $1 should not have a conflict"
+ FAILED=yes
+ fi
+}
+
+if [ `id -u` -ne 0 ]; then
+ echo "must be root"
+ exit 0
+fi
+
+if [ -r /etc/etcupdate.conf ]; then
+ echo "WARNING: /etc/etcupdate.conf settings may break some tests."
+fi
+
+# First run the test ignoring no patterns.
+
+build_trees
+
+$COMMAND -r -d $WORKDIR -D $TEST > $WORKDIR/test.out
+
+cat > $WORKDIR/correct.out <<EOF
+ D /dirchange/fromdir/extradir/file
+ C /difffiles/difffiles/difffiles/conflict
+ C /difftype/difftype/difffiles/file
+ C /second/second/difffiles/file
+Warnings:
+ Modified regular file remains: /dirchange/fromdir/conflict/somefile
+ Modified regular file remains: /first/difffiles/second/file
+ Modified symbolic link remains: /first/difflinks/second/link
+ Modified directory remains: /first/difftype/second/fifo
+ Modified directory remains: /rmdir/conflict/difftype
+ Non-empty directory remains: /rmdir/extra
+ Non-empty directory remains: /rmdir/conflict
+ Modified mismatch: /difffiles/difftype/difftype/file (regular file vs fifo file)
+ Removed file changed: /difffiles/first/first/file
+ Modified link changed: /difflinks/difflinks/difflinks/link ("old" became "new")
+ Modified mismatch: /difflinks/difftype/difftype/link (symbolic link vs regular file)
+ Removed link changed: /difflinks/first/first/link ("old" became "new")
+ New link conflict: /difftype/difftype/difflinks/link ("new" vs "test")
+ Modified regular file changed: /difftype/difftype/difftype/one (fifo file became directory)
+ Modified symbolic link changed: /difftype/difftype/difftype/two (directory became regular file)
+ Remove mismatch: /difftype/first/first/fifo (fifo file became directory)
+ Modified directory changed: /dirchange/fromdir/conflict (directory became fifo file)
+ Modified directory changed: /dirchange/fromdir/extradir (directory became symbolic link)
+ Modified regular file changed: /dirchange/todir/difffile (regular file became directory)
+ Modified fifo file changed: /dirchange/todir/difftype (regular file became directory)
+ New file mismatch: /adddir/conflict (directory vs regular file)
+ Directory mismatch: $TEST/adddir/conflict (regular file)
+ Directory mismatch: $TEST/dirchange/todir/difffile (regular file)
+ Directory mismatch: $TEST/dirchange/todir/difftype (fifo file)
+ New link conflict: /second/second/difflinks/link ("new link" vs "test link")
+ New file mismatch: /second/second/difftype/dir (directory vs fifo file)
+EOF
+
+echo "Differences for regular:"
+diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out \
+ || FAILED=yes
+
+## /first/difftype/second:
+present /first/difftype/second/fifo
+
+## /first/difflinks/second:
+link /first/difflinks/second/link "test link"
+
+## /first/difffiles/second:
+file /first/difffiles/second/file "bar"
+
+## /second/second/difftype:
+fifo /second/second/difftype/dir
+
+## /second/second/difflinks:
+link /second/second/difflinks/link "test link"
+
+## /second/second/difffiles:
+file /second/second/difffiles/file "test"
+conflict /second/second/difffiles/file 4f2ee8620a251fd53f06bb6112eb6ffa
+
+## /difftype/first/first:
+missing /difftype/first/first/fifo
+
+## /difftype/difftype/difftype:
+file /difftype/difftype/difftype/one "foo"
+link /difftype/difftype/difftype/two "bar"
+
+## /difftype/difftype/difflinks:
+link /difftype/difftype/difflinks/link "test"
+
+## /difftype/difftype/difffile:
+conflict /difftype/difftype/difffiles/file 117f2bcd1f6491f6044e79e5a57a9229
+
+## /difflinks/first/first:
+missing /difflinks/first/first/link
+
+## /difflinks/difftype/difftype:
+file /difflinks/difftype/difftype/link "test"
+
+## /difflinks/difflinks/difflinks:
+link /difflinks/difflinks/difflinks/link "test"
+
+## /difffiles/first/first:
+missing /difffiles/first/first/file
+
+## /difffiles/difftype/difftype:
+fifo /difffiles/difftype/difftype/file
+
+## /difffiles/difffiles/difffiles:
+file /difffiles/difffiles/difffiles/conflict "this is a test file"
+conflict /difffiles/difffiles/difffiles/conflict \
+ 8261cfdd89280c4a6c26e4ac86541fe9
+
+## /adddir/conflict:
+file /adddir/conflict
+
+## /rmdir/extra:
+dir /rmdir/extra
+file /rmdir/extra/localfile.txt "foo"
+
+## /rmdir/conflict:
+dir /rmdir/conflict/difftype
+present /rmdir/conflict
+
+## /dirchange/fromdir/extradir:
+missing /dirchange/fromdir/extradir/file
+fifo /dirchange/fromdir/extradir/fifo
+
+## /dirchange/fromdir/conflict:
+file /dirchange/fromdir/conflict/somefile "bar"
+
+## /dirchange/todir/difffile:
+file /dirchange/todir/difffile "bar"
+
+## /dirchange/todir/difftype:
+fifo /dirchange/todir/difftype
+
+# Now test with -A '/first*' -A '/second* /*di*'. This should remove
+# most of the warnings and conflicts.
+
+build_trees
+
+$COMMAND -r -A '/first*' -A '/second* /*di*' -d $WORKDIR -D $TEST > \
+ $WORKDIR/test1.out
+
+cat > $WORKDIR/correct1.out <<EOF
+ D /dirchange/fromdir/extradir/file
+ U /difffiles/difffiles/difffiles/conflict
+ U /difffiles/difftype/difftype/file
+ A /difffiles/first/first/file
+ U /difflinks/difflinks/difflinks/link
+ U /difflinks/difftype/difftype/link
+ A /difflinks/first/first/link
+ U /difftype/difftype/difffiles/file
+ U /difftype/difftype/difflinks/link
+ D /difftype/difftype/difftype/one
+ U /difftype/difftype/difftype/two
+ U /dirchange/todir/difffile
+ U /dirchange/todir/difftype
+ U /adddir/conflict
+ A /adddir/conflict/newfile
+ A /dirchange/todir/difffile/file
+ A /dirchange/todir/difftype/file
+ U /second/second/difffiles/file
+ U /second/second/difflinks/link
+ D /second/second/difftype/dir
+Warnings:
+ Modified regular file remains: /dirchange/fromdir/conflict/somefile
+ Modified regular file remains: /first/difffiles/second/file
+ Modified symbolic link remains: /first/difflinks/second/link
+ Modified directory remains: /first/difftype/second/fifo
+ Modified directory remains: /rmdir/conflict/difftype
+ Non-empty directory remains: /rmdir/extra
+ Non-empty directory remains: /rmdir/conflict
+ Modified directory changed: /dirchange/fromdir/conflict (directory became fifo file)
+ Modified directory changed: /dirchange/fromdir/extradir (directory became symbolic link)
+EOF
+
+echo "Differences for -A '/first*' -A '/second* /*di*':"
+diff -u -L "correct" $WORKDIR/correct1.out -L "test" $WORKDIR/test1.out \
+ || FAILED=yes
+
+## /first/difftype/second:
+present /first/difftype/second/fifo
+
+## /first/difflinks/second:
+link /first/difflinks/second/link "test link"
+
+## /first/difffiles/second:
+file /first/difffiles/second/file "bar"
+
+## /second/second/difftype:
+missing /second/second/difftype/dir
+
+## /second/second/difflinks:
+link /second/second/difflinks/link "new link"
+
+## /second/second/difffiles:
+file /second/second/difffiles/file "new"
+noconflict /second/second/difffiles/file
+
+## /difftype/first/first:
+missing /difftype/first/first/fifo
+
+## /difftype/difftype/difftype:
+missing /difftype/difftype/difftype/one
+file /difftype/difftype/difftype/two "baz"
+
+## /difftype/difftype/difflinks:
+link /difftype/difftype/difflinks/link "new"
+
+## /difftype/difftype/difffile:
+noconflict /difftype/difftype/difffiles/file
+file /difftype/difftype/difffiles/file "foo"
+
+## /difflinks/first/first:
+link /difflinks/first/first/link "new"
+
+## /difflinks/difftype/difftype:
+link /difflinks/difftype/difftype/link "new"
+
+## /difflinks/difflinks/difflinks:
+link /difflinks/difflinks/difflinks/link "new"
+
+## /difffiles/first/first:
+file /difffiles/first/first/file "bar"
+
+## /difffiles/difftype/difftype:
+file /difffiles/difftype/difftype/file "new"
+
+## /difffiles/difffiles/difffiles:
+noconflict /difffiles/difffiles/difffiles/conflict
+file /difffiles/difffiles/difffiles/conflict "this is a new file"
+
+## /adddir/conflict:
+file /adddir/conflict/newfile
+
+## /rmdir/extra:
+dir /rmdir/extra
+file /rmdir/extra/localfile.txt "foo"
+
+## /rmdir/conflict:
+dir /rmdir/conflict/difftype
+present /rmdir/conflict
+
+## /dirchange/fromdir/extradir:
+missing /dirchange/fromdir/extradir/file
+fifo /dirchange/fromdir/extradir/fifo
+
+## /dirchange/fromdir/conflict:
+file /dirchange/fromdir/conflict/somefile "bar"
+
+## /dirchange/todir/difffile:
+file /dirchange/todir/difffile/file "baz"
+
+## /dirchange/todir/difftype:
+file /dirchange/todir/difftype/file "baz"
+
+[ "${FAILED}" = no ]
diff --git a/usr.sbin/etcupdate/tests/conflicts_test.sh b/usr.sbin/etcupdate/tests/conflicts_test.sh
new file mode 100644
index 0000000..816c180
--- /dev/null
+++ b/usr.sbin/etcupdate/tests/conflicts_test.sh
@@ -0,0 +1,294 @@
+#!/bin/sh
+#
+# Copyright (c) 2010 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$
+
+# Various regression tests to run for the 'resolve' command.
+
+FAILED=no
+WORKDIR=work
+
+usage()
+{
+ echo "Usage: conflicts.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
+OLD=$WORKDIR/old
+NEW=$WORKDIR/current
+TEST=$WORKDIR/test
+
+# These tests deal with conflicts to a single file. For each test, we
+# generate a conflict in /etc/login.conf. Each resolve option is tested
+# to ensure it DTRT.
+build_login_conflict()
+{
+
+ rm -rf $OLD $NEW $TEST $CONFLICTS
+ mkdir -p $OLD/etc $NEW/etc $TEST/etc
+
+ # Generate a conflict in /etc/login.conf.
+ cat > $OLD/etc/login.conf <<EOF
+default:\\
+ :passwd_format=md5:
+EOF
+ cat > $NEW/etc/login.conf <<EOF
+default:\\
+ :passwd_format=md5:\\
+ :copyright=/etc/COPYRIGHT
+EOF
+ cat > $TEST/etc/login.conf <<EOF
+default:\\
+ :passwd_format=md5:\\
+ :welcome=/etc/motd:
+EOF
+
+ $COMMAND -r -d $WORKDIR -D $TEST >/dev/null
+}
+
+# This is used to verify special handling for /etc/mail/aliases and
+# the newaliases warning.
+build_aliases_conflict()
+{
+
+ rm -rf $OLD $NEW $TEST $CONFLICTS
+ mkdir -p $OLD/etc/mail $NEW/etc/mail $TEST/etc/mail
+
+ # Generate a conflict in /etc/mail/aliases
+ cat > $OLD/etc/mail/aliases <<EOF
+# root: me@my.domain
+
+# Basic system aliases -- these MUST be present
+MAILER-DAEMON: postmaster
+postmaster: root
+EOF
+ cat > $NEW/etc/mail/aliases <<EOF
+# root: me@my.domain
+
+# Basic system aliases -- these MUST be present
+MAILER-DAEMON: postmaster
+postmaster: root
+
+# General redirections for pseudo accounts
+_dhcp: root
+_pflogd: root
+EOF
+ cat > $TEST/etc/mail/aliases <<EOF
+root: someone@example.com
+
+# Basic system aliases -- these MUST be present
+MAILER-DAEMON: postmaster
+postmaster: foo
+EOF
+
+ $COMMAND -r -d $WORKDIR -D $TEST >/dev/null
+}
+
+# $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"
+ FAILED=yes
+ 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"
+ FAILED=yes
+ 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"
+ FAILED=yes
+ elif [ $# -eq 2 ]; then
+ contents=`cat $TEST/$1`
+ if [ "$contents" != "$2" ]; then
+ echo "File $1 has wrong contents"
+ FAILED=yes
+ fi
+ elif [ $# -eq 3 ]; then
+ sum=`md5 -q $TEST/$1`
+ if [ "$sum" != "$3" ]; then
+ echo "File $1 has wrong contents"
+ FAILED=yes
+ 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"
+ FAILED=yes
+ elif [ $# -gt 1 ]; then
+ sum=`md5 -q $CONFLICTS/$1`
+ if [ "$sum" != "$2" ]; then
+ echo "Conflict $1 has wrong contents"
+ FAILED=yes
+ fi
+ fi
+}
+
+# $1 - relative path to a regular file that should no longer have a conflict
+resolved()
+{
+ if [ -f $CONFLICTS/$1 ]; then
+ echo "Conflict $1 should be resolved"
+ FAILED=yes
+ fi
+}
+
+if [ `id -u` -ne 0 ]; then
+ echo "must be root"
+ exit 0
+fi
+
+if [ -r /etc/etcupdate.conf ]; then
+ echo "WARNING: /etc/etcupdate.conf settings may break some tests."
+fi
+
+# Test each of the following resolve options: 'p', 'mf', 'tf', 'r'.
+
+build_login_conflict
+
+# Verify that 'p' doesn't do anything.
+echo "Checking 'p':"
+echo 'p' | $COMMAND resolve -d $WORKDIR -D $TEST >/dev/null
+
+file /etc/login.conf "" 95de92ea3f1bb1bf4f612a8b5908cddd
+missing /etc/login.conf.db
+conflict /etc/login.conf
+
+# Verify that 'mf' removes the conflict, but does nothing else.
+echo "Checking 'mf':"
+echo 'mf' | $COMMAND resolve -d $WORKDIR -D $TEST >/dev/null
+
+file /etc/login.conf "" 95de92ea3f1bb1bf4f612a8b5908cddd
+missing /etc/login.conf.db
+resolved /etc/login.conf
+
+build_login_conflict
+
+# Verify that 'tf' installs the new version of the file.
+echo "Checking 'tf':"
+echo 'tf' | $COMMAND resolve -d $WORKDIR -D $TEST >/dev/null
+
+file /etc/login.conf "" 7774a0f9a3a372c7c109c32fd31c4b6b
+file /etc/login.conf.db
+resolved /etc/login.conf
+
+build_login_conflict
+
+# Verify that 'r' installs the resolved version of the file. To
+# simulate this, manually edit the merged file so that it doesn't
+# contain conflict markers.
+echo "Checking 'r':"
+cat > $CONFLICTS/etc/login.conf <<EOF
+default:\\
+ :passwd_format=md5:\\
+ :copyright=/etc/COPYRIGHT\\
+ :welcome=/etc/motd:
+EOF
+
+echo 'r' | $COMMAND resolve -d $WORKDIR -D $TEST >/dev/null
+
+file /etc/login.conf "" 966e25984b9b63da8eaac8479dcb0d4d
+file /etc/login.conf.db
+resolved /etc/login.conf
+
+build_aliases_conflict
+
+# Verify that 'p' and 'mf' do not generate the newaliases warning.
+echo "Checking newalias warning for 'p'":
+echo 'p' | $COMMAND resolve -d $WORKDIR -D $TEST | grep -q newalias
+if [ $? -eq 0 ]; then
+ echo "+ Extra warning"
+ FAILED=yes
+fi
+echo "Checking newalias warning for 'mf'":
+echo 'mf' | $COMMAND resolve -d $WORKDIR -D $TEST | grep -q newalias
+if [ $? -eq 0 ]; then
+ echo "+ Extra warning"
+ FAILED=yes
+fi
+
+# Verify that 'tf' and 'r' do generate the newaliases warning.
+build_aliases_conflict
+echo "Checking newalias warning for 'tf'":
+echo 'tf' | $COMMAND resolve -d $WORKDIR -D $TEST | grep -q newalias
+if [ $? -ne 0 ]; then
+ echo "- Missing warning"
+ FAILED=yes
+fi
+
+build_aliases_conflict
+cp $TEST/etc/mail/aliases $CONFLICTS/etc/mail/aliases
+echo 'r' | $COMMAND resolve -d $WORKDIR -D $TEST | grep -q newalias
+if [ $? -ne 0 ]; then
+ echo "- Missing warning"
+ FAILED=yes
+fi
+
+[ "${FAILED}" = no ]
diff --git a/usr.sbin/etcupdate/tests/fbsdid_test.sh b/usr.sbin/etcupdate/tests/fbsdid_test.sh
new file mode 100644
index 0000000..c062c06
--- /dev/null
+++ b/usr.sbin/etcupdate/tests/fbsdid_test.sh
@@ -0,0 +1,394 @@
+#!/bin/sh
+#
+# Copyright (c) 2010 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$
+
+# Various regression tests to test the -F flag to the 'update' command.
+
+FAILED=no
+WORKDIR=work
+
+usage()
+{
+ echo "Usage: fbsdid.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
+OLD=$WORKDIR/old
+NEW=$WORKDIR/current
+TEST=$WORKDIR/test
+
+# Store a FreeBSD ID string in a specified file. The first argument
+# is the file, the remaining arguments are the comment to use.
+store_id()
+{
+ local file
+
+ file=$1
+ shift
+
+ echo -n '# $FreeBSD' >> $file
+ echo -n "$@" >> $file
+ echo '$' >> $file
+}
+
+# These tests deal with FreeBSD ID string conflicts. We run the test
+# twice, once without -F and once with -F.
+build_trees()
+{
+ local i
+
+ rm -rf $OLD $NEW $TEST $CONFLICTS
+ mkdir -p $OLD $NEW $TEST
+
+ # remove: Remove a file where the only local difference is a
+ # change in the FreeBSD ID string.
+ store_id $OLD/remove
+ store_id $TEST/remove ": head/remove 12345 jhb "
+
+ # old: Modify a file where the only local difference between
+ # the old and test files is a change in the FreeBSD ID string.
+ store_id $OLD/old ": src/old,v 1.1 jhb Exp "
+ store_id $NEW/old ": head/old 12345 jhb "
+ store_id $TEST/old ": head/old 12000 jhb "
+ for i in $OLD $TEST; do
+ cat >> $i/old <<EOF
+
+an old file
+EOF
+ done
+ cat >> $NEW/old <<EOF
+
+a new file
+EOF
+
+ # already: Modify a file where the local file already matches
+ # the new file except for a change in the FreeBSD ID string.
+ store_id $OLD/already ": src/already,v 1.1 jhb Exp "
+ store_id $NEW/already ": head/already 12345 jhb "
+ store_id $TEST/already ": src/already,v 1.2 jhb Exp "
+ cat >> $OLD/already <<EOF
+
+another old file
+EOF
+ for i in $NEW $TEST; do
+ cat >> $i/already <<EOF
+
+another new file
+EOF
+ done
+
+ # add: Add a file that already exists where the only local
+ # difference is a change in the FreeBSD ID string.
+ store_id $NEW/add ": head/add 12345 jhb "
+ store_id $TEST/add ""
+
+ # conflict: Modify a file where the local file has a different
+ # FreeBSD ID string. This should still generate a conflict
+ # even in the -F case.
+ store_id $OLD/conflict ": head/conflict 12000 jhb "
+ store_id $NEW/conflict ": head/conflict 12345 jhb "
+ store_id $TEST/conflict ""
+ cat >> $OLD/conflict <<EOF
+
+this is the old file
+EOF
+ cat >> $NEW/conflict <<EOF
+
+this is the new file
+EOF
+ cat >> $TEST/conflict <<EOF
+
+this is the local file
+EOF
+
+ # local: A file with local modifications has a different
+ # FreeBSD ID string and the only differences between the old
+ # and new versions are a change in the FreeBSD ID string.
+ # This will just update the FreeBSD ID string in the -F case.
+ for i in $OLD $NEW $TEST; do
+ cat >> $i/local <<EOF
+# Some leading text
+#
+EOF
+ done
+
+ store_id $OLD/local ": head/local 12000 jhb "
+ store_id $NEW/local ": head/local 12345 jhb "
+ store_id $TEST/local ": src/local,v 1.5 jhb Exp "
+
+ for i in $OLD $NEW $TEST; do
+ cat >> $i/local <<EOF
+
+this is a file
+EOF
+ done
+
+ cat >> $TEST/local <<EOF
+
+these are some local mods to the file
+EOF
+
+ # local-already: A file with local modifications has the same
+ # FreeBSD ID string as the new version of the file and the
+ # only differences between the old and new versions are a
+ # change in the FreeBSD ID string. Nothing should happen in
+ # the -F case.
+ store_id $OLD/local-already ": head/local 12000 jhb "
+ for i in $NEW $TEST; do
+ store_id $i/local-already ": head/local 12345 jhb "
+ done
+
+ for i in $OLD $NEW $TEST; do
+ cat >> $i/local-already <<EOF
+
+this is a file
+EOF
+ done
+
+ cat >> $TEST/local-already <<EOF
+
+these are some local mods to the file
+EOF
+
+ # local-remove: A file removed locally changed it's FreeBSD ID
+ # but nothing else
+ store_id $OLD/local-remove ": head/local-remove 12000 jhb "
+ store_id $NEW/local-remove ": head/local-remove 12345 jhb "
+ for i in $OLD $NEW; do
+ cat >> $i/local-remove <<EOF
+
+this is a file
+EOF
+ done
+}
+
+# $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"
+ FAILED=yes
+ 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"
+ FAILED=yes
+ 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"
+ FAILED=yes
+ elif [ $# -eq 2 ]; then
+ contents=`cat $TEST/$1`
+ if [ "$contents" != "$2" ]; then
+ echo "File $1 has wrong contents"
+ FAILED=yes
+ fi
+ elif [ $# -eq 3 ]; then
+ sum=`md5 -q $TEST/$1`
+ if [ "$sum" != "$3" ]; then
+ echo "File $1 has wrong contents"
+ FAILED=yes
+ 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"
+ FAILED=yes
+ elif [ $# -gt 1 ]; then
+ sum=`md5 -q $CONFLICTS/$1`
+ if [ "$sum" != "$2" ]; then
+ echo "Conflict $1 has wrong contents"
+ FAILED=yes
+ fi
+ fi
+}
+
+# $1 - relative path to a regular file that should not have a conflict
+noconflict()
+{
+ if [ -f $CONFLICTS/$1 ]; then
+ echo "File $1 should not have a conflict"
+ FAILED=yes
+ fi
+}
+
+if [ `id -u` -ne 0 ]; then
+ echo "must be root"
+ exit 0
+fi
+
+if [ -r /etc/etcupdate.conf ]; then
+ echo "WARNING: /etc/etcupdate.conf settings may break some tests."
+fi
+
+# First run the test without -F.
+
+build_trees
+
+$COMMAND -r -d $WORKDIR -D $TEST > $WORKDIR/test.out
+
+cat > $WORKDIR/correct.out <<EOF
+ C /already
+ C /conflict
+ C /local
+ M /local-already
+ C /old
+ C /add
+Warnings:
+ Modified regular file remains: /remove
+ Removed file changed: /local-remove
+EOF
+
+echo "Differences for regular:"
+diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out \
+ || FAILED=yes
+
+file /remove "" 1bb4776213af107077be78fead8a351c
+file /old "" 2f799a7addc4132563ef9b44adc66157
+conflict /old 8441be64a1540f2ff584015279682425
+file /already "" aa53bd506f65d01d766e7ba028585e1d
+conflict /already f44105abb1fa3293e95c5d77e428d418
+file /add "" 1dc8c617e541d1fd1b4c70212f71d8ae
+conflict /add f99081e0da9a07f3cfebb430c0414941
+file /conflict "" dc27978df125b0daeb7d9b93265f03fd
+conflict /conflict 868452f666fea1c60ffb918ad9ad9607
+file /local "" aa33e614b5e749449f230e2a2b0072eb
+conflict /local 3df93e64043c8e348fc625b93ea220f4
+file /local-already "" 0298b958a603049f45ae6a109c4f7fea
+missing /local-remove
+
+# Now test with -F.
+
+build_trees
+
+$COMMAND -rF -d $WORKDIR -D $TEST > $WORKDIR/testF.out
+
+cat > $WORKDIR/correctF.out <<EOF
+ D /remove
+ U /already
+ C /conflict
+ M /local
+ U /old
+ U /add
+EOF
+
+echo "Differences for -F:"
+diff -u -L "correct" $WORKDIR/correctF.out -L "test" $WORKDIR/testF.out \
+ || FAILED=yes
+
+missing /remove
+file /old "" 6a9f34f109d94406a4de3bc5d72de259
+noconflict /old
+file /already "" 21f4eca3aacc702c49878c8da7afd3d0
+noconflict /already
+file /add "" 0208bd647111fedf6318511712ab9e97
+noconflict /add
+file /conflict "" dc27978df125b0daeb7d9b93265f03fd
+conflict /conflict 868452f666fea1c60ffb918ad9ad9607
+file /local "" 3ed5a35e380c8a93fb5f599d4c052713
+file /local-already "" 0298b958a603049f45ae6a109c4f7fea
+missing /local-remove
+
+# Now test with -F and -A forcing all installs. (-A should have
+# precedence over -F)
+
+build_trees
+
+$COMMAND -A '/*' -rF -d $WORKDIR -D $TEST > $WORKDIR/testAF.out
+
+cat > $WORKDIR/correctAF.out <<EOF
+ D /remove
+ U /already
+ U /conflict
+ U /local
+ U /local-already
+ A /local-remove
+ U /old
+ U /add
+EOF
+
+echo "Differences for -A '/*' -F:"
+diff -u -L "correct" $WORKDIR/correctAF.out -L "test" $WORKDIR/testAF.out \
+ || FAILED=yes
+
+missing /remove
+file /old "" 6a9f34f109d94406a4de3bc5d72de259
+noconflict /old
+file /already "" 21f4eca3aacc702c49878c8da7afd3d0
+noconflict /already
+file /add "" 0208bd647111fedf6318511712ab9e97
+noconflict /add
+file /conflict "" 75ee141c4136beaf14e39de92efa84e4
+noconflict /conflict
+file /local "" 6a8fc5c2755b7a49015089f5e1dbe092
+file /local-already "" 49045f8b51542dd634655301cd296f66
+file /local-remove "" 5c38322efed4014797d7127f5c652d9d
+
+[ "${FAILED}" = no ]
diff --git a/usr.sbin/etcupdate/tests/ignore_test.sh b/usr.sbin/etcupdate/tests/ignore_test.sh
new file mode 100644
index 0000000..2d3d2f5
--- /dev/null
+++ b/usr.sbin/etcupdate/tests/ignore_test.sh
@@ -0,0 +1,276 @@
+#!/bin/sh
+#
+# Copyright (c) 2010 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$
+
+# Various regression tests to test the -I flag to the 'update' command.
+
+FAILED=no
+WORKDIR=work
+
+usage()
+{
+ echo "Usage: ignore.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
+OLD=$WORKDIR/old
+NEW=$WORKDIR/current
+TEST=$WORKDIR/test
+
+# These tests deal with ignoring certain patterns of files. We run the
+# test multiple times ignoring different patterns.
+build_trees()
+{
+ local i
+
+ rm -rf $OLD $NEW $TEST $CONFLICTS
+ mkdir -p $OLD $NEW $TEST
+
+ for i in $OLD $NEW $TEST; do
+ mkdir -p $i/tree
+ done
+
+ # tree: Test three different cases (add, modify, remove) that all
+ # match the tree/* glob.
+ echo "foo" > $NEW/tree/add
+ for i in $OLD $TEST; do
+ echo "old" > $i/tree/modify
+ done
+ echo "new" > $NEW/tree/modify
+ for i in $OLD $TEST; do
+ echo "old" > $i/tree/remove
+ done
+
+ # rmdir: Remove a whole tree.
+ for i in $OLD $TEST; do
+ mkdir $i/rmdir
+ echo "foo" > $i/rmdir/file
+ done
+}
+
+# $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"
+ FAILED=yes
+ 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"
+ FAILED=yes
+ fi
+}
+
+# $1 - relative path to file that should be a directory in TEST
+dir()
+{
+ if ! [ -d $TEST/$1 ]; then
+ echo "File $1 should be a directory"
+ FAILED=yes
+ 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"
+ FAILED=yes
+ elif [ $# -eq 2 ]; then
+ contents=`cat $TEST/$1`
+ if [ "$contents" != "$2" ]; then
+ echo "File $1 has wrong contents"
+ FAILED=yes
+ fi
+ elif [ $# -eq 3 ]; then
+ sum=`md5 -q $TEST/$1`
+ if [ "$sum" != "$3" ]; then
+ echo "File $1 has wrong contents"
+ FAILED=yes
+ 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"
+ FAILED=yes
+ elif [ $# -gt 1 ]; then
+ sum=`md5 -q $CONFLICTS/$1`
+ if [ "$sum" != "$2" ]; then
+ echo "Conflict $1 has wrong contents"
+ FAILED=yes
+ fi
+ fi
+}
+
+# $1 - relative path to a regular file that should not have a conflict
+noconflict()
+{
+ if [ -f $CONFLICTS/$1 ]; then
+ echo "File $1 should not have a conflict"
+ FAILED=yes
+ fi
+}
+
+if [ `id -u` -ne 0 ]; then
+ echo "must be root"
+ exit 0
+fi
+
+if [ -r /etc/etcupdate.conf ]; then
+ echo "WARNING: /etc/etcupdate.conf settings may break some tests."
+fi
+
+# First run the test ignoring no patterns.
+
+build_trees
+
+$COMMAND -r -d $WORKDIR -D $TEST > $WORKDIR/test.out
+
+cat > $WORKDIR/correct.out <<EOF
+ D /rmdir/file
+ D /tree/remove
+ D /rmdir
+ U /tree/modify
+ A /tree/add
+EOF
+
+echo "Differences for regular:"
+diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out \
+ || FAILED=yes
+
+missing /tree/remove
+file /tree/modify "new"
+file /tree/add "foo"
+missing /rmdir/file
+missing /rmdir
+
+# Now test with -I '/tree/*'. This should preserve the /tree files.
+
+build_trees
+
+$COMMAND -r -I '/tree/*' -d $WORKDIR -D $TEST > $WORKDIR/test1.out
+
+cat > $WORKDIR/correct1.out <<EOF
+ D /rmdir/file
+ D /rmdir
+EOF
+
+echo "Differences for -I '/tree/*':"
+diff -u -L "correct" $WORKDIR/correct1.out -L "test" $WORKDIR/test1.out \
+ || FAILED=yes
+
+file /tree/remove "old"
+file /tree/modify "old"
+missing /tree/add
+missing /rmdir/file
+missing /rmdir
+
+# Now test with two patterns. This should preserve everything.
+
+build_trees
+
+$COMMAND -r -I '/tree/*' -I '/rmdir*' -d $WORKDIR -D $TEST > \
+ $WORKDIR/test2.out
+
+cat > $WORKDIR/correct2.out <<EOF
+EOF
+
+echo "Differences for -I '/tree/*' -I '/rmdir*':"
+
+diff -u -L "correct" $WORKDIR/correct2.out -L "test" $WORKDIR/test2.out \
+ || FAILED=yes
+
+file /tree/remove "old"
+file /tree/modify "old"
+missing /tree/add
+file /rmdir/file "foo"
+
+# Now test with a pattern that should cause a warning on /rmdir by
+# only ignoring the files under that directory. Note that this also
+# tests putting two patterns into a single -I argument.
+
+build_trees
+
+$COMMAND -r -I '/tree/* /rmdir/*' -d $WORKDIR -D $TEST > \
+ $WORKDIR/test3.out
+
+cat > $WORKDIR/correct3.out <<EOF
+Warnings:
+ Non-empty directory remains: /rmdir
+EOF
+
+echo "Differences for -I '/tree/* /rmdir/*':"
+
+diff -u -L "correct" $WORKDIR/correct3.out -L "test" $WORKDIR/test3.out \
+ || FAILED=yes
+
+file /tree/remove "old"
+file /tree/modify "old"
+missing /tree/add
+file /rmdir/file "foo"
+dir /rmdir
+
+[ "${FAILED}" = no ]
diff --git a/usr.sbin/etcupdate/tests/preworld_test.sh b/usr.sbin/etcupdate/tests/preworld_test.sh
new file mode 100644
index 0000000..c731293
--- /dev/null
+++ b/usr.sbin/etcupdate/tests/preworld_test.sh
@@ -0,0 +1,252 @@
+#!/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
+
+FAILED=no
+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 additional files
+ # 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
+ touch $TEST/etc/localtime
+
+ # 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"
+ FAILED=yes
+ 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"
+ FAILED=yes
+ 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"
+ FAILED=yes
+ elif [ $# -eq 2 ]; then
+ contents=`cat $TEST/$1`
+ if [ "$contents" != "$2" ]; then
+ echo "File $1 has wrong contents"
+ FAILED=yes
+ fi
+ elif [ $# -eq 3 ]; then
+ sum=`md5 -q $TEST/$1`
+ if [ "$sum" != "$3" ]; then
+ echo "File $1 has wrong contents"
+ FAILED=yes
+ 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"
+ FAILED=yes
+ elif [ $# -gt 1 ]; then
+ sum=`md5 -q $CONFLICTS/$1`
+ if [ "$sum" != "$2" ]; then
+ echo "Conflict $1 has wrong contents"
+ FAILED=yes
+ 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"
+ exit 0
+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 \
+ || FAILED=yes
+
+$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 \
+ || FAILED=yes
+
+check_trees
+
+[ "${FAILED}" = no ]
diff --git a/usr.sbin/etcupdate/tests/tests_test.sh b/usr.sbin/etcupdate/tests/tests_test.sh
new file mode 100644
index 0000000..b99bbef
--- /dev/null
+++ b/usr.sbin/etcupdate/tests/tests_test.sh
@@ -0,0 +1,1021 @@
+#!/bin/sh
+#
+# Copyright (c) 2010 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$
+
+# Various regression tests to run for the 'update' command.
+
+FAILED=no
+WORKDIR=work
+
+usage()
+{
+ echo "Usage: tests.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
+OLD=$WORKDIR/old
+NEW=$WORKDIR/current
+TEST=$WORKDIR/test
+
+# The various states of the comparison of a file between two trees.
+states="equal first second difftype difflinks difffiles"
+
+build_trees()
+{
+ local i j k
+
+ rm -rf $OLD $NEW $TEST $CONFLICTS
+ mkdir -p $OLD/etc $NEW/etc $TEST/etc
+
+ # For an given file, there are three different pair-wise
+ # relations between the three threes (old, new, and test): old
+ # vs new, old vs test, and new vs test. Each of these
+ # relations takes on one of six different states from the
+ # 'compare()' function in etcupdate: equal, onlyfirst,
+ # onlysecond, difftype, difflinks, difffiles. In addition,
+ # there are special considerations for considering cases such
+ # as a file merge that results in conflicts versus one that
+ # does not, special treatment of directories, etc. The tests
+ # below attempt to enumerate the three dimensional test matrix
+ # by having the path name use the three different tree states
+ # for the parent directories.
+ #
+ # Note that if the old and new files are identical (so first
+ # compare is "equal"), then the second and third comparisons
+ # will be the same.
+ #
+ # Note also that etcupdate only cares about files that are
+ # present in at least one of the old or new trees. Thus, none
+ # of the '*/second/second' cases are relevant.
+
+ for i in $states; do
+ for j in $states; do
+ for k in $states; do
+ mkdir -p $OLD/$i/$j/$k $NEW/$i/$j/$k \
+ $TEST/$i/$j/$k
+ done
+ done
+ done
+
+ # /equal/equal/equal: Everything is equal. Nothing should happen.
+ for i in $OLD $NEW $TEST; do
+ mkfifo $i/equal/equal/equal/fifo
+ echo "foo" > $i/equal/equal/equal/file
+ mkdir $i/equal/equal/equal/dir
+ ln -s "bar" $i/equal/equal/equal/link
+ done
+
+ # /equal/first/first: The file is missing from the test
+ # directory. Nothing should happen.
+ for i in $OLD $NEW; do
+ mkfifo $i/equal/first/first/fifo
+ echo "foo" > $i/equal/first/first/file
+ mkdir $i/equal/first/first/dir
+ ln -s "bar" $i/equal/first/first/link
+ done
+
+ # /equal/difftype/difftype: The local file is a different
+ # type. Nothing should happen.
+ for i in $OLD $NEW; do
+ mkfifo $i/equal/difftype/difftype/fifo
+ mkdir $i/equal/difftype/difftype/fromdir
+ done
+ echo "bar" > $TEST/equal/difftype/difftype/fifo
+ ln -s "test" $TEST/equal/difftype/difftype/fromdir
+
+ # /equal/difflinks/difflinks: The local file is a modified
+ # link. Nothing should happen.
+ for i in $OLD $NEW; do
+ ln -s "foo" $i/equal/difflinks/difflinks/link
+ done
+ ln -s "bar" $TEST/equal/difflinks/difflinks/link
+
+ # /equal/difffiles/difffiles: The local file is a modified
+ # file. Nothing should happen.
+ for i in $OLD $NEW; do
+ echo "foo" > $i/equal/difffiles/difffiles/file
+ done
+ echo "bar" > $TEST/equal/difffiles/difffiles/file
+
+ # /first/equal/second: Remove unmodified files. The files
+ # should all be removed.
+ for i in $OLD $TEST; do
+ mkfifo $i/first/equal/second/fifo
+ echo "foo" > $i/first/equal/second/file
+ mkdir $i/first/equal/second/emptydir
+ ln -s "bar" $i/first/equal/second/link
+ mkdir $i/first/equal/second/fulldir
+ echo "foo" > $i/first/equal/second/fulldir/file
+ done
+
+ # /first/equal/*: Cannot occur. If the file is missing from
+ # new, then new vs test will always be 'second'.
+
+ # /first/first/equal: Removed files are already removed.
+ # Nothing should happen.
+ mkfifo $OLD/first/first/equal/fifo
+ echo "foo" > $OLD/first/first/equal/file
+ mkdir $OLD/first/first/equal/dir
+ ln -s "bar" $OLD/first/first/equal/link
+
+ # /first/first/*: Cannot occur. The files are missing from
+ # both new and test.
+
+ # /first/second/*: Cannot happen, if the file is in old for
+ # old vs new, it cannot be missing for old vs test.
+
+ # /first/difftype/second: File with different local type
+ # removed. Should generate a warning.
+ mkfifo $OLD/first/difftype/second/fifo
+ mkdir $TEST/first/difftype/second/fifo
+
+ # /first/difftype/*: Cannot happen since the file is missing
+ # from new but present in test.
+
+ # /first/difflinks/second: Modified link removed. Should
+ # generate a warning.
+ ln -s "old link" $OLD/first/difflinks/second/link
+ ln -s "test link" $TEST/first/difflinks/second/link
+
+ # /first/difflinks/*: Cannot happen since the file is missing
+ # from new but present in test.
+
+ # /first/difffiles/second: Modified file removed. Should
+ # generate a warning.
+ echo "foo" > $OLD/first/difffiles/second/file
+ echo "bar" > $TEST/first/difffiles/second/file
+
+ # /first/difffiles/*: Cannot happen since the file is missing
+ # from new but present in test.
+
+ # /second/equal/first: Added a new file that isn't present in
+ # test. The empty directory should be ignored.
+ echo "bar" > $NEW/second/equal/first/file
+ mkfifo $NEW/second/equal/first/fifo
+ ln -s "new" $NEW/second/equal/first/link
+ mkdir $NEW/second/equal/first/emptydir
+ mkdir $NEW/second/equal/first/fulldir
+ echo "foo" > $NEW/second/equal/first/fulldir/file
+
+ # /second/equal/*: Cannot happen since the file is missing
+ # from test but present in new.
+
+ # /second/first/*: Cannot happen since the file is missing
+ # from old.
+
+ # /second/second/equal: Newly added file is already present in
+ # the test directory and identical to the new file. Nothing
+ # should happen.
+ for i in $NEW $TEST; do
+ mkfifo $i/second/second/equal/fifo
+ echo "foo" > $i/second/second/equal/file
+ mkdir $i/second/second/equal/dir
+ ln -s "bar" $i/second/second/equal/link
+ done
+
+ # /second/second/first: Cannot happen. The file is in dest in
+ # the second test, so it can't be missing from the third test.
+
+ # /second/second/second: Cannot happen. The file is in new in
+ # the first test, so it can't be missing from the third test.
+
+ # /second/second/difftype: Newly added file conflicts with
+ # existing file in test tree of a different type. Should
+ # generate a warning.
+ mkdir $NEW/second/second/difftype/dir
+ mkfifo $TEST/second/second/difftype/dir
+
+ # /second/second/difflinks: Newly added link conflicts with
+ # existing link in test tree. Should generate a warning.
+ ln -s "new link" $NEW/second/second/difflinks/link
+ ln -s "test link" $TEST/second/second/difflinks/link
+
+ # /second/second/difffiles: Newly added file conflicts with
+ # existing file in test tree. Should generate a warning.
+ echo "new" > $NEW/second/second/difffiles/file
+ echo "test" > $TEST/second/second/difffiles/file
+
+ # /second/difftype/*: Cannot happen since the file is missing
+ # from old.
+
+ # /second/difflinks/*: Cannot happen since the file is missing
+ # from old.
+
+ # /second/difffiles/*: Cannot happen since the file is missing
+ # from old.
+
+ # /difftype/equal/difftype: Unmodified file has changed type.
+ # File should be updated to the new file. In the 'todir' case
+ # the directory won't actually be created because it is empty.
+ for i in $OLD $TEST; do
+ echo "foo" > $i/difftype/equal/difftype/file
+ mkdir $i/difftype/equal/difftype/fromdir
+ ln -s "old" $i/difftype/equal/difftype/todir
+ done
+ ln -s "test" $NEW/difftype/equal/difftype/file
+ mkfifo $NEW/difftype/equal/difftype/fromdir
+ mkdir $NEW/difftype/equal/difftype/todir
+
+ # /difftype/equal/*: Cannot happen. Since the old file is a
+ # difftype from the new file and the test file is identical to
+ # the old file, the test file must be a difftype from the new
+ # file.
+
+ # /difftype/first/first: A removed file has changed type.
+ # This should generate a warning.
+ mkfifo $OLD/difftype/first/first/fifo
+ mkdir $NEW/difftype/first/first/fifo
+
+ # /difftype/first/*: Cannot happen. Since the new file exists
+ # and the dest file is missing, the last test must be 'first'.
+
+ # /difftype/second/*: Cannot happen. The old file exists in
+ # the first test, so it cannot be missing in the second test.
+
+ # /difftype/difftype/equal: A file has changed type, but the
+ # file in the test directory already matches the new file. Do
+ # nothing.
+ echo "foo" > $OLD/difftype/difftype/equal/fifo
+ mkfifo $OLD/difftype/difftype/equal/file
+ for i in $NEW $TEST; do
+ mkfifo $i/difftype/difftype/equal/fifo
+ echo "bar" > $i/difftype/difftype/equal/file
+ done
+
+ # /difftype/difftype/first: Cannot happen. The dest file
+ # exists in the second test.
+
+ # /difftype/difftype/second: Cannot happen. The new file
+ # exists in the first test.
+
+ # /difftype/difftype/difftype: All three files (old, new, and
+ # test) are different types from each other. This should
+ # generate a warning.
+ mkfifo $OLD/difftype/difftype/difftype/one
+ mkdir $NEW/difftype/difftype/difftype/one
+ echo "foo" > $TEST/difftype/difftype/difftype/one
+ mkdir $OLD/difftype/difftype/difftype/two
+ echo "baz" > $NEW/difftype/difftype/difftype/two
+ ln -s "bar" $TEST/difftype/difftype/difftype/two
+
+ # /difftype/difftype/difflinks: A file has changed from a
+ # non-link to a link in both the new and test trees, but the
+ # target of the new and test links differ. This should
+ # generate a new link conflict.
+ mkfifo $OLD/difftype/difftype/difflinks/link
+ ln -s "new" $NEW/difftype/difftype/difflinks/link
+ ln -s "test" $TEST/difftype/difftype/difflinks/link
+
+ # /difftype/difftype/difffile: A file has changed from a
+ # non-regular file to a regular file in both the new and test
+ # trees, but the contents in the new and test files differ.
+ # This should generate a new file conflict.
+ ln -s "old" $OLD/difftype/difftype/difffiles/file
+ echo "foo" > $NEW/difftype/difftype/difffiles/file
+ echo "bar" > $TEST/difftype/difftype/difffiles/file
+
+ # /difflinks/equal/difflinks: An unmodified symlink has
+ # changed. The link should be updated.
+ for i in $OLD $TEST; do
+ ln -s "old" $i/difflinks/equal/difflinks/link
+ done
+ ln -s "new" $NEW/difflinks/equal/difflinks/link
+
+ # /difflinks/equal/*: Cannot happen. Since old is identical
+ # to test, the third test must be 'difflinks'.
+
+ # /difflinks/first/first: A modified link is missing in the
+ # test tree. This should generate a warning.
+ ln -s "old" $OLD/difflinks/first/first/link
+ ln -s "new" $NEW/difflinks/first/first/link
+
+ # /difflinks/first/*: Cannot happen. Since the test file is
+ # missing in the second test, it must be missing in the third
+ # test.
+
+ # /difflinks/second/*: Cannot happen. The old link is present
+ # in the first test, so it cannot be missing in the second
+ # test.
+
+ # /difflinks/difftype/difftype: An updated link has been
+ # changed to a different file type in the test tree. This
+ # should generate a warning.
+ ln -s "old" $OLD/difflinks/difftype/difftype/link
+ ln -s "new" $NEW/difflinks/difftype/difftype/link
+ echo "test" > $TEST/difflinks/difftype/difftype/link
+
+ # /difflinks/difftype/*: Cannot happen. The old and new files
+ # are both links and the test file is not a link, so the third
+ # test must be 'difftype'.
+
+ # /difflinks/difflinks/equal: An updated link has already been
+ # updated to the new target in the test tree. Nothing should
+ # happen.
+ ln -s "old" $OLD/difflinks/difflinks/equal/link
+ for i in $NEW $TEST; do
+ ln -s "new" $i/difflinks/difflinks/equal/link
+ done
+
+ # /difflinks/difflinks/difflinks: An updated link has been
+ # modified in the test tree and doesn't match either the old
+ # or new links. This should generate a warning.
+ ln -s "old" $OLD/difflinks/difflinks/difflinks/link
+ ln -s "new" $NEW/difflinks/difflinks/difflinks/link
+ ln -s "test" $TEST/difflinks/difflinks/difflinks/link
+
+ # /difflinks/difflinks/*: Cannot happen. All three files are
+ # links from the first two tests, so the third test can only
+ # be 'equal' or 'difflink'.
+
+ # /difflinks/difffiles/*: Cannot happen. The old file is a
+ # link in the first test, so it cannot be a regular file in
+ # the second.
+
+ # /difffiles/equal/difffiles: An unmodified file has been
+ # changed in new tree. The file should be updated to the new
+ # version.
+ for i in $OLD $TEST; do
+ echo "foo" > $i/difffiles/equal/difffiles/file
+ done
+ echo "bar" > $NEW/difffiles/equal/difffiles/file
+
+ # /difffiles/equal/*: Cannot happen. Since the old file is
+ # identical to the test file, the third test must be
+ # 'difffiles'.
+
+ # /difffiles/first/first: A removed file has been changed in
+ # the new tree. This should generate a warning.
+ echo "foo" > $OLD/difffiles/first/first/file
+ echo "bar" > $NEW/difffiles/first/first/file
+
+ # /difffiles/first/*: Cannot happen. The new file is a
+ # regular file from the first test and the test file is
+ # missing in the second test, so the third test must be
+ # 'first'.
+
+ # /difffiles/second/*: Cannot happen. The old file is present
+ # in the first test, so it must be present in the second test.
+
+ # /difffiles/difftype/difftype: An updated regular file has
+ # been changed to a different file type in the test tree.
+ # This should generate a warning.
+ echo "old" > $OLD/difffiles/difftype/difftype/file
+ echo "new" > $NEW/difffiles/difftype/difftype/file
+ mkfifo $TEST/difffiles/difftype/difftype/file
+
+ # /difffiles/difftype/*: Cannot happen. The new file is known
+ # to be a regular file from the first test, and the test file
+ # is known to exist as a different file type from the second
+ # test. The third test must be 'difftype'.
+
+ # /difffiles/difflink/*: Cannot happen. The old file is known
+ # to be a regular file from the first test, so it cannot be a
+ # link in the second test.
+
+ # /difffiles/difffiles/equal: An updated regular file has
+ # already been updated to match the new file in the test tree.
+ # Nothing should happen.
+ echo "foo" > $OLD/difffiles/difffiles/equal/file
+ for i in $NEW $TEST; do
+ echo "bar" > $i/difffiles/difffiles/equal/file
+ done
+
+ # /difffiles/difffiles/difffiles: A modified regular file was
+ # updated in the new tree. The changes should be merged into
+ # to the new file if possible. If the merge fails, a conflict
+ # should be generated.
+ cat > $OLD/difffiles/difffiles/difffiles/simple <<EOF
+this is an old line
+
+EOF
+ cat > $NEW/difffiles/difffiles/difffiles/simple <<EOF
+this is a new line
+
+EOF
+ cat > $TEST/difffiles/difffiles/difffiles/simple <<EOF
+this is an old line
+
+this is a local line
+EOF
+ cat > $OLD/difffiles/difffiles/difffiles/conflict <<EOF
+this is an old file
+EOF
+ cat > $NEW/difffiles/difffiles/difffiles/conflict <<EOF
+this is a new file
+EOF
+ cat > $TEST/difffiles/difffiles/difffiles/conflict <<EOF
+this is a test file
+EOF
+
+ # /difffiles/difffiles/*: Cannot happen. From the first three
+ # tests, all three files are regular files. The test file can
+ # either be identical to the new file ('equal') or not
+ # ('difffiles').
+
+ ## Tests for adding directories
+ mkdir -p $OLD/adddir $NEW/adddir $TEST/adddir
+
+ # /adddir/conflict: Add a new file in a directory that already
+ # exists as a file. This should generate two warnings.
+ mkdir $NEW/adddir/conflict
+ touch $NEW/adddir/conflict/newfile
+ touch $TEST/adddir/conflict
+
+ # /adddir/partial: Add a new file in a directory. The
+ # directory already exists in the test tree and contains a
+ # different local file. The new file from the new tree should
+ # be added.
+ for i in $NEW $TEST; do
+ mkdir $i/adddir/partial
+ done
+ echo "foo" > $NEW/adddir/partial/file
+ mkfifo $TEST/adddir/partial/fifo
+
+ ## Tests for removing directories
+ mkdir -p $OLD/rmdir $NEW/rmdir $TEST/rmdir
+
+ # /rmdir/extra: Do not remove a directory with an extra local file.
+ # This should generate a warning.
+ for i in $OLD $TEST; do
+ mkdir $i/rmdir/extra
+ done
+ echo "foo" > $TEST/rmdir/extra/localfile.txt
+
+ # /rmdir/conflict: Do not remove a directory with a conflicted
+ # remove file. This should generate a warning.
+ for i in $OLD $TEST; do
+ mkdir $i/rmdir/conflict
+ done
+ mkfifo $OLD/rmdir/conflict/difftype
+ mkdir $TEST/rmdir/conflict/difftype
+
+ # /rmdir/partial: Remove a complete hierarchy when part of the
+ # tree has already been removed locally.
+ for i in $OLD $TEST; do
+ mkdir -p $i/rmdir/partial/subdir
+ mkfifo $i/rmdir/partial/subdir/fifo
+ done
+ echo "foo" > $OLD/rmdir/partial/subdir/file
+
+ ## Tests for converting files to directories and vice versa
+ for i in $OLD $NEW $TEST; do
+ for j in already old fromdir todir; do
+ mkdir -p $i/dirchange/$j
+ done
+ done
+
+ # /dirchange/already/fromdir: Convert a directory tree to a
+ # file without conflicts where the test tree already has the
+ # new file. Nothing should happen.
+ mkdir $OLD/dirchange/already/fromdir
+ echo "blah" > $OLD/dirchange/already/fromdir/somefile
+ for i in $NEW $TEST; do
+ echo "bar" > $i/dirchange/already/fromdir
+ done
+
+ # /dirchange/already/todir: Convert an unmodified file to a
+ # directory tree where the test tree already has the new
+ # tree. Nothing should happen.
+ echo "baz" > $OLD/dirchange/already/todir
+ for i in $NEW $TEST; do
+ mkdir $i/dirchange/already/todir
+ echo "blah" > $i/dirchange/already/todir/somefile
+ done
+
+ # /dirchange/old/fromdir: Convert a directory tree to a file.
+ # The old files are unmodified and should be changed to the new tree.
+ for i in $OLD $TEST; do
+ mkdir $i/dirchange/old/fromdir
+ echo "blah" > $i/dirchange/old/fromdir/somefile
+ done
+ echo "bar" > $NEW/dirchange/old/fromdir
+
+ # /dirchange/old/todir: Convert a file to a directory tree.
+ # The old file is unmodified and should be changed to the new
+ # tree.
+ for i in $OLD $TEST; do
+ echo "foo" > $i/dirchange/old/todir
+ done
+ mkdir $NEW/dirchange/old/todir
+ echo "bar" > $NEW/dirchange/old/todir/file
+
+ # /dirchange/fromdir/extradir: Convert a directory tree to a
+ # file. The test tree includes an extra file in the directory
+ # that is not present in the old tree. This should generate a
+ # warning.
+ for i in $OLD $TEST; do
+ mkdir $i/dirchange/fromdir/extradir
+ echo "foo" > $i/dirchange/fromdir/extradir/file
+ done
+ mkfifo $TEST/dirchange/fromdir/extradir/fifo
+ ln -s "bar" $NEW/dirchange/fromdir/extradir
+
+ # /dirchange/fromdir/conflict: Convert a directory tree to a
+ # file. The test tree includes a local change that generates
+ # a warning and prevents the removal of the directory.
+ for i in $OLD $TEST; do
+ mkdir $i/dirchange/fromdir/conflict
+ done
+ echo "foo" > $OLD/dirchange/fromdir/conflict/somefile
+ echo "bar" > $TEST/dirchange/fromdir/conflict/somefile
+ mkfifo $NEW/dirchange/fromdir/conflict
+
+ # /dirchange/todir/difffile: Convert a file to a directory
+ # tree. The test tree has a locally modified version of the
+ # file so that the conversion fails with a warning.
+ echo "foo" > $OLD/dirchange/todir/difffile
+ mkdir $NEW/dirchange/todir/difffile
+ echo "baz" > $NEW/dirchange/todir/difffile/file
+ echo "bar" > $TEST/dirchange/todir/difffile
+
+ # /dirchange/todir/difftype: Similar to the previous test, but
+ # the conflict is due to a change in the file type.
+ echo "foo" > $OLD/dirchange/todir/difftype
+ mkdir $NEW/dirchange/todir/difftype
+ echo "baz" > $NEW/dirchange/todir/difftype/file
+ mkfifo $TEST/dirchange/todir/difftype
+
+ ## Tests for post-install actions
+
+ # - Adding /etc/master.passwd should cause pwd_mkdb to be run
+ echo "foo:*:16000:100::0:0:& user:/home/foo:/bin/tcsh" > \
+ $NEW/etc/master.passwd
+
+ # - Verify that updating an unmodified /etc/login.conf builds
+ # /etc/login.conf.db.
+ cat > $OLD/etc/login.conf <<EOF
+default:\\
+ :passwd_format=md5:
+EOF
+ cat > $NEW/etc/login.conf <<EOF
+default:\\
+ :passwd_format=md5:\\
+ :copyright=/etc/COPYRIGHT
+EOF
+ cp $OLD/etc/login.conf $TEST/etc/login.conf
+
+ # - Verify that a merge without conflicts to /etc/mail/aliases
+ # will trigger a newaliases run request.
+ mkdir -p $OLD/etc/mail $NEW/etc/mail $TEST/etc/mail
+ cat > $OLD/etc/mail/aliases <<EOF
+# root: me@my.domain
+
+# Basic system aliases -- these MUST be present
+MAILER-DAEMON: postmaster
+postmaster: root
+EOF
+ cat > $NEW/etc/mail/aliases <<EOF
+# root: me@my.domain
+
+# Basic system aliases -- these MUST be present
+MAILER-DAEMON: postmaster
+postmaster: root
+
+# General redirections for pseudo accounts
+_dhcp: root
+_pflogd: root
+EOF
+ cat > $TEST/etc/mail/aliases <<EOF
+root: someone@example.com
+
+# Basic system aliases -- these MUST be present
+MAILER-DAEMON: postmaster
+postmaster: root
+EOF
+
+ # - Verify that updating an unmodified /etc/services builds
+ # /var/db/services.db.
+ cat > $OLD/etc/services <<EOF
+rtmp 1/ddp #Routing Table Maintenance Protocol
+tcpmux 1/tcp #TCP Port Service Multiplexer
+tcpmux 1/udp #TCP Port Service Multiplexer
+EOF
+ cat > $NEW/etc/services <<EOF
+rtmp 1/ddp #Routing Table Maintenance Protocol
+tcpmux 1/tcp #TCP Port Service Multiplexer
+tcpmux 1/udp #TCP Port Service Multiplexer
+nbp 2/ddp #Name Binding Protocol
+compressnet 2/tcp #Management Utility
+compressnet 2/udp #Management Utility
+EOF
+ cp $OLD/etc/services $TEST/etc/services
+ mkdir -p $TEST/var/db
+}
+
+# $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"
+ FAILED=yes
+ 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"
+ FAILED=yes
+ fi
+}
+
+# $1 - relative path to file that should be a fifo in TEST
+fifo()
+{
+ if ! [ -p $TEST/$1 ]; then
+ echo "File $1 should be a FIFO"
+ FAILED=yes
+ fi
+}
+
+# $1 - relative path to file that should be a directory in TEST
+dir()
+{
+ if ! [ -d $TEST/$1 ]; then
+ echo "File $1 should be a directory"
+ FAILED=yes
+ fi
+}
+
+# $1 - relative path to file that should be a symlink in TEST
+# $2 - optional value of the link
+link()
+{
+ local val
+
+ if ! [ -L $TEST/$1 ]; then
+ echo "File $1 should be a link"
+ FAILED=yes
+ elif [ $# -gt 1 ]; then
+ val=`readlink $TEST/$1`
+ if [ "$val" != "$2" ]; then
+ echo "Link $1 should link to \"$2\""
+ FAILED=yes
+ fi
+ 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"
+ FAILED=yes
+ elif [ $# -eq 2 ]; then
+ contents=`cat $TEST/$1`
+ if [ "$contents" != "$2" ]; then
+ echo "File $1 has wrong contents"
+ FAILED=yes
+ fi
+ elif [ $# -eq 3 ]; then
+ sum=`md5 -q $TEST/$1`
+ if [ "$sum" != "$3" ]; then
+ echo "File $1 has wrong contents"
+ FAILED=yes
+ 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"
+ FAILED=yes
+ elif [ $# -gt 1 ]; then
+ sum=`md5 -q $CONFLICTS/$1`
+ if [ "$sum" != "$2" ]; then
+ echo "Conflict $1 has wrong contents"
+ FAILED=yes
+ fi
+ fi
+}
+
+check_trees()
+{
+
+ echo "Checking tree for correct results:"
+
+ ## /equal/equal/equal:
+ fifo /equal/equal/equal/fifo
+ file /equal/equal/equal/file "foo"
+ dir /equal/equal/equal/dir
+ link /equal/equal/equal/link "bar"
+
+ ## /equal/first/first:
+ missing /equal/first/first/fifo
+ missing /equal/first/first/file
+ missing /equal/first/first/dir
+ missing /equal/first/first/link
+
+ ## /equal/difftype/difftype:
+ file /equal/difftype/difftype/fifo "bar"
+ link /equal/difftype/difftype/fromdir "test"
+
+ ## /equal/difflinks/difflinks:
+ link /equal/difflinks/difflinks/link "bar"
+
+ ## /equal/difffiles/difffiles:
+ file /equal/difffiles/difffiles/file "bar"
+
+ ## /first/equal/second:
+ missing /first/equal/second/fifo
+ missing /first/equal/second/file
+ missing /first/equal/second/emptydir
+ missing /first/equal/second/link
+ missing /first/equal/second/fulldir
+
+ ## /first/first/equal:
+ missing /first/first/equal/fifo
+ missing /first/first/equal/file
+ missing /first/first/equal/dir
+ missing /first/first/equal/link
+
+ ## /first/difftype/second:
+ present /first/difftype/second/fifo
+
+ ## /first/difflinks/second:
+ link /first/difflinks/second/link "test link"
+
+ ## /first/difffiles/second:
+ file /first/difffiles/second/file "bar"
+
+ ## /second/equal/first:
+ file /second/equal/first/file "bar"
+ fifo /second/equal/first/fifo
+ link /second/equal/first/link "new"
+ missing /second/equal/first/emptydir
+ file /second/equal/first/fulldir/file "foo"
+
+ ## /second/second/equal:
+ fifo /second/second/equal/fifo
+ file /second/second/equal/file "foo"
+ dir /second/second/equal/dir
+ link /second/second/equal/link "bar"
+
+ ## /second/second/difftype:
+ fifo /second/second/difftype/dir
+
+ ## /second/second/difflinks:
+ link /second/second/difflinks/link "test link"
+
+ ## /second/second/difffiles:
+ file /second/second/difffiles/file "test"
+ conflict /second/second/difffiles/file 4f2ee8620a251fd53f06bb6112eb6ffa
+
+ ## /difftype/equal/difftype:
+ link /difftype/equal/difftype/file "test"
+ fifo /difftype/equal/difftype/fromdir
+ missing /difftype/equal/difftype/todir
+
+ ## /difftype/first/first:
+ missing /difftype/first/first/fifo
+
+ ## /difftype/difftype/equal:
+ fifo /difftype/difftype/equal/fifo
+ file /difftype/difftype/equal/file "bar"
+
+ ## /difftype/difftype/difftype:
+ file /difftype/difftype/difftype/one "foo"
+ link /difftype/difftype/difftype/two "bar"
+
+ ## /difftype/difftype/difflinks:
+ link /difftype/difftype/difflinks/link "test"
+
+ ## /difftype/difftype/difffile:
+ conflict /difftype/difftype/difffiles/file \
+ 117f2bcd1f6491f6044e79e5a57a9229
+
+ ## /difflinks/equal/difflinks:
+ link /difflinks/equal/difflinks/link "new"
+
+ ## /difflinks/first/first:
+ missing /difflinks/first/first/link
+
+ ## /difflinks/difftype/difftype:
+ file /difflinks/difftype/difftype/link "test"
+
+ ## /difflinks/difflinks/equal:
+ link /difflinks/difflinks/equal/link "new"
+
+ ## /difflinks/difflinks/difflinks:
+ link /difflinks/difflinks/difflinks/link "test"
+
+ ## /difffiles/equal/difffiles:
+ file /difffiles/equal/difffiles/file "bar"
+
+ ## /difffiles/first/first:
+ missing /difffiles/first/first/file
+
+ ## /difffiles/difftype/difftype:
+ fifo /difffiles/difftype/difftype/file
+
+ ## /difffiles/difffiles/equal:
+ file /difffiles/difffiles/equal/file "bar"
+
+ ## /difffiles/difffiles/difffiles:
+ file /difffiles/difffiles/difffiles/simple "" \
+ cabc7e5e80b0946d79edd555e9648486
+ file /difffiles/difffiles/difffiles/conflict "this is a test file"
+ conflict /difffiles/difffiles/difffiles/conflict \
+ 8261cfdd89280c4a6c26e4ac86541fe9
+
+ ## /adddir/conflict:
+ file /adddir/conflict
+
+ ## /adddir/partial:
+ file /adddir/partial/file "foo"
+ fifo /adddir/partial/fifo
+
+ ## /rmdir/extra:
+ dir /rmdir/extra
+ file /rmdir/extra/localfile.txt "foo"
+
+ ## /rmdir/conflict:
+ dir /rmdir/conflict/difftype
+ present /rmdir/conflict
+
+ ## /rmdir/partial:
+ missing /rmdir/partial
+
+ ## /dirchange/already/fromdir:
+ file /dirchange/already/fromdir "bar"
+
+ ## /dirchange/already/todir:
+ file /dirchange/already/todir/somefile "blah"
+
+ ## /dirchange/old/fromdir:
+ file /dirchange/old/fromdir "bar"
+
+ ## /dirchange/old/todir
+ file /dirchange/old/todir/file "bar"
+
+ ## /dirchange/fromdir/extradir:
+ missing /dirchange/fromdir/extradir/file
+ fifo /dirchange/fromdir/extradir/fifo
+
+ ## /dirchange/fromdir/conflict:
+ file /dirchange/fromdir/conflict/somefile "bar"
+
+ ## /dirchange/todir/difffile:
+ file /dirchange/todir/difffile "bar"
+
+ ## /dirchange/todir/difftype:
+ fifo /dirchange/todir/difftype
+
+ ## Tests for post-install actions
+ file /etc/master.passwd
+ file /etc/passwd
+ file /etc/pwd.db
+ file /etc/spwd.db
+ file /etc/login.conf "" 7774a0f9a3a372c7c109c32fd31c4b6b
+ file /etc/login.conf.db
+ file /etc/mail/aliases "" 7d598f89ec040ab56af54011bdb83337
+ file /etc/services "" 37fb6a8d1273f3b78329d431f21d9c7d
+ file /var/db/services.db
+}
+
+if [ `id -u` -ne 0 ]; then
+ echo "must be root"
+ exit 0
+fi
+
+if [ -r /etc/etcupdate.conf ]; then
+ echo "WARNING: /etc/etcupdate.conf settings may break some tests."
+fi
+
+build_trees
+
+$COMMAND -nr -d $WORKDIR -D $TEST > $WORKDIR/testn.out
+
+cat > $WORKDIR/correct.out <<EOF
+ D /dirchange/fromdir/extradir/file
+ D /dirchange/old/fromdir/somefile
+ D /first/equal/second/fifo
+ D /first/equal/second/file
+ D /first/equal/second/fulldir/file
+ D /first/equal/second/link
+ D /rmdir/partial/subdir/fifo
+ D /rmdir/partial/subdir
+ D /rmdir/partial
+ D /first/equal/second/fulldir
+ D /first/equal/second/emptydir
+ C /difffiles/difffiles/difffiles/conflict
+ M /difffiles/difffiles/difffiles/simple
+ U /difffiles/equal/difffiles/file
+ U /difflinks/equal/difflinks/link
+ C /difftype/difftype/difffiles/file
+ U /difftype/equal/difftype/file
+ U /difftype/equal/difftype/fromdir
+ D /difftype/equal/difftype/todir
+ U /dirchange/old/fromdir
+ U /dirchange/old/todir
+ U /etc/login.conf
+ M /etc/mail/aliases
+ U /etc/services
+ A /adddir/partial/file
+ A /dirchange/old/todir/file
+ A /etc/master.passwd
+ A /second/equal/first/fifo
+ A /second/equal/first/file
+ A /second/equal/first/fulldir/file
+ A /second/equal/first/link
+ C /second/second/difffiles/file
+Warnings:
+ Modified regular file remains: /dirchange/fromdir/conflict/somefile
+ Modified regular file remains: /first/difffiles/second/file
+ Modified symbolic link remains: /first/difflinks/second/link
+ Modified directory remains: /first/difftype/second/fifo
+ Modified directory remains: /rmdir/conflict/difftype
+ Non-empty directory remains: /rmdir/extra
+ Non-empty directory remains: /rmdir/conflict
+ Modified mismatch: /difffiles/difftype/difftype/file (regular file vs fifo file)
+ Removed file changed: /difffiles/first/first/file
+ Modified link changed: /difflinks/difflinks/difflinks/link ("old" became "new")
+ Modified mismatch: /difflinks/difftype/difftype/link (symbolic link vs regular file)
+ Removed link changed: /difflinks/first/first/link ("old" became "new")
+ New link conflict: /difftype/difftype/difflinks/link ("new" vs "test")
+ Modified regular file changed: /difftype/difftype/difftype/one (fifo file became directory)
+ Modified symbolic link changed: /difftype/difftype/difftype/two (directory became regular file)
+ Remove mismatch: /difftype/first/first/fifo (fifo file became directory)
+ Modified directory changed: /dirchange/fromdir/conflict (directory became fifo file)
+ Modified directory changed: /dirchange/fromdir/extradir (directory became symbolic link)
+ Modified regular file changed: /dirchange/todir/difffile (regular file became directory)
+ Modified fifo file changed: /dirchange/todir/difftype (regular file became directory)
+ New file mismatch: /adddir/conflict (directory vs regular file)
+ Directory mismatch: $TEST/adddir/conflict (regular file)
+ Directory mismatch: $TEST/dirchange/todir/difffile (regular file)
+ Directory mismatch: $TEST/dirchange/todir/difftype (fifo file)
+ New link conflict: /second/second/difflinks/link ("new link" vs "test link")
+ New file mismatch: /second/second/difftype/dir (directory vs fifo file)
+ Needs update: /etc/mail/aliases.db (requires manual update via newaliases(1))
+EOF
+
+echo "Differences for -n:"
+diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/testn.out \
+ || failed=YES
+
+$COMMAND -r -d $WORKDIR -D $TEST > $WORKDIR/test.out
+
+echo "Differences for real:"
+diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out \
+ || failed=YES
+
+check_trees
+
+[ "${FAILED}" = no ]
diff --git a/usr.sbin/etcupdate/tests/tzsetup_test.sh b/usr.sbin/etcupdate/tests/tzsetup_test.sh
new file mode 100644
index 0000000..b102938
--- /dev/null
+++ b/usr.sbin/etcupdate/tests/tzsetup_test.sh
@@ -0,0 +1,239 @@
+#!/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$
+
+# Various regression tests for the tzsetup handling in the 'update' command.
+
+FAILED=no
+WORKDIR=work
+
+usage()
+{
+ echo "Usage: tzsetup.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
+OLD=$WORKDIR/old
+NEW=$WORKDIR/current
+TEST=$WORKDIR/test
+
+build_trees()
+{
+
+ # Build the base tree, but not /etc/localtime itself
+ local i j k
+
+ rm -rf $OLD $NEW $TEST $CONFLICTS
+ mkdir -p $OLD $NEW $TEST
+ mkdir -p $TEST/etc
+ mkdir -p $TEST/var/db
+ mkdir -p $TEST/usr/share/zoneinfo
+
+ # Create a dummy timezone file
+ echo "foo" > $TEST/usr/share/zoneinfo/foo
+
+}
+
+# $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"
+ FAILED=yes
+ fi
+}
+
+# $1 - relative path to file that should be a symlink in TEST
+# $2 - optional value of the link
+link()
+{
+ local val
+
+ if ! [ -L $TEST/$1 ]; then
+ echo "File $1 should be a link"
+ FAILED=yes
+ elif [ $# -gt 1 ]; then
+ val=`readlink $TEST/$1`
+ if [ "$val" != "$2" ]; then
+ echo "Link $1 should link to \"$2\""
+ FAILED=yes
+ fi
+ 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"
+ FAILED=yes
+ elif [ $# -eq 2 ]; then
+ contents=`cat $TEST/$1`
+ if [ "$contents" != "$2" ]; then
+ echo "File $1 has wrong contents"
+ FAILED=yes
+ fi
+ elif [ $# -eq 3 ]; then
+ sum=`md5 -q $TEST/$1`
+ if [ "$sum" != "$3" ]; then
+ echo "File $1 has wrong contents"
+ FAILED=yes
+ fi
+ fi
+}
+
+if [ `id -u` -ne 0 ]; then
+ echo "must be root"
+ exit 0
+fi
+
+if [ -r /etc/etcupdate.conf ]; then
+ echo "WARNING: /etc/etcupdate.conf settings may break some tests."
+fi
+
+# First, test for /etc/localtime not existing
+
+build_trees
+
+$COMMAND -nr -d $WORKDIR -D $TEST > $WORKDIR/testn.out
+
+cat > $WORKDIR/correct.out <<EOF
+EOF
+
+echo "Differences for no /etc/localtime with -n:"
+diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/testn.out \
+ || FAILED=yes
+
+$COMMAND -r -d $WORKDIR -D $TEST > $WORKDIR/test.out
+
+echo "Differences for no /etc/localtime:"
+diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out \
+ || FAILED=yes
+
+missing /etc/localtime
+missing /var/db/zoneinfo
+
+# Second, test for /etc/localtime being a symlink
+
+build_trees
+ln -s /dev/null $TEST/etc/localtime
+
+$COMMAND -nr -d $WORKDIR -D $TEST > $WORKDIR/testn.out
+
+cat > $WORKDIR/correct.out <<EOF
+EOF
+
+echo "Differences for symlinked /etc/localtime with -n:"
+diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/testn.out \
+ || FAILED=yes
+
+$COMMAND -r -d $WORKDIR -D $TEST > $WORKDIR/test.out
+
+echo "Differences for symlinked /etc/localtime:"
+diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out \
+ || FAILED=yes
+
+link /etc/localtime "/dev/null"
+missing /var/db/zoneinfo
+
+# Third, test for /etc/localtime as a file and a missing /var/db/zoneinfo
+
+build_trees
+echo "bar" > $TEST/etc/localtime
+
+$COMMAND -nr -d $WORKDIR -D $TEST > $WORKDIR/testn.out
+
+cat > $WORKDIR/correct.out <<EOF
+Warnings:
+ Needs update: /etc/localtime (required manual update via tzsetup(1))
+EOF
+
+echo "Differences for missing /var/db/zoneinfo with -n:"
+diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/testn.out \
+ || FAILED=yes
+
+$COMMAND -r -d $WORKDIR -D $TEST > $WORKDIR/test.out
+
+echo "Differences for missing /var/db/zoneinfo:"
+diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out \
+ || FAILED=yes
+
+file /etc/localtime "bar"
+missing /var/db/zoneinfo
+
+# Finally, test the case where it should update /etc/localtime
+
+build_trees
+echo "bar" > $TEST/etc/localtime
+echo "foo" > $TEST/var/db/zoneinfo
+
+$COMMAND -nr -d $WORKDIR -D $TEST > $WORKDIR/testn.out
+
+cat > $WORKDIR/correct.out <<EOF
+EOF
+
+echo "Differences for real update with -n:"
+diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/testn.out \
+ || FAILED=yes
+
+$COMMAND -r -d $WORKDIR -D $TEST > $WORKDIR/test.out
+
+echo "Differences for real update:"
+diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out \
+ || FAILED=yes
+
+file /etc/localtime "foo"
+file /var/db/zoneinfo "foo"
+
+[ "${FAILED}" = no ]
diff --git a/usr.sbin/newsyslog/Makefile b/usr.sbin/newsyslog/Makefile
index ebc297b..4e3ae55 100644
--- a/usr.sbin/newsyslog/Makefile
+++ b/usr.sbin/newsyslog/Makefile
@@ -1,7 +1,13 @@
# $FreeBSD$
+.include <bsd.own.mk>
+
PROG= newsyslog
MAN= newsyslog.8 newsyslog.conf.5
SRCS= newsyslog.c ptimes.c
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
.include <bsd.prog.mk>
diff --git a/usr.sbin/newsyslog/tests/Makefile b/usr.sbin/newsyslog/tests/Makefile
new file mode 100644
index 0000000..f8ad273
--- /dev/null
+++ b/usr.sbin/newsyslog/tests/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/usr.sbin/newsyslog
+
+TAP_TESTS_SH= legacy_test
+
+.include <bsd.test.mk>
diff --git a/usr.sbin/newsyslog/tests/legacy_test.sh b/usr.sbin/newsyslog/tests/legacy_test.sh
new file mode 100644
index 0000000..ba10f2c
--- /dev/null
+++ b/usr.sbin/newsyslog/tests/legacy_test.sh
@@ -0,0 +1,444 @@
+#!/bin/sh
+
+# $FreeBSD$
+
+COUNT=0
+TMPDIR=$(pwd)/work
+if [ $? -ne 0 ]; then
+ echo "$0: Can't create temp dir, exiting..."
+ exit 1
+fi
+
+# Begin an individual test
+begin()
+{
+ COUNT=`expr $COUNT + 1`
+ OK=1
+ NAME="$1"
+}
+
+# End an individual test
+end()
+{
+ if [ $OK = 1 ]
+ then
+ printf 'ok '
+ else
+ printf 'not ok '
+ fi
+ echo "$COUNT - $NAME"
+}
+
+# Make a file that can later be verified
+mkf()
+{
+ CN=`basename $1`
+ echo "$CN-$CN" >$1
+}
+
+# Verify that the file specified is correct
+ckf()
+{
+ if [ -f $2 ] && echo "$1-$1" | diff - $2 >/dev/null
+ then
+ ok
+ else
+ notok
+ fi
+}
+
+# Check that a file exists
+ckfe()
+{
+ if [ -f $1 ]
+ then
+ ok
+ else
+ notok
+ fi
+}
+
+# Verify that the specified file does not exist
+# (is not there)
+cknt()
+{
+ if [ -r $1 ]
+ then
+ notok
+ else
+ ok
+ fi
+}
+
+# Check if a file is there, depending of if it's supposed to or not -
+# basically how many log files we are supposed to keep vs. how many we
+# actually keep.
+ckntfe()
+{
+ curcnt=$1
+ keepcnt=$2
+ f=$3
+
+ if [ $curcnt -le $keepcnt ]
+ then
+ #echo Assuming file there
+ ckfe $f
+ else
+ #echo Assuming file NOT there
+ cknt $f
+ fi
+}
+
+
+
+# A part of a test succeeds
+ok()
+{
+ :
+}
+
+# A part of a test fails
+notok()
+{
+ OK=0
+}
+
+# Verify that the exit code passed is for unsuccessful termination
+ckfail()
+{
+ if [ $1 -gt 0 ]
+ then
+ ok
+ else
+ notok
+ fi
+}
+
+# Verify that the exit code passed is for successful termination
+ckok()
+{
+ if [ $1 -eq 0 ]
+ then
+ ok
+ else
+ notok
+ fi
+}
+
+# Check that there are X files which match expr
+chkfcnt()
+{
+ cnt=$1; shift
+ if [ $cnt -eq `echo "$@" | wc -w` ]
+ then
+ ok
+ else
+ notok
+ fi
+}
+
+# Check that two strings are alike
+ckstr()
+{
+ if [ "$1" = "$2" ]
+ then
+ ok
+ else
+ notok
+ fi
+}
+
+tmpdir_create()
+{
+ mkdir -p ${TMPDIR}/log ${TMPDIR}/alog
+ cd ${TMPDIR}/log
+}
+
+tmpdir_clean()
+{
+ cd ${TMPDIR}
+ rm -rf "${TMPDIR}/log" "${TMPDIR}/alog" newsyslog.conf
+}
+
+run_newsyslog()
+{
+
+ newsyslog -f ../newsyslog.conf -F -r "$@"
+}
+
+tests_normal_rotate() {
+ ext="$1"
+ dir="$2"
+
+ if [ -n "$dir" ]; then
+ newsyslog_args=" -a ${dir}"
+ name_postfix="${ext} archive dir"
+ else
+ newsyslog_args=""
+ name_postfix="${ext}"
+ fi
+
+ tmpdir_create
+
+ begin "create file ${name_postfix}" -newdir
+ run_newsyslog -C
+ ckfe $LOGFNAME
+ cknt ${dir}${LOGFNAME}.0${ext}
+ end
+
+ begin "rotate normal 1 ${name_postfix}"
+ run_newsyslog $newsyslog_args
+ ckfe ${LOGFNAME}
+ ckfe ${dir}${LOGFNAME}.0${ext}
+ cknt ${dir}${LOGFNAME}.1${ext}
+ end
+
+ begin "rotate normal 2 ${name_postfix}"
+ run_newsyslog $newsyslog_args
+ ckfe ${LOGFNAME}
+ ckfe ${dir}${LOGFNAME}.0${ext}
+ ckfe ${dir}${LOGFNAME}.1${ext}
+ cknt ${dir}${LOGFNAME}.2${ext}
+ end
+
+ begin "rotate normal 3 ${name_postfix}"
+ run_newsyslog $newsyslog_args
+ ckfe ${LOGFNAME}
+ ckfe ${dir}${LOGFNAME}.0${ext}
+ ckfe ${dir}${LOGFNAME}.1${ext}
+ ckfe ${dir}${LOGFNAME}.2${ext}
+ cknt ${dir}${LOGFNAME}.3${ext}
+ end
+
+ begin "rotate normal 4 ${name_postfix}"
+ run_newsyslog $newsyslog_args
+ ckfe ${LOGFNAME}
+ ckfe ${dir}${LOGFNAME}.0${ext}
+ ckfe ${dir}${LOGFNAME}.1${ext}
+ ckfe ${dir}${LOGFNAME}.2${ext}
+ cknt ${dir}${LOGFNAME}.4${ext}
+ end
+
+ begin "rotate normal 5 ${name_postfix}"
+ run_newsyslog $newsyslog_args
+ ckfe ${LOGFNAME}
+ ckfe ${dir}${LOGFNAME}.0${ext}
+ ckfe ${dir}${LOGFNAME}.1${ext}
+ ckfe ${dir}${LOGFNAME}.2${ext}
+ cknt ${dir}${LOGFNAME}.4${ext}
+ end
+
+ # Wait a bit so we can see if the noaction test rotates files
+ sleep 1.1
+
+ begin "noaction ${name_postfix}"
+ ofiles=`ls -Tl ${dir}${LOGFNAME}.*${ext} | tr -d '\n'`
+ run_newsyslog ${newsyslog_args} -n >/dev/null
+ ckfe ${LOGFNAME}
+ ckstr "$ofiles" "`ls -lT ${dir}${LOGFNAME}.*${ext} | tr -d '\n'`"
+ end
+
+ tmpdir_clean
+}
+
+tests_normal_rotate_keepn() {
+ cnt="$1"
+ ext="$2"
+ dir="$3"
+
+ if [ -n "$dir" ]; then
+ newsyslog_args=" -a ${dir}"
+ name_postfix="${ext} archive dir"
+ else
+ newsyslog_args=""
+ name_postfix="${ext}"
+ fi
+
+ tmpdir_create
+
+ begin "create file ${name_postfix}" -newdir
+ run_newsyslog -C
+ ckfe $LOGFNAME
+ cknt ${dir}${LOGFNAME}.0${ext}
+ end
+
+ begin "rotate normal 1 cnt=$cnt ${name_postfix}"
+ run_newsyslog $newsyslog_args
+ ckfe ${LOGFNAME}
+ ckntfe 1 $cnt ${dir}${LOGFNAME}.0${ext}
+ cknt ${dir}${LOGFNAME}.1${ext}
+ end
+
+ begin "rotate normal 2 cnt=$cnt ${name_postfix}"
+ run_newsyslog $newsyslog_args
+ ckfe ${LOGFNAME}
+ ckntfe 1 $cnt ${dir}${LOGFNAME}.0${ext}
+ ckntfe 2 $cnt ${dir}${LOGFNAME}.1${ext}
+ cknt ${dir}${LOGFNAME}.2${ext}
+ end
+
+ begin "rotate normal 3 cnt=$cnt ${name_postfix}"
+ run_newsyslog $newsyslog_args
+ ckfe ${LOGFNAME}
+ ckntfe 1 $cnt ${dir}${LOGFNAME}.0${ext}
+ ckntfe 2 $cnt ${dir}${LOGFNAME}.1${ext}
+ ckntfe 3 $cnt ${dir}${LOGFNAME}.2${ext}
+ cknt ${dir}${LOGFNAME}.3${ext}
+ end
+
+ begin "rotate normal 3 cnt=$cnt ${name_postfix}"
+ run_newsyslog $newsyslog_args
+ ckfe ${LOGFNAME}
+ ckntfe 1 $cnt ${dir}${LOGFNAME}.0${ext}
+ ckntfe 2 $cnt ${dir}${LOGFNAME}.1${ext}
+ ckntfe 3 $cnt ${dir}${LOGFNAME}.2${ext}
+ ckntfe 4 $cnt ${dir}${LOGFNAME}.3${ext}
+ cknt ${dir}${LOGFNAME}.4${ext}
+ end
+
+ # Wait a bit so we can see if the noaction test rotates files
+ sleep 1.1
+
+ begin "noaction ${name_postfix}"
+ osum=`md5 ${dir}${LOGFNAME} | tr -d '\n'`
+ run_newsyslog ${newsyslog_args} -n >/dev/null
+ ckfe ${LOGFNAME}
+ ckstr "$osum" "`md5 ${dir}${LOGFNAME} | tr -d '\n'`"
+ end
+
+ tmpdir_clean
+}
+
+tests_time_rotate() {
+ ext="$1"
+ dir="$2"
+
+ if [ -n "$dir" ]; then
+ newsyslog_args="-t DEFAULT -a ${dir}"
+ name_postfix="${ext} archive dir"
+ else
+ newsyslog_args="-t DEFAULT"
+ name_postfix="${ext}"
+ fi
+
+ tmpdir_create
+
+ begin "create file ${name_postfix}" -newdir
+ run_newsyslog -C ${newsyslog_args}
+ ckfe ${LOGFNAME}
+ end
+
+ begin "rotate time 1 ${name_postfix}"
+ run_newsyslog ${newsyslog_args}
+ ckfe ${LOGFNAME}
+ chkfcnt 1 ${dir}${LOGFNAME}.*${ext}
+ end
+
+ sleep 1.1
+
+ begin "rotate time 2 ${name_postfix}"
+ run_newsyslog ${newsyslog_args}
+ ckfe ${LOGFNAME}
+ chkfcnt 2 ${dir}${LOGFNAME}.*${ext}
+ end
+
+ sleep 1.1
+
+ begin "rotate time 3 ${name_postfix}"
+ run_newsyslog ${newsyslog_args}
+ ckfe ${LOGFNAME}
+ chkfcnt 3 ${dir}${LOGFNAME}.*${ext}
+ end
+
+ sleep 1.1
+
+ begin "rotate time 4 ${name_postfix}"
+ run_newsyslog ${newsyslog_args}
+ ckfe ${LOGFNAME}
+ chkfcnt 3 ${dir}${LOGFNAME}.*${ext}
+ end
+
+ begin "noaction ${name_postfix}"
+ ofiles=`ls -1 ${dir}${LOGFNAME}.*${ext} | tr -d '\n'`
+ run_newsyslog ${newsyslog_args} -n >/dev/null
+ ckfe ${LOGFNAME}
+ ckstr "$ofiles" "`ls -1 ${dir}${LOGFNAME}.*${ext} | tr -d '\n'`"
+ end
+
+ tmpdir_clean
+}
+
+echo 1..126
+mkdir -p ${TMPDIR}
+cd ${TMPDIR}
+
+LOGFNAME=foo.log
+LOGFPATH=${TMPDIR}/log/${LOGFNAME}
+
+# Normal, no archive dir, keep X files
+echo "$LOGFPATH 640 0 * @T00 NC" > newsyslog.conf
+tests_normal_rotate_keepn 0
+
+echo "$LOGFPATH 640 1 * @T00 NC" > newsyslog.conf
+tests_normal_rotate_keepn 1
+
+echo "$LOGFPATH 640 2 * @T00 NC" > newsyslog.conf
+tests_normal_rotate_keepn 2
+
+echo "$LOGFPATH 640 3 * @T00 NC" > newsyslog.conf
+tests_normal_rotate_keepn 3
+
+# Normal, no archive dir, keep X files, gz
+echo "$LOGFPATH 640 0 * @T00 NCZ" > newsyslog.conf
+tests_normal_rotate_keepn 0 ".gz"
+
+echo "$LOGFPATH 640 1 * @T00 NCZ" > newsyslog.conf
+tests_normal_rotate_keepn 1 ".gz"
+
+echo "$LOGFPATH 640 2 * @T00 NCZ" > newsyslog.conf
+tests_normal_rotate_keepn 2 ".gz"
+
+echo "$LOGFPATH 640 3 * @T00 NCZ" > newsyslog.conf
+tests_normal_rotate_keepn 3 ".gz"
+
+# Normal, no archive dir
+echo "$LOGFPATH 640 3 * @T00 NC" > newsyslog.conf
+tests_normal_rotate
+
+echo "$LOGFPATH 640 3 * @T00 NCZ" > newsyslog.conf
+tests_normal_rotate ".gz"
+
+echo "$LOGFPATH 640 3 * @T00 NCJ" > newsyslog.conf
+tests_normal_rotate ".bz2"
+
+# Normal, archive dir
+echo "$LOGFPATH 640 3 * @T00 NC" > newsyslog.conf
+tests_normal_rotate "" "${TMPDIR}/alog/"
+
+echo "$LOGFPATH 640 3 * @T00 NCZ" > newsyslog.conf
+tests_normal_rotate ".gz" "${TMPDIR}/alog/"
+
+echo "$LOGFPATH 640 3 * @T00 NCJ" > newsyslog.conf
+tests_normal_rotate ".bz2" "${TMPDIR}/alog/"
+
+# Time based, no archive dir
+echo "$LOGFPATH 640 3 * @T00 NC" > newsyslog.conf
+tests_time_rotate
+
+echo "$LOGFPATH 640 3 * @T00 NCZ" > newsyslog.conf
+tests_time_rotate "gz" ""
+
+echo "$LOGFPATH 640 3 * @T00 NCJ" > newsyslog.conf
+tests_time_rotate "bz2" ""
+
+# Time based, archive dir
+echo "$LOGFPATH 640 3 * @T00 NC" > newsyslog.conf
+tests_time_rotate "" "${TMPDIR}/alog/"
+
+echo "$LOGFPATH 640 3 * @T00 NCZ" > newsyslog.conf
+tests_time_rotate "gz" "${TMPDIR}/alog/"
+
+echo "$LOGFPATH 640 3 * @T00 NCJ" > newsyslog.conf
+tests_time_rotate "bz2" "${TMPDIR}/alog/"
+
+rm -rf "${TMPDIR}"
diff --git a/usr.sbin/sa/Makefile b/usr.sbin/sa/Makefile
index 0adf1f8..23f9bf2 100644
--- a/usr.sbin/sa/Makefile
+++ b/usr.sbin/sa/Makefile
@@ -1,9 +1,15 @@
# $FreeBSD$
+.include <bsd.own.mk>
+
.PATH: ${.CURDIR}/../../usr.bin/lastcomm
PROG= sa
MAN= sa.8
SRCS= main.c db.c pdb.c usrdb.c readrec.c
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
.include <bsd.prog.mk>
diff --git a/usr.sbin/sa/tests/Makefile b/usr.sbin/sa/tests/Makefile
new file mode 100644
index 0000000..204b510
--- /dev/null
+++ b/usr.sbin/sa/tests/Makefile
@@ -0,0 +1,33 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/usr.sbin/sa
+
+TAP_TESTS_SH= legacy_test
+
+FILESDIR= ${TESTSDIR}
+FILES= v1-amd64-sav.in
+FILES+= v1-amd64-sav.out
+FILES+= v1-amd64-u.out
+FILES+= v1-amd64-usr.in
+FILES+= v1-amd64-usr.out
+FILES+= v1-i386-sav.in
+FILES+= v1-i386-sav.out
+FILES+= v1-i386-u.out
+FILES+= v1-i386-usr.in
+FILES+= v1-i386-usr.out
+FILES+= v1-sparc64-sav.in
+FILES+= v1-sparc64-sav.out
+FILES+= v1-sparc64-u.out
+FILES+= v1-sparc64-usr.in
+FILES+= v1-sparc64-usr.out
+FILES+= v2-amd64-sav.in
+FILES+= v2-amd64-u.out
+FILES+= v2-amd64-usr.in
+FILES+= v2-i386-sav.in
+FILES+= v2-i386-u.out
+FILES+= v2-i386-usr.in
+FILES+= v2-sparc64-sav.in
+FILES+= v2-sparc64-u.out
+FILES+= v2-sparc64-usr.in
+
+.include <bsd.test.mk>
diff --git a/usr.sbin/sa/tests/legacy_test.sh b/usr.sbin/sa/tests/legacy_test.sh
new file mode 100644
index 0000000..d0d8f42
--- /dev/null
+++ b/usr.sbin/sa/tests/legacy_test.sh
@@ -0,0 +1,78 @@
+#!/bin/sh
+#
+# $FreeBSD$
+#
+
+DIR=`dirname $0`
+LCDIR=`dirname $0`/../../usr.bin/lastcomm
+ARCH=`uname -m`
+
+collapse_whitespace()
+{
+ sed -E 's,[ ]+, ,g'
+}
+
+check()
+{
+ NUM=$1
+ shift
+ collapse_whitespace | \
+ if diff -q - $1
+ then
+ echo "ok $NUM"
+ else
+ echo "not ok $NUM"
+ fi
+}
+
+install -c -m 644 $LCDIR/v1-$ARCH-acct.in v1-$ARCH-acct.in
+install -c -m 644 $LCDIR/v2-$ARCH-acct.in v2-$ARCH-acct.in
+
+echo 1..13
+
+# Command listings of the two acct versions
+sa -u v1-$ARCH-acct.in | check 1 $DIR/v1-$ARCH-u.out
+sa -u v2-$ARCH-acct.in | check 2 $DIR/v2-$ARCH-u.out
+
+# Plain summaries of user/process
+sa -i v1-$ARCH-acct.in | check 3 $DIR/v1-$ARCH-sav.out
+sa -im v1-$ARCH-acct.in | check 4 $DIR/v1-$ARCH-usr.out
+
+# Backward compatibility of v1 summary files
+sa -P $DIR/v1-$ARCH-sav.in -U $DIR/v1-$ARCH-usr.in /dev/null |
+ check 5 $DIR/v1-$ARCH-sav.out
+sa -m -P $DIR/v1-$ARCH-sav.in -U $DIR/v1-$ARCH-usr.in /dev/null |
+ check 6 $DIR/v1-$ARCH-usr.out
+
+# Convert old summary format to new
+install -c -m 644 $DIR/v1-$ARCH-sav.in v2c-$ARCH-sav.in
+install -c -m 644 $DIR/v1-$ARCH-usr.in v2c-$ARCH-usr.in
+sa -s -P v2c-$ARCH-sav.in -U v2c-$ARCH-usr.in /dev/null >/dev/null
+sa -P v2c-$ARCH-sav.in -U v2c-$ARCH-usr.in /dev/null |
+ check 7 $DIR/v1-$ARCH-sav.out
+sa -m -P v2c-$ARCH-sav.in -U v2c-$ARCH-usr.in /dev/null |
+ check 8 $DIR/v1-$ARCH-usr.out
+
+# Reading v2 summary files
+sa -P $DIR/v2-$ARCH-sav.in -U $DIR/v2-$ARCH-usr.in /dev/null |
+ check 9 $DIR/v1-$ARCH-sav.out
+sa -m -P $DIR/v2-$ARCH-sav.in -U $DIR/v2-$ARCH-usr.in /dev/null |
+ check 10 $DIR/v1-$ARCH-usr.out
+
+# Summarize
+sa -is -P v2c-$ARCH-sav.in -U v2c-$ARCH-usr.in v1-$ARCH-acct.in >/dev/null
+sa -P v2c-$ARCH-sav.in -U v2c-$ARCH-usr.in /dev/null |
+ check 11 $DIR/v1-$ARCH-sav.out
+sa -m -P v2c-$ARCH-sav.in -U v2c-$ARCH-usr.in /dev/null |
+ check 12 $DIR/v1-$ARCH-usr.out
+
+# Accumulate
+install -c -m 644 $LCDIR/v1-$ARCH-acct.in v1-$ARCH-acct.in
+sa -is -P v2c-$ARCH-sav.in -U v2c-$ARCH-usr.in v1-$ARCH-acct.in >/dev/null
+install -c -m 644 $LCDIR/v1-$ARCH-acct.in v1-$ARCH-acct.in
+sa -s -P v2c-$ARCH-sav.in -U v2c-$ARCH-usr.in v1-$ARCH-acct.in \
+ | collapse_whitespace >double
+cp $LCDIR/v1-$ARCH-acct.in v1-$ARCH-acct.in
+sa -i v1-$ARCH-acct.in v1-$ARCH-acct.in | check 13 double
+
+exit 0
diff --git a/usr.sbin/sa/tests/prime.sh b/usr.sbin/sa/tests/prime.sh
new file mode 100755
index 0000000..6992f45
--- /dev/null
+++ b/usr.sbin/sa/tests/prime.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+#
+# Configure and run this script to create the files for regression testing
+# for a new architecture/configuration.
+#
+# $FreeBSD$
+#
+
+TZ=UTC; export TZ
+
+# Set this to the path of the current sa command
+SANEW=/usr/sbin/sa
+
+# Set this to the path of the sa as of 2007-05-19.
+# You can obtain it with a command like:
+# cvs co -D '2007-05-19' sa
+# To compile it you will also need sys/acct.h from that date
+# and sa configured to use that file, instead of the current version.
+SAOLD=/$HOME/src/sa/sa
+
+# Machine architecture
+ARCH=`uname -m`
+
+# Location of lastcomm regression files
+LCDIR=../../usr.bin/lastcomm
+
+$SANEW -u $LCDIR/v1-$ARCH-acct.in >v1-$ARCH-u.out
+$SANEW -u $LCDIR/v2-$ARCH-acct.in >v2-$ARCH-u.out
+$SANEW -i $LCDIR/v1-$ARCH-acct.in >v1-$ARCH-sav.out
+$SANEW -im $LCDIR/v1-$ARCH-acct.in >v1-$ARCH-usr.out
+cp $LCDIR/v1-$ARCH-acct.in acct.in
+rm -f v1-$ARCH-sav.in v1-$ARCH-usr.in
+$SAOLD -s -P v1-$ARCH-sav.in -U v1-$ARCH-usr.in acct.in >/dev/null
+cp $LCDIR/v1-$ARCH-acct.in acct.in
+rm -f v2-$ARCH-sav.in v2-$ARCH-usr.in
+$SANEW -s -P v2-$ARCH-sav.in -U v2-$ARCH-usr.in acct.in >/dev/null
+rm acct.in
diff --git a/usr.sbin/sa/tests/v1-amd64-sav.in b/usr.sbin/sa/tests/v1-amd64-sav.in
new file mode 100644
index 0000000..adc38dd
--- /dev/null
+++ b/usr.sbin/sa/tests/v1-amd64-sav.in
Binary files differ
diff --git a/usr.sbin/sa/tests/v1-amd64-sav.out b/usr.sbin/sa/tests/v1-amd64-sav.out
new file mode 100644
index 0000000..a2289ee
--- /dev/null
+++ b/usr.sbin/sa/tests/v1-amd64-sav.out
@@ -0,0 +1,5 @@
+ 28 0.282re 0.06cp 40avio 957k
+ 13 0.141re 0.06cp 87avio 903k ***other
+ 3 0.000re 0.00cp 0avio 0k ln
+ 9 0.141re 0.00cp 0avio 19700k time
+ 3 0.000re 0.00cp 0avio 0k time*
diff --git a/usr.sbin/sa/tests/v1-amd64-u.out b/usr.sbin/sa/tests/v1-amd64-u.out
new file mode 100644
index 0000000..4c13b76
--- /dev/null
+++ b/usr.sbin/sa/tests/v1-amd64-u.out
@@ -0,0 +1,28 @@
+ 0 0.000 cpu 0k mem 0 io accton
+ 0 0.172 cpu 41k mem 0 io awk
+ 0 0.000 cpu 140k mem 0 io time
+ 0 3.031 cpu 45k mem 1 io egrep
+ 0 0.000 cpu 0k mem 0 io time
+ 0 0.250 cpu 42k mem 1087 io find
+ 0 0.000 cpu 0k mem 0 io time
+ 0 0.000 cpu 0k mem 0 io sleep
+ 0 0.000 cpu 57k mem 0 io time
+ 0 0.016 cpu 31k mem 16 io dd
+ 0 0.000 cpu 0k mem 0 io time
+ 0 0.203 cpu 1976k mem 0 io diff
+ 0 0.000 cpu 0k mem 0 io time
+ 0 0.000 cpu 0k mem 0 io ln
+ 0 0.000 cpu 0k mem 0 io time*
+ 0 0.000 cpu 0k mem 0 io time
+ 0 0.000 cpu 0k mem 0 io ln
+ 0 0.000 cpu 0k mem 0 io time*
+ 0 0.000 cpu 0k mem 0 io time
+ 0 0.000 cpu 0k mem 0 io ln
+ 0 0.000 cpu 0k mem 0 io time*
+ 0 0.000 cpu 0k mem 0 io time
+ 0 0.000 cpu 713k mem 0 io cc1
+ 0 0.000 cpu 0k mem 0 io as
+ 0 0.000 cpu 228k mem 1 io ld
+ 0 0.000 cpu 196k mem 9 io cc
+ 0 0.000 cpu 45k mem 7 io core
+ 0 0.000 cpu 0k mem 9 io core*
diff --git a/usr.sbin/sa/tests/v1-amd64-usr.in b/usr.sbin/sa/tests/v1-amd64-usr.in
new file mode 100644
index 0000000..6896d32
--- /dev/null
+++ b/usr.sbin/sa/tests/v1-amd64-usr.in
Binary files differ
diff --git a/usr.sbin/sa/tests/v1-amd64-usr.out b/usr.sbin/sa/tests/v1-amd64-usr.out
new file mode 100644
index 0000000..2282808
--- /dev/null
+++ b/usr.sbin/sa/tests/v1-amd64-usr.out
@@ -0,0 +1 @@
+root 28 0.06cpu 1130tio 3514k*sec
diff --git a/usr.sbin/sa/tests/v1-i386-sav.in b/usr.sbin/sa/tests/v1-i386-sav.in
new file mode 100644
index 0000000..4ed7aef
--- /dev/null
+++ b/usr.sbin/sa/tests/v1-i386-sav.in
Binary files differ
diff --git a/usr.sbin/sa/tests/v1-i386-sav.out b/usr.sbin/sa/tests/v1-i386-sav.out
new file mode 100644
index 0000000..a8d68b1
--- /dev/null
+++ b/usr.sbin/sa/tests/v1-i386-sav.out
@@ -0,0 +1,5 @@
+ 28 0.425re 0.10cp 143avio 477k
+ 14 0.220re 0.10cp 286avio 411k ***other
+ 2 0.000re 0.00cp 0avio 0k 1234567890123456
+ 3 0.000re 0.00cp 0avio 0k ln
+ 9 0.205re 0.00cp 0avio 40400k time
diff --git a/usr.sbin/sa/tests/v1-i386-u.out b/usr.sbin/sa/tests/v1-i386-u.out
new file mode 100644
index 0000000..17c28be
--- /dev/null
+++ b/usr.sbin/sa/tests/v1-i386-u.out
@@ -0,0 +1,28 @@
+ 0 0.000 cpu 264k mem 0 io accton
+ 0 0.453 cpu 41k mem 0 io awk
+ 0 0.000 cpu 0k mem 0 io time
+ 0 4.984 cpu 41k mem 28 io egrep
+ 0 0.000 cpu 140k mem 0 io time
+ 0 0.266 cpu 36k mem 3921 io find
+ 0 0.000 cpu 0k mem 0 io time
+ 0 0.000 cpu 0k mem 0 io sleep
+ 0 0.000 cpu 0k mem 0 io time
+ 0 0.016 cpu 25k mem 16 io dd
+ 0 0.000 cpu 0k mem 0 io time
+ 0 0.312 cpu 1361k mem 0 io diff
+ 0 0.000 cpu 0k mem 0 io time
+ 0 0.000 cpu 0k mem 0 io ln
+ 0 0.000 cpu 0k mem 0 io 123456789012345
+ 0 0.000 cpu 0k mem 0 io time
+ 0 0.000 cpu 0k mem 0 io ln
+ 0 0.000 cpu 0k mem 0 io 1234567890123456
+ 0 0.000 cpu 264k mem 0 io time
+ 0 0.000 cpu 0k mem 0 io ln
+ 0 0.000 cpu 0k mem 0 io 1234567890123456
+ 0 0.000 cpu 0k mem 0 io time
+ 0 0.016 cpu 233k mem 1 io cc1
+ 0 0.000 cpu 482k mem 1 io as
+ 0 0.000 cpu 0k mem 11 io ld
+ 0 0.000 cpu 0k mem 6 io cc
+ 0 0.000 cpu 0k mem 12 io core
+ 0 0.000 cpu 0k mem 7 io core*
diff --git a/usr.sbin/sa/tests/v1-i386-usr.in b/usr.sbin/sa/tests/v1-i386-usr.in
new file mode 100644
index 0000000..791b6ed
--- /dev/null
+++ b/usr.sbin/sa/tests/v1-i386-usr.in
Binary files differ
diff --git a/usr.sbin/sa/tests/v1-i386-usr.out b/usr.sbin/sa/tests/v1-i386-usr.out
new file mode 100644
index 0000000..cf9e7bd
--- /dev/null
+++ b/usr.sbin/sa/tests/v1-i386-usr.out
@@ -0,0 +1 @@
+root 28 0.10cpu 4003tio 2887k*sec
diff --git a/usr.sbin/sa/tests/v1-sparc64-sav.in b/usr.sbin/sa/tests/v1-sparc64-sav.in
new file mode 100644
index 0000000..d6911cf
--- /dev/null
+++ b/usr.sbin/sa/tests/v1-sparc64-sav.in
Binary files differ
diff --git a/usr.sbin/sa/tests/v1-sparc64-sav.out b/usr.sbin/sa/tests/v1-sparc64-sav.out
new file mode 100644
index 0000000..1905420
--- /dev/null
+++ b/usr.sbin/sa/tests/v1-sparc64-sav.out
@@ -0,0 +1,5 @@
+ 28 1.839re 0.66cp 161avio 252k
+ 14 0.930re 0.66cp 322avio 197k ***other
+ 9 0.908re 0.00cp 0avio 10190k time
+ 3 0.001re 0.00cp 0avio 16256k ln
+ 2 0.001re 0.00cp 0avio 27900k 1234567890123456
diff --git a/usr.sbin/sa/tests/v1-sparc64-u.out b/usr.sbin/sa/tests/v1-sparc64-u.out
new file mode 100644
index 0000000..d0ecb51
--- /dev/null
+++ b/usr.sbin/sa/tests/v1-sparc64-u.out
@@ -0,0 +1,28 @@
+ 0 0.016 cpu 162k mem 0 io accton
+ 0 1.609 cpu 273k mem 0 io awk
+ 0 0.016 cpu 174k mem 0 io time
+ 0 29.750 cpu 233k mem 26 io egrep
+ 0 0.016 cpu 161k mem 0 io time
+ 0 5.516 cpu 184k mem 4437 io find
+ 0 0.016 cpu 156k mem 0 io time
+ 0 0.000 cpu 136k mem 0 io sleep
+ 0 0.016 cpu 152k mem 0 io time
+ 0 0.562 cpu 161k mem 16 io dd
+ 0 0.016 cpu 156k mem 0 io time
+ 0 1.641 cpu 193k mem 0 io diff
+ 0 0.016 cpu 156k mem 0 io time
+ 0 0.000 cpu 169k mem 0 io ln
+ 0 0.000 cpu 144k mem 0 io 123456789012345
+ 0 0.016 cpu 166k mem 0 io time
+ 0 0.016 cpu 170k mem 0 io ln
+ 0 0.000 cpu 144k mem 0 io 1234567890123456
+ 0 0.016 cpu 156k mem 0 io time
+ 0 0.016 cpu 169k mem 0 io ln
+ 0 0.000 cpu 135k mem 0 io 1234567890123456
+ 0 0.016 cpu 156k mem 0 io time
+ 0 0.094 cpu 3462k mem 2 io cc1
+ 0 0.016 cpu 1047k mem 1 io as
+ 0 0.094 cpu 1118k mem 10 io ld
+ 0 0.016 cpu 361k mem 5 io cc
+ 0 0.031 cpu 165k mem 7 io core
+ 0 0.000 cpu 112k mem 4 io core*
diff --git a/usr.sbin/sa/tests/v1-sparc64-usr.in b/usr.sbin/sa/tests/v1-sparc64-usr.in
new file mode 100644
index 0000000..08d795b
--- /dev/null
+++ b/usr.sbin/sa/tests/v1-sparc64-usr.in
Binary files differ
diff --git a/usr.sbin/sa/tests/v1-sparc64-usr.out b/usr.sbin/sa/tests/v1-sparc64-usr.out
new file mode 100644
index 0000000..cab001f
--- /dev/null
+++ b/usr.sbin/sa/tests/v1-sparc64-usr.out
@@ -0,0 +1 @@
+root 28 0.66cpu 4508tio 9971k*sec
diff --git a/usr.sbin/sa/tests/v2-amd64-sav.in b/usr.sbin/sa/tests/v2-amd64-sav.in
new file mode 100644
index 0000000..24f863b
--- /dev/null
+++ b/usr.sbin/sa/tests/v2-amd64-sav.in
Binary files differ
diff --git a/usr.sbin/sa/tests/v2-amd64-u.out b/usr.sbin/sa/tests/v2-amd64-u.out
new file mode 100644
index 0000000..4196f4a
--- /dev/null
+++ b/usr.sbin/sa/tests/v2-amd64-u.out
@@ -0,0 +1,28 @@
+ 0 0.002 cpu 68k mem 0 io accton
+ 0 0.163 cpu 35k mem 0 io awk
+ 0 0.003 cpu 0k mem 0 io time
+ 0 3.247 cpu 29k mem 26 io egrep
+ 0 0.003 cpu 93k mem 0 io time
+ 0 0.822 cpu 19k mem 4472 io find
+ 0 0.003 cpu 0k mem 0 io time
+ 0 0.002 cpu 0k mem 0 io sleep
+ 0 0.004 cpu 88k mem 0 io time
+ 0 0.076 cpu 18k mem 16 io dd
+ 0 0.003 cpu 0k mem 0 io time
+ 0 0.223 cpu 24k mem 0 io diff
+ 0 0.003 cpu 0k mem 0 io time
+ 0 0.003 cpu 0k mem 0 io ln
+ 0 0.002 cpu 0k mem 0 io 123456789012345
+ 0 0.003 cpu 0k mem 0 io time
+ 0 0.002 cpu 0k mem 0 io ln
+ 0 0.002 cpu 0k mem 0 io 1234567890123456
+ 0 0.003 cpu 0k mem 0 io time
+ 0 0.002 cpu 0k mem 0 io ln
+ 0 0.002 cpu 70k mem 0 io 1234567890123456
+ 0 0.003 cpu 0k mem 0 io time
+ 0 0.024 cpu 661k mem 2 io cc1
+ 0 0.005 cpu 0k mem 1 io as
+ 0 0.014 cpu 192k mem 9 io ld
+ 0 0.005 cpu 162k mem 5 io cc
+ 0 0.005 cpu 0k mem 13 io core
+ 0 0.002 cpu 0k mem 7 io core*
diff --git a/usr.sbin/sa/tests/v2-amd64-usr.in b/usr.sbin/sa/tests/v2-amd64-usr.in
new file mode 100644
index 0000000..4c3b136
--- /dev/null
+++ b/usr.sbin/sa/tests/v2-amd64-usr.in
Binary files differ
diff --git a/usr.sbin/sa/tests/v2-i386-sav.in b/usr.sbin/sa/tests/v2-i386-sav.in
new file mode 100644
index 0000000..d3172db
--- /dev/null
+++ b/usr.sbin/sa/tests/v2-i386-sav.in
Binary files differ
diff --git a/usr.sbin/sa/tests/v2-i386-u.out b/usr.sbin/sa/tests/v2-i386-u.out
new file mode 100644
index 0000000..b553eb8
--- /dev/null
+++ b/usr.sbin/sa/tests/v2-i386-u.out
@@ -0,0 +1,28 @@
+ 0 0.001 cpu 0k mem 0 io accton
+ 0 0.448 cpu 112k mem 0 io awk
+ 0 0.001 cpu 0k mem 0 io time
+ 0 6.680 cpu 110k mem 0 io egrep
+ 0 0.001 cpu 0k mem 0 io time
+ 0 0.248 cpu 108k mem 0 io find
+ 0 0.001 cpu 0k mem 0 io time
+ 0 0.001 cpu 0k mem 0 io sleep
+ 0 0.001 cpu 0k mem 0 io time
+ 0 0.025 cpu 103k mem 16 io dd
+ 0 0.001 cpu 0k mem 0 io time
+ 0 0.423 cpu 110k mem 0 io diff
+ 0 0.001 cpu 0k mem 0 io time
+ 0 0.001 cpu 0k mem 0 io ln
+ 0 0.001 cpu 0k mem 0 io 123456789012345
+ 0 0.001 cpu 0k mem 0 io time
+ 0 0.001 cpu 0k mem 0 io ln
+ 0 0.001 cpu 0k mem 0 io 1234567890123456
+ 0 0.001 cpu 140k mem 0 io time
+ 0 0.001 cpu 0k mem 0 io ln
+ 0 0.001 cpu 0k mem 0 io 1234567890123456
+ 0 0.001 cpu 0k mem 0 io time
+ 0 0.016 cpu 620k mem 0 io cc1
+ 0 0.002 cpu 432k mem 0 io as
+ 0 0.028 cpu 96k mem 0 io ld
+ 0 0.002 cpu 0k mem 0 io cc
+ 0 0.002 cpu 68k mem 12 io core
+ 0 0.000 cpu 0k mem 7 io core*
diff --git a/usr.sbin/sa/tests/v2-i386-usr.in b/usr.sbin/sa/tests/v2-i386-usr.in
new file mode 100644
index 0000000..465fdb4
--- /dev/null
+++ b/usr.sbin/sa/tests/v2-i386-usr.in
Binary files differ
diff --git a/usr.sbin/sa/tests/v2-sparc64-sav.in b/usr.sbin/sa/tests/v2-sparc64-sav.in
new file mode 100644
index 0000000..b6d836a
--- /dev/null
+++ b/usr.sbin/sa/tests/v2-sparc64-sav.in
Binary files differ
diff --git a/usr.sbin/sa/tests/v2-sparc64-u.out b/usr.sbin/sa/tests/v2-sparc64-u.out
new file mode 100644
index 0000000..9339238
--- /dev/null
+++ b/usr.sbin/sa/tests/v2-sparc64-u.out
@@ -0,0 +1,36 @@
+ 0 0.019 cpu 163k mem 0 io accton
+ 0 1.644 cpu 272k mem 0 io awk
+ 0 0.029 cpu 175k mem 0 io time
+ 0 0.019 cpu 163k mem 0 io sleep
+ 0 0.032 cpu 214k mem 35 io fsck_ufs
+ 0 0.028 cpu 213k mem 10 io fsck_ufs
+ 0 0.028 cpu 189k mem 8 io fsck_ufs
+ 0 0.028 cpu 196k mem 7 io fsck_ufs
+ 0 0.055 cpu 168k mem 0 io fsck
+ 0 0.008 cpu 204k mem 0 io sh*
+ 0 0.023 cpu 179k mem 0 io logger
+ 0 26.715 cpu 233k mem 25 io egrep
+ 0 0.029 cpu 162k mem 0 io time
+ 0 5.703 cpu 184k mem 4444 io find
+ 0 0.029 cpu 166k mem 0 io time
+ 0 0.018 cpu 136k mem 0 io sleep
+ 0 0.028 cpu 157k mem 0 io time
+ 0 0.588 cpu 160k mem 16 io dd
+ 0 0.027 cpu 162k mem 0 io time
+ 0 1.636 cpu 193k mem 0 io diff
+ 0 0.029 cpu 172k mem 0 io time
+ 0 0.020 cpu 170k mem 0 io ln
+ 0 0.018 cpu 135k mem 0 io 123456789012345
+ 0 0.029 cpu 167k mem 0 io time
+ 0 0.019 cpu 163k mem 0 io ln
+ 0 0.017 cpu 135k mem 0 io 1234567890123456
+ 0 0.029 cpu 157k mem 0 io time
+ 0 0.019 cpu 163k mem 0 io ln
+ 0 0.017 cpu 135k mem 0 io 1234567890123456
+ 0 0.029 cpu 162k mem 0 io time
+ 0 0.105 cpu 3358k mem 2 io cc1
+ 0 0.030 cpu 996k mem 1 io as
+ 0 0.186 cpu 1114k mem 11 io ld
+ 0 0.033 cpu 386k mem 6 io cc
+ 0 0.037 cpu 158k mem 12 io core
+ 0 0.010 cpu 129k mem 7 io core*
diff --git a/usr.sbin/sa/tests/v2-sparc64-usr.in b/usr.sbin/sa/tests/v2-sparc64-usr.in
new file mode 100644
index 0000000..01a1bdc
--- /dev/null
+++ b/usr.sbin/sa/tests/v2-sparc64-usr.in
Binary files differ
diff --git a/usr.sbin/tests/Makefile b/usr.sbin/tests/Makefile
new file mode 100644
index 0000000..a7e9c71
--- /dev/null
+++ b/usr.sbin/tests/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/usr.sbin
+
+.PATH: ${.CURDIR:H:H}/tests
+KYUAFILE= yes
+
+.include <bsd.test.mk>
OpenPOWER on IntegriCloud