1#!/bin/sh
2#
3# Copyright (c) 2010 Hudson River Trading LLC
4# Written by: John H. Baldwin <jhb@FreeBSD.org>
5# All rights reserved.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
10# 1. Redistributions of source code must retain the above copyright
11#    notice, this list of conditions and the following disclaimer.
12# 2. Redistributions in binary form must reproduce the above copyright
13#    notice, this list of conditions and the following disclaimer in the
14#    documentation and/or other materials provided with the distribution.
15#
16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26# SUCH DAMAGE.
27#
28
29# Various regression tests to run for the 'update' command.
30
31FAILED=no
32WORKDIR=work
33
34usage()
35{
36	echo "Usage: tests.sh [-s script] [-w workdir]"
37	exit 1
38}
39
40# Allow the user to specify an alternate work directory or script.
41COMMAND=etcupdate
42while getopts "s:w:" option; do
43	case $option in
44		s)
45			COMMAND="sh $OPTARG"
46			;;
47		w)
48			WORKDIR=$OPTARG
49			;;
50		*)
51			echo
52			usage
53			;;
54	esac
55done
56shift $((OPTIND - 1))
57if [ $# -ne 0 ]; then
58	usage
59fi
60
61CONFLICTS=$WORKDIR/conflicts
62OLD=$WORKDIR/old
63NEW=$WORKDIR/current
64TEST=$WORKDIR/test
65
66# The various states of the comparison of a file between two trees.
67states="equal first second difftype difflinks difffiles"
68
69build_trees()
70{
71	local i j k
72
73	rm -rf $OLD $NEW $TEST $CONFLICTS
74	mkdir -p $OLD/etc $NEW/etc $TEST/etc
75
76	# For an given file, there are three different pair-wise
77	# relations between the three threes (old, new, and test): old
78	# vs new, old vs test, and new vs test.  Each of these
79	# relations takes on one of six different states from the
80	# 'compare()' function in etcupdate: equal, onlyfirst,
81	# onlysecond, difftype, difflinks, difffiles.  In addition,
82	# there are special considerations for considering cases such
83	# as a file merge that results in conflicts versus one that
84	# does not, special treatment of directories, etc.  The tests
85	# below attempt to enumerate the three dimensional test matrix
86	# by having the path name use the three different tree states
87	# for the parent directories.
88	#
89	# Note that if the old and new files are identical (so first
90	# compare is "equal"), then the second and third comparisons
91	# will be the same.
92	#
93	# Note also that etcupdate only cares about files that are
94	# present in at least one of the old or new trees.  Thus, none
95	# of the '*/second/second' cases are relevant.
96
97	for i in $states; do
98		for j in $states; do
99			for k in $states; do
100				mkdir -p $OLD/$i/$j/$k $NEW/$i/$j/$k \
101				    $TEST/$i/$j/$k
102			done
103		done
104	done
105
106	# /equal/equal/equal: Everything is equal.  Nothing should happen.
107	for i in $OLD $NEW $TEST; do
108		mkfifo $i/equal/equal/equal/fifo
109		echo "foo" > $i/equal/equal/equal/file
110		mkdir $i/equal/equal/equal/dir
111		ln -s "bar" $i/equal/equal/equal/link
112	done
113
114	# /equal/first/first: The file is missing from the test
115	# directory.  Nothing should happen.
116	for i in $OLD $NEW; do
117		mkfifo $i/equal/first/first/fifo
118		echo "foo" > $i/equal/first/first/file
119		mkdir $i/equal/first/first/dir
120		ln -s "bar" $i/equal/first/first/link
121	done
122
123	# /equal/difftype/difftype: The local file is a different
124	# type.  Nothing should happen.
125	for i in $OLD $NEW; do
126		mkfifo $i/equal/difftype/difftype/fifo
127		mkdir $i/equal/difftype/difftype/fromdir
128	done
129	echo "bar" > $TEST/equal/difftype/difftype/fifo
130	ln -s "test" $TEST/equal/difftype/difftype/fromdir
131
132	# /equal/difflinks/difflinks: The local file is a modified
133	# link. Nothing should happen.
134	for i in $OLD $NEW; do
135		ln -s "foo" $i/equal/difflinks/difflinks/link
136	done
137	ln -s "bar" $TEST/equal/difflinks/difflinks/link
138
139	# /equal/difffiles/difffiles: The local file is a modified
140	# file.  Nothing should happen.
141	for i in $OLD $NEW; do
142		echo "foo" > $i/equal/difffiles/difffiles/file
143	done
144	echo "bar" > $TEST/equal/difffiles/difffiles/file
145
146	# /first/equal/second: Remove unmodified files.  The files
147	# should all be removed.
148	for i in $OLD $TEST; do
149		mkfifo $i/first/equal/second/fifo
150		echo "foo" > $i/first/equal/second/file
151		mkdir $i/first/equal/second/emptydir
152		ln -s "bar" $i/first/equal/second/link
153		mkdir $i/first/equal/second/fulldir
154		echo "foo" > $i/first/equal/second/fulldir/file
155	done
156
157	# /first/equal/*: Cannot occur.  If the file is missing from
158	# new, then new vs test will always be 'second'.
159
160	# /first/first/equal: Removed files are already removed.
161	# Nothing should happen.
162	mkfifo $OLD/first/first/equal/fifo
163	echo "foo" > $OLD/first/first/equal/file
164	mkdir $OLD/first/first/equal/dir
165	ln -s "bar" $OLD/first/first/equal/link
166
167	# /first/first/*: Cannot occur.  The files are missing from
168	# both new and test.
169
170	# /first/second/*: Cannot happen, if the file is in old for
171	# old vs new, it cannot be missing for old vs test.
172
173	# /first/difftype/second: File with different local type
174	# removed.  Should generate a warning.
175	mkfifo $OLD/first/difftype/second/fifo
176	mkdir $TEST/first/difftype/second/fifo
177
178	# /first/difftype/*: Cannot happen since the file is missing
179	# from new but present in test.
180
181	# /first/difflinks/second: Modified link removed.  Should
182	# generate a warning.
183	ln -s "old link" $OLD/first/difflinks/second/link
184	ln -s "test link" $TEST/first/difflinks/second/link
185
186	# /first/difflinks/*: Cannot happen since the file is missing
187	# from new but present in test.
188
189	# /first/difffiles/second: Modified file removed.  Should
190	# generate a warning.
191	echo "foo" > $OLD/first/difffiles/second/file
192	echo "bar" > $TEST/first/difffiles/second/file
193
194	# /first/difffiles/*: Cannot happen since the file is missing
195	# from new but present in test.
196
197	# /second/equal/first: Added a new file that isn't present in
198	# test.  The empty directory should be ignored.
199	echo "bar" > $NEW/second/equal/first/file
200	mkfifo $NEW/second/equal/first/fifo
201	ln -s "new" $NEW/second/equal/first/link
202	mkdir $NEW/second/equal/first/emptydir
203	mkdir $NEW/second/equal/first/fulldir
204	echo "foo" > $NEW/second/equal/first/fulldir/file
205
206	# /second/equal/*: Cannot happen since the file is missing
207	# from test but present in new.
208
209	# /second/first/*: Cannot happen since the file is missing
210	# from old.
211
212	# /second/second/equal: Newly added file is already present in
213	# the test directory and identical to the new file.  Nothing
214	# should happen.
215	for i in $NEW $TEST; do
216		mkfifo $i/second/second/equal/fifo
217		echo "foo" > $i/second/second/equal/file
218		mkdir $i/second/second/equal/dir
219		ln -s "bar" $i/second/second/equal/link
220	done
221
222	# /second/second/first: Cannot happen.  The file is in dest in
223	# the second test, so it can't be missing from the third test.
224
225	# /second/second/second: Cannot happen.  The file is in new in
226	# the first test, so it can't be missing from the third test.
227
228	# /second/second/difftype: Newly added file conflicts with
229	# existing file in test tree of a different type.  Should
230	# generate a warning.
231	mkdir $NEW/second/second/difftype/dir
232	mkfifo $TEST/second/second/difftype/dir
233
234	# /second/second/difflinks: Newly added link conflicts with
235	# existing link in test tree.  Should generate a warning.
236	ln -s "new link" $NEW/second/second/difflinks/link
237	ln -s "test link" $TEST/second/second/difflinks/link
238
239	# /second/second/difffiles: Newly added file conflicts with
240	# existing file in test tree.  Should generate a warning.
241	echo "new" > $NEW/second/second/difffiles/file
242	echo "test" > $TEST/second/second/difffiles/file
243
244	# /second/difftype/*: Cannot happen since the file is missing
245	# from old.
246
247	# /second/difflinks/*: Cannot happen since the file is missing
248	# from old.
249
250	# /second/difffiles/*: Cannot happen since the file is missing
251	# from old.
252
253	# /difftype/equal/difftype: Unmodified file has changed type.
254	# File should be updated to the new file.  In the 'todir' case
255	# the directory won't actually be created because it is empty.
256	for i in $OLD $TEST; do
257		echo "foo" > $i/difftype/equal/difftype/file
258		mkdir $i/difftype/equal/difftype/fromdir
259		ln -s "old" $i/difftype/equal/difftype/todir
260	done
261	ln -s "test" $NEW/difftype/equal/difftype/file
262	mkfifo $NEW/difftype/equal/difftype/fromdir
263	mkdir $NEW/difftype/equal/difftype/todir
264
265	# /difftype/equal/*: Cannot happen.  Since the old file is a
266	# difftype from the new file and the test file is identical to
267	# the old file, the test file must be a difftype from the new
268	# file.
269
270	# /difftype/first/first: A removed file has changed type.
271	# This should generate a warning.
272	mkfifo $OLD/difftype/first/first/fifo
273	mkdir $NEW/difftype/first/first/fifo
274
275	# /difftype/first/*: Cannot happen.  Since the new file exists
276	# and the dest file is missing, the last test must be 'first'.
277
278	# /difftype/second/*: Cannot happen.  The old file exists in
279	# the first test, so it cannot be missing in the second test.
280
281	# /difftype/difftype/equal: A file has changed type, but the
282	# file in the test directory already matches the new file.  Do
283	# nothing.
284	echo "foo" > $OLD/difftype/difftype/equal/fifo
285	mkfifo $OLD/difftype/difftype/equal/file
286	for i in $NEW $TEST; do
287		mkfifo $i/difftype/difftype/equal/fifo
288		echo "bar" > $i/difftype/difftype/equal/file
289	done
290
291	# /difftype/difftype/first: Cannot happen.  The dest file
292	# exists in the second test.
293
294	# /difftype/difftype/second: Cannot happen.  The new file
295	# exists in the first test.
296
297	# /difftype/difftype/difftype: All three files (old, new, and
298	# test) are different types from each other.  This should
299	# generate a warning.
300	mkfifo $OLD/difftype/difftype/difftype/one
301	mkdir $NEW/difftype/difftype/difftype/one
302	echo "foo" > $TEST/difftype/difftype/difftype/one
303	mkdir $OLD/difftype/difftype/difftype/two
304	echo "baz" > $NEW/difftype/difftype/difftype/two
305	ln -s "bar" $TEST/difftype/difftype/difftype/two
306
307	# /difftype/difftype/difflinks: A file has changed from a
308	# non-link to a link in both the new and test trees, but the
309	# target of the new and test links differ.  This should
310	# generate a new link conflict.
311	mkfifo $OLD/difftype/difftype/difflinks/link
312	ln -s "new" $NEW/difftype/difftype/difflinks/link
313	ln -s "test" $TEST/difftype/difftype/difflinks/link
314
315	# /difftype/difftype/difffile: A file has changed from a
316	# non-regular file to a regular file in both the new and test
317	# trees, but the contents in the new and test files differ.
318	# This should generate a new file conflict.
319	ln -s "old" $OLD/difftype/difftype/difffiles/file
320	echo "foo" > $NEW/difftype/difftype/difffiles/file
321	echo "bar" > $TEST/difftype/difftype/difffiles/file
322
323	# /difflinks/equal/difflinks: An unmodified symlink has
324	# changed.  The link should be updated.
325	for i in $OLD $TEST; do
326		ln -s "old" $i/difflinks/equal/difflinks/link
327	done
328	ln -s "new" $NEW/difflinks/equal/difflinks/link
329
330	# /difflinks/equal/*: Cannot happen.  Since old is identical
331	# to test, the third test must be 'difflinks'.
332
333	# /difflinks/first/first: A modified link is missing in the
334	# test tree.  This should generate a warning.
335	ln -s "old" $OLD/difflinks/first/first/link
336	ln -s "new" $NEW/difflinks/first/first/link
337
338	# /difflinks/first/*: Cannot happen.  Since the test file is
339	# missing in the second test, it must be missing in the third
340	# test.
341
342	# /difflinks/second/*: Cannot happen.  The old link is present
343	# in the first test, so it cannot be missing in the second
344	# test.
345
346	# /difflinks/difftype/difftype: An updated link has been
347	# changed to a different file type in the test tree.  This
348	# should generate a warning.
349	ln -s "old" $OLD/difflinks/difftype/difftype/link
350	ln -s "new" $NEW/difflinks/difftype/difftype/link
351	echo "test" > $TEST/difflinks/difftype/difftype/link
352
353	# /difflinks/difftype/*: Cannot happen.  The old and new files
354	# are both links and the test file is not a link, so the third
355	# test must be 'difftype'.
356
357	# /difflinks/difflinks/equal: An updated link has already been
358	# updated to the new target in the test tree.  Nothing should
359	# happen.
360	ln -s "old" $OLD/difflinks/difflinks/equal/link
361	for i in $NEW $TEST; do
362		ln -s "new" $i/difflinks/difflinks/equal/link
363	done
364
365	# /difflinks/difflinks/difflinks: An updated link has been
366	# modified in the test tree and doesn't match either the old
367	# or new links.  This should generate a warning.
368	ln -s "old" $OLD/difflinks/difflinks/difflinks/link
369	ln -s "new" $NEW/difflinks/difflinks/difflinks/link
370	ln -s "test" $TEST/difflinks/difflinks/difflinks/link
371
372	# /difflinks/difflinks/*: Cannot happen.  All three files are
373	# links from the first two tests, so the third test can only
374	# be 'equal' or 'difflink'.
375
376	# /difflinks/difffiles/*: Cannot happen.  The old file is a
377	# link in the first test, so it cannot be a regular file in
378	# the second.
379
380	# /difffiles/equal/difffiles: An unmodified file has been
381	# changed in new tree.  The file should be updated to the new
382	# version.
383	for i in $OLD $TEST; do
384		echo "foo" > $i/difffiles/equal/difffiles/file
385	done
386	echo "bar" > $NEW/difffiles/equal/difffiles/file
387
388	# /difffiles/equal/*: Cannot happen.  Since the old file is
389	# identical to the test file, the third test must be
390	# 'difffiles'.
391
392	# /difffiles/first/first: A removed file has been changed in
393	# the new tree.  This should generate a warning.
394	echo "foo" > $OLD/difffiles/first/first/file
395	echo "bar" > $NEW/difffiles/first/first/file
396
397	# /difffiles/first/*: Cannot happen.  The new file is a
398	# regular file from the first test and the test file is
399	# missing in the second test, so the third test must be
400	# 'first'.
401
402	# /difffiles/second/*: Cannot happen.  The old file is present
403	# in the first test, so it must be present in the second test.
404
405	# /difffiles/difftype/difftype: An updated regular file has
406	# been changed to a different file type in the test tree.
407	# This should generate a warning.
408	echo "old" > $OLD/difffiles/difftype/difftype/file
409	echo "new" > $NEW/difffiles/difftype/difftype/file
410	mkfifo $TEST/difffiles/difftype/difftype/file
411
412	# /difffiles/difftype/*: Cannot happen.  The new file is known
413	# to be a regular file from the first test, and the test file
414	# is known to exist as a different file type from the second
415	# test.  The third test must be 'difftype'.
416
417	# /difffiles/difflink/*: Cannot happen.  The old file is known
418	# to be a regular file from the first test, so it cannot be a
419	# link in the second test.
420
421	# /difffiles/difffiles/equal: An updated regular file has
422	# already been updated to match the new file in the test tree.
423	# Nothing should happen.
424	echo "foo" > $OLD/difffiles/difffiles/equal/file
425	for i in $NEW $TEST; do
426		echo "bar" > $i/difffiles/difffiles/equal/file
427	done
428
429	# /difffiles/difffiles/difffiles: A modified regular file was
430	# updated in the new tree.  The changes should be merged into
431	# to the new file if possible.  If the merge fails, a conflict
432	# should be generated.
433	cat > $OLD/difffiles/difffiles/difffiles/simple <<EOF
434this is an old line
435
436EOF
437	cat > $NEW/difffiles/difffiles/difffiles/simple <<EOF
438this is a new line
439
440EOF
441	cat > $TEST/difffiles/difffiles/difffiles/simple <<EOF
442this is an old line
443
444this is a local line
445EOF
446	cat > $OLD/difffiles/difffiles/difffiles/conflict <<EOF
447this is an old file
448EOF
449	cat > $NEW/difffiles/difffiles/difffiles/conflict <<EOF
450this is a new file
451EOF
452	cat > $TEST/difffiles/difffiles/difffiles/conflict <<EOF
453this is a test file
454EOF
455
456	# /difffiles/difffiles/*: Cannot happen.  From the first three
457	# tests, all three files are regular files.  The test file can
458	# either be identical to the new file ('equal') or not
459	# ('difffiles').
460
461	## Tests for adding directories
462	mkdir -p $OLD/adddir $NEW/adddir $TEST/adddir
463
464	# /adddir/conflict: Add a new file in a directory that already
465	# exists as a file.  This should generate two warnings.
466	mkdir $NEW/adddir/conflict
467	touch $NEW/adddir/conflict/newfile
468	touch $TEST/adddir/conflict
469
470	# /adddir/partial: Add a new file in a directory.  The
471	# directory already exists in the test tree and contains a
472	# different local file.  The new file from the new tree should
473	# be added.
474	for i in $NEW $TEST; do
475		mkdir $i/adddir/partial
476	done
477	echo "foo" > $NEW/adddir/partial/file
478	mkfifo $TEST/adddir/partial/fifo
479
480	## Tests for removing directories
481	mkdir -p $OLD/rmdir $NEW/rmdir $TEST/rmdir
482
483	# /rmdir/extra: Do not remove a directory with an extra local file.
484	# This should generate a warning.
485	for i in $OLD $TEST; do
486		mkdir $i/rmdir/extra
487	done
488	echo "foo" > $TEST/rmdir/extra/localfile.txt
489
490	# /rmdir/conflict: Do not remove a directory with a conflicted
491	# remove file.  This should generate a warning.
492	for i in $OLD $TEST; do
493		mkdir $i/rmdir/conflict
494	done
495	mkfifo $OLD/rmdir/conflict/difftype
496	mkdir $TEST/rmdir/conflict/difftype
497
498	# /rmdir/partial: Remove a complete hierarchy when part of the
499	# tree has already been removed locally.
500	for i in $OLD $TEST; do
501		mkdir -p $i/rmdir/partial/subdir
502		mkfifo $i/rmdir/partial/subdir/fifo
503	done
504	echo "foo" > $OLD/rmdir/partial/subdir/file
505
506	## Tests for converting files to directories and vice versa
507	for i in $OLD $NEW $TEST; do
508		for j in already old fromdir todir; do
509			mkdir -p $i/dirchange/$j
510		done
511	done
512
513	# /dirchange/already/fromdir: Convert a directory tree to a
514	# file without conflicts where the test tree already has the
515	# new file.  Nothing should happen.
516	mkdir $OLD/dirchange/already/fromdir
517	echo "blah" > $OLD/dirchange/already/fromdir/somefile
518	for i in $NEW $TEST; do
519		echo "bar" > $i/dirchange/already/fromdir
520	done
521
522	# /dirchange/already/todir: Convert an unmodified file to a
523	# directory tree where the test tree already has the new
524	# tree.  Nothing should happen.
525	echo "baz" > $OLD/dirchange/already/todir
526	for i in $NEW $TEST; do
527		mkdir $i/dirchange/already/todir
528		echo "blah" > $i/dirchange/already/todir/somefile
529	done
530
531	# /dirchange/old/fromdir: Convert a directory tree to a file.
532	# The old files are unmodified and should be changed to the new tree.
533	for i in $OLD $TEST; do
534		mkdir $i/dirchange/old/fromdir
535		echo "blah" > $i/dirchange/old/fromdir/somefile
536	done
537	echo "bar" > $NEW/dirchange/old/fromdir
538
539	# /dirchange/old/todir: Convert a file to a directory tree.
540	# The old file is unmodified and should be changed to the new
541	# tree.
542	for i in $OLD $TEST; do
543		echo "foo" > $i/dirchange/old/todir
544	done
545	mkdir $NEW/dirchange/old/todir
546	echo "bar" > $NEW/dirchange/old/todir/file
547
548	# /dirchange/fromdir/extradir: Convert a directory tree to a
549	# file.  The test tree includes an extra file in the directory
550	# that is not present in the old tree.  This should generate a
551	# warning.
552	for i in $OLD $TEST; do
553		mkdir $i/dirchange/fromdir/extradir
554		echo "foo" > $i/dirchange/fromdir/extradir/file
555	done
556	mkfifo $TEST/dirchange/fromdir/extradir/fifo
557	ln -s "bar" $NEW/dirchange/fromdir/extradir
558
559	# /dirchange/fromdir/conflict: Convert a directory tree to a
560	# file.  The test tree includes a local change that generates
561	# a warning and prevents the removal of the directory.
562	for i in $OLD $TEST; do
563		mkdir $i/dirchange/fromdir/conflict
564	done
565	echo "foo" > $OLD/dirchange/fromdir/conflict/somefile
566	echo "bar" > $TEST/dirchange/fromdir/conflict/somefile
567	mkfifo $NEW/dirchange/fromdir/conflict
568
569	# /dirchange/todir/difffile: Convert a file to a directory
570	# tree.  The test tree has a locally modified version of the
571	# file so that the conversion fails with a warning.
572	echo "foo" > $OLD/dirchange/todir/difffile
573	mkdir $NEW/dirchange/todir/difffile
574	echo "baz" > $NEW/dirchange/todir/difffile/file
575	echo "bar" > $TEST/dirchange/todir/difffile
576
577	# /dirchange/todir/difftype: Similar to the previous test, but
578	# the conflict is due to a change in the file type.
579	echo "foo" > $OLD/dirchange/todir/difftype
580	mkdir $NEW/dirchange/todir/difftype
581	echo "baz" > $NEW/dirchange/todir/difftype/file
582	mkfifo $TEST/dirchange/todir/difftype
583
584	## Tests for post-install actions
585
586	# - Adding /etc/master.passwd should cause pwd_mkdb to be run
587	echo "foo:*:16000:100::0:0:& user:/home/foo:/bin/tcsh" > \
588	    $NEW/etc/master.passwd
589
590	# - Verify that updating an unmodified /etc/login.conf builds
591	# /etc/login.conf.db.
592	cat > $OLD/etc/login.conf <<EOF
593default:\\
594	:passwd_format=md5:
595EOF
596	cat > $NEW/etc/login.conf <<EOF
597default:\\
598	:passwd_format=md5:\\
599	:copyright=/etc/COPYRIGHT
600EOF
601	cp $OLD/etc/login.conf $TEST/etc/login.conf
602
603	# - Verify that a merge without conflicts to /etc/mail/aliases
604	# will trigger a newaliases run request.
605	mkdir -p $OLD/etc/mail $NEW/etc/mail $TEST/etc/mail
606	cat > $OLD/etc/mail/aliases <<EOF
607# root: me@my.domain
608
609# Basic system aliases -- these MUST be present
610MAILER-DAEMON: postmaster
611postmaster: root
612EOF
613	cat > $NEW/etc/mail/aliases <<EOF
614# root: me@my.domain
615
616# Basic system aliases -- these MUST be present
617MAILER-DAEMON: postmaster
618postmaster: root
619
620# General redirections for pseudo accounts
621_dhcp:  root
622_pflogd: root
623EOF
624	cat > $TEST/etc/mail/aliases <<EOF
625root: someone@example.com
626
627# Basic system aliases -- these MUST be present
628MAILER-DAEMON: postmaster
629postmaster: root
630EOF
631
632	# - Verify that updating an unmodified /etc/services builds
633	# /var/db/services.db.
634	cat > $OLD/etc/services <<EOF
635rtmp		  1/ddp	   #Routing Table Maintenance Protocol
636tcpmux		  1/tcp	   #TCP Port Service Multiplexer
637tcpmux		  1/udp	   #TCP Port Service Multiplexer
638EOF
639	cat > $NEW/etc/services <<EOF
640rtmp		  1/ddp	   #Routing Table Maintenance Protocol
641tcpmux		  1/tcp	   #TCP Port Service Multiplexer
642tcpmux		  1/udp	   #TCP Port Service Multiplexer
643nbp		  2/ddp	   #Name Binding Protocol
644compressnet	  2/tcp	   #Management Utility
645compressnet	  2/udp	   #Management Utility
646EOF
647	cp $OLD/etc/services $TEST/etc/services
648	mkdir -p $TEST/var/db
649}
650
651# $1 - relative path to file that should be missing from TEST
652missing()
653{
654	if [ -e $TEST/$1 -o -L $TEST/$1 ]; then
655		echo "File $1 should be missing"
656		FAILED=yes
657	fi
658}
659
660# $1 - relative path to file that should be present in TEST
661present()
662{
663	if ! [ -e $TEST/$1 -o -L $TEST/$1 ]; then
664		echo "File $1 should be present"
665		FAILED=yes
666	fi
667}
668
669# $1 - relative path to file that should be a fifo in TEST
670fifo()
671{
672	if ! [ -p $TEST/$1 ]; then
673		echo "File $1 should be a FIFO"
674		FAILED=yes
675	fi
676}
677
678# $1 - relative path to file that should be a directory in TEST
679dir()
680{
681	if ! [ -d $TEST/$1 ]; then
682		echo "File $1 should be a directory"
683		FAILED=yes
684	fi
685}
686
687# $1 - relative path to file that should be a symlink in TEST
688# $2 - optional value of the link
689link()
690{
691	local val
692
693	if ! [ -L $TEST/$1 ]; then
694		echo "File $1 should be a link"
695		FAILED=yes
696	elif [ $# -gt 1 ]; then
697		val=`readlink $TEST/$1`
698		if [ "$val" != "$2" ]; then
699			echo "Link $1 should link to \"$2\""
700			FAILED=yes
701		fi
702	fi
703}
704
705# $1 - relative path to regular file that should be present in TEST
706# $2 - optional string that should match file contents
707# $3 - optional MD5 of the flie contents, overrides $2 if present
708file()
709{
710	local contents sum
711
712	if ! [ -f $TEST/$1 ]; then
713		echo "File $1 should be a regular file"
714		FAILED=yes
715	elif [ $# -eq 2 ]; then
716		contents=`cat $TEST/$1`
717		if [ "$contents" != "$2" ]; then
718			echo "File $1 has wrong contents"
719			FAILED=yes
720		fi
721	elif [ $# -eq 3 ]; then
722		sum=`md5 -q $TEST/$1`
723		if [ "$sum" != "$3" ]; then
724			echo "File $1 has wrong contents"
725			FAILED=yes
726		fi
727	fi
728}
729
730# $1 - relative path to a regular file that should have a conflict
731# $2 - optional MD5 of the conflict file contents
732conflict()
733{
734	local sum
735
736	if ! [ -f $CONFLICTS/$1 ]; then
737		echo "File $1 missing conflict"
738		FAILED=yes
739	elif [ $# -gt 1 ]; then
740		sum=`md5 -q $CONFLICTS/$1`
741		if [ "$sum" != "$2" ]; then
742			echo "Conflict $1 has wrong contents"
743			FAILED=yes
744		fi
745	fi
746}
747
748check_trees()
749{
750
751	echo "Checking tree for correct results:"
752
753	## /equal/equal/equal:
754	fifo /equal/equal/equal/fifo
755	file /equal/equal/equal/file "foo"
756	dir /equal/equal/equal/dir
757	link /equal/equal/equal/link "bar"
758
759	## /equal/first/first:
760	missing /equal/first/first/fifo
761	missing /equal/first/first/file
762	missing /equal/first/first/dir
763	missing /equal/first/first/link
764
765	## /equal/difftype/difftype:
766	file /equal/difftype/difftype/fifo "bar"
767	link /equal/difftype/difftype/fromdir "test"
768
769	## /equal/difflinks/difflinks:
770	link /equal/difflinks/difflinks/link "bar"
771
772	## /equal/difffiles/difffiles:
773	file /equal/difffiles/difffiles/file "bar"
774
775	## /first/equal/second:
776	missing /first/equal/second/fifo
777	missing /first/equal/second/file
778	missing /first/equal/second/emptydir
779	missing /first/equal/second/link
780	missing /first/equal/second/fulldir
781
782	## /first/first/equal:
783	missing /first/first/equal/fifo
784	missing /first/first/equal/file
785	missing /first/first/equal/dir
786	missing /first/first/equal/link
787
788	## /first/difftype/second:
789	present /first/difftype/second/fifo
790
791	## /first/difflinks/second:
792	link /first/difflinks/second/link "test link"
793
794	## /first/difffiles/second:
795	file /first/difffiles/second/file "bar"
796
797	## /second/equal/first:
798	file /second/equal/first/file "bar"
799	fifo /second/equal/first/fifo
800	link /second/equal/first/link "new"
801	missing /second/equal/first/emptydir
802	file /second/equal/first/fulldir/file "foo"
803
804	## /second/second/equal:
805	fifo /second/second/equal/fifo
806	file /second/second/equal/file "foo"
807	dir /second/second/equal/dir
808	link /second/second/equal/link "bar"
809
810	## /second/second/difftype:
811	fifo /second/second/difftype/dir
812
813	## /second/second/difflinks:
814	link /second/second/difflinks/link "test link"
815
816	## /second/second/difffiles:
817	file /second/second/difffiles/file "test"
818	conflict /second/second/difffiles/file 4f2ee8620a251fd53f06bb6112eb6ffa
819
820	## /difftype/equal/difftype:
821	link /difftype/equal/difftype/file "test"
822	fifo /difftype/equal/difftype/fromdir
823	missing /difftype/equal/difftype/todir
824
825	## /difftype/first/first:
826	missing /difftype/first/first/fifo
827
828	## /difftype/difftype/equal:
829	fifo /difftype/difftype/equal/fifo
830	file /difftype/difftype/equal/file "bar"
831
832	## /difftype/difftype/difftype:
833	file /difftype/difftype/difftype/one "foo"
834	link /difftype/difftype/difftype/two "bar"
835
836	## /difftype/difftype/difflinks:
837	link /difftype/difftype/difflinks/link "test"
838
839	## /difftype/difftype/difffile:
840	conflict /difftype/difftype/difffiles/file \
841	    117f2bcd1f6491f6044e79e5a57a9229
842
843	## /difflinks/equal/difflinks:
844	link /difflinks/equal/difflinks/link "new"
845
846	## /difflinks/first/first:
847	missing /difflinks/first/first/link
848
849	## /difflinks/difftype/difftype:
850	file /difflinks/difftype/difftype/link "test"
851
852	## /difflinks/difflinks/equal:
853	link /difflinks/difflinks/equal/link "new"
854
855	## /difflinks/difflinks/difflinks:
856	link /difflinks/difflinks/difflinks/link "test"
857
858	## /difffiles/equal/difffiles:
859	file /difffiles/equal/difffiles/file "bar"
860
861	## /difffiles/first/first:
862	missing /difffiles/first/first/file
863
864	## /difffiles/difftype/difftype:
865	fifo /difffiles/difftype/difftype/file
866
867	## /difffiles/difffiles/equal:
868	file /difffiles/difffiles/equal/file "bar"
869
870	## /difffiles/difffiles/difffiles:
871	file /difffiles/difffiles/difffiles/simple "" \
872	    cabc7e5e80b0946d79edd555e9648486
873	file /difffiles/difffiles/difffiles/conflict "this is a test file"
874	conflict /difffiles/difffiles/difffiles/conflict \
875	    8261cfdd89280c4a6c26e4ac86541fe9
876
877	## /adddir/conflict:
878	file /adddir/conflict
879
880	## /adddir/partial:
881	file /adddir/partial/file "foo"
882	fifo /adddir/partial/fifo
883
884	## /rmdir/extra:
885	dir /rmdir/extra
886	file /rmdir/extra/localfile.txt "foo"
887
888	## /rmdir/conflict:
889	dir /rmdir/conflict/difftype
890	present /rmdir/conflict
891
892	## /rmdir/partial:
893	missing /rmdir/partial
894
895	## /dirchange/already/fromdir:
896	file /dirchange/already/fromdir "bar"
897
898	## /dirchange/already/todir:
899	file /dirchange/already/todir/somefile "blah"
900
901	## /dirchange/old/fromdir:
902	file /dirchange/old/fromdir "bar"
903
904	## /dirchange/old/todir
905	file /dirchange/old/todir/file "bar"
906
907	## /dirchange/fromdir/extradir:
908	missing /dirchange/fromdir/extradir/file
909	fifo /dirchange/fromdir/extradir/fifo
910
911	## /dirchange/fromdir/conflict:
912	file /dirchange/fromdir/conflict/somefile "bar"
913
914	## /dirchange/todir/difffile:
915	file /dirchange/todir/difffile "bar"
916
917	## /dirchange/todir/difftype:
918	fifo /dirchange/todir/difftype
919
920	## Tests for post-install actions
921	file /etc/master.passwd
922	file /etc/passwd
923	file /etc/pwd.db
924	file /etc/spwd.db
925	file /etc/login.conf "" 7774a0f9a3a372c7c109c32fd31c4b6b
926	file /etc/login.conf.db
927	file /etc/mail/aliases "" 7d598f89ec040ab56af54011bdb83337
928	file /etc/services "" 37fb6a8d1273f3b78329d431f21d9c7d
929	file /var/db/services.db
930}
931
932if [ `id -u` -ne 0 ]; then
933	echo "must be root"
934	exit 0
935fi
936
937if [ -r /etc/etcupdate.conf ]; then
938	echo "WARNING: /etc/etcupdate.conf settings may break some tests."
939fi
940
941build_trees
942
943$COMMAND -nr -d $WORKDIR -D $TEST > $WORKDIR/testn.out
944
945cat > $WORKDIR/correct.out <<EOF
946  D /dirchange/fromdir/extradir/file
947  D /dirchange/old/fromdir/somefile
948  D /first/equal/second/fifo
949  D /first/equal/second/file
950  D /first/equal/second/fulldir/file
951  D /first/equal/second/link
952  D /rmdir/partial/subdir/fifo
953  D /rmdir/partial/subdir
954  D /rmdir/partial
955  D /first/equal/second/fulldir
956  D /first/equal/second/emptydir
957  C /difffiles/difffiles/difffiles/conflict
958  M /difffiles/difffiles/difffiles/simple
959  U /difffiles/equal/difffiles/file
960  U /difflinks/equal/difflinks/link
961  C /difftype/difftype/difffiles/file
962  U /difftype/equal/difftype/file
963  U /difftype/equal/difftype/fromdir
964  D /difftype/equal/difftype/todir
965  U /dirchange/old/fromdir
966  U /dirchange/old/todir
967  U /etc/login.conf
968  M /etc/mail/aliases
969  U /etc/services
970  A /adddir/partial/file
971  A /dirchange/old/todir/file
972  A /etc/master.passwd
973  A /second/equal/first/fifo
974  A /second/equal/first/file
975  A /second/equal/first/fulldir/file
976  A /second/equal/first/link
977  C /second/second/difffiles/file
978Warnings:
979  Modified regular file remains: /dirchange/fromdir/conflict/somefile
980  Modified regular file remains: /first/difffiles/second/file
981  Modified symbolic link remains: /first/difflinks/second/link
982  Modified directory remains: /first/difftype/second/fifo
983  Modified directory remains: /rmdir/conflict/difftype
984  Non-empty directory remains: /rmdir/extra
985  Non-empty directory remains: /rmdir/conflict
986  Modified mismatch: /difffiles/difftype/difftype/file (regular file vs fifo file)
987  Removed file changed: /difffiles/first/first/file
988  Modified link changed: /difflinks/difflinks/difflinks/link ("old" became "new")
989  Modified mismatch: /difflinks/difftype/difftype/link (symbolic link vs regular file)
990  Removed link changed: /difflinks/first/first/link ("old" became "new")
991  New link conflict: /difftype/difftype/difflinks/link ("new" vs "test")
992  Modified regular file changed: /difftype/difftype/difftype/one (fifo file became directory)
993  Modified symbolic link changed: /difftype/difftype/difftype/two (directory became regular file)
994  Remove mismatch: /difftype/first/first/fifo (fifo file became directory)
995  Modified directory changed: /dirchange/fromdir/conflict (directory became fifo file)
996  Modified directory changed: /dirchange/fromdir/extradir (directory became symbolic link)
997  Modified regular file changed: /dirchange/todir/difffile (regular file became directory)
998  Modified fifo file changed: /dirchange/todir/difftype (regular file became directory)
999  New file mismatch: /adddir/conflict (directory vs regular file)
1000  Directory mismatch: $TEST/adddir/conflict (regular file)
1001  Directory mismatch: $TEST/dirchange/todir/difffile (regular file)
1002  Directory mismatch: $TEST/dirchange/todir/difftype (fifo file)
1003  New link conflict: /second/second/difflinks/link ("new link" vs "test link")
1004  New file mismatch: /second/second/difftype/dir (directory vs fifo file)
1005  Needs update: /etc/mail/aliases.db (requires manual update via newaliases(1))
1006EOF
1007
1008echo "Differences for -n:"
1009diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/testn.out \
1010    || failed=YES
1011
1012$COMMAND -r -d $WORKDIR -D $TEST > $WORKDIR/test.out
1013
1014echo "Differences for real:"
1015diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out \
1016    || failed=YES
1017
1018check_trees
1019
1020[ "${FAILED}" = no ]
1021