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 test the -A flag to the 'update' command. 30 31FAILED=no 32WORKDIR=work 33 34usage() 35{ 36 echo "Usage: always.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 69# These tests deal with ignoring certain patterns of files. We run 70# the test multiple times forcing the install of different patterns. 71build_trees() 72{ 73 local i 74 75 rm -rf $OLD $NEW $TEST $CONFLICTS 76 77 for i in $states; do 78 for j in $states; do 79 for k in $states; do 80 mkdir -p $OLD/$i/$j/$k $NEW/$i/$j/$k \ 81 $TEST/$i/$j/$k 82 done 83 done 84 done 85 86 # What follows are the various warning/conflict cases from the 87 # larger regression tests. These results of many of these 88 # tests should be changed when installation is forced. The 89 # cases when these updates should still fail even when forced 90 # are: 1) it should not force the removal of a modified file 91 # and 2) it should not remove a subdirectory that contains a 92 # modified or added file. 93 94 # /first/difftype/second: File with different local type 95 # removed. Should generate a warning. 96 mkfifo $OLD/first/difftype/second/fifo 97 mkdir $TEST/first/difftype/second/fifo 98 99 # /first/difflinks/second: Modified link removed. Should 100 # generate a warning. 101 ln -s "old link" $OLD/first/difflinks/second/link 102 ln -s "test link" $TEST/first/difflinks/second/link 103 104 # /first/difffiles/second: Modified file removed. Should 105 # generate a warning. 106 echo "foo" > $OLD/first/difffiles/second/file 107 echo "bar" > $TEST/first/difffiles/second/file 108 109 # /second/second/difftype: Newly added file conflicts with 110 # existing file in test tree of a different type. Should 111 # generate a warning. 112 mkdir $NEW/second/second/difftype/dir 113 mkfifo $TEST/second/second/difftype/dir 114 115 # /second/second/difflinks: Newly added link conflicts with 116 # existing link in test tree. Should generate a warning. 117 ln -s "new link" $NEW/second/second/difflinks/link 118 ln -s "test link" $TEST/second/second/difflinks/link 119 120 # /second/second/difffiles: Newly added file conflicts with 121 # existing file in test tree. Should generate a warning. 122 echo "new" > $NEW/second/second/difffiles/file 123 echo "test" > $TEST/second/second/difffiles/file 124 125 # /difftype/first/first: A removed file has changed type. 126 # This should generate a warning. 127 mkfifo $OLD/difftype/first/first/fifo 128 mkdir $NEW/difftype/first/first/fifo 129 130 # /difftype/difftype/difftype: All three files (old, new, and 131 # test) are different types from each other. This should 132 # generate a warning. 133 mkfifo $OLD/difftype/difftype/difftype/one 134 mkdir $NEW/difftype/difftype/difftype/one 135 echo "foo" > $TEST/difftype/difftype/difftype/one 136 mkdir $OLD/difftype/difftype/difftype/two 137 echo "baz" > $NEW/difftype/difftype/difftype/two 138 ln -s "bar" $TEST/difftype/difftype/difftype/two 139 140 # /difftype/difftype/difflinks: A file has changed from a 141 # non-link to a link in both the new and test trees, but the 142 # target of the new and test links differ. This should 143 # generate a new link conflict. 144 mkfifo $OLD/difftype/difftype/difflinks/link 145 ln -s "new" $NEW/difftype/difftype/difflinks/link 146 ln -s "test" $TEST/difftype/difftype/difflinks/link 147 148 # /difftype/difftype/difffile: A file has changed from a 149 # non-regular file to a regular file in both the new and test 150 # trees, but the contents in the new and test files differ. 151 # This should generate a new file conflict. 152 ln -s "old" $OLD/difftype/difftype/difffiles/file 153 echo "foo" > $NEW/difftype/difftype/difffiles/file 154 echo "bar" > $TEST/difftype/difftype/difffiles/file 155 156 # /difflinks/first/first: A modified link is missing in the 157 # test tree. This should generate a warning. 158 ln -s "old" $OLD/difflinks/first/first/link 159 ln -s "new" $NEW/difflinks/first/first/link 160 161 # /difflinks/difftype/difftype: An updated link has been 162 # changed to a different file type in the test tree. This 163 # should generate a warning. 164 ln -s "old" $OLD/difflinks/difftype/difftype/link 165 ln -s "new" $NEW/difflinks/difftype/difftype/link 166 echo "test" > $TEST/difflinks/difftype/difftype/link 167 168 # /difflinks/difflinks/difflinks: An updated link has been 169 # modified in the test tree and doesn't match either the old 170 # or new links. This should generate a warning. 171 ln -s "old" $OLD/difflinks/difflinks/difflinks/link 172 ln -s "new" $NEW/difflinks/difflinks/difflinks/link 173 ln -s "test" $TEST/difflinks/difflinks/difflinks/link 174 175 # /difffiles/first/first: A removed file has been changed in 176 # the new tree. This should generate a warning. 177 echo "foo" > $OLD/difffiles/first/first/file 178 echo "bar" > $NEW/difffiles/first/first/file 179 180 # /difffiles/difftype/difftype: An updated regular file has 181 # been changed to a different file type in the test tree. 182 # This should generate a warning. 183 echo "old" > $OLD/difffiles/difftype/difftype/file 184 echo "new" > $NEW/difffiles/difftype/difftype/file 185 mkfifo $TEST/difffiles/difftype/difftype/file 186 187 # /difffiles/difffiles/difffiles: A modified regular file was 188 # updated in the new tree. The changes should be merged into 189 # to the new file if possible. If the merge fails, a conflict 190 # should be generated. For this test we just include the 191 # conflict case. 192 cat > $OLD/difffiles/difffiles/difffiles/conflict <<EOF 193this is an old file 194EOF 195 cat > $NEW/difffiles/difffiles/difffiles/conflict <<EOF 196this is a new file 197EOF 198 cat > $TEST/difffiles/difffiles/difffiles/conflict <<EOF 199this is a test file 200EOF 201 202 ## Tests for adding directories 203 mkdir -p $OLD/adddir $NEW/adddir $TEST/adddir 204 205 # /adddir/conflict: Add a new file in a directory that already 206 # exists as a file. This should generate two warnings. 207 mkdir $NEW/adddir/conflict 208 touch $NEW/adddir/conflict/newfile 209 touch $TEST/adddir/conflict 210 211 ## Tests for removing directories 212 mkdir -p $OLD/rmdir $NEW/rmdir $TEST/rmdir 213 214 # /rmdir/extra: Do not remove a directory with an extra local file. 215 # This should generate a warning. 216 for i in $OLD $TEST; do 217 mkdir $i/rmdir/extra 218 done 219 echo "foo" > $TEST/rmdir/extra/localfile.txt 220 221 # /rmdir/conflict: Do not remove a directory with a conflicted 222 # remove file. This should generate a warning. 223 for i in $OLD $TEST; do 224 mkdir $i/rmdir/conflict 225 done 226 mkfifo $OLD/rmdir/conflict/difftype 227 mkdir $TEST/rmdir/conflict/difftype 228 229 ## Tests for converting files to directories and vice versa 230 for i in $OLD $NEW $TEST; do 231 for j in already old fromdir todir; do 232 mkdir -p $i/dirchange/$j 233 done 234 done 235 236 # /dirchange/fromdir/extradir: Convert a directory tree to a 237 # file. The test tree includes an extra file in the directory 238 # that is not present in the old tree. This should generate a 239 # warning. 240 for i in $OLD $TEST; do 241 mkdir $i/dirchange/fromdir/extradir 242 echo "foo" > $i/dirchange/fromdir/extradir/file 243 done 244 mkfifo $TEST/dirchange/fromdir/extradir/fifo 245 ln -s "bar" $NEW/dirchange/fromdir/extradir 246 247 # /dirchange/fromdir/conflict: Convert a directory tree to a 248 # file. The test tree includes a local change that generates 249 # a warning and prevents the removal of the directory. 250 for i in $OLD $TEST; do 251 mkdir $i/dirchange/fromdir/conflict 252 done 253 echo "foo" > $OLD/dirchange/fromdir/conflict/somefile 254 echo "bar" > $TEST/dirchange/fromdir/conflict/somefile 255 mkfifo $NEW/dirchange/fromdir/conflict 256 257 # /dirchange/todir/difffile: Convert a file to a directory 258 # tree. The test tree has a locally modified version of the 259 # file so that the conversion fails with a warning. 260 echo "foo" > $OLD/dirchange/todir/difffile 261 mkdir $NEW/dirchange/todir/difffile 262 echo "baz" > $NEW/dirchange/todir/difffile/file 263 echo "bar" > $TEST/dirchange/todir/difffile 264 265 # /dirchange/todir/difftype: Similar to the previous test, but 266 # the conflict is due to a change in the file type. 267 echo "foo" > $OLD/dirchange/todir/difftype 268 mkdir $NEW/dirchange/todir/difftype 269 echo "baz" > $NEW/dirchange/todir/difftype/file 270 mkfifo $TEST/dirchange/todir/difftype 271} 272 273# $1 - relative path to file that should be missing from TEST 274missing() 275{ 276 if [ -e $TEST/$1 -o -L $TEST/$1 ]; then 277 echo "File $1 should be missing" 278 FAILED=yes 279 fi 280} 281 282# $1 - relative path to file that should be present in TEST 283present() 284{ 285 if ! [ -e $TEST/$1 -o -L $TEST/$1 ]; then 286 echo "File $1 should be present" 287 FAILED=yes 288 fi 289} 290 291# $1 - relative path to file that should be a fifo in TEST 292fifo() 293{ 294 if ! [ -p $TEST/$1 ]; then 295 echo "File $1 should be a FIFO" 296 FAILED=yes 297 fi 298} 299 300# $1 - relative path to file that should be a directory in TEST 301dir() 302{ 303 if ! [ -d $TEST/$1 ]; then 304 echo "File $1 should be a directory" 305 FAILED=yes 306 fi 307} 308 309# $1 - relative path to file that should be a symlink in TEST 310# $2 - optional value of the link 311link() 312{ 313 local val 314 315 if ! [ -L $TEST/$1 ]; then 316 echo "File $1 should be a link" 317 FAILED=yes 318 elif [ $# -gt 1 ]; then 319 val=`readlink $TEST/$1` 320 if [ "$val" != "$2" ]; then 321 echo "Link $1 should link to \"$2\"" 322 FAILED=yes 323 fi 324 fi 325} 326 327# $1 - relative path to regular file that should be present in TEST 328# $2 - optional string that should match file contents 329# $3 - optional MD5 of the flie contents, overrides $2 if present 330file() 331{ 332 local contents sum 333 334 if ! [ -f $TEST/$1 ]; then 335 echo "File $1 should be a regular file" 336 FAILED=yes 337 elif [ $# -eq 2 ]; then 338 contents=`cat $TEST/$1` 339 if [ "$contents" != "$2" ]; then 340 echo "File $1 has wrong contents" 341 FAILED=yes 342 fi 343 elif [ $# -eq 3 ]; then 344 sum=`md5 -q $TEST/$1` 345 if [ "$sum" != "$3" ]; then 346 echo "File $1 has wrong contents" 347 FAILED=yes 348 fi 349 fi 350} 351 352# $1 - relative path to a regular file that should have a conflict 353# $2 - optional MD5 of the conflict file contents 354conflict() 355{ 356 local sum 357 358 if ! [ -f $CONFLICTS/$1 ]; then 359 echo "File $1 missing conflict" 360 FAILED=yes 361 elif [ $# -gt 1 ]; then 362 sum=`md5 -q $CONFLICTS/$1` 363 if [ "$sum" != "$2" ]; then 364 echo "Conflict $1 has wrong contents" 365 FAILED=yes 366 fi 367 fi 368} 369 370# $1 - relative path to a regular file that should not have a conflict 371noconflict() 372{ 373 if [ -f $CONFLICTS/$1 ]; then 374 echo "File $1 should not have a conflict" 375 FAILED=yes 376 fi 377} 378 379if [ `id -u` -ne 0 ]; then 380 echo "must be root" 381 exit 0 382fi 383 384if [ -r /etc/etcupdate.conf ]; then 385 echo "WARNING: /etc/etcupdate.conf settings may break some tests." 386fi 387 388# First run the test ignoring no patterns. 389 390build_trees 391 392$COMMAND -r -d $WORKDIR -D $TEST > $WORKDIR/test.out 393 394cat > $WORKDIR/correct.out <<EOF 395 D /dirchange/fromdir/extradir/file 396 C /difffiles/difffiles/difffiles/conflict 397 C /difftype/difftype/difffiles/file 398 C /second/second/difffiles/file 399Warnings: 400 Modified regular file remains: /dirchange/fromdir/conflict/somefile 401 Modified regular file remains: /first/difffiles/second/file 402 Modified symbolic link remains: /first/difflinks/second/link 403 Modified directory remains: /first/difftype/second/fifo 404 Modified directory remains: /rmdir/conflict/difftype 405 Non-empty directory remains: /rmdir/extra 406 Non-empty directory remains: /rmdir/conflict 407 Modified mismatch: /difffiles/difftype/difftype/file (regular file vs fifo file) 408 Removed file changed: /difffiles/first/first/file 409 Modified link changed: /difflinks/difflinks/difflinks/link ("old" became "new") 410 Modified mismatch: /difflinks/difftype/difftype/link (symbolic link vs regular file) 411 Removed link changed: /difflinks/first/first/link ("old" became "new") 412 New link conflict: /difftype/difftype/difflinks/link ("new" vs "test") 413 Modified regular file changed: /difftype/difftype/difftype/one (fifo file became directory) 414 Modified symbolic link changed: /difftype/difftype/difftype/two (directory became regular file) 415 Remove mismatch: /difftype/first/first/fifo (fifo file became directory) 416 Modified directory changed: /dirchange/fromdir/conflict (directory became fifo file) 417 Modified directory changed: /dirchange/fromdir/extradir (directory became symbolic link) 418 Modified regular file changed: /dirchange/todir/difffile (regular file became directory) 419 Modified fifo file changed: /dirchange/todir/difftype (regular file became directory) 420 New file mismatch: /adddir/conflict (directory vs regular file) 421 Directory mismatch: $TEST/adddir/conflict (regular file) 422 Directory mismatch: $TEST/dirchange/todir/difffile (regular file) 423 Directory mismatch: $TEST/dirchange/todir/difftype (fifo file) 424 New link conflict: /second/second/difflinks/link ("new link" vs "test link") 425 New file mismatch: /second/second/difftype/dir (directory vs fifo file) 426EOF 427 428echo "Differences for regular:" 429diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out \ 430 || FAILED=yes 431 432## /first/difftype/second: 433present /first/difftype/second/fifo 434 435## /first/difflinks/second: 436link /first/difflinks/second/link "test link" 437 438## /first/difffiles/second: 439file /first/difffiles/second/file "bar" 440 441## /second/second/difftype: 442fifo /second/second/difftype/dir 443 444## /second/second/difflinks: 445link /second/second/difflinks/link "test link" 446 447## /second/second/difffiles: 448file /second/second/difffiles/file "test" 449conflict /second/second/difffiles/file 4f2ee8620a251fd53f06bb6112eb6ffa 450 451## /difftype/first/first: 452missing /difftype/first/first/fifo 453 454## /difftype/difftype/difftype: 455file /difftype/difftype/difftype/one "foo" 456link /difftype/difftype/difftype/two "bar" 457 458## /difftype/difftype/difflinks: 459link /difftype/difftype/difflinks/link "test" 460 461## /difftype/difftype/difffile: 462conflict /difftype/difftype/difffiles/file 117f2bcd1f6491f6044e79e5a57a9229 463 464## /difflinks/first/first: 465missing /difflinks/first/first/link 466 467## /difflinks/difftype/difftype: 468file /difflinks/difftype/difftype/link "test" 469 470## /difflinks/difflinks/difflinks: 471link /difflinks/difflinks/difflinks/link "test" 472 473## /difffiles/first/first: 474missing /difffiles/first/first/file 475 476## /difffiles/difftype/difftype: 477fifo /difffiles/difftype/difftype/file 478 479## /difffiles/difffiles/difffiles: 480file /difffiles/difffiles/difffiles/conflict "this is a test file" 481conflict /difffiles/difffiles/difffiles/conflict \ 482 8261cfdd89280c4a6c26e4ac86541fe9 483 484## /adddir/conflict: 485file /adddir/conflict 486 487## /rmdir/extra: 488dir /rmdir/extra 489file /rmdir/extra/localfile.txt "foo" 490 491## /rmdir/conflict: 492dir /rmdir/conflict/difftype 493present /rmdir/conflict 494 495## /dirchange/fromdir/extradir: 496missing /dirchange/fromdir/extradir/file 497fifo /dirchange/fromdir/extradir/fifo 498 499## /dirchange/fromdir/conflict: 500file /dirchange/fromdir/conflict/somefile "bar" 501 502## /dirchange/todir/difffile: 503file /dirchange/todir/difffile "bar" 504 505## /dirchange/todir/difftype: 506fifo /dirchange/todir/difftype 507 508# Now test with -A '/first*' -A '/second* /*di*'. This should remove 509# most of the warnings and conflicts. 510 511build_trees 512 513$COMMAND -r -A '/first*' -A '/second* /*di*' -d $WORKDIR -D $TEST > \ 514 $WORKDIR/test1.out 515 516cat > $WORKDIR/correct1.out <<EOF 517 D /dirchange/fromdir/extradir/file 518 U /difffiles/difffiles/difffiles/conflict 519 U /difffiles/difftype/difftype/file 520 A /difffiles/first/first/file 521 U /difflinks/difflinks/difflinks/link 522 U /difflinks/difftype/difftype/link 523 A /difflinks/first/first/link 524 U /difftype/difftype/difffiles/file 525 U /difftype/difftype/difflinks/link 526 D /difftype/difftype/difftype/one 527 U /difftype/difftype/difftype/two 528 U /dirchange/todir/difffile 529 U /dirchange/todir/difftype 530 U /adddir/conflict 531 A /adddir/conflict/newfile 532 A /dirchange/todir/difffile/file 533 A /dirchange/todir/difftype/file 534 U /second/second/difffiles/file 535 U /second/second/difflinks/link 536 D /second/second/difftype/dir 537Warnings: 538 Modified regular file remains: /dirchange/fromdir/conflict/somefile 539 Modified regular file remains: /first/difffiles/second/file 540 Modified symbolic link remains: /first/difflinks/second/link 541 Modified directory remains: /first/difftype/second/fifo 542 Modified directory remains: /rmdir/conflict/difftype 543 Non-empty directory remains: /rmdir/extra 544 Non-empty directory remains: /rmdir/conflict 545 Modified directory changed: /dirchange/fromdir/conflict (directory became fifo file) 546 Modified directory changed: /dirchange/fromdir/extradir (directory became symbolic link) 547EOF 548 549echo "Differences for -A '/first*' -A '/second* /*di*':" 550diff -u -L "correct" $WORKDIR/correct1.out -L "test" $WORKDIR/test1.out \ 551 || FAILED=yes 552 553## /first/difftype/second: 554present /first/difftype/second/fifo 555 556## /first/difflinks/second: 557link /first/difflinks/second/link "test link" 558 559## /first/difffiles/second: 560file /first/difffiles/second/file "bar" 561 562## /second/second/difftype: 563missing /second/second/difftype/dir 564 565## /second/second/difflinks: 566link /second/second/difflinks/link "new link" 567 568## /second/second/difffiles: 569file /second/second/difffiles/file "new" 570noconflict /second/second/difffiles/file 571 572## /difftype/first/first: 573missing /difftype/first/first/fifo 574 575## /difftype/difftype/difftype: 576missing /difftype/difftype/difftype/one 577file /difftype/difftype/difftype/two "baz" 578 579## /difftype/difftype/difflinks: 580link /difftype/difftype/difflinks/link "new" 581 582## /difftype/difftype/difffile: 583noconflict /difftype/difftype/difffiles/file 584file /difftype/difftype/difffiles/file "foo" 585 586## /difflinks/first/first: 587link /difflinks/first/first/link "new" 588 589## /difflinks/difftype/difftype: 590link /difflinks/difftype/difftype/link "new" 591 592## /difflinks/difflinks/difflinks: 593link /difflinks/difflinks/difflinks/link "new" 594 595## /difffiles/first/first: 596file /difffiles/first/first/file "bar" 597 598## /difffiles/difftype/difftype: 599file /difffiles/difftype/difftype/file "new" 600 601## /difffiles/difffiles/difffiles: 602noconflict /difffiles/difffiles/difffiles/conflict 603file /difffiles/difffiles/difffiles/conflict "this is a new file" 604 605## /adddir/conflict: 606file /adddir/conflict/newfile 607 608## /rmdir/extra: 609dir /rmdir/extra 610file /rmdir/extra/localfile.txt "foo" 611 612## /rmdir/conflict: 613dir /rmdir/conflict/difftype 614present /rmdir/conflict 615 616## /dirchange/fromdir/extradir: 617missing /dirchange/fromdir/extradir/file 618fifo /dirchange/fromdir/extradir/fifo 619 620## /dirchange/fromdir/conflict: 621file /dirchange/fromdir/conflict/somefile "bar" 622 623## /dirchange/todir/difffile: 624file /dirchange/todir/difffile/file "baz" 625 626## /dirchange/todir/difftype: 627file /dirchange/todir/difftype/file "baz" 628 629[ "${FAILED}" = no ] 630