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