1#!/bin/ksh -p
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 https://opensource.org/licenses/CDDL-1.0.
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#
24# Copyright 2017, loli10K <ezomori.nozomu@gmail.com>. All rights reserved.
25# Copyright 2019, 2020 by Christian Schwarz. All rights reserved.
26#
27
28. $STF_SUITE/include/libtest.shlib
29
30#
31# DESCRIPTION:
32# 'zfs bookmark' should work with both full and short arguments.
33#
34# STRATEGY:
35# 1. Create initial snapshot
36#
37# 2. Verify we can create a bookmark specifying snapshot and bookmark full paths
38# 3. Verify we can create a bookmark specifying the short snapshot name
39# 4. Verify we can create a bookmark specifying the short bookmark name
40# 5. Verify at least a full dataset path is required and both snapshot and
41#    bookmark name must be valid
42#
43# 6. Verify we can copy a bookmark by specifying the source bookmark and new
44#    bookmark full paths.
45# 7. Verify we can copy a bookmark specifying the short source name
46# 8. Verify we can copy a bookmark specifying the short new name
47# 9. Verify two short paths are not allowed, and test empty paths
48# 10. Verify we cannot copy a bookmark if the new bookmark already exists
49# 11. Verify that copying a bookmark only works if new and source name
50#     have the same dataset
51#
52
53verify_runnable "both"
54
55function cleanup
56{
57	snapexists "$DATASET@$TESTSNAP" && \
58		destroy_dataset "$DATASET@$TESTSNAP"
59
60	bkmarkexists "$DATASET#$TESTBM" && \
61		destroy_dataset "$DATASET#$TESTBM"
62
63	bkmarkexists "$DATASET#$TESTBMCOPY" && \
64		destroy_dataset "$DATASET#$TESTBMCOPY"
65
66	log_must rm -f "$TEST_BASE_DIR/zfstest_datastream.$$"
67}
68
69log_assert "'zfs bookmark' should work only when passed valid arguments."
70log_onexit cleanup
71
72DATASET="$TESTPOOL/$TESTFS"
73DATASET_TWO="$TESTPOOL/${TESTFS}_two"
74TESTSNAP='snapshot'
75TESTSNAP2='snapshot2'
76TESTBM='bookmark'
77TESTBMCOPY='bookmark_copy'
78
79
80# Create initial snapshot
81log_must zfs snapshot "$DATASET@$TESTSNAP"
82
83#
84# Bookmark creation tests
85#
86
87# Verify we can create a bookmark specifying snapshot and bookmark full paths
88log_must zfs bookmark "$DATASET@$TESTSNAP" "$DATASET#$TESTBM"
89log_must eval "bkmarkexists $DATASET#$TESTBM"
90log_must zfs destroy "$DATASET#$TESTBM"
91
92# Verify we can create a bookmark specifying the snapshot name
93log_must zfs bookmark "@$TESTSNAP" "$DATASET#$TESTBM"
94log_must eval "bkmarkexists $DATASET#$TESTBM"
95log_must zfs destroy "$DATASET#$TESTBM"
96
97# Verify we can create a bookmark specifying the bookmark name
98log_must zfs bookmark "$DATASET@$TESTSNAP" "#$TESTBM"
99log_must eval "bkmarkexists $DATASET#$TESTBM"
100log_must zfs destroy "$DATASET#$TESTBM"
101
102# Verify at least a full dataset path is required and both snapshot and
103# bookmark name must be valid
104log_mustnot zfs bookmark "@$TESTSNAP" "#$TESTBM"
105log_mustnot zfs bookmark "$TESTSNAP" "#$TESTBM"
106log_mustnot zfs bookmark "@$TESTSNAP" "$TESTBM"
107log_mustnot zfs bookmark "$TESTSNAP" "$TESTBM"
108log_mustnot zfs bookmark "$TESTSNAP" "$DATASET#$TESTBM"
109log_mustnot zfs bookmark "$DATASET" "$TESTBM"
110log_mustnot zfs bookmark "$DATASET@" "$TESTBM"
111log_mustnot zfs bookmark "$DATASET" "#$TESTBM"
112log_mustnot zfs bookmark "$DATASET@" "#$TESTBM"
113log_mustnot zfs bookmark "$DATASET@$TESTSNAP" "$TESTBM"
114log_mustnot zfs bookmark "@" "#$TESTBM"
115log_mustnot zfs bookmark "@" "#"
116log_mustnot zfs bookmark "@$TESTSNAP" "#"
117log_mustnot zfs bookmark "@$TESTSNAP" "$DATASET#"
118log_mustnot zfs bookmark "@$TESTSNAP" "$DATASET"
119log_mustnot zfs bookmark "$TESTSNAP" "$DATASET#"
120log_mustnot zfs bookmark "$TESTSNAP" "$DATASET"
121log_mustnot eval "bkmarkexists $DATASET#$TESTBM"
122
123# Verify that we can create a bookmarks on another origin filesystem
124log_must zfs clone "$DATASET@$TESTSNAP" "$DATASET_TWO"
125log_must zfs bookmark "$DATASET@$TESTSNAP" "$DATASET_TWO#$TESTBM"
126log_must eval "destroy_dataset $DATASET_TWO"
127
128# Verify that we can cannot create bookmarks on a non-origin filesystem
129log_must zfs create "$DATASET_TWO"
130log_mustnot_expect "source is not an ancestor of the new bookmark's dataset" zfs bookmark "$DATASET@$TESTSNAP" "$DATASET_TWO#$TESTBM"
131log_must zfs destroy "$DATASET_TWO"
132
133# Verify that we can create bookmarks of snapshots on the pool dataset
134log_must zfs snapshot "$TESTPOOL@$TESTSNAP"
135log_must zfs bookmark "$TESTPOOL@$TESTSNAP" "$TESTPOOL#$TESTBM"
136log_must zfs destroy "$TESTPOOL#$TESTBM"
137log_must zfs destroy "$TESTPOOL@$TESTSNAP"
138
139#
140# Bookmark copying tests
141#
142
143# create the source bookmark
144log_must zfs bookmark "$DATASET@$TESTSNAP" "$DATASET#$TESTBM"
145
146# Verify we can copy a bookmark by specifying the source bookmark
147# and new bookmark full paths.
148log_must eval "bkmarkexists $DATASET#$TESTBM"
149log_must zfs bookmark "$DATASET#$TESTBM" "$DATASET#$TESTBMCOPY"
150log_must eval "bkmarkexists $DATASET#$TESTBMCOPY"
151## validate destroy once (should be truly independent bookmarks)
152log_must zfs destroy "$DATASET#$TESTBM"
153log_mustnot eval "bkmarkexists $DATASET#$TESTBM"
154log_must eval "bkmarkexists $DATASET#$TESTBMCOPY"
155log_must zfs destroy "$DATASET#$TESTBMCOPY"
156log_mustnot eval "bkmarkexists $DATASET#$TESTBMCOPY"
157log_mustnot eval "bkmarkexists $DATASET#$TESTBM"
158## recreate the source bookmark
159log_must zfs bookmark "$DATASET@$TESTSNAP" "$DATASET#$TESTBM"
160
161# Verify we can copy a bookmark specifying the short source name
162log_must zfs bookmark "#$TESTBM" "$DATASET#$TESTBMCOPY"
163log_must eval "bkmarkexists $DATASET#$TESTBMCOPY"
164log_must zfs destroy "$DATASET#$TESTBMCOPY"
165
166# Verify we can copy a bookmark specifying the short bookmark name
167log_must zfs bookmark "$DATASET#$TESTBM" "#$TESTBMCOPY"
168log_must eval "bkmarkexists $DATASET#$TESTBMCOPY"
169log_must zfs destroy "$DATASET#$TESTBMCOPY"
170
171# Verify two short paths are not allowed, and test empty paths
172log_mustnot zfs bookmark "#$TESTBM" "#$TESTBMCOPY"
173log_mustnot zfs bookmark "#$TESTBM" "#"
174log_mustnot zfs bookmark "#"        "#$TESTBMCOPY"
175log_mustnot zfs bookmark "#"        "#"
176log_mustnot zfs bookmark "#"        ""
177log_mustnot zfs bookmark ""         "#"
178log_mustnot zfs bookmark ""         ""
179
180# Verify that we can copy bookmarks on another origin filesystem
181log_must zfs clone "$DATASET@$TESTSNAP" "$DATASET_TWO"
182log_must zfs bookmark "$DATASET#$TESTBM" "$DATASET_TWO#$TESTBMCOPY"
183log_must zfs destroy "$DATASET_TWO"
184
185# Verify that we can cannot create bookmarks on another non-origin filesystem
186log_must zfs create "$DATASET_TWO"
187log_mustnot_expect "source is not an ancestor of the new bookmark's dataset" zfs bookmark "$DATASET#$TESTBM" "$DATASET_TWO#$TESTBMCOPY"
188log_must zfs destroy "$DATASET_TWO"
189
190# Verify that we can copy bookmarks on the pool dataset
191log_must zfs snapshot "$TESTPOOL@$TESTSNAP"
192log_must zfs bookmark "$TESTPOOL@$TESTSNAP" "$TESTPOOL#$TESTBM"
193log_must zfs bookmark "$TESTPOOL#$TESTBM" "$TESTPOOL#$TESTBMCOPY"
194log_must zfs destroy "$TESTPOOL#$TESTBM"
195log_must zfs destroy "$TESTPOOL#$TESTBMCOPY"
196log_must zfs destroy "$TESTPOOL@$TESTSNAP"
197
198# Verify that copied 'normal' bookmarks are independent of the source bookmark
199log_must zfs bookmark "$DATASET#$TESTBM" "$DATASET#$TESTBMCOPY"
200log_must zfs destroy "$DATASET#$TESTBM"
201log_must eval "zfs send $DATASET@$TESTSNAP > $TEST_BASE_DIR/zfstest_datastream.$$"
202log_must eval "destroy_dataset $TESTPOOL/$TESTFS/recv"
203log_must eval "zfs recv -o mountpoint=none $TESTPOOL/$TESTFS/recv < $TEST_BASE_DIR/zfstest_datastream.$$"
204log_must zfs snapshot "$DATASET@$TESTSNAP2"
205log_must eval "zfs send -i \#$TESTBMCOPY $DATASET@$TESTSNAP2 > $TEST_BASE_DIR/zfstest_datastream.$$"
206log_must eval "zfs recv $TESTPOOL/$TESTFS/recv < $TEST_BASE_DIR/zfstest_datastream.$$"
207# cleanup
208log_must eval "destroy_dataset $DATASET@$TESTSNAP2"
209log_must zfs destroy "$DATASET#$TESTBMCOPY"
210log_must zfs bookmark "$DATASET@$TESTSNAP" "$DATASET#$TESTBM"
211
212# Verify that copied redaction bookmarks are independent of the source bookmark
213## create redaction bookmark
214log_must zfs destroy "$DATASET#$TESTBM"
215log_must zfs destroy "$DATASET@$TESTSNAP"
216log_must eval "echo secret > $TESTDIR/secret"
217log_must zfs snapshot "$DATASET@$TESTSNAP"
218log_must eval "echo redacted > $TESTDIR/secret"
219log_must zfs snapshot "$DATASET@$TESTSNAP2" # TESTSNAP2 is the redaction snapshot
220log_must zfs list -t all -o name,createtxg,guid,mountpoint,written
221log_must zfs redact "$DATASET@$TESTSNAP" "$TESTBM" "$DATASET@$TESTSNAP2"
222# ensure our primitive for testing whether a bookmark is a redaction bookmark works
223log_must eval "zfs get all $DATASET#$TESTBM | grep redact_snaps"
224## copy the redaction bookmark
225log_must zfs bookmark "$DATASET#$TESTBM" "#$TESTBMCOPY"
226log_mustnot eval "zfs get all $DATASET#$TESTBMCOPY | grep redact_snaps"
227log_must eval "zfs send --redact "$TESTBMCOPY" -i $DATASET@$TESTSNAP $DATASET@$TESTSNAP2 2>&1 | head -n 100 | grep 'not a redaction bookmark'"
228# try the above again after destroying the source bookmark, preventive measure for future work
229log_must zfs destroy "$DATASET#$TESTBM"
230log_mustnot eval "zfs get all $DATASET#$TESTBMCOPY | grep redact_snaps"
231log_must eval "zfs send --redact "$TESTBMCOPY" -i $DATASET@$TESTSNAP $DATASET@$TESTSNAP2 2>&1 | head -n 100 | grep 'not a redaction bookmark'"
232## cleanup
233log_must eval "destroy_dataset $DATASET@$TESTSNAP2"
234log_must zfs destroy "$DATASET#$TESTBMCOPY"
235log_must eval "destroy_dataset $DATASET@$TESTSNAP"
236log_must zfs snapshot "$DATASET@$TESTSNAP"
237log_must zfs bookmark "$DATASET@$TESTSNAP" "$DATASET#$TESTBM"
238
239log_pass "'zfs bookmark' works as expected"
240