xref: /illumos-gate/usr/src/test/zfs-tests/tests/functional/delegate/delegate_common.kshlib (revision 71f3ceb939e47627273608fb7ea4b3aa1c3b37e7)
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 2008 Sun Microsystems, Inc.  All rights reserved.
24# Use is subject to license terms.
25#
26
27#
28# Copyright (c) 2013, 2016 by Delphix. All rights reserved.
29# Copyright 2016 Nexenta Systems, Inc.
30# Copyright 2023 Bill Sommerfeld <sommerfeld@alum.mit.edu>
31#
32
33. $STF_SUITE/include/libtest.shlib
34. $STF_SUITE/tests/functional/delegate/delegate.cfg
35
36#
37# Cleanup exist user/group.
38#
39function cleanup_user_group
40{
41	typeset i
42	for i in $STAFF1 $STAFF2 $OTHER1 $OTHER2 ; do
43		del_user $i
44	done
45	for i in $STAFF_GROUP $OTHER_GROUP ; do
46		del_group $i
47	done
48
49	return 0
50}
51
52#
53# Restore test file system to the original status.
54#
55function restore_root_datasets
56{
57	destroy_dataset "$ROOT_TESTFS" "-Rf"
58	log_must zfs create $ROOT_TESTFS
59
60	if is_global_zone ; then
61		destroy_dataset "$ROOT_TESTVOL" "-Rf"
62		log_must zfs create -V $VOLSIZE $ROOT_TESTVOL
63	fi
64
65	return 0
66}
67
68#
69# Verify the specified user have permission on the dataset
70#
71# $1 dataset
72# $2 permissions which are separated by comma(,)
73# $3-n users
74#
75function verify_perm
76{
77	typeset dtst=$1
78	typeset permissions=$2
79	shift 2
80
81	if [[ -z $@ || -z $permissions || -z $dtst ]]; then
82		return 1
83	fi
84
85	typeset type=$(get_prop type $dtst)
86	permissions=$(echo $permissions | tr -s "," " ")
87
88	typeset user
89	for user in $@; do
90		typeset perm
91		for perm in $permissions; do
92			typeset -i ret=1
93			if [[ $type == "filesystem" ]]; then
94				check_fs_perm $user $perm $dtst
95				ret=$?
96			elif [[ $type == "volume" ]]; then
97				check_vol_perm $user $perm $dtst
98				ret=$?
99			fi
100
101			if ((ret != 0)) ; then
102				log_note "Fail: $user should have $perm " \
103					"on $dtst"
104				return 1
105			fi
106		done
107	done
108
109	return 0
110}
111
112#
113# Verify the specified user have no permission on the dataset
114#
115# $1 dataset
116# $2 permissions which are separated by comma(,)
117# $3-n users
118#
119function verify_noperm
120{
121	typeset dtst=$1
122	typeset permissions=$2
123	shift 2
124
125	if [[ -z $@ || -z $permissions || -z $dtst ]]; then
126		return 1
127	fi
128
129	typeset type=$(get_prop type $dtst)
130	permissions=$(echo $permissions | tr -s "," " ")
131
132	typeset user
133	for user in $@; do
134		typeset perm
135		for perm in $permissions; do
136			typeset -i ret=1
137			if [[ $type == "filesystem" ]]; then
138				check_fs_perm $user $perm $dtst
139				ret=$?
140			elif [[ $type == "volume" ]]; then
141				check_vol_perm $user $perm $dtst
142				ret=$?
143			fi
144
145			if ((ret == 0)) ; then
146				log_note "Fail: $user should not have $perm " \
147					"on $dtst"
148				return 1
149			fi
150		done
151	done
152
153	return 0
154}
155
156function common_perm
157{
158	typeset user=$1
159	typeset perm=$2
160	typeset dtst=$3
161
162	typeset -i ret=1
163	case $perm in
164		send)
165			verify_send $user $perm $dtst
166			ret=$?
167			;;
168		allow)
169			verify_allow $user $perm $dtst
170			ret=$?
171			;;
172		userprop)
173			verify_userprop $user $perm $dtst
174			ret=$?
175			;;
176		compression|checksum|readonly)
177			verify_ccr $user $perm $dtst
178			ret=$?
179			;;
180		copies)
181			verify_copies $user $perm $dtst
182			ret=$?
183			;;
184		reservation)
185			verify_reservation $user $perm $dtst
186			ret=$?
187			;;
188		*)
189			ret=1
190			;;
191	esac
192
193	return $ret
194}
195
196function check_fs_perm
197{
198	typeset user=$1
199	typeset perm=$2
200	typeset fs=$3
201
202	typeset -i ret=1
203	case $perm in
204		create)
205			verify_fs_create $user $perm $fs
206			ret=$?
207			;;
208		destroy)
209			verify_fs_destroy $user $perm $fs
210			ret=$?
211			;;
212		snapshot)
213			verify_fs_snapshot $user $perm $fs
214			ret=$?
215			;;
216		rollback)
217			verify_fs_rollback $user $perm $fs
218			ret=$?
219			;;
220		clone)
221			verify_fs_clone $user $perm $fs
222			ret=$?
223			;;
224		rename)
225			verify_fs_rename $user $perm $fs
226			ret=$?
227			;;
228		mount)
229			verify_fs_mount $user $perm $fs
230			ret=$?
231			;;
232		share)
233			verify_fs_share $user $perm $fs
234			ret=$?
235			;;
236		mountpoint)
237			verify_fs_mountpoint $user $perm $fs
238			ret=$?
239			;;
240		promote)
241			verify_fs_promote $user $perm $fs
242			ret=$?
243			;;
244		canmount)
245			verify_fs_canmount $user $perm $fs
246			ret=$?
247			;;
248		dnodesize)
249			verify_fs_dnodesize $user $perm $fs
250			ret=$?
251			;;
252		recordsize)
253			verify_fs_recordsize $user $perm $fs
254			ret=$?
255			;;
256		quota)
257			verify_fs_quota $user $perm $fs
258			ret=$?
259			;;
260		aclmode)
261			verify_fs_aclmode $user $perm $fs
262			ret=$?
263			;;
264		aclinherit)
265			verify_fs_aclinherit $user $perm $fs
266			ret=$?
267			;;
268		snapdir)
269			verify_fs_snapdir $user $perm $fs
270			ret=$?
271			;;
272		atime|exec|devices|setuid|xattr)
273			verify_fs_aedsx $user $perm $fs
274			ret=$?
275			;;
276		zoned)
277			verify_fs_zoned $user $perm $fs
278			ret=$?
279			;;
280		sharenfs)
281			verify_fs_sharenfs $user $perm $fs
282			ret=$?
283			;;
284		receive)
285			verify_fs_receive $user $perm $fs
286			ret=$?
287			;;
288		*)
289			common_perm $user $perm $fs
290			ret=$?
291			;;
292	esac
293
294	return $ret
295}
296
297function check_vol_perm
298{
299	typeset user=$1
300	typeset perm=$2
301	typeset vol=$3
302
303	typeset -i ret=1
304	case $perm in
305		destroy)
306			verify_vol_destroy $user $perm $vol
307			ret=$?
308			;;
309		snapshot)
310			verify_vol_snapshot $user $perm $vol
311			ret=$?
312			;;
313		rollback)
314			verify_vol_rollback $user $perm $vol
315			ret=$?
316			;;
317		clone)
318			verify_vol_clone $user $perm $vol
319			ret=$?
320			;;
321		rename)
322			verify_vol_rename $user $perm $vol
323			ret=$?
324			;;
325		promote)
326			verify_vol_promote $user $perm $vol
327			ret=$?
328			;;
329		volsize)
330			verify_vol_volsize $user $perm $vol
331			ret=$?
332			;;
333		*)
334			common_perm $user $perm $vol
335			ret=$?
336			;;
337	esac
338
339	return $ret
340}
341
342function setup_unallow_testenv
343{
344	log_must restore_root_datasets
345
346	log_must zfs create $SUBFS
347
348	for dtst in $DATASETS ; do
349		log_must zfs allow -l $STAFF1 $LOCAL_SET $dtst
350		log_must zfs allow -d $STAFF2 $DESC_SET  $dtst
351		log_must zfs allow $OTHER1 $LOCAL_DESC_SET $dtst
352		log_must zfs allow $OTHER2 $LOCAL_DESC_SET $dtst
353
354		log_must verify_perm $dtst $LOCAL_SET $STAFF1
355		log_must verify_perm $dtst $LOCAL_DESC_SET $OTHER1
356		log_must verify_perm $dtst $LOCAL_DESC_SET $OTHER2
357		if [[ $dtst == $ROOT_TESTFS ]]; then
358			log_must verify_perm $SUBFS $DESC_SET $STAFF2
359			log_must verify_perm $SUBFS $LOCAL_DESC_SET $OTHER1
360			log_must verify_perm $SUBFS $LOCAL_DESC_SET $OTHER2
361		fi
362	done
363
364	return 0
365}
366
367#
368# Verify permission send for specified user on the dataset
369# $1 user
370# $2 permission
371# $3 dataset
372#
373function verify_send
374{
375	typeset user=$1
376	typeset perm=$2
377	typeset dtst=$3
378
379	typeset oldval
380	typeset stamp=${perm}.${user}.$RANDOM
381	typeset snap=$dtst@snap.$stamp
382
383	typeset -i ret=1
384
385	log_must zfs snapshot $snap
386	typeset bak_user=/tmp/bak.$user.$stamp
387	typeset bak_root=/tmp/bak.root.$stamp
388
389	user_run $user eval "zfs send $snap > $bak_user"
390	log_must eval "zfs send $snap > $bak_root"
391
392	if [[ $(checksum $bak_user) == $(checksum $bak_root) ]]; then
393		ret=0
394	fi
395
396	rm -rf $bak_user > /dev/null
397	rm -rf $bak_root > /dev/null
398
399	return $ret
400}
401
402function verify_fs_receive
403{
404	typeset user=$1
405	typeset perm=$2
406	typeset fs=$3
407
408	typeset dtst
409	typeset stamp=${perm}.${user}.$RANDOM
410	typeset newfs=$fs/newfs.$stamp
411	typeset newvol=$fs/newvol.$stamp
412	typeset bak_user=/tmp/bak.$user.$stamp
413	typeset bak_root=/tmp/bak.root.$stamp
414
415	log_must zfs create $newfs
416	typeset datasets="$newfs"
417	if is_global_zone ; then
418		log_must zfs create -V $VOLSIZE $newvol
419		datasets="$newfs $newvol"
420	fi
421
422	for dtst in $datasets ; do
423
424		typeset dtstsnap=$dtst@snap.$stamp
425		log_must zfs snapshot $dtstsnap
426
427		log_must eval "zfs send $dtstsnap > $bak_root"
428		log_must zfs destroy -rf $dtst
429
430		user_run $user eval "zfs receive $dtst < $bak_root"
431		if datasetexists $dtstsnap ; then
432			return 1
433		fi
434
435		log_must zfs allow $user create $fs
436		user_run $user eval "zfs receive $dtst < $bak_root"
437		log_must zfs unallow $user create $fs
438		if datasetexists $dtstsnap ; then
439			return 1
440		fi
441
442		log_must zfs allow $user mount $fs
443		user_run $user eval "zfs receive $dtst < $bak_root"
444		log_must zfs unallow $user mount $fs
445		if datasetexists $dtstsnap ; then
446			return 1
447		fi
448
449		log_must zfs allow $user mount,create $fs
450		user_run $user eval "zfs receive $dtst < $bak_root"
451		log_must zfs unallow $user mount,create $fs
452		if ! datasetexists $dtstsnap ; then
453			return 1
454		fi
455
456		# check the data integrity
457		log_must eval "zfs send $dtstsnap > $bak_user"
458		log_must zfs destroy -rf $dtst
459		log_must eval "zfs receive $dtst < $bak_root"
460		log_must eval "zfs send $dtstsnap > $bak_root"
461		log_must zfs destroy -rf $dtst
462		if [[ $(checksum $bak_user) != $(checksum $bak_root) ]]; then
463			return 1
464		fi
465
466		rm -rf $bak_user > /dev/null
467		rm -rf $bak_root > /dev/null
468
469	done
470
471	return 0
472}
473
474function verify_userprop
475{
476	typeset user=$1
477	typeset perm=$2
478	typeset dtst=$3
479
480	typeset stamp=${perm}.${user}.$RANDOM
481
482	user_run $user zfs set "$user:ts=$stamp" $dtst
483	sync_pool ${dtst%%/*}
484	if [[ $stamp != $(get_prop "$user:ts" $dtst) ]]; then
485		return 1
486	fi
487	user_run $user zfs inherit "$user:ts" $dtst
488
489	return 0
490}
491
492function verify_ccr
493{
494	typeset user=$1
495	typeset perm=$2
496	typeset dtst=$3
497
498	typeset oldval
499
500	set -A modes "on" "off"
501	oldval=$(get_prop $perm $dtst)
502	if [[ $oldval == "on" ]]; then
503		n=1
504	elif [[ $oldval == "off" ]]; then
505		n=0
506	fi
507	log_note "$user zfs set $perm=${modes[$n]} $dtst"
508	user_run $user zfs set $perm=${modes[$n]} $dtst
509	if [[ ${modes[$n]} != $(get_prop $perm $dtst) ]]; then
510		return 1
511	fi
512
513	return 0
514}
515
516function verify_copies
517{
518	typeset user=$1
519	typeset perm=$2
520	typeset dtst=$3
521
522	typeset oldval
523
524	set -A modes 1 2 3
525	oldval=$(get_prop $perm $dtst)
526	if [[ $oldval -eq 1 ]]; then
527		n=1
528	elif [[ $oldval -eq 2 ]]; then
529		n=2
530	elif [[ $oldval -eq 3 ]]; then
531		n=0
532	fi
533	log_note "$user zfs set $perm=${modes[$n]} $dtst"
534	user_run $user zfs set $perm=${modes[$n]} $dtst
535	if [[ ${modes[$n]} != $(get_prop $perm $dtst) ]]; then
536		return 1
537	fi
538
539	return 0
540}
541
542function verify_reservation
543{
544	typeset user=$1
545	typeset perm=$2
546	typeset dtst=$3
547
548	typeset value32m=$(( 1024 * 1024 * 32 ))
549	typeset oldval=$(get_prop reservation $dtst)
550	user_run $user zfs set reservation=$value32m $dtst
551	if [[ $value32m != $(get_prop reservation $dtst) ]]; then
552		log_must zfs set reservation=$oldval $dtst
553		return 1
554	fi
555
556	log_must zfs set reservation=$oldval $dtst
557	return 0
558}
559
560function verify_fs_create
561{
562	typeset user=$1
563	typeset perm=$2
564	typeset fs=$3
565
566	typeset stamp=${perm}.${user}.$RANDOM
567	typeset newfs=$fs/nfs.$stamp
568	typeset newvol=$fs/nvol.$stamp
569
570	user_run $user zfs create $newfs
571	if datasetexists $newfs ; then
572		return 1
573	fi
574
575	log_must zfs allow $user mount $fs
576	user_run $user zfs create $newfs
577	log_must zfs unallow $user mount $fs
578	if ! datasetexists $newfs ; then
579		return 1
580	fi
581
582	log_must zfs destroy $newfs
583
584	if is_global_zone ; then
585		# mount permission is required for sparse volume
586		user_run $user zfs create -V 150m -s $newvol
587		if datasetexists $newvol ; then
588			return 1
589		fi
590
591		log_must zfs allow $user mount $fs
592		user_run $user zfs create -V 150m -s $newvol
593		log_must zfs unallow $user mount $fs
594		if ! datasetexists $newvol ; then
595			return 1
596		fi
597		log_must zfs destroy $newvol
598
599		# mount and reserveration permission are
600		# required for normal volume
601		user_run $user zfs create -V 150m $newvol
602		if datasetexists $newvol ; then
603			return 1
604		fi
605
606		log_must zfs allow $user mount $fs
607		user_run $user zfs create -V 150m $newvol
608		log_must zfs unallow $user mount $fs
609		if datasetexists $newvol ; then
610			return 1
611		fi
612
613		log_must zfs allow $user reservation $fs
614		user_run $user zfs create -V 150m $newvol
615		log_must zfs unallow $user reservation $fs
616		if datasetexists $newvol ; then
617			return 1
618		fi
619
620		log_must zfs allow $user refreservation $fs
621		user_run $user zfs create -V 150m $newvol
622		log_must zfs unallow $user refreservation $fs
623		if datasetexists $newvol ; then
624			return 1
625		fi
626
627		log_must zfs allow $user mount $fs
628		log_must zfs allow $user reservation $fs
629		log_must zfs allow $user refreservation $fs
630		user_run $user zfs create -V 150m $newvol
631		log_must zfs unallow $user mount $fs
632		log_must zfs unallow $user reservation $fs
633		log_must zfs unallow $user refreservation $fs
634		if ! datasetexists $newvol ; then
635			return 1
636		fi
637		log_must zfs destroy $newvol
638	fi
639
640	return 0
641}
642
643function verify_fs_destroy
644{
645	typeset user=$1
646	typeset perm=$2
647	typeset fs=$3
648
649	if ! ismounted $fs ; then
650		user_run $user zfs destroy $fs
651		if datasetexists $fs ; then
652			return 1
653		fi
654	fi
655
656	if ismounted $fs ; then
657		user_run $user zfs destroy $fs
658		if ! datasetexists $fs ; then
659			return 1
660		fi
661
662		# mount permission is required
663		log_must zfs allow $user mount $fs
664		user_run $user zfs destroy $fs
665		if datasetexists $fs ; then
666			return 1
667		fi
668	fi
669
670	return 0
671}
672
673# Verify that given the correct delegation, a regular user can:
674#	Take a snapshot of an unmounted dataset
675#	Take a snapshot of an mounted dataset
676#	Create a snapshot by making a directory in the .zfs/snapshot directory
677function verify_fs_snapshot
678{
679	typeset user=$1
680	typeset perm=$2
681	typeset fs=$3
682
683	typeset stamp=${perm}.${user}.$RANDOM
684	typeset snap=$fs@snap.$stamp
685	typeset mntpt=$(get_prop mountpoint $fs)
686
687	if [[ "yes" == $(get_prop mounted $fs) ]]; then
688		log_must zfs umount $fs
689	fi
690
691	user_run $user zfs snapshot $snap
692	if ! datasetexists $snap ; then
693		return 1
694	fi
695	log_must zfs destroy $snap
696
697	if [[ "no" == $(get_prop mounted $fs) ]]; then
698		log_must zfs mount $fs
699	fi
700
701	user_run $user zfs snapshot $snap
702	if ! datasetexists $snap ; then
703		return 1
704	fi
705	log_must zfs destroy $snap
706
707	typeset snapdir=${mntpt}/.zfs/snapshot/snap.$stamp
708	user_run $user mkdir $snapdir
709	if ! datasetexists $snap ; then
710		return 1
711	fi
712	log_must zfs destroy $snap
713
714	return 0
715}
716
717function verify_fs_rollback
718{
719	typeset user=$1
720	typeset perm=$2
721	typeset fs=$3
722
723	typeset oldval
724	typeset stamp=${perm}.${user}.$RANDOM
725	typeset snap=$fs@snap.$stamp
726	typeset mntpt=$(get_prop mountpoint $fs)
727
728	oldval=$(datasetcksum $fs)
729	log_must zfs snapshot $snap
730
731	if ! ismounted $fs; then
732		log_must zfs mount $fs
733	fi
734	log_must touch $mntpt/testfile.$stamp
735
736	user_run $user zfs rollback -R $snap
737	if is_global_zone ; then
738		if [[ $oldval != $(datasetcksum $fs) ]]; then
739			return 1
740		fi
741	else
742		# datasetcksum can not be used in local zone
743		if [[ -e $mntpt/testfile.$stamp ]]; then
744			return 1
745		fi
746	fi
747
748	return 0
749}
750
751function verify_fs_clone
752{
753	typeset user=$1
754	typeset perm=$2
755	typeset fs=$3
756
757	typeset stamp=${perm}.${user}.$RANDOM
758	typeset basefs=${fs%/*}
759	typeset snap=$fs@snap.$stamp
760	typeset clone=$basefs/cfs.$stamp
761
762	log_must zfs snapshot $snap
763	user_run $user zfs clone $snap $clone
764	if datasetexists $clone ; then
765		return 1
766	fi
767
768	log_must zfs allow $user create $basefs
769	user_run $user zfs clone $snap $clone
770	log_must zfs unallow $user create $basefs
771	if datasetexists $clone ; then
772		return 1
773	fi
774
775	log_must zfs allow $user mount $basefs
776	user_run $user zfs clone $snap $clone
777	log_must zfs unallow $user mount $basefs
778	if datasetexists $clone ; then
779		return 1
780	fi
781
782	log_must zfs allow $user mount $basefs
783	log_must zfs allow $user create $basefs
784	user_run $user zfs clone $snap $clone
785	log_must zfs unallow $user create $basefs
786	log_must zfs unallow $user mount $basefs
787	if ! datasetexists $clone ; then
788		return 1
789	fi
790
791	log_must zfs destroy -R $snap
792
793	return 0
794}
795
796function verify_fs_rename
797{
798	typeset user=$1
799	typeset perm=$2
800	typeset fs=$3
801
802	typeset stamp=${perm}.${user}.$RANDOM
803	typeset basefs=${fs%/*}
804	typeset snap=$fs@snap.$stamp
805	typeset renamefs=$basefs/nfs.$stamp
806
807	if ! ismounted $fs; then
808		log_must zfs mount $fs
809	fi
810
811	# case 1
812	user_run $user zfs rename $fs $renamefs
813	if datasetexists $renamefs ; then
814		return 1
815	fi
816
817	# case 2
818	log_must zfs allow $user create $basefs
819	user_run $user zfs rename $fs $renamefs
820	log_must zfs unallow $user create $basefs
821	if datasetexists $renamefs ; then
822		return 1
823	fi
824
825	# case 3
826	log_must zfs allow $user mount $basefs
827	user_run $user zfs rename $fs $renamefs
828	log_must zfs unallow $user mount $basefs
829	if datasetexists $renamefs ; then
830		return 1
831	fi
832
833	# case 4
834	log_must zfs allow $user mount $fs
835	user_run $user zfs rename $fs $renamefs
836	if datasetexists $renamefs ; then
837		log_must zfs unallow $user mount $renamefs
838		return 1
839	fi
840	log_must zfs unallow $user mount $fs
841
842	# case 5
843	log_must zfs allow $user create $basefs
844	log_must zfs allow $user mount $fs
845	user_run $user zfs rename $fs $renamefs
846	log_must zfs unallow $user create $basefs
847	if datasetexists $renamefs ; then
848		log_must zfs unallow $user mount $renamefs
849		return 1
850	fi
851	log_must zfs unallow $user mount $fs
852
853	# case 6
854	log_must zfs allow $user mount $basefs
855	log_must zfs allow $user mount $fs
856	user_run $user zfs rename $fs $renamefs
857	log_must zfs unallow $user mount $basefs
858	if datasetexists $renamefs ; then
859		log_must zfs unallow $user mount $renamefs
860		return 1
861	fi
862	log_must zfs unallow $user mount $fs
863
864	# case 7
865	log_must zfs allow $user create $basefs
866	log_must zfs allow $user mount $basefs
867	user_run $user zfs rename $fs $renamefs
868	log_must zfs unallow $user mount $basefs
869	log_must zfs unallow $user create $basefs
870	if ! datasetexists $renamefs ; then
871		return 1
872	fi
873
874	log_must zfs rename $renamefs $fs
875
876	return 0
877}
878
879function verify_fs_mount
880{
881	typeset user=$1
882	typeset perm=$2
883	typeset fs=$3
884
885	typeset stamp=${perm}.${user}.$RANDOM
886	typeset mntpt=$(get_prop mountpoint $fs)
887	typeset newmntpt=/tmp/mnt.$stamp
888
889	if ismounted $fs ; then
890		user_run $user zfs unmount $fs
891		if ismounted $fs ; then
892			return 1
893		fi
894	fi
895
896	if ! ismounted $fs ; then
897		log_must zfs set mountpoint=$newmntpt $fs
898		log_must rm -rf $newmntpt
899		log_must mkdir $newmntpt
900
901		user_run $user zfs mount $fs
902		if ismounted $fs ; then
903			return 1
904		fi
905
906		# mountpoint's owner must be the user
907		log_must chown $user $newmntpt
908		user_run $user zfs mount $fs
909		if ! ismounted $fs ; then
910			return 1
911		fi
912		log_must zfs umount $fs
913		log_must rm -rf $newmntpt
914		log_must zfs set mountpoint=$mntpt $fs
915	fi
916
917	return 0
918}
919
920function verify_fs_share
921{
922	typeset user=$1
923	typeset perm=$2
924	typeset fs=$3
925	typeset -i ret=0
926
927	svcadm enable -rs nfs/server
928	typeset stat=$(svcs -H -o STA nfs/server:default)
929	if [[ $stat != "ON" ]]; then
930		log_fail "Could not enable nfs/server"
931	fi
932
933	log_must zfs set sharenfs=on $fs
934	zfs unshare $fs
935
936	user_run $user zfs share $fs
937	if ! is_shared $fs; then
938		ret=1
939	fi
940
941	zfs unshare $fs
942	log_must zfs set sharenfs=off $fs
943
944	return $ret
945}
946
947function verify_fs_mountpoint
948{
949	typeset user=$1
950	typeset perm=$2
951	typeset fs=$3
952
953	typeset stamp=${perm}.${user}.$RANDOM
954	typeset mntpt=$(get_prop mountpoint $fs)
955	typeset newmntpt=/tmp/mnt.$stamp
956
957	if ! ismounted $fs ; then
958		user_run $user zfs set mountpoint=$newmntpt $fs
959		if [[ $newmntpt != \
960			$(get_prop mountpoint $fs) ]] ; then
961			return 1
962		fi
963		log_must zfs set mountpoint=$mntpt $fs
964	fi
965
966	if ismounted $fs ; then
967		user_run $user zfs set mountpoint=$newmntpt $fs
968		if [[ $mntpt != $(get_prop mountpoint $fs) ]]; then
969			return 1
970		fi
971
972		# require mount permission when fs is mounted
973		log_must zfs allow $user mount $fs
974		user_run $user zfs set mountpoint=$newmntpt $fs
975		log_must zfs unallow $user mount $fs
976		if [[ $newmntpt != \
977			$(get_prop mountpoint $fs) ]] ; then
978			return 1
979		fi
980		log_must zfs set mountpoint=$mntpt $fs
981	fi
982
983	return 0
984}
985
986function verify_fs_promote
987{
988	typeset user=$1
989	typeset perm=$2
990	typeset fs=$3
991
992	typeset stamp=${perm}.${user}.$RANDOM
993	typeset basefs=${fs%/*}
994	typeset snap=$fs@snap.$stamp
995	typeset clone=$basefs/cfs.$stamp
996
997	log_must zfs snapshot $snap
998	log_must zfs clone $snap $clone
999	log_must zfs promote $clone
1000
1001	typeset fs_orig=$(get_prop origin $fs)
1002	typeset clone_orig=$(get_prop origin $clone)
1003
1004	user_run $user zfs promote $fs
1005	# promote should fail if original fs does not have
1006	# promote permission
1007	if [[ $fs_orig != $(get_prop origin $fs) || \
1008		$clone_orig != $(get_prop origin $clone) ]]; then
1009		return 1
1010	fi
1011
1012	log_must zfs allow $user promote $clone
1013	user_run $user zfs promote $fs
1014	log_must zfs unallow $user promote $clone
1015	if [[ $fs_orig != $(get_prop origin $fs) || \
1016		$clone_orig != $(get_prop origin $clone) ]]; then
1017		return 1
1018	fi
1019
1020	log_must zfs allow $user mount $fs
1021	user_run $user zfs promote $fs
1022	log_must zfs unallow $user mount $fs
1023	if [[ $fs_orig != $(get_prop origin $fs) || \
1024		$clone_orig != $(get_prop origin $clone) ]]; then
1025		return 1
1026	fi
1027
1028	log_must zfs allow $user mount $fs
1029	log_must zfs allow $user promote $clone
1030	user_run $user zfs promote $fs
1031	log_must zfs unallow $user promote $clone
1032	log_must zfs unallow $user mount $fs
1033	if [[ $snap != $(get_prop origin $clone) || \
1034		$clone_orig != $(get_prop origin $fs) ]]; then
1035		return 1
1036	fi
1037
1038	return 0
1039}
1040
1041function verify_fs_canmount
1042{
1043	typeset user=$1
1044	typeset perm=$2
1045	typeset fs=$3
1046
1047	typeset oldval
1048	typeset stamp=${perm}.${user}.$RANDOM
1049
1050	if ! ismounted $fs ; then
1051		set -A modes "on" "off"
1052		oldval=$(get_prop $perm $fs)
1053		if [[ $oldval == "on" ]]; then
1054			n=1
1055		elif [[ $oldval == "off" ]]; then
1056			n=0
1057		fi
1058		log_note "$user zfs set $perm=${modes[$n]} $fs"
1059		user_run $user zfs set $perm=${modes[$n]} $fs
1060		if [[ ${modes[$n]} != $(get_prop $perm $fs) ]]; then
1061			return 1
1062		fi
1063	fi
1064
1065
1066	# fs is mounted
1067	if ismounted $fs ; then
1068		# property value does not change if
1069		# no mount permission
1070		set -A modes "on" "off"
1071		oldval=$(get_prop $perm $fs)
1072		if [[ $oldval == "on" ]]; then
1073			n=1
1074		elif [[ $oldval == "off" ]]; then
1075			n=0
1076		fi
1077		log_note "$user zfs set $perm=${modes[$n]} $fs"
1078		log_must zfs allow $user mount $fs
1079		user_run $user zfs set $perm=${modes[$n]} $fs
1080		log_must zfs unallow $user mount $fs
1081		if [[ ${modes[$n]} != $(get_prop $perm $fs) ]]; then
1082			return 1
1083		fi
1084	fi
1085
1086	return 0
1087}
1088
1089function verify_fs_recordsize
1090{
1091	typeset user=$1
1092	typeset perm=$2
1093	typeset fs=$3
1094
1095	typeset value8k=$(( 1024 * 8 ))
1096	user_run $user zfs set recordsize=$value8k $fs
1097	if [[ $value8k != $(get_prop recordsize $fs) ]]; then
1098		return 1
1099	fi
1100
1101	return 0
1102}
1103
1104function verify_fs_dnodesize
1105{
1106	typeset user=$1
1107	typeset perm=$2
1108	typeset fs=$3
1109	value="2k"
1110
1111	user_run $user zfs set dnodesize=$value $fs
1112	if [[ $value != $(get_prop dnodesize $fs) ]]; then
1113		return 1
1114	fi
1115
1116	return 0
1117}
1118
1119function verify_fs_quota
1120{
1121	typeset user=$1
1122	typeset perm=$2
1123	typeset fs=$3
1124
1125	typeset value32m=$(( 1024 * 1024 * 32 ))
1126	user_run $user zfs set quota=$value32m $fs
1127	if [[ $value32m != $(get_prop quota $fs) ]]; then
1128		return 1
1129	fi
1130
1131	return 0
1132}
1133
1134function verify_fs_aclmode
1135{
1136	typeset user=$1
1137	typeset perm=$2
1138	typeset fs=$3
1139
1140	typeset oldval
1141	set -A modes "discard" "groupmask" "passthrough"
1142	oldval=$(get_prop $perm $fs)
1143	if [[ $oldval == "discard" ]]; then
1144		n=1
1145	elif [[ $oldval == "groupmask" ]]; then
1146		n=2
1147	elif [[ $oldval == "passthrough" ]]; then
1148		n=0
1149	fi
1150	log_note "$user zfs set aclmode=${modes[$n]} $fs"
1151	user_run $user zfs set aclmode=${modes[$n]} $fs
1152	if [[ ${modes[$n]} != $(get_prop aclmode $fs) ]]; then
1153		return 1
1154	fi
1155
1156	return 0
1157}
1158
1159function verify_fs_aclinherit
1160{
1161	typeset user=$1
1162	typeset perm=$2
1163	typeset fs=$3
1164
1165	#
1166	# PSARC/2008/231 change the default value of aclinherit to "restricted"
1167	# but still keep the old interface of "secure"
1168	#
1169
1170	typeset oldval
1171	set -A modes "discard" "noallow" "secure" "passthrough"
1172	oldval=$(get_prop $perm $fs)
1173	if [[ $oldval == "discard" ]]; then
1174		n=1
1175	elif [[ $oldval == "noallow" ]]; then
1176		n=2
1177	elif [[ $oldval == "secure" || $oldval == "restricted" ]]; then
1178		n=3
1179	elif [[ $oldval == "passthrough" ]]; then
1180		n=0
1181	fi
1182	log_note "$user zfs set aclinherit=${modes[$n]} $fs"
1183	user_run $user zfs set aclinherit=${modes[$n]} $fs
1184
1185	typeset newval=$(get_prop aclinherit $fs)
1186	if [[ ${modes[$n]} == "secure" && $newval == "restricted" ]]; then
1187		return 0
1188	elif [[ ${modes[$n]} != $(get_prop aclinherit $fs) ]]; then
1189		return 1
1190	fi
1191
1192	return 0
1193}
1194
1195function verify_fs_snapdir
1196{
1197	typeset user=$1
1198	typeset perm=$2
1199	typeset fs=$3
1200
1201	typeset oldval
1202	set -A modes "visible" "hidden"
1203	oldval=$(get_prop $perm $fs)
1204	if [[ $oldval == "visible" ]]; then
1205		n=1
1206	elif [[ $oldval == "hidden" ]]; then
1207		n=0
1208	fi
1209	log_note "$user zfs set snapdir=${modes[$n]} $fs"
1210	user_run $user zfs set snapdir=${modes[$n]} $fs
1211	if [[ ${modes[$n]} != $(get_prop snapdir $fs) ]]; then
1212		return 1
1213	fi
1214
1215	return 0
1216}
1217
1218function verify_fs_aedsx
1219{
1220	typeset user=$1
1221	typeset perm=$2
1222	typeset fs=$3
1223
1224	typeset oldval
1225	set -A modes "on" "off"
1226	oldval=$(get_prop $perm $fs)
1227	if [[ $oldval == "on" ]]; then
1228		n=1
1229	elif [[ $oldval == "off" ]]; then
1230		n=0
1231	fi
1232	log_note "$user zfs set $perm=${modes[$n]} $fs"
1233	user_run $user zfs set $perm=${modes[$n]} $fs
1234	if [[ ${modes[$n]} != $(get_prop $perm $fs) ]]; then
1235		return 1
1236	fi
1237
1238	return 0
1239}
1240
1241function verify_fs_zoned
1242{
1243	typeset user=$1
1244	typeset perm=$2
1245	typeset fs=$3
1246
1247	typeset oldval
1248	set -A modes "on" "off"
1249	oldval=$(get_prop $perm $fs)
1250	if [[ $oldval == "on" ]]; then
1251		n=1
1252	elif [[ $oldval == "off" ]]; then
1253		n=0
1254	fi
1255	log_note "$user zfs set $perm=${modes[$n]} $fs"
1256	if is_global_zone ; then
1257		if ! ismounted $fs ; then
1258			user_run $user zfs set \
1259				$perm=${modes[$n]} $fs
1260			if [[ ${modes[$n]} != \
1261				$(get_prop $perm $fs) ]]; then
1262				return 1
1263			fi
1264			if [[ $n -eq 0 ]]; then
1265				log_mustnot zfs mount $fs
1266			else
1267				log_must zfs mount $fs
1268			fi
1269		fi
1270
1271		if ismounted $fs; then
1272			# n always is 1 in this case
1273			user_run $user zfs set \
1274				$perm=${modes[$n]} $fs
1275			if [[ $oldval != \
1276				$(get_prop $perm $fs) ]]; then
1277				return 1
1278			fi
1279
1280			# mount permission is needed
1281			# to make zoned=on
1282			log_must zfs allow $user mount $fs
1283			user_run $user zfs set \
1284				$perm=${modes[$n]} $fs
1285			log_must zfs unallow $user mount $fs
1286			if [[ ${modes[$n]} != \
1287				$(get_prop $perm $fs) ]]; then
1288				return 1
1289			fi
1290		fi
1291	fi
1292
1293	if ! is_global_zone; then
1294		user_run $user zfs set $perm=${modes[$n]} $fs
1295		if [[ $oldval != $(get_prop $perm $fs) ]]; then
1296			return 1
1297		fi
1298	fi
1299
1300	return 0
1301}
1302
1303function verify_fs_sharenfs
1304{
1305	typeset user=$1
1306	typeset perm=$2
1307	typeset fs=$3
1308	typeset nmode omode
1309
1310	omode=$(get_prop $perm $fs)
1311	if [[ $omode == "off" ]]; then
1312		nmode="on"
1313	else
1314		nmode="off"
1315	fi
1316
1317	log_note "$user zfs set $perm=$nmode $fs"
1318	user_run $user zfs set $perm=$nmode $fs
1319	if [[ $(get_prop $perm $fs) != $nmode ]]; then
1320		return 1
1321	fi
1322
1323	log_note "$user zfs set $perm=$omode $fs"
1324	user_run $user zfs set $perm=$omode $fs
1325	if [[ $(get_prop $perm $fs) != $omode ]]; then
1326		return 1
1327	fi
1328
1329	return 0
1330}
1331
1332function verify_vol_destroy
1333{
1334	typeset user=$1
1335	typeset perm=$2
1336	typeset vol=$3
1337
1338	user_run $user zfs destroy $vol
1339	if ! datasetexists $vol ; then
1340		return 1
1341	fi
1342
1343	# mount permission is required
1344	log_must zfs allow $user mount $vol
1345	user_run $user zfs destroy $vol
1346	if datasetexists $vol ; then
1347		return 1
1348	fi
1349
1350	return 0
1351}
1352
1353function verify_vol_snapshot
1354{
1355	typeset user=$1
1356	typeset perm=$2
1357	typeset vol=$3
1358
1359	typeset stamp=${perm}.${user}.$RANDOM
1360	typeset basevol=${vol%/*}
1361	typeset snap=$vol@snap.$stamp
1362
1363	user_run $user zfs snapshot $snap
1364	if datasetexists $snap ; then
1365		return 1
1366	fi
1367
1368	log_must zfs allow $user mount $vol
1369	user_run $user zfs snapshot $snap
1370	log_must zfs unallow $user mount $vol
1371	if ! datasetexists $snap ; then
1372		return 1
1373	fi
1374
1375	return 0
1376}
1377
1378function verify_vol_rollback
1379{
1380	typeset user=$1
1381	typeset perm=$2
1382	typeset vol=$3
1383
1384	typeset stamp=${perm}.${user}.$RANDOM
1385	typeset basevol=${vol%/*}
1386	typeset snap=$vol@snap.$stamp
1387
1388	typeset oldval
1389	log_must zfs snapshot $snap
1390	oldval=$(datasetcksum $vol)
1391
1392	log_must dd if=/dev/random of=/dev/zvol/rdsk/$vol \
1393		bs=512 count=1
1394
1395	user_run $user zfs rollback -R $snap
1396	sleep 10
1397	if [[ $oldval == $(datasetcksum $vol) ]]; then
1398		return 1
1399	fi
1400
1401	# rollback on volume has to be with mount permission
1402	log_must zfs allow $user mount $vol
1403	user_run $user zfs rollback -R $snap
1404	sleep 10
1405	log_must zfs unallow $user mount $vol
1406	if [[ $oldval != $(datasetcksum $vol) ]]; then
1407		return 1
1408	fi
1409
1410	return 0
1411}
1412
1413function verify_vol_clone
1414{
1415	typeset user=$1
1416	typeset perm=$2
1417	typeset vol=$3
1418
1419	typeset stamp=${perm}.${user}.$RANDOM
1420	typeset basevol=${vol%/*}
1421	typeset snap=$vol@snap.$stamp
1422	typeset clone=$basevol/cvol.$stamp
1423
1424	log_must zfs snapshot $snap
1425
1426	user_run $user zfs clone $snap $clone
1427	if datasetexists $clone ; then
1428		return 1
1429	fi
1430
1431	log_must zfs allow $user create $basevol
1432	user_run $user zfs clone $snap $clone
1433	log_must zfs unallow $user create $basevol
1434	if datasetexists $clone ; then
1435		return 1
1436	fi
1437
1438	log_must zfs allow $user mount $basevol
1439	user_run $user zfs clone $snap $clone
1440	log_must zfs unallow $user mount $basevol
1441	if datasetexists $clone ; then
1442		return 1
1443	fi
1444
1445	# require create permission on parent and
1446	# mount permission on itself as well
1447	log_must zfs allow $user mount $basevol
1448	log_must zfs allow $user create $basevol
1449	user_run $user zfs clone $snap $clone
1450	log_must zfs unallow $user create $basevol
1451	log_must zfs unallow $user mount $basevol
1452	if ! datasetexists $clone ; then
1453		return 1
1454	fi
1455
1456	return 0
1457}
1458
1459function verify_vol_rename
1460{
1461	typeset user=$1
1462	typeset perm=$2
1463	typeset vol=$3
1464
1465	typeset stamp=${perm}.${user}.$RANDOM
1466	typeset basevol=${vol%/*}
1467	typeset snap=$vol@snap.$stamp
1468	typeset clone=$basevol/cvol.$stamp
1469	typeset renamevol=$basevol/nvol.$stamp
1470
1471	user_run $user zfs rename $vol $renamevol
1472	if datasetexists $renamevol ; then
1473		return 1
1474	fi
1475
1476	log_must zfs allow $user create $basevol
1477	user_run $user zfs rename $vol $renamevol
1478	log_must zfs unallow $user create $basevol
1479	if datasetexists $renamevol ; then
1480		return 1
1481	fi
1482
1483	log_must zfs allow $user mount $basevol
1484	user_run $user zfs rename $vol $renamevol
1485	log_must zfs unallow $user mount $basevol
1486	if datasetexists $renamevol ; then
1487		return 1
1488	fi
1489
1490	# require both create permission on parent and
1491	# mount permission on parent as well
1492	log_must zfs allow $user mount $basevol
1493	log_must zfs allow $user create $basevol
1494	user_run $user zfs rename $vol $renamevol
1495	log_must zfs unallow $user mount $basevol
1496	log_must zfs unallow $user create $basevol
1497	if ! datasetexists $renamevol ; then
1498		return 1
1499	fi
1500
1501	log_must zfs rename $renamevol $vol
1502
1503	return 0
1504}
1505
1506function verify_vol_promote
1507{
1508	typeset user=$1
1509	typeset perm=$2
1510	typeset vol=$3
1511
1512	typeset stamp=${perm}.${user}.$RANDOM
1513	typeset basevol=${vol%/*}
1514	typeset snap=$vol@snap.$stamp
1515	typeset clone=$basevol/cvol.$stamp
1516
1517	log_must zfs snapshot $snap
1518	log_must zfs clone $snap $clone
1519	log_must zfs promote $clone
1520
1521	typeset vol_orig=$(get_prop origin $vol)
1522	typeset clone_orig=$(get_prop origin $clone)
1523
1524	# promote should fail if $vol and $clone
1525	# miss either mount or promote permission
1526	# case 1
1527	user_run $user zfs promote $vol
1528	if [[ $vol_orig != $(get_prop origin $vol) || \
1529		$clone_orig != $(get_prop origin $clone) ]];
1530	then
1531		return 1
1532	fi
1533
1534	# promote should fail if $vol and $clone
1535	# miss either mount or promote permission
1536	# case 2
1537	log_must zfs allow $user promote $clone
1538	user_run $user zfs promote $vol
1539	log_must zfs unallow $user promote $clone
1540	if [[ $vol_orig != $(get_prop origin $vol) || \
1541		$clone_orig != $(get_prop origin $clone) ]];
1542	then
1543		return 1
1544	fi
1545
1546	# promote should fail if $vol and $clone
1547	# miss either mount or promote permission
1548	# case 3
1549	log_must zfs allow $user mount $vol
1550	user_run $user zfs promote $vol
1551	log_must zfs unallow $user mount $vol
1552	if [[ $vol_orig != $(get_prop origin $vol) || \
1553		$clone_orig != $(get_prop origin $clone) ]];
1554	then
1555		return 1
1556	fi
1557
1558	# promote should fail if $vol and $clone
1559	# miss either mount or promote permission
1560	# case 4
1561	log_must zfs allow $user mount $clone
1562	user_run $user zfs promote $vol
1563	log_must zfs unallow $user mount $clone
1564	if [[ $vol_orig != $(get_prop origin $vol) || \
1565		$clone_orig != $(get_prop origin $clone) ]];
1566	then
1567		return 1
1568	fi
1569
1570	# promote should fail if $vol and $clone
1571	# miss either mount or promote permission
1572	# case 5
1573	log_must zfs allow $user promote $clone
1574	log_must zfs allow $user mount $vol
1575	user_run $user zfs promote $vol
1576	log_must zfs unallow $user promote $clone
1577	log_must zfs unallow $user mount $vol
1578	if [[ $vol_orig != $(get_prop origin $vol) || \
1579		$clone_orig != $(get_prop origin $clone) ]];
1580	then
1581		return 1
1582	fi
1583
1584	# promote should fail if $vol and $clone
1585	# miss either mount or promote permission
1586	# case 6
1587	log_must zfs allow $user promote $clone
1588	log_must zfs allow $user mount $clone
1589	user_run $user zfs promote $vol
1590	log_must zfs unallow $user promote $clone
1591	log_must zfs unallow $user mount $vol
1592	if [[ $vol_orig != $(get_prop origin $vol) || \
1593		$clone_orig != $(get_prop origin $clone) ]];
1594	then
1595		return 1
1596	fi
1597
1598	# promote should fail if $vol and $clone
1599	# miss either mount or promote permission
1600	# case 7
1601	log_must zfs allow $user mount $vol
1602	log_must zfs allow $user mount $clone
1603	user_run $user zfs promote $vol
1604	log_must zfs unallow $user mount $vol
1605	log_must zfs unallow $user mount $clone
1606	if [[ $vol_orig != $(get_prop origin $vol) || \
1607		$clone_orig != $(get_prop origin $clone) ]];
1608	then
1609		return 1
1610	fi
1611
1612	# promote only succeeds when $vol and $clone
1613	# have both mount and promote permission
1614	# case 8
1615	log_must zfs allow $user promote $clone
1616	log_must zfs allow $user mount $vol
1617	log_must zfs allow $user mount $clone
1618	user_run $user zfs promote $vol
1619	log_must zfs unallow $user promote $clone
1620	log_must zfs unallow $user mount $vol
1621	log_must zfs unallow $user mount $clone
1622	if [[ $snap != $(get_prop origin $clone) || \
1623		$clone_orig != $(get_prop origin $vol) ]]; then
1624		return 1
1625	fi
1626
1627	return 0
1628}
1629
1630function verify_vol_volsize
1631{
1632	typeset user=$1
1633	typeset perm=$2
1634	typeset vol=$3
1635
1636	typeset oldval
1637	oldval=$(get_prop volsize $vol)
1638	(( newval = oldval * 2 ))
1639
1640	reserv_size=$(get_prop refreservation $vol)
1641
1642	if [[ "0" == $reserv_size ]]; then
1643		# sparse volume
1644		user_run $user zfs set volsize=$newval $vol
1645		if [[ $oldval == $(get_prop volsize $vol) ]];
1646		then
1647			return 1
1648		fi
1649
1650	else
1651		# normal volume, reservation permission
1652		# is required
1653		user_run $user zfs set volsize=$newval $vol
1654		if [[ $newval == $(get_prop volsize $vol) ]];
1655		then
1656			return 1
1657		fi
1658
1659		log_must zfs allow $user reservation $vol
1660		log_must zfs allow $user refreservation $vol
1661		user_run $user zfs set volsize=$newval $vol
1662		log_must zfs unallow $user reservation $vol
1663		log_must zfs unallow $user refreservation $vol
1664		if [[ $oldval == $(get_prop volsize $vol) ]];
1665		then
1666			return 1
1667		fi
1668	fi
1669
1670	return 0
1671}
1672
1673function verify_allow
1674{
1675	typeset user=$1
1676	typeset perm=$2
1677	typeset dtst=$3
1678
1679	typeset -i ret
1680
1681	user_run $user zfs allow $user allow $dtst
1682	ret=$?
1683	if [[ $ret -eq 0 ]]; then
1684		return 1
1685	fi
1686
1687	log_must zfs allow $user copies $dtst
1688	user_run $user zfs allow $user copies $dtst
1689	ret=$?
1690	log_must zfs unallow $user copies $dtst
1691	if [[ $ret -eq 1 ]]; then
1692		return 1
1693	fi
1694
1695	return 0
1696
1697}
1698
1699function verify_allow_output
1700{
1701	typeset dtst=$1
1702
1703	shift
1704	cat >>/tmp/allow_template.$$ <<EOF
1705---- Permissions on $dtst
1706EOF
1707
1708	while (( $# > 0 )); do
1709		typeset section=$1
1710		typeset content=$2
1711
1712		cat >>/tmp/allow_template.$$ <<EOF
1713${section}:
1714	$content
1715EOF
1716		shift 2
1717	done
1718
1719	# chop variable-length trailing dashes
1720	zfs allow $dtst | sed 's/ --*$//' >/tmp/allow_output.$$
1721
1722	typeset -i ret
1723	log_must diff -u /tmp/allow_template.$$ /tmp/allow_output.$$
1724	ret=$?
1725	rm -f  /tmp/allow_template.$$ /tmp/allow_output.$$
1726
1727	if [[ $ret -eq 0 ]]; then
1728		return 0
1729	fi
1730
1731	return 1
1732}
1733