xref: /illumos-gate/usr/src/test/util-tests/tests/cpmvln/ln-LP.ksh (revision 0f1762c0ba4c6b14fab6b990e30c1f3a82f5ac10)
1*0f1762c0SRobert Mustacchi#!/usr/bin/ksh
2*0f1762c0SRobert Mustacchi#
3*0f1762c0SRobert Mustacchi# This file and its contents are supplied under the terms of the
4*0f1762c0SRobert Mustacchi# Common Development and Distribution License ("CDDL"), version 1.0.
5*0f1762c0SRobert Mustacchi# You may only use this file in accordance with the terms of version
6*0f1762c0SRobert Mustacchi# 1.0 of the CDDL.
7*0f1762c0SRobert Mustacchi#
8*0f1762c0SRobert Mustacchi# A full copy of the text of the CDDL should have accompanied this
9*0f1762c0SRobert Mustacchi# source.  A copy of the CDDL is also available via the Internet at
10*0f1762c0SRobert Mustacchi# http://www.illumos.org/license/CDDL.
11*0f1762c0SRobert Mustacchi#
12*0f1762c0SRobert Mustacchi
13*0f1762c0SRobert Mustacchi#
14*0f1762c0SRobert Mustacchi# Copyright 2026 Oxide Computer Company
15*0f1762c0SRobert Mustacchi#
16*0f1762c0SRobert Mustacchi
17*0f1762c0SRobert Mustacchi#
18*0f1762c0SRobert Mustacchi# This program goes through and tests how ln acts by default and with its -L and
19*0f1762c0SRobert Mustacchi# -P flags as well as the default behavior. The basic summary is:
20*0f1762c0SRobert Mustacchi#
21*0f1762c0SRobert Mustacchi# 1. All of these flags should be ignored when used with -s.
22*0f1762c0SRobert Mustacchi# 2. -L should cause us to dereference a symlink when making a hardlink. That is
23*0f1762c0SRobert Mustacchi#    we should get a hardlink to the underlying object (if allowed).
24*0f1762c0SRobert Mustacchi# 3. -P should cause us to get a hardlink to the symlink itself.
25*0f1762c0SRobert Mustacchi# 4. /usr/bin/ln defaults to -P behavior. /usr/xpg4/bin/ln defaults to -L
26*0f1762c0SRobert Mustacchi#    behavior.
27*0f1762c0SRobert Mustacchi#
28*0f1762c0SRobert Mustacchi# Finally, we want to see how this works across a variety of symlinks to the
29*0f1762c0SRobert Mustacchi# following file types: regular files, directories, doors, fifos, unix domain
30*0f1762c0SRobert Mustacchi# sockets. We must be very careful not to create hardlinks to directories here
31*0f1762c0SRobert Mustacchi# as tests are sometimes run by privileged users.
32*0f1762c0SRobert Mustacchi#
33*0f1762c0SRobert Mustacchi
34*0f1762c0SRobert Mustacchiunalias -a
35*0f1762c0SRobert Mustacchiset -o pipefail
36*0f1762c0SRobert Mustacchiexport LANG=C.UTF-8
37*0f1762c0SRobert Mustacchi
38*0f1762c0SRobert MustacchiLN=${LN:-"/usr/bin/ln"}
39*0f1762c0SRobert MustacchiXLN=${XLN:-"/usr/xpg4/bin/ln"}
40*0f1762c0SRobert Mustacchi
41*0f1762c0SRobert Mustacchilnlp_exit=0
42*0f1762c0SRobert Mustacchilnlp_arg0=$(basename $0)
43*0f1762c0SRobert Mustacchilnlp_tdir=$(dirname $0)
44*0f1762c0SRobert Mustacchilnlp_mkobj="$lnlp_tdir/mkobj"
45*0f1762c0SRobert Mustacchilnlp_equiv="$lnlp_tdir/equiv"
46*0f1762c0SRobert Mustacchilnlp_work="/tmp/$lnlp_arg0.$$"
47*0f1762c0SRobert Mustacchi
48*0f1762c0SRobert Mustacchi#
49*0f1762c0SRobert Mustacchi# The following table describes the files that we're testing against. hardlinks
50*0f1762c0SRobert Mustacchi# will not work with doors as doors are considered to be on a different file
51*0f1762c0SRobert Mustacchi# system. Directories will fail because we are running as a non-root user to
52*0f1762c0SRobert Mustacchi# ensure that we don't create hardlink to directory madness.
53*0f1762c0SRobert Mustacchi#
54*0f1762c0SRobert Mustacchitypeset -A lnlp_files=(
55*0f1762c0SRobert Mustacchi	["file"]=(make="touch" hard="pass" soft="pass")
56*0f1762c0SRobert Mustacchi	["dir"]=(make="mkdir" hard="fail" soft="pass")
57*0f1762c0SRobert Mustacchi	["fifo"]=(make="$lnlp_mkobj -f" hard="pass" soft="pass")
58*0f1762c0SRobert Mustacchi	["door"]=(make="$lnlp_mkobj -d" hard="fail" soft="pass")
59*0f1762c0SRobert Mustacchi	["uds"]=(make="$lnlp_mkobj -s" hard="pass" soft="pass")
60*0f1762c0SRobert Mustacchi)
61*0f1762c0SRobert Mustacchi
62*0f1762c0SRobert Mustacchifunction fatal
63*0f1762c0SRobert Mustacchi{
64*0f1762c0SRobert Mustacchi	typeset msg="$*"
65*0f1762c0SRobert Mustacchi	echo "TEST FAILED: $msg" >&2
66*0f1762c0SRobert Mustacchi	exit 1
67*0f1762c0SRobert Mustacchi}
68*0f1762c0SRobert Mustacchi
69*0f1762c0SRobert Mustacchifunction warn
70*0f1762c0SRobert Mustacchi{
71*0f1762c0SRobert Mustacchi	typeset msg="$*"
72*0f1762c0SRobert Mustacchi	echo "TEST FAILED: $msg" >&2
73*0f1762c0SRobert Mustacchi	lnlp_exit=1
74*0f1762c0SRobert Mustacchi}
75*0f1762c0SRobert Mustacchi
76*0f1762c0SRobert Mustacchifunction cleanup
77*0f1762c0SRobert Mustacchi{
78*0f1762c0SRobert Mustacchi	rm -rf $lnlp_work/
79*0f1762c0SRobert Mustacchi}
80*0f1762c0SRobert Mustacchi
81*0f1762c0SRobert Mustacchi#
82*0f1762c0SRobert Mustacchi# Create the series of objects and symlinks that we expect to exist.
83*0f1762c0SRobert Mustacchi#
84*0f1762c0SRobert Mustacchifunction setup
85*0f1762c0SRobert Mustacchi{
86*0f1762c0SRobert Mustacchi	mkdir "$lnlp_work" || fatal "failed to make test directory"
87*0f1762c0SRobert Mustacchi	for f in ${!lnlp_files[@]}; do
88*0f1762c0SRobert Mustacchi		typeset targ="${lnlp_work}/$f"
89*0f1762c0SRobert Mustacchi		typeset sym="${targ}_symlink"
90*0f1762c0SRobert Mustacchi
91*0f1762c0SRobert Mustacchi		${lnlp_files[$f].make} $targ || fatal "failed to make $f"
92*0f1762c0SRobert Mustacchi		ln -s $targ $sym || fatal "failed to create symlink to $f"
93*0f1762c0SRobert Mustacchi	done
94*0f1762c0SRobert Mustacchi}
95*0f1762c0SRobert Mustacchi
96*0f1762c0SRobert Mustacchi#
97*0f1762c0SRobert Mustacchi# Run a single ln hardlink invocation. This invocation is expected to pass. $dst
98*0f1762c0SRobert Mustacchi# should match the contents of $exp.
99*0f1762c0SRobert Mustacchi#
100*0f1762c0SRobert Mustacchifunction test_one_hl
101*0f1762c0SRobert Mustacchi{
102*0f1762c0SRobert Mustacchi	typeset desc="$1"
103*0f1762c0SRobert Mustacchi	typeset src="$lnlp_work/${2}_symlink"
104*0f1762c0SRobert Mustacchi	typeset exp_base="$3"
105*0f1762c0SRobert Mustacchi	typeset exp="$lnlp_work/$3"
106*0f1762c0SRobert Mustacchi	typeset dst="$lnlp_work/test"
107*0f1762c0SRobert Mustacchi
108*0f1762c0SRobert Mustacchi	#
109*0f1762c0SRobert Mustacchi	# Remaining arguments after this are the correct ln program and flags to
110*0f1762c0SRobert Mustacchi	# use.
111*0f1762c0SRobert Mustacchi	#
112*0f1762c0SRobert Mustacchi	shift; shift; shift
113*0f1762c0SRobert Mustacchi
114*0f1762c0SRobert Mustacchi	rm -f $dst
115*0f1762c0SRobert Mustacchi	if ! $* "$src" "$dst"; then
116*0f1762c0SRobert Mustacchi		warn "$desc: $* $src $dst failed unexpectedly"
117*0f1762c0SRobert Mustacchi		return
118*0f1762c0SRobert Mustacchi	fi
119*0f1762c0SRobert Mustacchi
120*0f1762c0SRobert Mustacchi	if ! $lnlp_equiv $exp $dst; then
121*0f1762c0SRobert Mustacchi		warn "$desc: ln didn't result in expected file $3"
122*0f1762c0SRobert Mustacchi		return
123*0f1762c0SRobert Mustacchi	fi
124*0f1762c0SRobert Mustacchi
125*0f1762c0SRobert Mustacchi	printf "TEST PASSED: %s\n" "$desc"
126*0f1762c0SRobert Mustacchi}
127*0f1762c0SRobert Mustacchi
128*0f1762c0SRobert Mustacchi#
129*0f1762c0SRobert Mustacchi# This is variant where the ln results should fail. This is generally used when
130*0f1762c0SRobert Mustacchi# using hardlinks on doors and directories.
131*0f1762c0SRobert Mustacchi#
132*0f1762c0SRobert Mustacchifunction test_one_fail
133*0f1762c0SRobert Mustacchi{
134*0f1762c0SRobert Mustacchi	typeset desc="$1"
135*0f1762c0SRobert Mustacchi	typeset src="$lnlp_work/${2}_symlink"
136*0f1762c0SRobert Mustacchi	typeset dst="$lnlp_work/test"
137*0f1762c0SRobert Mustacchi
138*0f1762c0SRobert Mustacchi	shift; shift
139*0f1762c0SRobert Mustacchi
140*0f1762c0SRobert Mustacchi	rm -f $dst
141*0f1762c0SRobert Mustacchi	if $* "$src" "$src" 2>/dev/null; then
142*0f1762c0SRobert Mustacchi		warn "$desc: $* unexpectedly worked?!"
143*0f1762c0SRobert Mustacchi		return
144*0f1762c0SRobert Mustacchi	fi
145*0f1762c0SRobert Mustacchi
146*0f1762c0SRobert Mustacchi	printf "TEST PASSED: %s failed correctly\n" "$desc"
147*0f1762c0SRobert Mustacchi}
148*0f1762c0SRobert Mustacchi
149*0f1762c0SRobert Mustacchi#
150*0f1762c0SRobert Mustacchi# For a given version of ln and its options, run through each of the different
151*0f1762c0SRobert Mustacchi# valid file types and see if it passes or fails.
152*0f1762c0SRobert Mustacchi#
153*0f1762c0SRobert Mustacchifunction test_series
154*0f1762c0SRobert Mustacchi{
155*0f1762c0SRobert Mustacchi	typeset bdesc="$1"
156*0f1762c0SRobert Mustacchi	typeset rtype="$2"
157*0f1762c0SRobert Mustacchi
158*0f1762c0SRobert Mustacchi	#
159*0f1762c0SRobert Mustacchi	# Options after this will be the flags and type of ln invocation we
160*0f1762c0SRobert Mustacchi	# should use.
161*0f1762c0SRobert Mustacchi	#
162*0f1762c0SRobert Mustacchi	shift; shift
163*0f1762c0SRobert Mustacchi	for f in ${!lnlp_files[@]}; do
164*0f1762c0SRobert Mustacchi		typeset test_exp
165*0f1762c0SRobert Mustacchi
166*0f1762c0SRobert Mustacchi		if [[ "$rtype" == "hard" ]]; then
167*0f1762c0SRobert Mustacchi			test_exp="$f"
168*0f1762c0SRobert Mustacchi		else
169*0f1762c0SRobert Mustacchi			test_exp="${f}_symlink"
170*0f1762c0SRobert Mustacchi		fi
171*0f1762c0SRobert Mustacchi
172*0f1762c0SRobert Mustacchi		if [[ ${lnlp_files[$f].[$rtype]} == "pass" ]]; then
173*0f1762c0SRobert Mustacchi			test_one_hl "$bdesc: $f results in $rtype" $f \
174*0f1762c0SRobert Mustacchi			    $test_exp $*
175*0f1762c0SRobert Mustacchi		else
176*0f1762c0SRobert Mustacchi			test_one_fail "$bdesc: $f ${rtype}link fails" $f $*
177*0f1762c0SRobert Mustacchi		fi
178*0f1762c0SRobert Mustacchi	done
179*0f1762c0SRobert Mustacchi}
180*0f1762c0SRobert Mustacchi
181*0f1762c0SRobert Mustacchi#
182*0f1762c0SRobert Mustacchi# Go through and make a symlink to each file and verify that it is a different
183*0f1762c0SRobert Mustacchi# inode than one that already exists. We skip doing this for every combination
184*0f1762c0SRobert Mustacchi# and just do it once for a file and a symlink.
185*0f1762c0SRobert Mustacchi#
186*0f1762c0SRobert Mustacchifunction test_symlink
187*0f1762c0SRobert Mustacchi{
188*0f1762c0SRobert Mustacchi	typeset dst="$lnlp_work/test"
189*0f1762c0SRobert Mustacchi	typeset src="$lnlp_work/file"
190*0f1762c0SRobert Mustacchi	typeset desc="$1"
191*0f1762c0SRobert Mustacchi	shift
192*0f1762c0SRobert Mustacchi
193*0f1762c0SRobert Mustacchi	rm -f $dst
194*0f1762c0SRobert Mustacchi	if ! $* $src $dst; then
195*0f1762c0SRobert Mustacchi		warn "$desc: $* $src $dst unexpectedly failed"
196*0f1762c0SRobert Mustacchi		return
197*0f1762c0SRobert Mustacchi	fi
198*0f1762c0SRobert Mustacchi
199*0f1762c0SRobert Mustacchi	if $lnlp_equiv $src $dst 1>/dev/null 2>/dev/null; then
200*0f1762c0SRobert Mustacchi		warn "$desc: ln -s somehow ended up with the same inode"
201*0f1762c0SRobert Mustacchi		return
202*0f1762c0SRobert Mustacchi	fi
203*0f1762c0SRobert Mustacchi
204*0f1762c0SRobert Mustacchi	src="$lnlp_work/file_symlink"
205*0f1762c0SRobert Mustacchi	rm -f $dst
206*0f1762c0SRobert Mustacchi	if ! $* $src $dst; then
207*0f1762c0SRobert Mustacchi		warn "$desc: $* $src $dst unexpectedly failed"
208*0f1762c0SRobert Mustacchi		return
209*0f1762c0SRobert Mustacchi	fi
210*0f1762c0SRobert Mustacchi
211*0f1762c0SRobert Mustacchi	if $lnlp_equiv $src $dst 1>/dev/null 2>/dev/null; then
212*0f1762c0SRobert Mustacchi		warn "$desc: ln -s somehow ended up with the same inode"
213*0f1762c0SRobert Mustacchi		return
214*0f1762c0SRobert Mustacchi	fi
215*0f1762c0SRobert Mustacchi
216*0f1762c0SRobert Mustacchi	printf "TEST PASSED: %s\n" "$desc"
217*0f1762c0SRobert Mustacchi}
218*0f1762c0SRobert Mustacchi
219*0f1762c0SRobert Mustacchi#
220*0f1762c0SRobert Mustacchi# Sanity check that we're not running as a privileged user. This won't catch
221*0f1762c0SRobert Mustacchi# some some cases where we have privileges, but this is better than nothing.
222*0f1762c0SRobert Mustacchi#
223*0f1762c0SRobert Mustacchilnlp_uid=$(id -u)
224*0f1762c0SRobert Mustacchiif (( lnlp_uid == 0 )); then
225*0f1762c0SRobert Mustacchi	printf "Running as uid 0 is not permitted try nobody instead\n" >&2
226*0f1762c0SRobert Mustacchi	exit 1
227*0f1762c0SRobert Mustacchifi
228*0f1762c0SRobert Mustacchi
229*0f1762c0SRobert Mustacchitrap cleanup EXIT
230*0f1762c0SRobert Mustacchi
231*0f1762c0SRobert Mustacchi#
232*0f1762c0SRobert Mustacchi# Create all of our different fields and the symlinks to them.
233*0f1762c0SRobert Mustacchi#
234*0f1762c0SRobert Mustacchisetup
235*0f1762c0SRobert Mustacchi
236*0f1762c0SRobert Mustacchi#
237*0f1762c0SRobert Mustacchi# First test the defaults of each command.
238*0f1762c0SRobert Mustacchi#
239*0f1762c0SRobert Mustacchitest_series "$LN defaults" soft $LN
240*0f1762c0SRobert Mustacchitest_series "$XLN defaults" hard $XLN
241*0f1762c0SRobert Mustacchi
242*0f1762c0SRobert Mustacchi#
243*0f1762c0SRobert Mustacchi# Now verify that they do identical thing with a single -L and -P.
244*0f1762c0SRobert Mustacchi#
245*0f1762c0SRobert Mustacchitest_series "$LN -P" soft $LN -P
246*0f1762c0SRobert Mustacchitest_series "$LN -L" hard $LN -L
247*0f1762c0SRobert Mustacchi
248*0f1762c0SRobert Mustacchitest_series "$LN -P wins (-LP)" soft $LN -LP
249*0f1762c0SRobert Mustacchitest_series "$LN -P wins (-PLPLP)" soft $LN -PLPLP
250*0f1762c0SRobert Mustacchitest_series "$LN -P wins (-LLLP)" soft $LN -LLLP
251*0f1762c0SRobert Mustacchitest_series "$LN -L wins (-PL)" hard $LN -PL
252*0f1762c0SRobert Mustacchitest_series "$LN -L wins (-LPLPL)" hard $LN -LPLPL
253*0f1762c0SRobert Mustacchitest_series "$LN -L wins (-PPPL)" hard $LN -PPPL
254*0f1762c0SRobert Mustacchi
255*0f1762c0SRobert Mustacchitest_series "$XLN -P wins (-LP)" soft $XLN -LP
256*0f1762c0SRobert Mustacchitest_series "$XLN -P wins (-PLPLP)" soft $XLN -PLPLP
257*0f1762c0SRobert Mustacchitest_series "$XLN -P wins (-LLLP)" soft $XLN -LLLP
258*0f1762c0SRobert Mustacchitest_series "$XLN -L wins (-PL)" hard $XLN -PL
259*0f1762c0SRobert Mustacchitest_series "$XLN -L wins (-LPLPL)" hard $XLN -LPLPL
260*0f1762c0SRobert Mustacchitest_series "$XLN -L wins (-PPPL)" hard $XLN -PPPL
261*0f1762c0SRobert Mustacchi
262*0f1762c0SRobert Mustacchi#
263*0f1762c0SRobert Mustacchi# Go through and manually do a few symlink related tests.
264*0f1762c0SRobert Mustacchi#
265*0f1762c0SRobert Mustacchitest_symlink "$LN -s" $LN -s
266*0f1762c0SRobert Mustacchitest_symlink "$LN -s -L" $LN -s -L
267*0f1762c0SRobert Mustacchitest_symlink "$LN -s -P" $LN -s -P
268*0f1762c0SRobert Mustacchitest_symlink "$LN -s -LP" $LN -s -LP
269*0f1762c0SRobert Mustacchitest_symlink "$LN -s -PL" $LN -s -PL
270*0f1762c0SRobert Mustacchi
271*0f1762c0SRobert Mustacchitest_symlink "$XLN -s" $XLN -s
272*0f1762c0SRobert Mustacchitest_symlink "$XLN -s -L" $XLN -s -L
273*0f1762c0SRobert Mustacchitest_symlink "$XLN -s -P" $XLN -s -P
274*0f1762c0SRobert Mustacchitest_symlink "$XLN -s -LP" $XLN -s -LP
275*0f1762c0SRobert Mustacchitest_symlink "$XLN -s -PL" $XLN -s -PL
276*0f1762c0SRobert Mustacchi
277*0f1762c0SRobert Mustacchiif (( lnlp_exit == 0 )); then
278*0f1762c0SRobert Mustacchi	printf "All tests passed successfully\n"
279*0f1762c0SRobert Mustacchifi
280*0f1762c0SRobert Mustacchiexit $lnlp_exit
281