xref: /illumos-gate/usr/src/test/util-tests/tests/cpmvln/overwrite.ksh (revision 6cf3cc9d1e40f89e90135a48f74f03f879fce639)
1#!/usr/bin/ksh
2#
3# This file and its contents are supplied under the terms of the
4# Common Development and Distribution License ("CDDL"), version 1.0.
5# You may only use this file in accordance with the terms of version
6# 1.0 of the CDDL.
7#
8# A full copy of the text of the CDDL should have accompanied this
9# source.  A copy of the CDDL is also available via the Internet at
10# http://www.illumos.org/license/CDDL.
11#
12
13#
14# Copyright 2024 Oxide Computer Company
15#
16
17#
18# This test exercises the various overwriting, interactivity, and related
19# features of cp, mv, and ln (which are all built from the same source). Each
20# program may be set up to operate interactively (-i), to not touch a file if it
21# already exists (-n), and to forcefully remove it anyways (-f). cp implements
22# -i and -n, -f means something different. mv implements all three flags. ln
23# implements -i and -f (-n is a pseudo-default).
24#
25
26unalias -a
27set -o pipefail
28export LANG=C.UTF-8
29
30#
31# Program paths for interposing while testing.
32#
33MV=${MV:-"/usr/bin/mv"}
34XMV=${XMV:-"/usr/xpg4/bin/mv"}
35CP=${CP:-"/usr/bin/cp"}
36XCP=${XCP:-"/usr/xpg4/bin/cp"}
37LN=${LN:-"/usr/bin/ln"}
38XLN=${XLN:-"/usr/xpg4/bin/ln"}
39
40ovr_exit=0
41ovr_arg0=$(basename $0)
42ovr_tdir=$(dirname $0)
43ovr_mkobj="$ovr_tdir/mkobj"
44ovr_check="$ovr_tdir/checker"
45ovr_work="/tmp/$ovr_arg0.$$"
46
47typeset -A ovr_files=(
48	["a"]=(type="file" path="$ovr_work/a")
49	["b"]=(type="file" path="$ovr_work/b")
50	["c"]=(type="noperms" path="$ovr_work/c")
51	["fifo"]=(type="fifo" path="$ovr_work/fifo")
52	["door"]=(type="door" path="$ovr_work/door")
53	["uds"]=(type="uds" path="$ovr_work/uds")
54	["symlink"]=(type="symlink" path="$ovr_work/symlink")
55	["dangle"]=(type="dangle" path="$ovr_work/dangle")
56	["dir"]=(type="dir" path="$ovr_work/dir")
57	["dir/a"]=(type="file-dm" path="$ovr_work/dir/a")
58	["dir/b"]=(type="empty" path="$ovr_work/dir/b")
59	["dir/c"]=(type="noperms-dm" path="$ovr_work/dir/c")
60	["dir/fifo"]=(type="fifo-dm" path="$ovr_work/dir/fifo")
61	["dir/door"]=(type="door-dm" path="$ovr_work/dir/door")
62	["dir/uds"]=(type="uds-dm" path="$ovr_work/dir/uds")
63	["dir/symlink"]=(type="symlink-dm" path="$ovr_work/dir/symlink")
64	["dir/dangle"]=(type="dangle-dm" path="$ovr_work/dir/dangle")
65)
66
67function fatal
68{
69	typeset msg="$*"
70	echo "TEST FAILED: $msg" >&2
71	exit 1
72}
73
74function warn
75{
76	typeset msg="$*"
77	echo "TEST FAILED: $msg" >&2
78	ovr_exit=1
79}
80
81function cleanup
82{
83	rm -rf $ovr_work/
84}
85
86#
87# Make the files that are required for this particular test.
88#
89function setup_files
90{
91	mkdir "$ovr_work" || fatal "failed to make test directory"
92	for f in $@; do
93		typeset targ=${ovr_files[$f].path}
94		typeset ftype=${ovr_files[$f].type}
95		case $ftype in
96		file)
97			echo $f > $targ || fatal "failed to create $f"
98			;;
99		empty)
100			touch $targ || fatal "failed to create $f"
101			;;
102		noperms)
103			echo $f > $targ || fatal "failed to create $f"
104			chmod 0000 $targ || fatal "failed to chmod $f"
105			;;
106		fifo)
107			$ovr_mkobj -f $targ || fatal "failed to make fifo"
108			;;
109		door)
110			$ovr_mkobj -d $targ || fatal "failed to make door"
111			;;
112		uds)
113			$ovr_mkobj -s $targ || fatal "failed to make uds"
114			;;
115		symlink)
116			ln -s ${ovr_files["b"].path} $targ || \
117			    fatal "failed to make symlink"
118			;;
119		dangle)
120			ln -s "$ovr_work/enoent" $targ || \
121			     fatal "failed to make dangling symlink"
122			;;
123		dir)
124			mkdir -p $targ || fatal "failed to make directory"
125			;;
126		*)
127			fatal "encountered unknown type $f: $ftype"
128		esac
129	done
130}
131
132#
133# Check files remain what we expect at this point. Arguments passed should be
134# the short form.
135#
136function check_files
137{
138	typeset desc=$1
139	shift
140	for f in $@; do
141		typeset targ=${ovr_files[$f].path}
142		typeset ftype=${ovr_files[$f].type}
143		typeset data=
144		case $ftype in
145		file*)
146			#
147			# A file should have the data that matches its short
148			# name inside of it.
149			#
150			typeset exp=${f##*/}
151			data=$(cat $targ)
152			if [[ $data != $exp ]]; then
153				warn "$desc: found unexpected file data $data" \
154				    "expected $exp"
155				return 1
156			fi
157			;;
158		noperms*)
159			if ! $ovr_check -n $targ; then
160				warn "$desc: $targ was clobbered"
161				return 1
162			fi
163			;;
164		fifo*)
165			if [[ ! -p $targ ]]; then
166				warn "$desc: $targ was is somehow no longer" \
167				    "a pipe: $(ls -l $targ)"
168				return 1
169			fi
170			;;
171		door*)
172			if ! $ovr_check -d $targ; then
173				warn "$desc: $targ was clobbered"
174				return 1
175			fi
176			;;
177		uds*)
178			if [[ ! -S $targ ]]; then
179				warn "$desc: $targ was is somehow no longer" \
180				    "a socket: $(ls -l $targ)"
181				return 1
182			fi
183			;;
184		symlink*|dangle*)
185			if [[ ! -L $targ ]]; then
186				warn "$desc: $targ was is somehow no longer" \
187				    "a symlink: $(ls -l $targ)"
188				return 1
189			fi
190			;;
191		dir)
192			if [[ ! -d $targ ]]; then
193				warn "$desc: directory $targ was removed?!"
194				return 1
195			fi
196			;;
197		*)
198			fatal "encountered unknown type $f: $ftype"
199		esac
200	done
201
202	return 0
203}
204
205function check_data
206{
207	typeset desc=$1
208	typeset targ=$2
209	typeset expect=$3
210	typeset data=
211
212	data=$(cat $targ)
213	if [[ $data != $expect ]]; then
214		warn "$desc: $targ wasn't overwritten found $data"
215		return 1;
216	fi
217
218	return 0
219}
220
221#
222# Run a test we expect to fail and verify that files haven't changed.
223#
224function exp_fail
225{
226	typeset desc="$1"
227	typeset prog="$2"
228	typeset files="$3"
229	typeset -a args
230
231	setup_files $files
232	for f in $files; do
233		args+=(${ovr_files[$f].path})
234	done
235
236	if $prog ${args[@]} 2>/dev/null; then
237		warn "$desc: command returned 0, but expected failure"
238		cleanup
239		return
240	fi
241
242	check_files "$desc" "$files" && printf "TEST PASSED: %s\n" "$desc"
243	cleanup
244}
245
246#
247# Run a test where we want to check a particular file's contents after the test
248# passes. The optional last pipe argument is used for testing interactive mode
249# (whether or not a prompt appears is a different question). Interactive mode
250# requires we don't have pipefail turned on to avoid propagating an error when
251# the initial program gets EPIPE or a signal.
252#
253function exp_pass
254{
255	typeset desc="$1"
256	typeset prog="$2"
257	typeset files="$3"
258	typeset expect="$4"
259	typeset pipe="$5"
260	typeset ret=
261	typeset -a args
262
263	setup_files $files
264	for f in $files; do
265		args+=(${ovr_files[$f].path})
266	done
267
268	if [[ -z "$pipe" ]]; then
269		$prog ${args[@]}
270		ret=$?
271	else
272		set +o pipefail
273		$pipe | $prog ${args[@]} 2>/dev/null
274		ret=$?
275		set -o pipefail
276	fi
277
278	if (( ret != 0 )); then
279		warn "$desc: command failed, but expected success"
280		cleanup
281		return
282	fi
283
284	check_data "$desc" "${args[-1]}" "$expect" && \
285	    printf "TEST PASSED: %s\n" "$desc"
286	cleanup
287}
288
289#
290# Variant on exp_pass that expects all the input files to remain the same.
291#
292function exp_retain
293{
294	typeset desc="$1"
295	typeset prog="$2"
296	typeset files="$3"
297	typeset -a args
298
299	setup_files $files
300	for f in $files; do
301		args+=(${ovr_files[$f].path})
302	done
303
304	if ! $prog ${args[@]}; then
305		warn "$desc: command failed, but expected success"
306		cleanup
307		return
308	fi
309
310	if check_files "$desc" "$files"; then
311		printf "TEST PASSED: %s\n" "$desc"
312	fi
313	cleanup
314}
315
316#
317# Tests for a directory. We always set up the files in the directory in addition
318# to what was asked for. Then based on our expectations we make sure that the
319# files were created that we expect. All tests in here should succeed.
320#
321function exp_dir
322{
323	typeset desc="$1"
324	typeset prog="$2"
325	typeset files="$3"
326	typeset rval="$4"
327	typeset exp="$5"
328	typeset bdata="$6"
329	typeset pipe="$7"
330	typeset pass=0
331	typeset -a args
332
333	setup_files $files dir dir/b
334	for f in $files; do
335		args+=(${ovr_files[$f].path})
336	done
337
338	if [[ -z "$pipe" ]]; then
339		$prog ${args[@]} 2>/dev/null
340		ret=$?
341	else
342		set +o pipefail
343		$pipe | $prog ${args[@]} 2>/dev/null
344		ret=$?
345		set -o pipefail
346	fi
347
348	if (( ret != rval )); then
349		warn "$desc: command returned $ret, but expected $rval"
350		cleanup
351		return
352	fi
353
354	if (( ret != 0 )); then
355		cleanup
356		return;
357	fi
358
359	check_files "$desc" $exp || pass=1
360	check_data "$desc" "${ovr_files[dir/b].path}" "$bdata" || pass=1
361	(( pass == 0 )) && printf "TEST PASSED: %s\n" "$desc"
362	cleanup
363}
364
365trap cleanup EXIT
366
367#
368# Start with ln which should fail without -f. Same with ln -s (a different code
369# path).
370#
371exp_fail "ln doesn't clobber a file (ln a b)" "$LN" "a b"
372exp_fail "ln doesn't clobber a file without perms (ln a c)" "$LN" "a c"
373exp_fail "ln doesn't clobber a uds (ln a uds)" "$LN" "a uds"
374exp_fail "ln doesn't clobber a fifo (ln a fifo)" "$LN" "a fifo"
375exp_fail "ln doesn't clobber a door (ln a door)" "$LN" "a door"
376exp_fail "ln doesn't clobber a valid symlink (ln a symlink)" "$LN" "a symlink"
377exp_fail "ln doesn't clobber a dangling symlink (ln a dangle)" "$LN" "a dangle"
378
379exp_fail "ln -s doesn't clobber a file (ln -s a b)" "$LN -s" "a b"
380exp_fail "ln -s doesn't clobber a file without perms (ln -s a c)" "$LN -s" "a c"
381exp_fail "ln -s doesn't clobber a uds (ln -s a uds)" "$LN -s" "a uds"
382exp_fail "ln -s doesn't clobber a fifo (ln -s a fifo)" "$LN -s" "a fifo"
383exp_fail "ln -s doesn't clobber a door (ln -s a door)" "$LN -s" "a door"
384exp_fail "ln -s doesn't clobber a valid symlink (ln -s a symlink)" "$LN -s" \
385    "a symlink"
386exp_fail "ln -s doesn't clobber a dangling symlink (ln -s a dangle)" "$LN -s" \
387    "a dangle"
388
389#
390# Now basic cp tests. We expect cp to fail on most of these because it doesn't
391# have -f specified and therefore can't open the file without permissions or
392# replace and deal with the socket and door. We don't use the fifo because it
393# will basically just cause us to block.
394#
395exp_pass "cp works on a file (cp a b)" "$CP" "a b" "a"
396exp_pass "XPG cp works on a file (cp a b)" "$XCP" "a b" "a"
397exp_fail "cp fails on a file without perms (cp a c)" "$CP" "a c"
398exp_fail "XPG cp fails on a file without perms (cp a c)" "$XCP" "a c"
399exp_fail "cp fails on a uds (cp a sock)" "$CP" "a uds"
400exp_fail "cp fails on a door (cp a door)" "$CP" "a door"
401exp_pass "cp works on a symlink (cp a symlink)" "$CP" "a symlink" "a"
402exp_pass "cp works on a dangling symlink (cp a dangle)" "$CP" "a dangle" "a"
403
404#
405# Basic mv tests. We expect mv to work on most things, but the door is a bit
406# complicated because rename will fail with EBUSY, but that depends on the file
407# system unfortunately (seems to fail on ZFS but work on tmpfs).
408#
409exp_pass "mv works on a file (mv a b)" "$MV" "a b" "a"
410exp_pass "mv works on a fifo (mv a fifo)" "$MV" "a fifo" "a"
411exp_pass "mv works on a uds (mv a sock)" "$MV" "a uds" "a"
412exp_pass "mv works on a symlink (mv a symlink)" "$MV" "a symlink" "a"
413exp_pass "mv works on a dangling symlink (mv a dangle)" "$MV" "a dangle" "a"
414
415#
416# Now we go into -f versions and cases where -f trumps -i. This should cause
417# everything to work for ln. For cp, the fifo and door will not work because it
418# will not remove them. We don't test the fifo due to hangs. For mv we expect
419# everything expect the door (which we skip) to work.
420#
421exp_pass "ln -f clobbers a file (ln -f a b)" "$LN -f" "a b" "a"
422exp_pass "ln -f clobbers a file without perms (ln -f a c)" "$LN -f" "a c" "a"
423exp_pass "ln -f clobbers a uds (ln -f a uds)" "$LN -f" "a uds" "a"
424exp_pass "ln -f clobbers a fifo (ln -f a fifo)" "$LN -f" "a fifo" "a"
425exp_pass "ln -f clobbers a door (ln -f a door)" "$LN -f" "a door" "a"
426exp_pass "ln -f clobbers a valid symlink (ln -f a symlink)" "$LN -f" \
427    "a symlink" "a"
428exp_pass "ln -f clobber a dangling symlink (ln -f a dangle)" "$LN -f" \
429    "a dangle" "a"
430exp_pass "ln -f beats -i on a file (ln -if a b)" "$LN -if" "a b" "a"
431exp_pass "ln -f beats -i on a file (ln -ifif a b)" "$LN -ifif" "a b" "a"
432
433exp_pass "ln -sf clobbers a file (ln -sf a b)" "$LN -sf" "a b" "a"
434exp_pass "ln -sf clobbers a file without perms (ln -sf a c)" "$LN -sf" "a c" "a"
435exp_pass "ln -sf clobbers a uds (ln -sf a uds)" "$LN -sf" "a uds" "a"
436exp_pass "ln -sf clobbers a fifo (ln -sf a fifo)" "$LN -sf" "a fifo" "a"
437exp_pass "ln -sf clobbers a door (ln -sf a door)" "$LN -sf" "a door" "a"
438exp_pass "ln -sf clobbers a valid symlink (ln -sf a symlink)" "$LN -sf" \
439    "a symlink" "a"
440exp_pass "ln -sf clobber a dangling symlink (ln -sf a dangle)" "$LN -sf" \
441    "a dangle" "a"
442exp_pass "ln -sf beats -i on a file (ln -s -if a b)" "$LN -s -if" "a b" "a"
443exp_pass "ln -sf beats -i on a file (ln -s -ifif a b)" "$LN -s -ifif" "a b" "a"
444
445
446exp_pass "cp -f clobbers a file (cp -f a b)" "$CP -f" "a b" "a"
447exp_pass "cp -f clobbers a file without perms (cp -f a c)" "$CP -f" "a c" "a"
448exp_pass "cp -f clobbers a uds (cp -f a uds)" "$CP -f" "a uds" "a"
449exp_fail "cp -f leaves a door alone (cp -f a door)" "$CP -f" "a door" "a"
450exp_pass "cp -f clobbers a valid symlink (cp -f a symlink)" "$CP -f" \
451    "a symlink" "a"
452exp_pass "cp -f clobber a dangling symlink (cp -f a dangle)" "$CP -f" \
453    "a dangle" "a"
454
455exp_pass "mv -f clobbers a file (mv -f a b)" "$MV -f" "a b" "a"
456exp_pass "mv -f clobbers a file without perms (mv -f a c)" "$MV -f" "a c" "a"
457exp_pass "mv -f clobbers a uds (mv -f a uds)" "$MV -f" "a uds" "a"
458exp_pass "mv -f clobbers a fifo (mv -f a fifo)" "$MV -f" "a fifo" "a"
459exp_pass "mv -f clobbers a valid symlink (mv -f a symlink)" "$MV -f" \
460    "a symlink" "a"
461exp_pass "mv -f clobber a dangling symlink (mv -f a dangle)" "$MV -f" \
462    "a dangle" "a"
463
464#
465# Now cp and mv -n tests. These should leave the target file as is, but pass.
466#
467exp_retain "cp -n doesn't clobber a file (cp -n a b)" "$CP -n" "a b"
468exp_retain "cp -n doesn't clobber a file without perms (cp -n a c)" "$CP -n" \
469    "a c"
470exp_retain "cp -n doesn't clobber a uds (cp -n a uds)" "$CP -n" "a uds"
471exp_retain "cp -n doesn't clobber a fifo (cp -n a fifo)" "$CP -n" "a fifo"
472exp_retain "cp -n doesn't clobber a door (cp -n a door)" "$CP -n" "a door"
473exp_retain "cp -n doesn't clobber a valid symlink (cp -n a symlink)" "$CP -n" \
474    "a symlink"
475exp_retain "cp -n doesn't clobber a dangling symlink (cp -n a dangle)" \
476    "$CP -n" "a dangle"
477
478exp_retain "mv -n doesn't clobber a file (mv -n a b)" "$MV -n" "a b"
479exp_retain "mv -n doesn't clobber a file without perms (mv -n a c)" "$MV -n" \
480    "a c"
481exp_retain "mv -n doesn't clobber a uds (mv -n a uds)" "$MV -n" "a uds"
482exp_retain "mv -n doesn't clobber a fifo (mv -n a fifo)" "$MV -n" "a fifo"
483exp_retain "mv -n doesn't clobber a door (mv -n a door)" "$MV -n" "a door"
484exp_retain "mv -n doesn't clobber a valid symlink (mv -n a symlink)" "$MV -n" \
485    "a symlink"
486exp_retain "mv -n doesn't clobber a dangling symlink (mv -n a dangle)" \
487    "$MV -n" "a dangle"
488
489#
490# -n, -f, and -i interleaving. None of these should cause prompts. non-XPG mv -f
491# will trump -i anywhere. XPG mv -i working normally is tested later on.
492#
493exp_retain "cp -n always beats -f (cp -nf a b)" "$CP -nf" "a b"
494exp_retain "cp -n always beats -f (cp -fn a b)" "$CP -fn" "a b"
495exp_retain "cp last -n wins (cp -in a b)" "$CP -in" "a b"
496exp_retain "cp last -n wins (cp -nin a b)" "$CP -nin" "a b"
497
498exp_retain "mv last -n wins (mv -in a b)" "$MV -in" "a b"
499exp_retain "mv last -n wins (mv -fn a b)" "$MV -fn" "a b"
500exp_retain "mv last -n wins (mv -ifn a b)" "$MV -ifn" "a b"
501exp_retain "mv last -n wins (mv -fifn a b)" "$MV -fifn" "a b"
502exp_pass "mv last -f wins (mv -nf a b)" "$MV -nf" "a b" "a"
503exp_pass "mv last -f wins (mv -if a b)" "$MV -if" "a b" "a"
504exp_pass "mv last -f wins (mv -fif a b)" "$MV -fif" "a b" "a"
505exp_pass "mv last -f wins (mv -nif a b)" "$MV -nif" "a b" "a"
506exp_pass "mv -f always beats -i (non-xpg) (mv -fi a b)" "$MV -fi" "a b" "a"
507exp_retain "XPG4 mv last -n wins (mv -in a b)" "$XMV -in" "a b"
508exp_retain "XPG4 mv last -n wins (mv -fn a b)" "$XMV -fn" "a b"
509exp_retain "XPG4 mv last -n wins (mv -ifn a b)" "$XMV -ifn" "a b"
510exp_retain "XPG4 mv last -n wins (mv -fifn a b)" "$XMV -fifn" "a b"
511exp_pass "XPG4 mv last -f wins (mv -nf a b)" "$XMV -nf" "a b" "a"
512exp_pass "XPG4 mv last -f wins (mv -if a b)" "$XMV -if" "a b" "a"
513exp_pass "XPG4 mv last -f wins (mv -fif a b)" "$XMV -fif" "a b" "a"
514exp_pass "XPG4 mv last -f wins (mv -nif a b)" "$XMV -nif" "a b" "a"
515
516
517#
518# Now onto interactive tests. Interactivity is a bit challenging. If stdin is
519# not a tty then a prompt will not appear if we're not in the XPG variant. This
520# means that it'll fall back to the program default (generally speaking to
521# overwrite).
522#
523exp_pass "XPG4 cp -i no normal file (cp -i a b)" "$XCP -i" "a b" "b" \
524    "cat /dev/zero"
525exp_pass "XPG4 cp -i yes normal file (cp -i a b)" "$XCP -i" "a b" "a" "yes"
526exp_pass "cp -i clobbers normal file regardless (cp -i a b)" "$CP -i" "a b" \
527    "a" "cat /dev/zero"
528
529exp_pass "XPG4 mv -i no normal file (mv -i a b)" "$XMV -i" "a b" "b" \
530    "cat /dev/zero"
531exp_pass "XPG4 mv -i yes normal file (mv -i a b)" "$XMV -i" "a b" "a" "yes"
532exp_pass "mv -i clobbers normal file regardless (mv -i a b)" "$MV -i" "a b" \
533    "a" "cat /dev/zero"
534
535exp_pass "XPG4 ln -i no normal file (ln -i a b)" "$XLN -i" "a b" "b" \
536    "cat /dev/zero"
537exp_pass "XPG4 ln -i yes normal file (ln -i a b)" "$XLN -i" "a b" "a" "yes"
538exp_pass "ln -i clobbers normal file regardless (ln -i a b)" "$LN -i" "a b" \
539    "a" "cat /dev/zero"
540
541exp_pass "XPG4 cp -i yes beats -n normal file (cp -ni a b)" "$XCP -ni" "a b" \
542    "a" "yes"
543exp_pass "cp -i beats -n (cp -ni a b)" "$CP -ni" "a b" "a" "cat /dev/zero"
544
545exp_pass "XPG4 mv -i beats -n (mv -ni a b)" "$XMV -ni" "a b" "a" "yes"
546exp_pass "mv -i beats -n (mv -ni a b)" "$MV -ni" "a b" "a" "cat /dev/zero"
547exp_pass "XPG4 mv -i beats -f (mv -fi a b)" "$XMV -fi" "a b" "a" "yes"
548
549exp_pass "XPG4 ln -fi no normal file (ln -fi a b)" "$XLN -fi" "a b" "b" \
550    "cat /dev/zero"
551exp_pass "XPG4 ln -fi yes normal file (ln -fi a b)" "$XLN -fi" "a b" "a" "yes"
552exp_pass "ln -fi clobbers normal file regardless (ln -fi a b)" "$LN -fi" \
553    "a b" "a" "cat /dev/zero"
554
555exp_pass "XPG4 ln -sfi no normal file (ln -sfi a b)" "$XLN -sfi" "a b" "b" \
556    "cat /dev/zero"
557exp_pass "XPG4 ln -sfi yes normal file (ln -sfi a b)" "$XLN -sfi" "a b" "a" \
558    "yes"
559exp_pass "ln -sfi clobbers normal file regardless (ln -sfi a b)" "$LN -sfi" \
560    "a b" "a" "cat /dev/zero"
561
562#
563# Now our last bit here is to do tests that operate on multiple files into a
564# directory and make sure that they end up as expected.
565#
566exp_dir "cp multi-file" "$CP" "a b dir" 0 "dir/a" "b"
567exp_fail "cp multi-file with socket fails" "$CP" "a b uds dir"
568exp_fail "cp multi-file with noperms fails" "$CP" "a b c dir"
569exp_dir "cp multi-file -n" "$CP -n" "a b dir" 0 "dir/a" ""
570exp_dir "XPG4 cp multi-file -i yes" "$XCP -i" "a b dir" 0 "dir/a" "b" "yes"
571exp_dir "XPG4 cp multi-file -i no" "$XCP -i" "a b dir" 0 "dir/a" "" \
572    "cat /dev/zero"
573exp_dir "cp multi-file -i clobbers anyways" "$CP -i" "a b dir" 0 "dir/a" "b" \
574    "cat /dev/zero"
575
576exp_dir "ln multi-file" "$LN" "a b dir" 2
577exp_fail "ln multi-file with door fails" "$LN" "a door dir"
578exp_dir "ln multi-file with socket works" "$LN" "a uds dir" 0 "dir/a dir/uds" ""
579exp_dir "ln multi-file with noperms works" "$LN" "a c dir" 0 "dir/a dir/c" ""
580exp_dir "ln multi-file -f" "$LN -f" "a b dir" 0 "dir/a" "b"
581exp_dir "XPG4 ln multi-file -i yes" "$XLN -i" "a b dir" 0 "dir/a" "b" "yes"
582exp_dir "XPG4 ln multi-file -i no" "$XLN -i" "a b dir" 0 "dir/a" "" \
583    "cat /dev/zero"
584exp_dir "ln multi-file -i clobbers anyways" "$LN -i" "a b dir" 0 "dir/a" "b" \
585    "cat /dev/zero"
586
587exp_dir "ln -s multi-file" "$LN -s" "a b dir" 2
588exp_dir "ln -s multi-file with door works" "$LN -s" "a door dir" 0
589exp_dir "ln -s multi-file with socket works" "$LN -s" "a uds dir" 0 \
590    "dir/a dir/uds" ""
591exp_dir "ln -s multi-file with noperms works" "$LN -s" "a c dir" 0 \
592    "dir/a dir/c" ""
593exp_dir "ln -s multi-file -f" "$LN -s -f" "a b dir" 0 "dir/a" "b"
594exp_dir "XPG4 ln -s multi-file -i yes" "$XLN -s -i" "a b dir" 0 "dir/a" "b" \
595    "yes"
596exp_dir "XPG4 ln -s multi-file -i no" "$XLN -s -i" "a b dir" 0 "dir/a" "" \
597    "cat /dev/zero"
598exp_dir "ln -s multi-file -i clobbers anyways" "$LN -s -i" "a b dir" 0 "dir/a" \
599    "b" "cat /dev/zero"
600
601exp_dir "mv multi-file" "$MV" "a b c fifo door uds symlink dangle dir" 0 \
602    "dir/a dir/c dir/fifo dir/door dir/uds dir/symlink dir/dangle" "b"
603exp_dir "mv -n multi-file" "$MV -n" "a b c fifo door uds symlink dangle dir" 0 \
604    "dir/a dir/c dir/fifo dir/door dir/uds dir/symlink dir/dangle" ""
605exp_dir "mv -f multi-file" "$MV -f" "a b c fifo door uds symlink dangle dir" 0 \
606    "dir/a dir/c dir/fifo dir/door dir/uds dir/symlink dir/dangle" "b"
607exp_dir "mv -i multi-file clobbers" "$MV -i" \
608    "a b c fifo door uds symlink dangle dir" 0 \
609    "dir/a dir/c dir/fifo dir/door dir/uds dir/symlink dir/dangle" "b" \
610    "cat /dev/null"
611exp_dir "XPG4 mv -i multi-file no" "$XMV -i" \
612    "a b c fifo door uds symlink dangle dir" 0 \
613    "dir/a dir/c dir/fifo dir/door dir/uds dir/symlink dir/dangle" "" \
614    "cat /dev/null"
615exp_dir "XPG4 mv -i multi-file yes" "$XMV -i" \
616    "a b c fifo door uds symlink dangle dir" 0 \
617    "dir/a dir/c dir/fifo dir/door dir/uds dir/symlink dir/dangle" "b" "yes"
618
619if (( ovr_exit == 0 )); then
620	printf "All tests passed successfully\n"
621fi
622exit $ovr_exit
623