1#!/bin/ksh
2
3#
4# CDDL HEADER START
5#
6# The contents of this file are subject to the terms of the
7# Common Development and Distribution License (the "License").
8# You may not use this file except in compliance with the License.
9#
10# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11# or https://opensource.org/licenses/CDDL-1.0.
12# See the License for the specific language governing permissions
13# and limitations under the License.
14#
15# When distributing Covered Code, include this CDDL HEADER in each
16# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17# If applicable, add the following below this CDDL HEADER, with the
18# fields enclosed by brackets "[]" replaced with your own identifying
19# information: Portions Copyright [yyyy] [name of copyright owner]
20#
21# CDDL HEADER END
22#
23
24#
25# Copyright (c) 2016, 2018 by Delphix. All rights reserved.
26#
27
28. $STF_SUITE/include/libtest.shlib
29. $STF_SUITE/tests/functional/rsend/rsend.kshlib
30. $STF_SUITE/tests/functional/redacted_send/redacted.cfg
31
32if ! is_linux; then
33	alias udevadm=:
34fi
35
36function setup_dataset
37{
38	typeset ds_name=$1
39	typeset opts=$2
40	typeset file_create_func=$3
41	typeset sendfs="$POOL/$ds_name"
42	[[ -n $file_create_func ]] || file_create_func=setup_common
43
44	log_must zfs create $opts $sendfs
45
46	$file_create_func $sendfs
47
48	log_must zfs snapshot $sendfs@snap
49	log_must zfs clone $opts $sendfs@snap $POOL/${ds_name}_clone
50	log_must zfs snapshot $POOL/${ds_name}_clone@snap
51}
52
53function setup_common
54{
55	typeset sendfs=$1
56
57	typeset mntpnt=$(get_prop mountpoint $sendfs)
58	typeset bs=$(get_prop recsize $sendfs)
59	log_must dd if=/dev/urandom of=$mntpnt/f1 bs=$bs count=16
60	log_must dd if=/dev/urandom of=$mntpnt/f2 bs=$bs count=32
61}
62
63function setup_embedded
64{
65	typeset sendfs=$1
66
67	typeset recsize
68	typeset mntpnt=$(get_prop mountpoint $sendfs)
69	for recsize in 512 1024 2048 4096 8192 16384; do
70		if is_illumos; then
71			log_must mkholes -d $((recsize - 8)):8 $mntpnt/$recsize
72		else
73			log_must dd if=/dev/urandom of=$mntpnt/$recsize bs=8 \
74			    count=1 seek=$(((recsize / 8) - 1))
75		fi
76	done
77}
78
79function setup_holes
80{
81	typeset sendfs=$1
82
83	typeset mntpnt=$(get_prop mountpoint $sendfs)
84	typeset M=$((1024 * 1024))
85
86	if is_illumos; then
87		log_must mkholes -d 0:$((8 * M)) $mntpnt/f1
88		log_must mkholes -d 0:$M -d $((7 * M)):$M $mntpnt/f2
89		log_must mkholes -d $M:$((6 * M)) -h $((7 * M)):$M $mntpnt/f3
90		log_must mkholes -h 0:$((8 * M)) $mntpnt/f4
91	else
92		log_must dd if=/dev/urandom of=$mntpnt/f1 bs=8M count=1
93
94		log_must dd if=/dev/urandom of=$mntpnt/f2 bs=1M count=1
95		log_must dd if=/dev/urandom of=$mntpnt/f2 bs=1M count=1 seek=7 \
96		    conv=notrunc
97
98		log_must dd if=/dev/urandom of=$mntpnt/f3 bs=1M count=6 seek=1
99		log_must truncate -s $((8 * M)) $mntpnt/f3
100
101		log_must truncate -s $((8 * M)) $mntpnt/f4
102	fi
103
104	log_must zfs create $sendfs/manyrm
105	for i in {1..256}; do
106		log_must stride_dd -i /dev/urandom -o $mntpnt/manyrm/f$i -b 512 \
107		    -c $(random_int_between 1 100) -s $(random_int_between 1 4)
108	done
109
110	log_must zfs snapshot $sendfs/manyrm@snap
111	log_must zfs clone $sendfs/manyrm@snap $sendfs/manyrm_clone
112	log_must zfs snapshot $sendfs/manyrm_clone@snap
113}
114
115function setup_incrementals
116{
117	typeset sendfs=$1
118
119	typeset mntpnt=$(get_prop mountpoint $sendfs)
120	typeset bs=$(get_prop recsize $sendfs)
121	log_must dd if=/dev/urandom of=$mntpnt/f1 bs=$bs count=16
122	log_must dd if=/dev/urandom of=$mntpnt/f2 bs=$bs count=32
123	log_must mkdir $mntpnt/d1
124	log_must eval "cat $mntpnt/f1 $mntpnt/f2 >$mntpnt/d1/f1"
125	log_must zfs snapshot $sendfs@snap0
126
127	log_must zfs clone $sendfs@snap0 $POOL/hole
128	mntpnt=$(get_prop mountpoint $POOL/hole)
129	log_must dd if=/dev/zero of=$mntpnt/f2 bs=$bs count=16 conv=notrunc
130	log_must zfs snapshot $POOL/hole@snap
131
132	log_must zfs clone $sendfs@snap0 $POOL/stride3
133	mntpnt=$(get_prop mountpoint $POOL/stride3)
134	log_must stride_dd -i /dev/urandom -o $mntpnt/f2 -b $bs -c 11 -s 3
135	log_must zfs snapshot $POOL/stride3@snap
136
137	log_must zfs clone $sendfs@snap0 $POOL/stride5
138	mntpnt=$(get_prop mountpoint $POOL/stride5)
139	log_must stride_dd -i /dev/urandom -o $mntpnt/f2 -b $bs -c 7 -s 5
140	log_must zfs snapshot $POOL/stride5@snap
141
142	log_must zfs clone $sendfs@snap0 $POOL/int
143	log_must zfs snapshot $POOL/int@snap
144
145	log_must zfs clone $POOL/int@snap $POOL/rm
146	mntpnt=$(get_prop mountpoint $POOL/rm)
147	log_must rm -rf $mntpnt/[df][12]
148	log_must zfs snapshot $POOL/rm@snap
149
150	log_must zfs clone $POOL/int@snap $POOL/write
151	mntpnt=$(get_prop mountpoint $POOL/write)
152	log_must dd if=/dev/urandom of=$mntpnt/f1 bs=512 count=16 conv=notrunc
153	log_must dd if=/dev/urandom of=$mntpnt/d1/f1 bs=512 count=16 seek=16 \
154	    conv=notrunc
155	log_must zfs snapshot $POOL/write@snap
156}
157
158function setup_mounts
159{
160	typeset sendfs=$1
161
162	typeset mntpnt=$(get_prop mountpoint $sendfs)
163	log_must touch $mntpnt/empty
164	log_must dd if=/dev/urandom of=$mntpnt/contents1 bs=512 count=2
165	log_must dd if=/dev/urandom of=$mntpnt/contents2 bs=512 count=2
166	log_must mkdir $mntpnt/dir1
167	log_must touch $mntpnt/dir1/empty
168	log_must dd if=/dev/urandom of=$mntpnt/dir1/contents1 bs=512 count=2
169	log_must dd if=/dev/urandom of=$mntpnt/dir1/contents2 bs=512 count=2
170	log_must mkdir $mntpnt/dir1/dir2
171	log_must touch $mntpnt/dir1/dir2/empty
172	log_must dd if=/dev/urandom of=$mntpnt/dir1/dir2/file bs=512 count=2
173
174	log_must zfs create -s -V 16p $sendfs/vol
175	log_must zfs snapshot $sendfs/vol@snap
176	log_must zfs clone $sendfs/vol@snap $sendfs/vol_clone
177	log_must zfs snapshot $sendfs/vol_clone@snap
178}
179
180function mount_redacted
181{
182	typeset flag=''
183	while getopts "f" opt; do
184		case $opt in
185		f)
186			flag='-f'
187			;;
188		esac
189	done
190	shift $(($OPTIND - 1))
191
192	typeset ds=$1
193	log_must set_tunable32 ALLOW_REDACTED_DATASET_MOUNT 1
194	zfs mount $flag -oro $ds || return 1
195	log_must set_tunable32 ALLOW_REDACTED_DATASET_MOUNT 0
196	return 0
197}
198
199function unmount_redacted
200{
201	typeset ds=$1
202
203	zfs unmount $ds
204}
205
206#
207# This function calls a utility that prints out the ranges where a file
208# and its redacted counterpart differ, each range on a new line like this:
209#
210# 0,131072
211# 1966080,131072
212# 3932160,131072
213#
214# The output is then checked against a variable containing the expected
215# output to verify the redacted ranges are the ones expected.
216#
217function compare_files
218{
219	typeset sendfs=$1
220	typeset recvfs=$2
221	typeset file=$3
222	typeset expected="$4"
223	typeset tmpfile="$tmpdir/get_file.out"
224
225	log_must mount_redacted -f $recvfs
226
227	typeset file1="$(get_prop mountpoint $sendfs)/$file"
228	typeset file2="$(get_prop mountpoint $recvfs)/$file"
229	log_note "Comparing $file1 and $file2"
230	[[ -f $file1 ]] || log_fail "File $file1 does not exist."
231	[[ -f $file2 ]] || log_fail "File $file2 does not exist."
232
233	log_must eval "get_diff $file1 $file2 >$tmpfile"
234	typeset range="$(<$tmpfile)"
235	log_must unmount_redacted $recvfs
236	[[ "$expected" = "$range" ]] || log_fail "Unexpected range: $range"
237}
238
239function redacted_cleanup
240{
241	typeset ds_list=$@
242	typeset ds
243
244	for ds in $ds_list; do
245		zfs destroy -R $ds
246	done
247
248	set_tunable32 ALLOW_REDACTED_DATASET_MOUNT 0
249	rm -f $(get_prop mountpoint $POOL)/tmp/*
250}
251
252# Retrieve the redaction list of a bookmark or snapshot, using
253# the property or zdb output, as requested.
254function get_guid_list
255{
256	typeset filename=$1
257	typeset dataset=$2
258	typeset use_zdb=${3:-false}
259
260	if $use_zdb; then
261		guid_list=$(zdb -vvvv $dataset | sed -e 's/,//g' \
262		    -ne 's/^.*Snapshots: \[\(.*\)\]/\1/p')
263	else
264		guid_list=$(get_prop redact_snaps $dataset)
265	fi
266
267	for guid in $(echo $guid_list | tr ',' ' '); do
268		echo $guid
269	done | sort >$filename
270}
271