1#!/bin/sh 2 3# Copyright (C) 2001 by Martin Pool <mbp@samba.org> 4 5# General-purpose test functions for rsync. 6 7# This program is free software; you can redistribute it and/or modify 8# it under the terms of the GNU General Public License version 9# 2 as published by the Free Software Foundation. 10# 11# This program is distributed in the hope that it will be useful, but 12# WITHOUT ANY WARRANTY; without even the implied warranty of 13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14# Lesser General Public License for more details. 15# 16# You should have received a copy of the GNU Lesser General Public 17# License along with this program; if not, write to the Free Software 18# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 20tmpdir="$scratchdir" 21fromdir="$tmpdir/from" 22todir="$tmpdir/to" 23chkdir="$tmpdir/chk" 24 25# For itemized output: 26all_plus='++++++++++' 27allspace=' ' 28dots='......' # trailing dots after changes 29tab_ch=' ' # a single tab character 30 31# Berkley's nice. 32PATH="$PATH:/usr/ucb" 33 34if diff -u "$suitedir/rsync.fns" "$suitedir/rsync.fns" >/dev/null 2>&1; then 35 diffopt="-u" 36else 37 diffopt="-c" 38fi 39 40HOME="$scratchdir" 41export HOME 42 43runtest() { 44 echo $ECHO_N "Test $1: $ECHO_C" 45 if eval "$2" 46 then 47 echo "$ECHO_T done." 48 return 0 49 else 50 echo "$ECHO_T failed!" 51 return 1 52 fi 53} 54 55set_cp_destdir() { 56 while test $# -gt 1; do 57 shift 58 done 59 destdir="$1" 60} 61 62# Perform a "cp -p", making sure that timestamps are really the same, 63# even if the copy rounded microsecond times on the destination file. 64cp_touch() { 65 cp_p "${@}" 66 if test $# -gt 2 -o -d "$2"; then 67 set_cp_destdir "${@}" # sets destdir var 68 while test $# -gt 1; do 69 destname="$destdir/`basename $1`" 70 touch -r "$destname" "$1" "$destname" 71 shift 72 done 73 else 74 touch -r "$2" "$1" "$2" 75 fi 76} 77 78# Call this if you want to filter out verbose messages (-v or -vv) from 79# the output of an rsync run (whittling the output down to just the file 80# messages). This isn't needed if you use -i without -v. 81filter_outfile() { 82 sed -e '/^building file list /d' \ 83 -e '/^sending incremental file list/d' \ 84 -e '/^created directory /d' \ 85 -e '/^done$/d' \ 86 -e '/ --whole-file$/d' \ 87 -e '/^total: /d' \ 88 -e '/^client charset: /d' \ 89 -e '/^server charset: /d' \ 90 -e '/^$/,$d' \ 91 <"$outfile" >"$outfile.new" 92 mv "$outfile.new" "$outfile" 93} 94 95printmsg() { 96 echo "$1" 97} 98 99rsync_ls_lR() { 100 find "$@" -name .git -prune -o -name auto-build-save -prune -o -print | \ 101 sort | sed 's/ /\\ /g' | xargs "$TOOLDIR/tls" $TLS_ARGS 102} 103 104get_testuid() { 105 uid=`id -u 2>/dev/null || true` 106 case "$uid" in 107 [0-9]*) echo "$uid" ;; 108 *) id 2>/dev/null | sed 's/^[^0-9]*\([0-9][0-9]*\).*/\1/' ;; 109 esac 110} 111 112get_rootuid() { 113 uid=`id -u root 2>/dev/null || true` 114 case "$uid" in 115 [0-9]*) echo "$uid" ;; 116 *) echo 0 ;; 117 esac 118} 119 120get_rootgid() { 121 gid=`id -g root 2>/dev/null || true` 122 case "$gid" in 123 [0-9]*) echo "$gid" ;; 124 *) echo 0 ;; 125 esac 126} 127 128# When copying via "cp -p", we want to ensure that a non-root user does not 129# preserve ownership (we want our files to be created as the testing user). 130# For instance, a Cygwin CI run might have git files owned by a different 131# user than the (admin) user running the tests. 132cp_cmd="cp -p" 133if test x`get_testuid` != x0; then 134 case `cp --help 2>/dev/null` in 135 *--no-preserve=*) cp_cmd="cp -p --no-preserve=ownership" ;; 136 esac 137fi 138cp_p() { 139 $cp_cmd "${@}" || test_fail "$cp_cmd failed" 140} 141 142check_perms() { 143 perms=`"$TOOLDIR/tls" "$1" | sed 's/^[-d]\(.........\).*/\1/'` 144 if test $perms = $2; then 145 return 0 146 fi 147 echo "permissions: $perms on $1" 148 echo "should be: $2" 149 test_fail "failed test $3" 150} 151 152rsync_getgroups() { 153 "$TOOLDIR/getgroups" 154} 155 156 157#################### 158# Build test directories $todir and $fromdir, with $fromdir full of files. 159 160hands_setup() { 161 # Clean before creation 162 rm -rf "$fromdir" 163 rm -rf "$todir" 164 165 [ -d "$tmpdir" ] || mkdir "$tmpdir" 166 [ -d "$fromdir" ] || mkdir "$fromdir" 167 [ -d "$todir" ] || mkdir "$todir" 168 169 # On some BSD systems, the umask affects the mode of created 170 # symlinks, even though the mode apparently has no effect on how 171 # the links behave in the future, and it cannot be changed using 172 # chmod! rsync always sets its umask to 000 so that it can 173 # accurately recreate permissions, but this script is probably run 174 # with a different umask. 175 176 # This causes a little problem that "ls -l" of the two will not be 177 # the same. So, we need to set our umask before doing any creations. 178 179 # set up test data 180 touch "$fromdir/empty" 181 mkdir "$fromdir/emptydir" 182 183 # a hundred lines of text or so 184 rsync_ls_lR "$srcdir" > "$fromdir/filelist" 185 186 echo $ECHO_N "This file has no trailing lf$ECHO_C" > "$fromdir/nolf" 187 umask 0 188 ln -s nolf "$fromdir/nolf-symlink" 189 umask 022 190 191 cat "$srcdir"/*.c > "$fromdir/text" 192 mkdir "$fromdir/dir" 193 cp "$fromdir/text" "$fromdir/dir" 194 mkdir "$fromdir/dir/subdir" 195 echo some data > "$fromdir/dir/subdir/foobar.baz" 196 mkdir "$fromdir/dir/subdir/subsubdir" 197 if [ -r /etc ]; then 198 ls -ltr /etc > "$fromdir/dir/subdir/subsubdir/etc-ltr-list" 199 else 200 ls -ltr / > "$fromdir/dir/subdir/subsubdir/etc-ltr-list" 201 fi 202 mkdir "$fromdir/dir/subdir/subsubdir2" 203 if [ -r /bin ]; then 204 ls -lt /bin > "$fromdir/dir/subdir/subsubdir2/bin-lt-list" 205 else 206 ls -lt / > "$fromdir/dir/subdir/subsubdir2/bin-lt-list" 207 fi 208 209# echo testing head: 210# ls -lR "$srcdir" | head -10 || echo failed 211} 212 213 214#################### 215# Many machines do not have "mkdir -p", so we have to build up long paths. 216# How boring. 217makepath() { 218 for p in "${@}"; do 219 (echo " makepath $p" 220 221 # Absolute Unix path. 222 if echo $p | grep '^/' >/dev/null 223 then 224 cd / 225 fi 226 227 # This will break if $p contains a space. 228 for c in `echo $p | tr '/' ' '` 229 do 230 if [ -d "$c" ] || mkdir "$c" 231 then 232 cd "$c" || return $? 233 else 234 echo "failed to create $c" >&2; return $? 235 fi 236 done) 237 done 238} 239 240 241 242########################### 243# Run a test (in '$1') then compare directories $2 and $3 to see if 244# there are any difference. If there are, explain them. 245 246# So normally basically $1 should be an rsync command, and $2 and $3 247# the source and destination directories. This is only good when you 248# expect to transfer the whole directory exactly as is. If some files 249# should be excluded, you might need to use something else. 250 251checkit() { 252 failed= 253 254 # We can just write everything to stdout/stderr, because the 255 # wrapper hides it unless there is a problem. 256 257 case "x$TLS_ARGS" in 258 *--atimes*) 259 ( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from" 260 ;; 261 *) 262 ;; 263 esac 264 265 echo "Running: \"$1\"" 266 eval "$1" 267 status=$? 268 if [ $status != 0 ]; then 269 failed="$failed status=$status" 270 fi 271 272 case "x$TLS_ARGS" in 273 *--atimes*) 274 ;; 275 *) 276 ( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from" 277 ;; 278 esac 279 280 echo "-------------" 281 echo "check how the directory listings compare with diff:" 282 echo "" 283 ( cd "$3" && rsync_ls_lR . ) > "$tmpdir/ls-to" 284 diff $diffopt "$tmpdir/ls-from" "$tmpdir/ls-to" || failed="$failed dir-diff" 285 286 echo "-------------" 287 echo "check how the files compare with diff:" 288 echo "" 289 if [ "x$4" != x ]; then 290 echo " === Skipping (as directed) ===" 291 else 292 diff -r $diffopt "$2" "$3" || failed="$failed file-diff" 293 fi 294 295 echo "-------------" 296 if [ -z "$failed" ] ; then 297 return 0 298 fi 299 300 echo "Failed: $failed" 301 return 1 302} 303 304 305build_rsyncd_conf() { 306 # Build an appropriate configuration file 307 conf="$scratchdir/test-rsyncd.conf" 308 echo "building configuration $conf" 309 310 port=2612 311 pidfile="$scratchdir/rsyncd.pid" 312 logfile="$scratchdir/rsyncd.log" 313 hostname=`uname -n` 314 315 my_uid=`get_testuid` 316 root_uid=`get_rootuid` 317 root_gid=`get_rootgid` 318 319 uid_setting="uid = $root_uid" 320 gid_setting="gid = $root_gid" 321 322 if test x"$my_uid" != x"$root_uid"; then 323 # Non-root cannot specify uid & gid settings 324 uid_setting="#$uid_setting" 325 gid_setting="#$gid_setting" 326 fi 327 328 cat >"$conf" <<EOF 329# rsyncd configuration file autogenerated by $0 330 331pid file = $pidfile 332use chroot = no 333munge symlinks = no 334hosts allow = localhost 127.0.0.0/24 192.168.0.0/16 10.0.0.0/8 $hostname 335log file = $logfile 336transfer logging = yes 337# We don't define log format here so that the test-hidden module will default 338# to the internal static string (since we had a crash trying to tweak it). 339exclude = ? foobar.baz 340max verbosity = 4 341$uid_setting 342$gid_setting 343 344[test-from] 345 path = $fromdir 346 log format = %i %h [%a] %m (%u) %l %f%L 347 read only = yes 348 comment = r/o 349 350[test-to] 351 path = $todir 352 log format = %i %h [%a] %m (%u) %l %f%L 353 read only = no 354 comment = r/w 355 356[test-scratch] 357 path = $scratchdir 358 log format = %i %h [%a] %m (%u) %l %f%L 359 read only = no 360 361[test-hidden] 362 path = $fromdir 363 list = no 364EOF 365 366 # Build a helper script to ignore exit code 23 367 ignore23="$scratchdir/ignore23" 368 echo "building help script $ignore23" 369 370 cat >"$ignore23" <<'EOT' 371if "${@}"; then 372 exit 373fi 374 375ret=$? 376 377if test $ret = 23; then 378 exit 379fi 380 381exit $ret 382EOT 383chmod +x "$ignore23" 384} 385 386 387build_symlinks() { 388 mkdir "$fromdir" 389 date >"$fromdir/referent" 390 ln -s referent "$fromdir/relative" 391 ln -s "$fromdir/referent" "$fromdir/absolute" 392 ln -s nonexistent "$fromdir/dangling" 393 ln -s "$srcdir/rsync.c" "$fromdir/unsafe" 394} 395 396test_fail() { 397 echo "$@" >&2 398 exit 1 399} 400 401test_skipped() { 402 echo "$@" >&2 403 echo "$@" > "$tmpdir/whyskipped" 404 exit 77 405} 406 407# It failed, but we expected that. don't dump out error logs, 408# because most users won't want to see them. But do leave 409# the working directory around. 410test_xfail() { 411 echo "$@" >&2 412 exit 78 413} 414 415# Determine what shell command will appropriately test for links. 416ln -s foo "$scratchdir/testlink" 417for cmd in test /bin/test /usr/bin/test /usr/ucb/bin/test /usr/ucb/test 418do 419 for switch in -h -L 420 do 421 if $cmd $switch "$scratchdir/testlink" 2>/dev/null 422 then 423 # how nice 424 TEST_SYMLINK_CMD="$cmd $switch" 425 # i wonder if break 2 is portable? 426 break 2 427 fi 428 done 429done 430# ok, now get rid of it 431rm "$scratchdir/testlink" 432 433 434if [ "x$TEST_SYMLINK_CMD" = 'x' ] 435then 436 test_fail "Couldn't determine how to test for symlinks" 437else 438 echo "Testing for symlinks using '$TEST_SYMLINK_CMD'" 439fi 440 441 442# Test whether something is a link, allowing for shell peculiarities 443is_a_link() { 444 # note the variable contains the first option and therefore is not quoted 445 $TEST_SYMLINK_CMD "$1" 446} 447 448 449# We need to set the umask to be reproducible. Note also that when we 450# do some daemon tests as root, we will setuid() and therefore the 451# directory has to be writable by the nobody user in some cases. The 452# best thing is probably to explicitly chmod those directories after 453# creation. 454 455umask 022 456