1#
2# CDDL HEADER START
3#
4# The contents of this file are subject to the terms of the
5# Common Development and Distribution License (the "License").
6# You may not use this file except in compliance with the License.
7#
8# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9# or http://www.opensolaris.org/os/licensing.
10# See the License for the specific language governing permissions
11# and limitations under the License.
12#
13# When distributing Covered Code, include this CDDL HEADER in each
14# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15# If applicable, add the following below this CDDL HEADER, with the
16# fields enclosed by brackets "[]" replaced with your own identifying
17# information: Portions Copyright [yyyy] [name of copyright owner]
18#
19# CDDL HEADER END
20#
21
22#
23# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24# Use is subject to license terms.
25#
26
27. $STF_SUITE/tests/functional/acl/acl.cfg
28. $STF_SUITE/include/libtest.shlib
29
30#
31# Get the given file/directory access mode
32#
33# $1 object -- file or directroy
34#
35function get_mode #<obj>
36{
37	typeset obj=$1
38	if (( ${#obj} == 0 )); then
39		return 1
40	fi
41
42	$LS -ld $obj | $AWK '{print $1}'
43}
44
45#
46# Get the given file/directory ACL
47#
48# $1 object -- file or directroy
49#
50function get_acl #<obj>
51{
52        typeset obj=$1
53	if (( ${#obj} == 0 )); then
54		return 1
55	fi
56
57	$LS -vd $obj | $NAWK '(NR != 1) {print $0}'
58}
59
60#
61# Get the given file/directory ACL
62#
63# $1 object -- file or directroy
64#
65function get_compact_acl #<obj>
66{
67        typeset obj=$1
68	if (( ${#obj} == 0 )); then
69		return 1
70	fi
71
72	$LS -Vd $obj | $NAWK '(NR != 1) {print $0}'
73}
74
75#
76# Check the given two files/directories have the same ACLs
77#
78# Return 0, if source object acl is equal to target object acl.
79#
80# $1 source object
81# $2 target object
82#
83function compare_acls #<src> <tgt>
84{
85        typeset src=$1
86        typeset tgt=$2
87
88	(( ${#src} == 0 || ${#tgt} == 0 )) && return 1
89	[[ $src == $tgt ]] && return 0
90
91	typeset tmpsrc=/tmp/compare_acls.src.$$
92	typeset tmptgt=/tmp/compare_acls.tgt.$$
93
94	get_acl $src > $tmpsrc
95	get_acl $tgt > $tmptgt
96	typeset -i ret=0
97	$DIFF $tmpsrc $tmptgt > /dev/null 2>&1
98	ret=$?
99	$RM -f $tmpsrc $tmptgt
100
101	if (( ret != 0 )); then
102		return $ret
103	fi
104
105	get_compact_acl $src > $tmpsrc
106	get_compact_acl $tgt > $tmptgt
107	$DIFF $tmpsrc $tmptgt > /dev/null 2>&1
108	ret=$?
109	$RM -f $tmpsrc $tmptgt
110
111	return $ret
112}
113
114#
115# Check that the given two objects have the same modes.
116# Return 0, if their modes are equal with each other. Otherwise, return 1.
117#
118# $1 source object
119# $2 target object
120#
121function compare_modes #<src> <tgt>
122{
123        typeset src=$1
124        typeset tgt=$2
125        typeset -i i=0
126        set -A mode
127
128	(( ${#src} == 0 || ${#tgt} == 0 )) && return 1
129	[[ $src == $tgt ]] && return 0
130
131	typeset obj
132        for obj in $src $tgt
133        do
134                mode[i]=$(get_mode $obj)
135
136                (( i = i + 1 ))
137        done
138
139        [[ ${mode[0]} != ${mode[1]} ]] && return 1
140
141        return 0
142}
143
144#
145# Check that the given two objects have the same xattrs.
146# Return 0, if their xattrs are equal with each other. Otherwise, return 1.
147#
148# $1 source object
149# $2 target object
150#
151function compare_xattrs #<src> <tgt>
152{
153        typeset src=$1
154        typeset tgt=$2
155
156	(( ${#src} == 0 || ${#tgt} == 0 )) && return 1
157	[[ $src == $tgt ]] && return 0
158
159	typeset tmpsrc=/tmp/compare_xattrs.src.$$
160	typeset tmptgt=/tmp/compare_xattrs.tgt.$$
161
162	get_xattr $src > $tmpsrc
163	get_xattr $tgt > $tmptgt
164	typeset -i ret=0
165	$DIFF $tmpsrc $tmptgt > /dev/null 2>&1
166	ret=$?
167	$RM -f $tmpsrc $tmptgt
168
169        return $ret
170}
171
172#
173# Check '+' is set for a given file/directory with 'ls [-l]' command
174#
175# $1 object -- file or directory.
176#
177function plus_sign_check_l #<obj>
178{
179	typeset obj=$1
180	if (( ${#obj} == 0 )); then
181		return 1
182	fi
183
184	$LS -ld $obj | $AWK '{print $1}' | $GREP "+\>" > /dev/null
185
186        return $?
187}
188
189#
190# Check '+' is set for a given file/directory with 'ls [-v]' command
191#
192# $1 object -- file or directory.
193#
194function plus_sign_check_v #<obj>
195{
196	typeset obj=$1
197	if (( ${#obj} == 0 )); then
198		return 1
199	fi
200
201	$LS -vd $obj | $NAWK '(NR == 1) {print $1}' | $GREP "+\>" > /dev/null
202
203        return $?
204}
205
206#
207# A wrapper function of c program
208#
209# $1 legal login name
210# $2-n commands and options
211#
212function chgusr_exec #<login_name> <commands> [...]
213{
214	$CHG_USR_EXEC $@
215	return $?
216}
217
218#
219# Export the current user for the following usr_exec operating.
220#
221# $1 legal login name
222#
223function set_cur_usr #<login_name>
224{
225	export ZFS_ACL_CUR_USER=$1
226}
227
228#
229# Run commands by $ZFS_ACL_CUR_USER
230#
231# $1-n commands and options
232#
233function usr_exec #<commands> [...]
234{
235	$CHG_USR_EXEC "$ZFS_ACL_CUR_USER" $@
236	return $?
237}
238
239#
240# Count how many ACEs for the speficied file or directory.
241#
242# $1 file or directroy name
243#
244function count_ACE #<file or dir name>
245{
246	if [[ ! -e $1 ]]; then
247		log_note "Need input file or directroy name."
248		return 1
249	fi
250
251	$LS -vd $1 | $NAWK 'BEGIN {count=0}
252			(NR != 1)&&(/[0-9]:/) {count++}
253			END {print count}'
254
255	return 0
256}
257
258#
259# Get specified number ACE content of specified file or directory.
260#
261# $1 file or directory name
262# $2 specified number
263#
264function get_ACE #<file or dir name> <specified number> <verbose|compact>
265{
266	if [[ ! -e $1 || $2 -ge $(count_ACE $1) ]]; then
267		return 1
268	fi
269
270	typeset file=$1
271	typeset -i num=$2
272	typeset format=${3:-verbose}
273	typeset -i next_num=-1
274
275        typeset tmpfile=/tmp/tmp_get_ACE.$$
276        typeset line=""
277	typeset args
278
279	case $format in
280		verbose) args="-vd"
281			;;
282		compact) args="-Vd"
283			;;
284		*) log_fail "Invalid parameter as ($format), " \
285			"only verbose|compact is supported."
286			;;
287	esac
288
289	$LS $args $file > $tmpfile
290	(( $? != 0 )) && log_fail "FAIL: $LS $args $file > $tmpfile"
291	while read line; do
292		[[ -z $line ]] && continue
293		if [[ $args == -vd ]]; then
294			if [[ $line == "$num":* ]]; then
295				(( next_num = num + 1 ))
296			fi
297			if [[ $line == "$next_num":* ]]; then
298				break
299			fi
300			if (( next_num != -1 )); then
301				print -n $line
302			fi
303		else
304			if (( next_num == num )); then
305				print -n $line
306			fi
307			(( next_num += 1 ))
308		fi
309	done < $tmpfile
310
311	$RM -f $tmpfile
312	(( $? != 0 )) && log_fail "FAIL: $RM -f $tmpfile"
313}
314
315#
316# Cleanup exist user/group.
317#
318function cleanup_user_group
319{
320	del_user $ZFS_ACL_ADMIN
321
322	del_user $ZFS_ACL_STAFF1
323	del_user $ZFS_ACL_STAFF2
324	del_group $ZFS_ACL_STAFF_GROUP
325
326	del_user $ZFS_ACL_OTHER1
327	del_user $ZFS_ACL_OTHER2
328	del_group $ZFS_ACL_OTHER_GROUP
329
330	return 0
331}
332
333#
334# Clean up testfile and test directory
335#
336function cleanup
337{
338	if [[ -d $TESTDIR ]]; then
339		cd $TESTDIR
340		$RM -rf $TESTDIR/*
341	fi
342}
343
344#
345# According to specified access or acl_spec, do relevant operating by using the
346# specified user.
347#
348# $1 specified user
349# $2 node
350# $3 acl_spec or access
351#
352function rwx_node #user node acl_spec|access
353{
354	typeset user=$1
355	typeset node=$2
356	typeset acl_spec=$3
357
358	if [[ $user == "" || $node == "" || $acl_spec == "" ]]; then
359		log_note "node or acl_spec are not defined."
360		return 1
361	fi
362
363	if [[ -d $node ]]; then
364		case $acl_spec in
365		*:read_data:*|read_data)
366			chgusr_exec $user $LS -l $node > /dev/null 2>&1
367			return $? ;;
368		*:write_data:*|write_data)
369			if [[ -f ${node}/tmpfile ]]; then
370				log_must $RM -f ${node}/tmpfile
371			fi
372			chgusr_exec $user $TOUCH ${node}/tmpfile > \
373				/dev/null 2>&1
374			return $? ;;
375		*"execute:"*|execute)
376			chgusr_exec $user $FIND $node > /dev/null 2>&1
377			return $? ;;
378		esac
379	else
380		case $acl_spec in
381		*:read_data:*|read_data)
382			chgusr_exec $user $CAT $node > /dev/null 2>&1
383			return $? ;;
384		*:write_data:*|write_data)
385			chgusr_exec $user $DD if=/usr/bin/ls of=$node > \
386				/dev/null 2>&1
387			return $? ;;
388		*"execute:"*|execute)
389			ZFS_ACL_ERR_STR=$(chgusr_exec $user $node 2>&1)
390			return $? ;;
391		esac
392	fi
393}
394
395#
396# Get the given file/directory xattr
397#
398# $1 object -- file or directroy
399#
400function get_xattr #<obj>
401{
402        typeset obj=$1
403	typeset xattr
404	if (( ${#obj} == 0 )); then
405		return 1
406	fi
407
408	for xattr in `$RUNAT $obj $LS | \
409		/usr/xpg4/bin/egrep -v -e SUNWattr_ro -e SUNWattr_rw` ; do
410		$RUNAT $obj $SUM $xattr
411	done
412}
413
414#
415# Get the owner of a file/directory
416#
417function get_owner #node
418{
419	typeset node=$1
420	typeset value
421
422	if [[ -z $node ]]; then
423		log_fail "node are not defined."
424	fi
425
426	if [[ -d $node ]]; then
427		value=$($LS -dl $node | $AWK '{print $3}')
428	elif [[ -e $node ]]; then
429		value=$($LS -l $node | $AWK '{print $3}')
430	fi
431
432	$ECHO $value
433}
434
435#
436# Get the group of a file/directory
437#
438function get_group #node
439{
440	typeset node=$1
441	typeset value
442
443	if [[ -z $node ]]; then
444		log_fail "node are not defined."
445	fi
446
447	if [[ -d $node ]]; then
448		value=$($LS -dl $node | $AWK '{print $4}')
449	elif [[ -e $node ]]; then
450		value=$($LS -l $node | $AWK '{print $4}')
451	fi
452
453	$ECHO $value
454}
455
456
457#
458# Get the group name that a UID belongs to
459#
460function get_user_group #uid
461{
462	typeset uid=$1
463	typeset value
464
465	if [[ -z $uid ]]; then
466		log_fail "UID not defined."
467	fi
468
469	value=$(id $uid)
470
471	if [[ $? -eq 0 ]]; then
472		value=${value##*\(}
473		value=${value%%\)*}
474		$ECHO $value
475	else
476		log_fail "Invalid UID (uid)."
477	fi
478}
479
480#
481# Get the specified item of the specified string
482#
483# $1:	Item number, count from 0.
484# $2-n: strings
485#
486function getitem
487{
488	typeset -i n=$1
489	shift
490
491	(( n += 1 ))
492	eval echo \${$n}
493}
494
495#
496# This function calculate the specified directory files checksum and write
497# to the specified array.
498#
499# $1 directory in which the files will be cksum.
500# $2 file array name which was used to store file cksum information.
501# $3 attribute array name which was used to store attribute information.
502#
503function cksum_files #<dir> <file_array_name> <attribute_array_name>
504{
505	typeset dir=$1
506	typeset farr_name=$2
507	typeset aarr_name=$3
508
509	[[ ! -d $dir ]] && return
510	typeset oldpwd=$PWD
511	cd $dir
512	typeset files=$($LS file*)
513
514	typeset -i i=0
515	typeset -i n=0
516	while (( i < NUM_FILE )); do
517		typeset f=$(getitem $i $files)
518		eval $farr_name[$i]=\$\(\$CKSUM $f\)
519
520		typeset -i j=0
521		while (( j < NUM_ATTR )); do
522			eval $aarr_name[$n]=\$\(\$RUNAT \$f \$CKSUM \
523				attribute.$j\)
524
525			(( j += 1 ))
526			(( n += 1 ))
527		done
528
529		(( i += 1 ))
530	done
531
532	cd $oldpwd
533}
534
535#
536# This function compare two cksum results array.
537#
538# $1 The array name which stored the cksum before operation.
539# $2 The array name which stored the cksum after operation.
540#
541function compare_cksum #<array1> <array2>
542{
543	typeset before=$1
544	typeset after=$2
545	eval typeset -i count=\${#$before[@]}
546
547	typeset -i i=0
548	while (( i < count )); do
549		eval typeset var1=\${$before[$i]}
550		eval typeset var2=\${$after[$i]}
551
552		if [[ $var1 != $var2 ]]; then
553			return 1
554		fi
555
556		(( i += 1 ))
557	done
558
559	return 0
560}
561
562#
563# This function calculate all the files cksum information in current directory
564# and output them to the specified file.
565#
566# $1 directory from which the files will be cksum.
567# $2 cksum output file
568#
569function record_cksum #<outfile>
570{
571	typeset dir=$1
572	typeset outfile=$2
573
574	[[ ! -d ${outfile%/*} ]] && usr_exec $MKDIR -p ${outfile%/*}
575
576	usr_exec cd $dir ; $FIND . -depth -type f -exec cksum {} \\\; | \
577	    $SORT > $outfile
578	usr_exec cd $dir ; $FIND . -depth -type f -xattr -exec runat {} \
579		cksum attribute* \\\; | $SORT >> $outfile
580}
581
582#
583# The function create_files creates the directories and files that the script
584# will operate on to test extended attribute functionality.
585#
586# $1 The base directory in which to create directories and files.
587#
588function create_files #<directory>
589{
590	typeset basedir=$1
591
592	[[ ! -d $basedir ]] && usr_exec $MKDIR -m 777 $basedir
593	[[ ! -d $RES_DIR  ]] && usr_exec $MKDIR -m 777 $RES_DIR
594	[[ ! -d $INI_DIR ]] && usr_exec $MKDIR -m 777 $INI_DIR
595	[[ ! -d $TST_DIR ]] && usr_exec $MKDIR -m 777 $TST_DIR
596	[[ ! -d $TMP_DIR  ]] && usr_exec $MKDIR -m 777 $TMP_DIR
597
598	#
599	# Create the original file and its attribute files.
600	#
601	[[ ! -a $RES_DIR/file ]] && \
602		usr_exec $FILE_WRITE -o create -f $RES_DIR/file \
603			-b 1024 -d 0 -c 1
604	[[ ! -a $RES_DIR/attribute ]] && \
605		usr_exec $CP $RES_DIR/file $RES_DIR/attribute
606
607	typeset oldpwd=$PWD
608	cd $INI_DIR
609
610	typeset -i i=0
611	while (( i < NUM_FILE )); do
612		typeset dstfile=$INI_DIR/file.$$.$i
613		usr_exec $CP $RES_DIR/file $dstfile
614
615		typeset -i j=0
616		while (( j < NUM_ATTR )); do
617			usr_exec $RUNAT $dstfile \
618				$CP $RES_DIR/attribute ./attribute.$j
619			(( j += 1 ))
620		done
621
622		(( i += 1 ))
623	done
624
625	cd $oldpwd
626}
627