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