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 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#
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
67log_assert "'zfs bookmark' should work only when passed valid arguments."
68log_onexit cleanup
69
70DATASET="$TESTPOOL/$TESTFS"
71DATASET_TWO="$TESTPOOL/${TESTFS}_two"
72TESTSNAP='snapshot'
73TESTSNAP2='snapshot2'
74TESTBM='bookmark'
75TESTBMCOPY='bookmark_copy'
76
77
78# Create initial snapshot
79log_must zfs snapshot "$DATASET@$TESTSNAP"
80
81#
82# Bookmark creation tests
83#
84
85# Verify we can create a bookmark specifying snapshot and bookmark full paths
86log_must zfs bookmark "$DATASET@$TESTSNAP" "$DATASET#$TESTBM"
87log_must eval "bkmarkexists $DATASET#$TESTBM"
88log_must zfs destroy "$DATASET#$TESTBM"
89
90# Verify we can create a bookmark specifying the snapshot name
91log_must zfs bookmark "@$TESTSNAP" "$DATASET#$TESTBM"
92log_must eval "bkmarkexists $DATASET#$TESTBM"
93log_must zfs destroy "$DATASET#$TESTBM"
94
95# Verify we can create a bookmark specifying the bookmark name
96log_must zfs bookmark "$DATASET@$TESTSNAP" "#$TESTBM"
97log_must eval "bkmarkexists $DATASET#$TESTBM"
98log_must zfs destroy "$DATASET#$TESTBM"
99
100# Verify at least a full dataset path is required and both snapshot and
101# bookmark name must be valid
102log_mustnot zfs bookmark "@$TESTSNAP" "#$TESTBM"
103log_mustnot zfs bookmark "$TESTSNAP" "#$TESTBM"
104log_mustnot zfs bookmark "@$TESTSNAP" "$TESTBM"
105log_mustnot zfs bookmark "$TESTSNAP" "$TESTBM"
106log_mustnot zfs bookmark "$TESTSNAP" "$DATASET#$TESTBM"
107log_mustnot zfs bookmark "$DATASET" "$TESTBM"
108log_mustnot zfs bookmark "$DATASET@" "$TESTBM"
109log_mustnot zfs bookmark "$DATASET" "#$TESTBM"
110log_mustnot zfs bookmark "$DATASET@" "#$TESTBM"
111log_mustnot zfs bookmark "$DATASET@$TESTSNAP" "$TESTBM"
112log_mustnot zfs bookmark "@" "#$TESTBM"
113log_mustnot zfs bookmark "@" "#"
114log_mustnot zfs bookmark "@$TESTSNAP" "#"
115log_mustnot zfs bookmark "@$TESTSNAP" "$DATASET#"
116log_mustnot zfs bookmark "@$TESTSNAP" "$DATASET"
117log_mustnot zfs bookmark "$TESTSNAP" "$DATASET#"
118log_mustnot zfs bookmark "$TESTSNAP" "$DATASET"
119log_mustnot eval "bkmarkexists $DATASET#$TESTBM"
120
121# Verify that we can create a bookmarks on another origin filesystem
122log_must zfs clone "$DATASET@$TESTSNAP" "$DATASET_TWO"
123log_must zfs bookmark "$DATASET@$TESTSNAP" "$DATASET_TWO#$TESTBM"
124log_must eval "destroy_dataset $DATASET_TWO"
125
126# Verify that we can cannot create bookmarks on a non-origin filesystem
127log_must zfs create "$DATASET_TWO"
128log_mustnot_expect "source is not an ancestor of the new bookmark's dataset" zfs bookmark "$DATASET@$TESTSNAP" "$DATASET_TWO#$TESTBM"
129log_must zfs destroy "$DATASET_TWO"
130
131# Verify that we can create bookmarks of snapshots on the pool dataset
132log_must zfs snapshot "$TESTPOOL@$TESTSNAP"
133log_must zfs bookmark "$TESTPOOL@$TESTSNAP" "$TESTPOOL#$TESTBM"
134log_must zfs destroy "$TESTPOOL#$TESTBM"
135log_must zfs destroy "$TESTPOOL@$TESTSNAP"
136
137#
138# Bookmark copying tests
139#
140
141# create the source bookmark
142log_must zfs bookmark "$DATASET@$TESTSNAP" "$DATASET#$TESTBM"
143
144# Verify we can copy a bookmark by specifying the source bookmark
145# and new bookmark full paths.
146log_must eval "bkmarkexists $DATASET#$TESTBM"
147log_must zfs bookmark "$DATASET#$TESTBM" "$DATASET#$TESTBMCOPY"
148log_must eval "bkmarkexists $DATASET#$TESTBMCOPY"
149## validate destroy once (should be truly independent bookmarks)
150log_must zfs destroy "$DATASET#$TESTBM"
151log_mustnot eval "bkmarkexists $DATASET#$TESTBM"
152log_must eval "bkmarkexists $DATASET#$TESTBMCOPY"
153log_must zfs destroy "$DATASET#$TESTBMCOPY"
154log_mustnot eval "bkmarkexists $DATASET#$TESTBMCOPY"
155log_mustnot eval "bkmarkexists $DATASET#$TESTBM"
156## recreate the source bookmark
157log_must zfs bookmark "$DATASET@$TESTSNAP" "$DATASET#$TESTBM"
158
159# Verify we can copy a bookmark specifying the short source name
160log_must zfs bookmark "#$TESTBM" "$DATASET#$TESTBMCOPY"
161log_must eval "bkmarkexists $DATASET#$TESTBMCOPY"
162log_must zfs destroy "$DATASET#$TESTBMCOPY"
163
164# Verify we can copy a bookmark specifying the short bookmark name
165log_must zfs bookmark "$DATASET#$TESTBM" "#$TESTBMCOPY"
166log_must eval "bkmarkexists $DATASET#$TESTBMCOPY"
167log_must zfs destroy "$DATASET#$TESTBMCOPY"
168
169# Verify two short paths are not allowed, and test empty paths
170log_mustnot zfs bookmark "#$TESTBM" "#$TESTBMCOPY"
171log_mustnot zfs bookmark "#$TESTBM" "#"
172log_mustnot zfs bookmark "#"        "#$TESTBMCOPY"
173log_mustnot zfs bookmark "#"        "#"
174log_mustnot zfs bookmark "#"        ""
175log_mustnot zfs bookmark ""         "#"
176log_mustnot zfs bookmark ""         ""
177
178# Verify that we can copy bookmarks on another origin filesystem
179log_must zfs clone "$DATASET@$TESTSNAP" "$DATASET_TWO"
180log_must zfs bookmark "$DATASET#$TESTBM" "$DATASET_TWO#$TESTBMCOPY"
181log_must zfs destroy "$DATASET_TWO"
182
183# Verify that we can cannot create bookmarks on another non-origin filesystem
184log_must zfs create "$DATASET_TWO"
185log_mustnot_expect "source is not an ancestor of the new bookmark's dataset" zfs bookmark "$DATASET#$TESTBM" "$DATASET_TWO#$TESTBMCOPY"
186log_must zfs destroy "$DATASET_TWO"
187
188# Verify that we can copy bookmarks on the pool dataset
189log_must zfs snapshot "$TESTPOOL@$TESTSNAP"
190log_must zfs bookmark "$TESTPOOL@$TESTSNAP" "$TESTPOOL#$TESTBM"
191log_must zfs bookmark "$TESTPOOL#$TESTBM" "$TESTPOOL#$TESTBMCOPY"
192log_must zfs destroy "$TESTPOOL#$TESTBM"
193log_must zfs destroy "$TESTPOOL#$TESTBMCOPY"
194log_must zfs destroy "$TESTPOOL@$TESTSNAP"
195
196# Verify that copied 'normal' bookmarks are independent of the source bookmark
197log_must zfs bookmark "$DATASET#$TESTBM" "$DATASET#$TESTBMCOPY"
198log_must zfs destroy "$DATASET#$TESTBM"
199log_must eval "zfs send $DATASET@$TESTSNAP > $TEST_BASE_DIR/zfstest_datastream.$$"
200log_must eval "destroy_dataset $TESTPOOL/$TESTFS/recv"
201log_must eval "zfs recv -o mountpoint=none $TESTPOOL/$TESTFS/recv < $TEST_BASE_DIR/zfstest_datastream.$$"
202log_must zfs snapshot "$DATASET@$TESTSNAP2"
203log_must eval "zfs send -i \#$TESTBMCOPY $DATASET@$TESTSNAP2 > $TEST_BASE_DIR/zfstest_datastream.$$"
204log_must eval "zfs recv $TESTPOOL/$TESTFS/recv < $TEST_BASE_DIR/zfstest_datastream.$$"
205# cleanup
206log_must eval "destroy_dataset $DATASET@$TESTSNAP2"
207log_must zfs destroy "$DATASET#$TESTBMCOPY"
208log_must zfs bookmark "$DATASET@$TESTSNAP" "$DATASET#$TESTBM"
209
210# Verify that copied redaction bookmarks are independent of the source bookmark
211## create redaction bookmark
212log_must zfs destroy "$DATASET#$TESTBM"
213log_must zfs destroy "$DATASET@$TESTSNAP"
214log_must eval "echo secret > $TESTDIR/secret"
215log_must zfs snapshot "$DATASET@$TESTSNAP"
216log_must eval "echo redacted > $TESTDIR/secret"
217log_must zfs snapshot "$DATASET@$TESTSNAP2" # TESTSNAP2 is the redaction snapshot
218log_must zfs list -t all -o name,createtxg,guid,mountpoint,written
219log_must zfs redact "$DATASET@$TESTSNAP" "$TESTBM" "$DATASET@$TESTSNAP2"
220# ensure our primitive for testing whether a bookmark is a redaction bookmark works
221log_must eval "zfs get all $DATASET#$TESTBM | grep redact_snaps"
222## copy the redaction bookmark
223log_must zfs bookmark "$DATASET#$TESTBM" "#$TESTBMCOPY"
224log_mustnot eval "zfs get all $DATASET#$TESTBMCOPY | grep redact_snaps"
225log_must eval "zfs send --redact "$TESTBMCOPY" -i $DATASET@$TESTSNAP $DATASET@$TESTSNAP2 2>&1 | head -n 100 | grep 'not a redaction bookmark'"
226# try the above again after destroying the source bookmark, preventive measure for future work
227log_must zfs destroy "$DATASET#$TESTBM"
228log_mustnot eval "zfs get all $DATASET#$TESTBMCOPY | grep redact_snaps"
229log_must eval "zfs send --redact "$TESTBMCOPY" -i $DATASET@$TESTSNAP $DATASET@$TESTSNAP2 2>&1 | head -n 100 | grep 'not a redaction bookmark'"
230## cleanup
231log_must eval "destroy_dataset $DATASET@$TESTSNAP2"
232log_must zfs destroy "$DATASET#$TESTBMCOPY"
233log_must eval "destroy_dataset $DATASET@$TESTSNAP"
234log_must zfs snapshot "$DATASET@$TESTSNAP"
235log_must zfs bookmark "$DATASET@$TESTSNAP" "$DATASET#$TESTBM"
236
237log_pass "'zfs bookmark' works as expected"
238