32
32
33
33
#include <assert.h>
34
34
#include <ctype.h>
35
+ #include <sys/debug.h>
35
36
#include <errno.h>
36
37
#include <getopt.h>
37
38
#include <libgen.h>
@@ -116,6 +117,7 @@ static int zfs_do_load_key(int argc, char **argv);
116
117
static int zfs_do_unload_key (int argc , char * * argv );
117
118
static int zfs_do_change_key (int argc , char * * argv );
118
119
static int zfs_do_project (int argc , char * * argv );
120
+ static int zfs_do_redact (int argc , char * * argv );
119
121
120
122
/*
121
123
* Enable a reasonable set of defaults for libumem debugging on DEBUG builds.
@@ -170,6 +172,7 @@ typedef enum {
170
172
HELP_LOAD_KEY ,
171
173
HELP_UNLOAD_KEY ,
172
174
HELP_CHANGE_KEY ,
175
+ HELP_REDACT ,
173
176
} zfs_help_t ;
174
177
175
178
typedef struct zfs_command {
@@ -232,6 +235,7 @@ static zfs_command_t command_table[] = {
232
235
{ "load-key" , zfs_do_load_key , HELP_LOAD_KEY },
233
236
{ "unload-key" , zfs_do_unload_key , HELP_UNLOAD_KEY },
234
237
{ "change-key" , zfs_do_change_key , HELP_CHANGE_KEY },
238
+ { "redact" , zfs_do_redact , HELP_REDACT },
235
239
};
236
240
237
241
#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0]))
@@ -273,7 +277,7 @@ get_usage(zfs_help_t idx)
273
277
"[filesystem|volume|snapshot] ...\n" ));
274
278
case HELP_MOUNT :
275
279
return (gettext ("\tmount\n"
276
- "\tmount [-lvO ] [-o opts] <-a | filesystem>\n" ));
280
+ "\tmount [-flvO ] [-o opts] <-a | filesystem>\n" ));
277
281
case HELP_PROMOTE :
278
282
return (gettext ("\tpromote <clone-filesystem>\n" ));
279
283
case HELP_RECEIVE :
@@ -296,6 +300,9 @@ get_usage(zfs_help_t idx)
296
300
"<snapshot>\n"
297
301
"\tsend [-nvPLecw] [-i snapshot|bookmark] "
298
302
"<filesystem|volume|snapshot>\n"
303
+ "[-i bookmark] <snapshot> <bookmark_name>\n"
304
+ "\tsend [-DnPpvLecr] [-i bookmark|snapshot] "
305
+ "--redact <bookmark> <snapshot>\n"
299
306
"\tsend [-nvPe] -t <receive_resume_token>\n" ));
300
307
case HELP_SET :
301
308
return (gettext ("\tset <property=value> ... "
@@ -378,6 +385,9 @@ get_usage(zfs_help_t idx)
378
385
"\t [-o keylocation=<value>] [-o pbkfd2iters=<value>]\n"
379
386
"\t <filesystem|volume>\n"
380
387
"\tchange-key -i [-l] <filesystem|volume>\n" ));
388
+ case HELP_REDACT :
389
+ return (gettext ("\tredact <snapshot> <bookmark> "
390
+ "<redaction_snapshot> ..." ));
381
391
}
382
392
383
393
abort ();
@@ -535,6 +545,8 @@ usage(boolean_t requested)
535
545
(void ) fprintf (fp , "YES NO <size> | none\n" );
536
546
(void ) fprintf (fp , "\t%-15s " , "written@<snap>" );
537
547
(void ) fprintf (fp , " NO NO <size>\n" );
548
+ (void ) fprintf (fp , "\t%-15s " , "written#<bookmark>" );
549
+ (void ) fprintf (fp , " NO NO <size>\n" );
538
550
539
551
(void ) fprintf (fp , gettext ("\nSizes are specified in bytes "
540
552
"with standard units such as K, M, G, etc.\n" ));
@@ -1493,6 +1505,13 @@ zfs_do_destroy(int argc, char **argv)
1493
1505
return (-1 );
1494
1506
}
1495
1507
1508
+ /*
1509
+ * Unfortunately, zfs_bookmark() doesn't honor the
1510
+ * casesensitivity setting. However, we can't simply
1511
+ * remove this check, because lzc_destroy_bookmarks()
1512
+ * ignores non-existent bookmarks, so this is necessary
1513
+ * to get a proper error message.
1514
+ */
1496
1515
if (!zfs_bookmark_exists (argv [0 ])) {
1497
1516
(void ) fprintf (stderr , gettext ("bookmark '%s' "
1498
1517
"does not exist.\n" ), argv [0 ]);
@@ -3557,6 +3576,73 @@ zfs_do_promote(int argc, char **argv)
3557
3576
return (ret );
3558
3577
}
3559
3578
3579
+ static int
3580
+ zfs_do_redact (int argc , char * * argv )
3581
+ {
3582
+ char * snap = NULL ;
3583
+ char * bookname = NULL ;
3584
+ char * * rsnaps = NULL ;
3585
+ int numrsnaps = 0 ;
3586
+ argv ++ ;
3587
+ argc -- ;
3588
+ if (argc < 3 ) {
3589
+ (void ) fprintf (stderr , gettext ("too few arguments" ));
3590
+ usage (B_FALSE );
3591
+ }
3592
+
3593
+ snap = argv [0 ];
3594
+ bookname = argv [1 ];
3595
+ rsnaps = argv + 2 ;
3596
+ numrsnaps = argc - 2 ;
3597
+
3598
+ nvlist_t * rsnapnv = fnvlist_alloc ();
3599
+
3600
+ for (int i = 0 ; i < numrsnaps ; i ++ ) {
3601
+ fnvlist_add_boolean (rsnapnv , rsnaps [i ]);
3602
+ }
3603
+
3604
+ int err = lzc_redact (snap , bookname , rsnapnv );
3605
+ fnvlist_free (rsnapnv );
3606
+
3607
+ switch (err ) {
3608
+ case 0 :
3609
+ break ;
3610
+ case ENOENT :
3611
+ (void ) fprintf (stderr ,
3612
+ gettext ("provided snapshot %s does not exist" ), snap );
3613
+ break ;
3614
+ case EEXIST :
3615
+ (void ) fprintf (stderr , gettext ("specified redaction bookmark "
3616
+ "(%s) provided already exists" ), bookname );
3617
+ break ;
3618
+ case ENAMETOOLONG :
3619
+ (void ) fprintf (stderr , gettext ("provided bookmark name cannot "
3620
+ "be used, final name would be too long" ));
3621
+ break ;
3622
+ case E2BIG :
3623
+ (void ) fprintf (stderr , gettext ("too many redaction snapshots "
3624
+ "specified" ));
3625
+ break ;
3626
+ case EINVAL :
3627
+ (void ) fprintf (stderr , gettext ("redaction snapshot must be "
3628
+ "descendent of snapshot being redacted" ));
3629
+ break ;
3630
+ case EALREADY :
3631
+ (void ) fprintf (stderr , gettext ("attempted to redact redacted "
3632
+ "dataset or with respect to redacted dataset" ));
3633
+ break ;
3634
+ case ENOTSUP :
3635
+ (void ) fprintf (stderr , gettext ("redaction bookmarks feature "
3636
+ "not enabled" ));
3637
+ break ;
3638
+ default :
3639
+ (void ) fprintf (stderr , gettext ("internal error: %s" ),
3640
+ strerror (errno ));
3641
+ }
3642
+
3643
+ return (err );
3644
+ }
3645
+
3560
3646
/*
3561
3647
* zfs rollback [-rRf] <snapshot>
3562
3648
*
@@ -3941,6 +4027,9 @@ zfs_do_snapshot(int argc, char **argv)
3941
4027
return (-1 );
3942
4028
}
3943
4029
4030
+
4031
+ #define REDACT_OPT 1024
4032
+
3944
4033
/*
3945
4034
* Send a backup stream to stdout.
3946
4035
*/
@@ -3955,10 +4044,11 @@ zfs_do_send(int argc, char **argv)
3955
4044
sendflags_t flags = { 0 };
3956
4045
int c , err ;
3957
4046
nvlist_t * dbgnv = NULL ;
3958
- boolean_t extraverbose = B_FALSE ;
4047
+ char * redactbook = NULL ;
3959
4048
3960
4049
struct option long_options [] = {
3961
4050
{"replicate" , no_argument , NULL , 'R' },
4051
+ {"redact-bookmark" , required_argument , NULL , REDACT_OPT },
3962
4052
{"props" , no_argument , NULL , 'p' },
3963
4053
{"parsable" , no_argument , NULL , 'P' },
3964
4054
{"dedup" , no_argument , NULL , 'D' },
@@ -3991,6 +4081,9 @@ zfs_do_send(int argc, char **argv)
3991
4081
case 'R' :
3992
4082
flags .replicate = B_TRUE ;
3993
4083
break ;
4084
+ case REDACT_OPT :
4085
+ redactbook = optarg ;
4086
+ break ;
3994
4087
case 'p' :
3995
4088
flags .props = B_TRUE ;
3996
4089
break ;
@@ -3999,12 +4092,9 @@ zfs_do_send(int argc, char **argv)
3999
4092
break ;
4000
4093
case 'P' :
4001
4094
flags .parsable = B_TRUE ;
4002
- flags .verbose = B_TRUE ;
4003
4095
break ;
4004
4096
case 'v' :
4005
- if (flags .verbose )
4006
- extraverbose = B_TRUE ;
4007
- flags .verbose = B_TRUE ;
4097
+ flags .verbosity ++ ;
4008
4098
flags .progress = B_TRUE ;
4009
4099
break ;
4010
4100
case 'D' :
@@ -4072,19 +4162,21 @@ zfs_do_send(int argc, char **argv)
4072
4162
}
4073
4163
}
4074
4164
4165
+ if (flags .parsable && flags .verbosity == 0 )
4166
+ flags .verbosity = 1 ;
4167
+
4075
4168
argc -= optind ;
4076
4169
argv += optind ;
4077
4170
4078
4171
if (resume_token != NULL ) {
4079
4172
if (fromname != NULL || flags .replicate || flags .props ||
4080
- flags .backup || flags .dedup ) {
4173
+ flags .backup || flags .dedup || redactbook != NULL ) {
4081
4174
(void ) fprintf (stderr ,
4082
4175
gettext ("invalid flags combined with -t\n" ));
4083
4176
usage (B_FALSE );
4084
4177
}
4085
- if (argc != 0 ) {
4086
- (void ) fprintf (stderr , gettext ("no additional "
4087
- "arguments are permitted with -t\n" ));
4178
+ if (argc > 0 ) {
4179
+ (void ) fprintf (stderr , gettext ("too many arguments\n" ));
4088
4180
usage (B_FALSE );
4089
4181
}
4090
4182
} else {
@@ -4112,43 +4204,70 @@ zfs_do_send(int argc, char **argv)
4112
4204
}
4113
4205
4114
4206
/*
4115
- * Special case sending a filesystem, or from a bookmark .
4207
+ * For everything except -R and -I, use the new, cleaner code path .
4116
4208
*/
4117
- if (strchr (argv [0 ], '@' ) == NULL ||
4118
- (fromname && strchr (fromname , '#' ) != NULL )) {
4209
+ if (!(flags .replicate || flags .doall )) {
4119
4210
char frombuf [ZFS_MAX_DATASET_NAME_LEN ];
4120
4211
4121
- if (flags .replicate || flags .doall || flags .props ||
4122
- flags .backup || flags .dedup ||
4123
- (strchr (argv [0 ], '@' ) == NULL &&
4124
- (flags .dryrun || flags .verbose || flags .progress ))) {
4125
- (void ) fprintf (stderr , gettext ("Error: "
4126
- "Unsupported flag with filesystem or bookmark.\n" ));
4127
- return (1 );
4212
+ if (redactbook != NULL ) {
4213
+ if (strchr (argv [0 ], '@' ) == NULL ) {
4214
+ (void ) fprintf (stderr , gettext ("Error: Cannot "
4215
+ "do a redacted send to a filesystem.\n" ));
4216
+ return (1 );
4217
+ }
4128
4218
}
4129
4219
4130
4220
zhp = zfs_open (g_zfs , argv [0 ], ZFS_TYPE_DATASET );
4131
4221
if (zhp == NULL )
4132
4222
return (1 );
4133
4223
4224
+ if (fromname != NULL && (strchr (fromname , '#' ) == NULL &&
4225
+ strchr (fromname , '@' ) == NULL )) {
4226
+ /*
4227
+ * Neither bookmark or snapshot was specified. Print a
4228
+ * warning, and assume snapshot.
4229
+ */
4230
+ (void ) fprintf (stderr , "Warning: incremental source "
4231
+ "didn't specify type, assuming snapshot. Use '@' "
4232
+ "or '#' prefix to avoid ambiguity.\n" );
4233
+ (void ) snprintf (frombuf , sizeof (frombuf ), "@%s" ,
4234
+ fromname );
4235
+ fromname = frombuf ;
4236
+ }
4134
4237
if (fromname != NULL &&
4135
4238
(fromname [0 ] == '#' || fromname [0 ] == '@' )) {
4136
4239
/*
4137
4240
* Incremental source name begins with # or @.
4138
4241
* Default to same fs as target.
4139
4242
*/
4243
+ char tmpbuf [ZFS_MAX_DATASET_NAME_LEN ];
4244
+ (void ) strlcpy (tmpbuf , fromname , sizeof (tmpbuf ));
4140
4245
(void ) strlcpy (frombuf , argv [0 ], sizeof (frombuf ));
4141
4246
cp = strchr (frombuf , '@' );
4142
4247
if (cp != NULL )
4143
4248
* cp = '\0' ;
4144
- (void ) strlcat (frombuf , fromname , sizeof (frombuf ));
4249
+ (void ) strlcat (frombuf , tmpbuf , sizeof (frombuf ));
4145
4250
fromname = frombuf ;
4146
4251
}
4147
- err = zfs_send_one (zhp , fromname , STDOUT_FILENO , flags );
4252
+ err = zfs_send_one (zhp , fromname , STDOUT_FILENO , & flags ,
4253
+ redactbook );
4148
4254
zfs_close (zhp );
4149
4255
return (err != 0 );
4150
4256
}
4151
4257
4258
+ if (fromname != NULL && strchr (fromname , '#' )) {
4259
+ (void ) fprintf (stderr ,
4260
+ gettext ("Error: multiple snapshots cannot be "
4261
+ "sent from a bookmark.\n" ));
4262
+ return (1 );
4263
+ }
4264
+
4265
+ if (redactbook != NULL ) {
4266
+ (void ) fprintf (stderr , gettext ("Error: multiple snapshots "
4267
+ "cannot be sent redacted.\n" ));
4268
+ return (1 );
4269
+ }
4270
+
4152
4271
cp = strchr (argv [0 ], '@' );
4153
4272
* cp = '\0' ;
4154
4273
toname = cp + 1 ;
@@ -4192,9 +4311,9 @@ zfs_do_send(int argc, char **argv)
4192
4311
flags .doall = B_TRUE ;
4193
4312
4194
4313
err = zfs_send (zhp , fromname , toname , & flags , STDOUT_FILENO , NULL , 0 ,
4195
- extraverbose ? & dbgnv : NULL );
4314
+ flags . verbosity >= 3 ? & dbgnv : NULL );
4196
4315
4197
- if (extraverbose && dbgnv != NULL ) {
4316
+ if (flags . verbosity >= 3 && dbgnv != NULL ) {
4198
4317
/*
4199
4318
* dump_nvlist prints to stdout, but that's been
4200
4319
* redirected to a file. Make it print to stderr
@@ -6278,6 +6397,17 @@ share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol,
6278
6397
return (1 );
6279
6398
}
6280
6399
6400
+ if (zfs_prop_get_int (zhp , ZFS_PROP_REDACTED ) && !(flags & MS_FORCE )) {
6401
+ if (!explicit )
6402
+ return (0 );
6403
+
6404
+ (void ) fprintf (stderr , gettext ("cannot %s '%s': "
6405
+ "Dataset is not complete, was created by receiving "
6406
+ "a redacted zfs send stream.\n" ), cmdname ,
6407
+ zfs_get_name (zhp ));
6408
+ return (1 );
6409
+ }
6410
+
6281
6411
/*
6282
6412
* At this point, we have verified that the mountpoint and/or
6283
6413
* shareopts are appropriate for auto management. If the
@@ -6413,7 +6543,7 @@ share_mount(int op, int argc, char **argv)
6413
6543
int flags = 0 ;
6414
6544
6415
6545
/* check options */
6416
- while ((c = getopt (argc , argv , op == OP_MOUNT ? ":alvo:O " : "al" ))
6546
+ while ((c = getopt (argc , argv , op == OP_MOUNT ? ":alvo:Of " : "al" ))
6417
6547
!= -1 ) {
6418
6548
switch (c ) {
6419
6549
case 'a' :
@@ -6441,6 +6571,9 @@ share_mount(int op, int argc, char **argv)
6441
6571
case 'O' :
6442
6572
flags |= MS_OVERLAY ;
6443
6573
break ;
6574
+ case 'f' :
6575
+ flags |= MS_FORCE ;
6576
+ break ;
6444
6577
case ':' :
6445
6578
(void ) fprintf (stderr , gettext ("missing argument for "
6446
6579
"'%c' option\n" ), optopt );
0 commit comments