33
33
34
34
#include <assert.h>
35
35
#include <ctype.h>
36
+ #include <sys/debug.h>
36
37
#include <errno.h>
37
38
#include <getopt.h>
38
39
#include <libgen.h>
@@ -119,6 +120,7 @@ static int zfs_do_unload_key(int argc, char **argv);
119
120
static int zfs_do_change_key (int argc , char * * argv );
120
121
static int zfs_do_project (int argc , char * * argv );
121
122
static int zfs_do_version (int argc , char * * argv );
123
+ static int zfs_do_redact (int argc , char * * argv );
122
124
123
125
/*
124
126
* Enable a reasonable set of defaults for libumem debugging on DEBUG builds.
@@ -173,7 +175,8 @@ typedef enum {
173
175
HELP_LOAD_KEY ,
174
176
HELP_UNLOAD_KEY ,
175
177
HELP_CHANGE_KEY ,
176
- HELP_VERSION
178
+ HELP_VERSION ,
179
+ HELP_REDACT ,
177
180
} zfs_help_t ;
178
181
179
182
typedef struct zfs_command {
@@ -238,6 +241,7 @@ static zfs_command_t command_table[] = {
238
241
{ "load-key" , zfs_do_load_key , HELP_LOAD_KEY },
239
242
{ "unload-key" , zfs_do_unload_key , HELP_UNLOAD_KEY },
240
243
{ "change-key" , zfs_do_change_key , HELP_CHANGE_KEY },
244
+ { "redact" , zfs_do_redact , HELP_REDACT },
241
245
};
242
246
243
247
#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0]))
@@ -279,7 +283,7 @@ get_usage(zfs_help_t idx)
279
283
"[filesystem|volume|snapshot] ...\n" ));
280
284
case HELP_MOUNT :
281
285
return (gettext ("\tmount\n"
282
- "\tmount [-lvO ] [-o opts] <-a | filesystem>\n" ));
286
+ "\tmount [-flvO ] [-o opts] <-a | filesystem>\n" ));
283
287
case HELP_PROMOTE :
284
288
return (gettext ("\tpromote <clone-filesystem>\n" ));
285
289
case HELP_RECEIVE :
@@ -302,6 +306,9 @@ get_usage(zfs_help_t idx)
302
306
"<snapshot>\n"
303
307
"\tsend [-nvPLecw] [-i snapshot|bookmark] "
304
308
"<filesystem|volume|snapshot>\n"
309
+ "[-i bookmark] <snapshot> <bookmark_name>\n"
310
+ "\tsend [-DnPpvLecr] [-i bookmark|snapshot] "
311
+ "--redact <bookmark> <snapshot>\n"
305
312
"\tsend [-nvPe] -t <receive_resume_token>\n" ));
306
313
case HELP_SET :
307
314
return (gettext ("\tset <property=value> ... "
@@ -386,6 +393,9 @@ get_usage(zfs_help_t idx)
386
393
"\tchange-key -i [-l] <filesystem|volume>\n" ));
387
394
case HELP_VERSION :
388
395
return (gettext ("\tversion\n" ));
396
+ case HELP_REDACT :
397
+ return (gettext ("\tredact <snapshot> <bookmark> "
398
+ "<redaction_snapshot> ..." ));
389
399
}
390
400
391
401
abort ();
@@ -543,6 +553,8 @@ usage(boolean_t requested)
543
553
(void ) fprintf (fp , "YES NO <size> | none\n" );
544
554
(void ) fprintf (fp , "\t%-15s " , "written@<snap>" );
545
555
(void ) fprintf (fp , " NO NO <size>\n" );
556
+ (void ) fprintf (fp , "\t%-15s " , "written#<bookmark>" );
557
+ (void ) fprintf (fp , " NO NO <size>\n" );
546
558
547
559
(void ) fprintf (fp , gettext ("\nSizes are specified in bytes "
548
560
"with standard units such as K, M, G, etc.\n" ));
@@ -1501,6 +1513,13 @@ zfs_do_destroy(int argc, char **argv)
1501
1513
return (-1 );
1502
1514
}
1503
1515
1516
+ /*
1517
+ * Unfortunately, zfs_bookmark() doesn't honor the
1518
+ * casesensitivity setting. However, we can't simply
1519
+ * remove this check, because lzc_destroy_bookmarks()
1520
+ * ignores non-existent bookmarks, so this is necessary
1521
+ * to get a proper error message.
1522
+ */
1504
1523
if (!zfs_bookmark_exists (argv [0 ])) {
1505
1524
(void ) fprintf (stderr , gettext ("bookmark '%s' "
1506
1525
"does not exist.\n" ), argv [0 ]);
@@ -3595,6 +3614,73 @@ zfs_do_promote(int argc, char **argv)
3595
3614
return (ret );
3596
3615
}
3597
3616
3617
+ static int
3618
+ zfs_do_redact (int argc , char * * argv )
3619
+ {
3620
+ char * snap = NULL ;
3621
+ char * bookname = NULL ;
3622
+ char * * rsnaps = NULL ;
3623
+ int numrsnaps = 0 ;
3624
+ argv ++ ;
3625
+ argc -- ;
3626
+ if (argc < 3 ) {
3627
+ (void ) fprintf (stderr , gettext ("too few arguments" ));
3628
+ usage (B_FALSE );
3629
+ }
3630
+
3631
+ snap = argv [0 ];
3632
+ bookname = argv [1 ];
3633
+ rsnaps = argv + 2 ;
3634
+ numrsnaps = argc - 2 ;
3635
+
3636
+ nvlist_t * rsnapnv = fnvlist_alloc ();
3637
+
3638
+ for (int i = 0 ; i < numrsnaps ; i ++ ) {
3639
+ fnvlist_add_boolean (rsnapnv , rsnaps [i ]);
3640
+ }
3641
+
3642
+ int err = lzc_redact (snap , bookname , rsnapnv );
3643
+ fnvlist_free (rsnapnv );
3644
+
3645
+ switch (err ) {
3646
+ case 0 :
3647
+ break ;
3648
+ case ENOENT :
3649
+ (void ) fprintf (stderr ,
3650
+ gettext ("provided snapshot %s does not exist" ), snap );
3651
+ break ;
3652
+ case EEXIST :
3653
+ (void ) fprintf (stderr , gettext ("specified redaction bookmark "
3654
+ "(%s) provided already exists" ), bookname );
3655
+ break ;
3656
+ case ENAMETOOLONG :
3657
+ (void ) fprintf (stderr , gettext ("provided bookmark name cannot "
3658
+ "be used, final name would be too long" ));
3659
+ break ;
3660
+ case E2BIG :
3661
+ (void ) fprintf (stderr , gettext ("too many redaction snapshots "
3662
+ "specified" ));
3663
+ break ;
3664
+ case EINVAL :
3665
+ (void ) fprintf (stderr , gettext ("redaction snapshot must be "
3666
+ "descendent of snapshot being redacted" ));
3667
+ break ;
3668
+ case EALREADY :
3669
+ (void ) fprintf (stderr , gettext ("attempted to redact redacted "
3670
+ "dataset or with respect to redacted dataset" ));
3671
+ break ;
3672
+ case ENOTSUP :
3673
+ (void ) fprintf (stderr , gettext ("redaction bookmarks feature "
3674
+ "not enabled" ));
3675
+ break ;
3676
+ default :
3677
+ (void ) fprintf (stderr , gettext ("internal error: %s" ),
3678
+ strerror (errno ));
3679
+ }
3680
+
3681
+ return (err );
3682
+ }
3683
+
3598
3684
/*
3599
3685
* zfs rollback [-rRf] <snapshot>
3600
3686
*
@@ -4006,6 +4092,7 @@ zfs_do_snapshot(int argc, char **argv)
4006
4092
return (-1 );
4007
4093
}
4008
4094
4095
+
4009
4096
/*
4010
4097
* Send a backup stream to stdout.
4011
4098
*/
@@ -4020,10 +4107,11 @@ zfs_do_send(int argc, char **argv)
4020
4107
sendflags_t flags = { 0 };
4021
4108
int c , err ;
4022
4109
nvlist_t * dbgnv = NULL ;
4023
- boolean_t extraverbose = B_FALSE ;
4110
+ char * redactbook = NULL ;
4024
4111
4025
4112
struct option long_options [] = {
4026
4113
{"replicate" , no_argument , NULL , 'R' },
4114
+ {"redact" , required_argument , NULL , 'd' },
4027
4115
{"props" , no_argument , NULL , 'p' },
4028
4116
{"parsable" , no_argument , NULL , 'P' },
4029
4117
{"dedup" , no_argument , NULL , 'D' },
@@ -4040,8 +4128,8 @@ zfs_do_send(int argc, char **argv)
4040
4128
};
4041
4129
4042
4130
/* check options */
4043
- while ((c = getopt_long (argc , argv , ":i:I:RDpvnPLeht:cwb" , long_options ,
4044
- NULL )) != -1 ) {
4131
+ while ((c = getopt_long (argc , argv , ":i:I:RDpvnPLeht:cwbd:" ,
4132
+ long_options , NULL )) != -1 ) {
4045
4133
switch (c ) {
4046
4134
case 'i' :
4047
4135
if (fromname )
@@ -4057,6 +4145,9 @@ zfs_do_send(int argc, char **argv)
4057
4145
case 'R' :
4058
4146
flags .replicate = B_TRUE ;
4059
4147
break ;
4148
+ case 'd' :
4149
+ redactbook = optarg ;
4150
+ break ;
4060
4151
case 'p' :
4061
4152
flags .props = B_TRUE ;
4062
4153
break ;
@@ -4068,12 +4159,9 @@ zfs_do_send(int argc, char **argv)
4068
4159
break ;
4069
4160
case 'P' :
4070
4161
flags .parsable = B_TRUE ;
4071
- flags .verbose = B_TRUE ;
4072
4162
break ;
4073
4163
case 'v' :
4074
- if (flags .verbose )
4075
- extraverbose = B_TRUE ;
4076
- flags .verbose = B_TRUE ;
4164
+ flags .verbosity ++ ;
4077
4165
flags .progress = B_TRUE ;
4078
4166
break ;
4079
4167
case 'D' :
@@ -4141,19 +4229,22 @@ zfs_do_send(int argc, char **argv)
4141
4229
}
4142
4230
}
4143
4231
4232
+ if (flags .parsable && flags .verbosity == 0 )
4233
+ flags .verbosity = 1 ;
4234
+
4144
4235
argc -= optind ;
4145
4236
argv += optind ;
4146
4237
4147
4238
if (resume_token != NULL ) {
4148
4239
if (fromname != NULL || flags .replicate || flags .props ||
4149
- flags .backup || flags .dedup ) {
4240
+ flags .backup || flags .dedup || flags .holds ||
4241
+ redactbook != NULL ) {
4150
4242
(void ) fprintf (stderr ,
4151
4243
gettext ("invalid flags combined with -t\n" ));
4152
4244
usage (B_FALSE );
4153
4245
}
4154
- if (argc != 0 ) {
4155
- (void ) fprintf (stderr , gettext ("no additional "
4156
- "arguments are permitted with -t\n" ));
4246
+ if (argc > 0 ) {
4247
+ (void ) fprintf (stderr , gettext ("too many arguments\n" ));
4157
4248
usage (B_FALSE );
4158
4249
}
4159
4250
} else {
@@ -4168,6 +4259,12 @@ zfs_do_send(int argc, char **argv)
4168
4259
}
4169
4260
}
4170
4261
4262
+ if (flags .raw && redactbook != NULL ) {
4263
+ (void ) fprintf (stderr ,
4264
+ gettext ("Error: raw sends may not be redacted.\n" ));
4265
+ return (1 );
4266
+ }
4267
+
4171
4268
if (!flags .dryrun && isatty (STDOUT_FILENO )) {
4172
4269
(void ) fprintf (stderr ,
4173
4270
gettext ("Error: Stream can not be written to a terminal.\n"
@@ -4181,43 +4278,70 @@ zfs_do_send(int argc, char **argv)
4181
4278
}
4182
4279
4183
4280
/*
4184
- * Special case sending a filesystem, or from a bookmark .
4281
+ * For everything except -R and -I, use the new, cleaner code path .
4185
4282
*/
4186
- if (strchr (argv [0 ], '@' ) == NULL ||
4187
- (fromname && strchr (fromname , '#' ) != NULL )) {
4283
+ if (!(flags .replicate || flags .doall )) {
4188
4284
char frombuf [ZFS_MAX_DATASET_NAME_LEN ];
4189
4285
4190
- if (flags .replicate || flags .doall || flags .props ||
4191
- flags .backup || flags .dedup || flags .holds ||
4192
- (strchr (argv [0 ], '@' ) == NULL &&
4193
- (flags .dryrun || flags .verbose || flags .progress ))) {
4194
- (void ) fprintf (stderr , gettext ("Error: "
4195
- "Unsupported flag with filesystem or bookmark.\n" ));
4196
- return (1 );
4286
+ if (redactbook != NULL ) {
4287
+ if (strchr (argv [0 ], '@' ) == NULL ) {
4288
+ (void ) fprintf (stderr , gettext ("Error: Cannot "
4289
+ "do a redacted send to a filesystem.\n" ));
4290
+ return (1 );
4291
+ }
4197
4292
}
4198
4293
4199
4294
zhp = zfs_open (g_zfs , argv [0 ], ZFS_TYPE_DATASET );
4200
4295
if (zhp == NULL )
4201
4296
return (1 );
4202
4297
4298
+ if (fromname != NULL && (strchr (fromname , '#' ) == NULL &&
4299
+ strchr (fromname , '@' ) == NULL )) {
4300
+ /*
4301
+ * Neither bookmark or snapshot was specified. Print a
4302
+ * warning, and assume snapshot.
4303
+ */
4304
+ (void ) fprintf (stderr , "Warning: incremental source "
4305
+ "didn't specify type, assuming snapshot. Use '@' "
4306
+ "or '#' prefix to avoid ambiguity.\n" );
4307
+ (void ) snprintf (frombuf , sizeof (frombuf ), "@%s" ,
4308
+ fromname );
4309
+ fromname = frombuf ;
4310
+ }
4203
4311
if (fromname != NULL &&
4204
4312
(fromname [0 ] == '#' || fromname [0 ] == '@' )) {
4205
4313
/*
4206
4314
* Incremental source name begins with # or @.
4207
4315
* Default to same fs as target.
4208
4316
*/
4317
+ char tmpbuf [ZFS_MAX_DATASET_NAME_LEN ];
4318
+ (void ) strlcpy (tmpbuf , fromname , sizeof (tmpbuf ));
4209
4319
(void ) strlcpy (frombuf , argv [0 ], sizeof (frombuf ));
4210
4320
cp = strchr (frombuf , '@' );
4211
4321
if (cp != NULL )
4212
4322
* cp = '\0' ;
4213
- (void ) strlcat (frombuf , fromname , sizeof (frombuf ));
4323
+ (void ) strlcat (frombuf , tmpbuf , sizeof (frombuf ));
4214
4324
fromname = frombuf ;
4215
4325
}
4216
- err = zfs_send_one (zhp , fromname , STDOUT_FILENO , flags );
4326
+ err = zfs_send_one (zhp , fromname , STDOUT_FILENO , & flags ,
4327
+ redactbook );
4217
4328
zfs_close (zhp );
4218
4329
return (err != 0 );
4219
4330
}
4220
4331
4332
+ if (fromname != NULL && strchr (fromname , '#' )) {
4333
+ (void ) fprintf (stderr ,
4334
+ gettext ("Error: multiple snapshots cannot be "
4335
+ "sent from a bookmark.\n" ));
4336
+ return (1 );
4337
+ }
4338
+
4339
+ if (redactbook != NULL ) {
4340
+ (void ) fprintf (stderr , gettext ("Error: multiple snapshots "
4341
+ "cannot be sent redacted.\n" ));
4342
+ return (1 );
4343
+ }
4344
+
4221
4345
cp = strchr (argv [0 ], '@' );
4222
4346
* cp = '\0' ;
4223
4347
toname = cp + 1 ;
@@ -4261,9 +4385,9 @@ zfs_do_send(int argc, char **argv)
4261
4385
flags .doall = B_TRUE ;
4262
4386
4263
4387
err = zfs_send (zhp , fromname , toname , & flags , STDOUT_FILENO , NULL , 0 ,
4264
- extraverbose ? & dbgnv : NULL );
4388
+ flags . verbosity >= 3 ? & dbgnv : NULL );
4265
4389
4266
- if (extraverbose && dbgnv != NULL ) {
4390
+ if (flags . verbosity >= 3 && dbgnv != NULL ) {
4267
4391
/*
4268
4392
* dump_nvlist prints to stdout, but that's been
4269
4393
* redirected to a file. Make it print to stderr
@@ -6379,6 +6503,17 @@ share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol,
6379
6503
return (1 );
6380
6504
}
6381
6505
6506
+ if (zfs_prop_get_int (zhp , ZFS_PROP_REDACTED ) && !(flags & MS_FORCE )) {
6507
+ if (!explicit )
6508
+ return (0 );
6509
+
6510
+ (void ) fprintf (stderr , gettext ("cannot %s '%s': "
6511
+ "Dataset is not complete, was created by receiving "
6512
+ "a redacted zfs send stream.\n" ), cmdname ,
6513
+ zfs_get_name (zhp ));
6514
+ return (1 );
6515
+ }
6516
+
6382
6517
/*
6383
6518
* At this point, we have verified that the mountpoint and/or
6384
6519
* shareopts are appropriate for auto management. If the
@@ -6537,7 +6672,7 @@ share_mount(int op, int argc, char **argv)
6537
6672
int flags = 0 ;
6538
6673
6539
6674
/* check options */
6540
- while ((c = getopt (argc , argv , op == OP_MOUNT ? ":alvo:O " : "al" ))
6675
+ while ((c = getopt (argc , argv , op == OP_MOUNT ? ":alvo:Of " : "al" ))
6541
6676
!= -1 ) {
6542
6677
switch (c ) {
6543
6678
case 'a' :
@@ -6565,6 +6700,9 @@ share_mount(int op, int argc, char **argv)
6565
6700
case 'O' :
6566
6701
flags |= MS_OVERLAY ;
6567
6702
break ;
6703
+ case 'f' :
6704
+ flags |= MS_FORCE ;
6705
+ break ;
6568
6706
case ':' :
6569
6707
(void ) fprintf (stderr , gettext ("missing argument for "
6570
6708
"'%c' option\n" ), optopt );
0 commit comments