man: zfs-send.8: fix -X synopses and description
Also clean up the horrendously verbose -X handling in zfs_main() Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz> Closes #13352
This commit is contained in:
parent
7eba3891e9
commit
6625262c70
|
@ -315,9 +315,9 @@ get_usage(zfs_help_t idx)
|
||||||
case HELP_ROLLBACK:
|
case HELP_ROLLBACK:
|
||||||
return (gettext("\trollback [-rRf] <snapshot>\n"));
|
return (gettext("\trollback [-rRf] <snapshot>\n"));
|
||||||
case HELP_SEND:
|
case HELP_SEND:
|
||||||
return (gettext("\tsend [-DnPpRvLecwhb] "
|
return (gettext("\tsend [-DLPbcehnpsvw] "
|
||||||
"[-X dataset[,dataset]...] "
|
"[-i|-I snapshot]\n"
|
||||||
"[-[i|I] snapshot] <snapshot>\n"
|
"\t [-R [-X dataset[,dataset]...]] <snapshot>\n"
|
||||||
"\tsend [-DnvPLecw] [-i snapshot|bookmark] "
|
"\tsend [-DnvPLecw] [-i snapshot|bookmark] "
|
||||||
"<filesystem|volume|snapshot>\n"
|
"<filesystem|volume|snapshot>\n"
|
||||||
"\tsend [-DnPpvLec] [-i bookmark|snapshot] "
|
"\tsend [-DnPpvLec] [-i bookmark|snapshot] "
|
||||||
|
@ -4315,74 +4315,28 @@ usage:
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Array of prefixes to exclude –
|
||||||
|
* a linear search, even if executed for each dataset,
|
||||||
|
* is plenty good enough.
|
||||||
|
*/
|
||||||
typedef struct zfs_send_exclude_arg {
|
typedef struct zfs_send_exclude_arg {
|
||||||
size_t count;
|
size_t count;
|
||||||
char **list;
|
const char **list;
|
||||||
} zfs_send_exclude_arg_t;
|
} zfs_send_exclude_arg_t;
|
||||||
|
|
||||||
/*
|
|
||||||
* This function creates the zfs_send_exclude_arg_t
|
|
||||||
* object described above; it can be called multiple
|
|
||||||
* times, and the input can be comma-separated.
|
|
||||||
* This is NOT the most efficient data layout; however,
|
|
||||||
* I couldn't think of a non-pathological case where
|
|
||||||
* it should have more than a couple dozen instances
|
|
||||||
* of excludes. If that turns out to be used in
|
|
||||||
* practice, we might want to instead use a tree.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
add_dataset_excludes(char *exclude, zfs_send_exclude_arg_t *context)
|
|
||||||
{
|
|
||||||
char *tok;
|
|
||||||
while ((tok = strsep(&exclude, ",")) != NULL) {
|
|
||||||
if (!zfs_name_valid(tok, ZFS_TYPE_DATASET) ||
|
|
||||||
strchr(tok, '/') == NULL) {
|
|
||||||
(void) fprintf(stderr, gettext("-X %s: "
|
|
||||||
"not a valid non-root dataset name.\n"), tok);
|
|
||||||
usage(B_FALSE);
|
|
||||||
}
|
|
||||||
context->list = safe_realloc(context->list,
|
|
||||||
(sizeof (char *)) * (context->count + 1));
|
|
||||||
context->list[context->count++] = tok;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
free_dataset_excludes(zfs_send_exclude_arg_t *exclude_list)
|
|
||||||
{
|
|
||||||
free(exclude_list->list);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is the call back used by zfs_send to
|
|
||||||
* determine if a dataset should be skipped.
|
|
||||||
* As stated above, this is not the most efficient
|
|
||||||
* data structure to use, but as long as the
|
|
||||||
* number of excluded datasets is relatively
|
|
||||||
* small (a couple of dozen or so), it won't
|
|
||||||
* have a big impact on performance on modern
|
|
||||||
* processors. Since it's excluding hierarchies,
|
|
||||||
* we'd probably want to move to a more complex
|
|
||||||
* tree structure in that case.
|
|
||||||
*/
|
|
||||||
static boolean_t
|
static boolean_t
|
||||||
zfs_do_send_exclude(zfs_handle_t *zhp, void *context)
|
zfs_do_send_exclude(zfs_handle_t *zhp, void *context)
|
||||||
{
|
{
|
||||||
zfs_send_exclude_arg_t *exclude = context;
|
zfs_send_exclude_arg_t *excludes = context;
|
||||||
const char *name = zfs_get_name(zhp);
|
const char *name = zfs_get_name(zhp);
|
||||||
|
|
||||||
for (size_t indx = 0; indx < exclude->count; indx++) {
|
for (size_t i = 0; i < excludes->count; ++i) {
|
||||||
char *exclude_name = exclude->list[indx];
|
size_t len = strlen(excludes->list[i]);
|
||||||
size_t len = strlen(exclude_name);
|
if (strncmp(name, excludes->list[i], len) == 0 &&
|
||||||
/* If it's shorter, it can't possibly match */
|
memchr("/@", name[len], sizeof ("/@")))
|
||||||
if (strlen(name) < len)
|
|
||||||
continue;
|
|
||||||
if (strncmp(name, exclude_name, len) == 0 &&
|
|
||||||
(name[len] == '/' || name[len] == '\0' ||
|
|
||||||
name[len] == '@')) {
|
|
||||||
return (B_FALSE);
|
return (B_FALSE);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return (B_TRUE);
|
return (B_TRUE);
|
||||||
}
|
}
|
||||||
|
@ -4402,7 +4356,7 @@ zfs_do_send(int argc, char **argv)
|
||||||
int c, err;
|
int c, err;
|
||||||
nvlist_t *dbgnv = NULL;
|
nvlist_t *dbgnv = NULL;
|
||||||
char *redactbook = NULL;
|
char *redactbook = NULL;
|
||||||
zfs_send_exclude_arg_t exclude_context = { 0 };
|
zfs_send_exclude_arg_t excludes = { 0 };
|
||||||
|
|
||||||
struct option long_options[] = {
|
struct option long_options[] = {
|
||||||
{"replicate", no_argument, NULL, 'R'},
|
{"replicate", no_argument, NULL, 'R'},
|
||||||
|
@ -4430,7 +4384,18 @@ zfs_do_send(int argc, char **argv)
|
||||||
long_options, NULL)) != -1) {
|
long_options, NULL)) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'X':
|
case 'X':
|
||||||
add_dataset_excludes(optarg, &exclude_context);
|
for (char *ds; (ds = strsep(&optarg, ",")) != NULL; ) {
|
||||||
|
if (!zfs_name_valid(ds, ZFS_TYPE_DATASET) ||
|
||||||
|
strchr(ds, '/') == NULL) {
|
||||||
|
(void) fprintf(stderr, gettext("-X %s: "
|
||||||
|
"not a valid non-root dataset name"
|
||||||
|
".\n"), ds);
|
||||||
|
usage(B_FALSE);
|
||||||
|
}
|
||||||
|
excludes.list = safe_realloc(excludes.list,
|
||||||
|
sizeof (char *) * (excludes.count + 1));
|
||||||
|
excludes.list[excludes.count++] = ds;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
if (fromname)
|
if (fromname)
|
||||||
|
@ -4541,7 +4506,7 @@ zfs_do_send(int argc, char **argv)
|
||||||
if (flags.parsable && flags.verbosity == 0)
|
if (flags.parsable && flags.verbosity == 0)
|
||||||
flags.verbosity = 1;
|
flags.verbosity = 1;
|
||||||
|
|
||||||
if (exclude_context.count > 0 && !flags.replicate) {
|
if (excludes.count > 0 && !flags.replicate) {
|
||||||
(void) fprintf(stderr, gettext("Cannot specify "
|
(void) fprintf(stderr, gettext("Cannot specify "
|
||||||
"dataset exclusion (-X) on a non-recursive "
|
"dataset exclusion (-X) on a non-recursive "
|
||||||
"send.\n"));
|
"send.\n"));
|
||||||
|
@ -4730,10 +4695,8 @@ zfs_do_send(int argc, char **argv)
|
||||||
flags.doall = B_TRUE;
|
flags.doall = B_TRUE;
|
||||||
|
|
||||||
err = zfs_send(zhp, fromname, toname, &flags, STDOUT_FILENO,
|
err = zfs_send(zhp, fromname, toname, &flags, STDOUT_FILENO,
|
||||||
exclude_context.count > 0 ? zfs_do_send_exclude : NULL,
|
excludes.count > 0 ? zfs_do_send_exclude : NULL,
|
||||||
&exclude_context, flags.verbosity >= 3 ? &dbgnv : NULL);
|
&excludes, flags.verbosity >= 3 ? &dbgnv : NULL);
|
||||||
|
|
||||||
free_dataset_excludes(&exclude_context);
|
|
||||||
|
|
||||||
if (flags.verbosity >= 3 && dbgnv != NULL) {
|
if (flags.verbosity >= 3 && dbgnv != NULL) {
|
||||||
/*
|
/*
|
||||||
|
@ -4745,8 +4708,9 @@ zfs_do_send(int argc, char **argv)
|
||||||
dump_nvlist(dbgnv, 0);
|
dump_nvlist(dbgnv, 0);
|
||||||
nvlist_free(dbgnv);
|
nvlist_free(dbgnv);
|
||||||
}
|
}
|
||||||
zfs_close(zhp);
|
|
||||||
|
|
||||||
|
zfs_close(zhp);
|
||||||
|
free(excludes.list);
|
||||||
return (err != 0);
|
return (err != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,8 +39,8 @@
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm zfs
|
.Nm zfs
|
||||||
.Cm send
|
.Cm send
|
||||||
.Op Fl DLPRbcehnpsvw
|
.Op Fl DLPbcehnpsvw
|
||||||
.Op Fl X Ar dataset Ns Oo , Ns Ar dataset Oc Ns …
|
.Op Fl R Op Fl X Ar dataset Ns Oo , Ns Ar dataset Oc Ns …
|
||||||
.Op Oo Fl I Ns | Ns Fl i Oc Ar snapshot
|
.Op Oo Fl I Ns | Ns Fl i Oc Ar snapshot
|
||||||
.Ar snapshot
|
.Ar snapshot
|
||||||
.Nm zfs
|
.Nm zfs
|
||||||
|
@ -73,8 +73,8 @@
|
||||||
.It Xo
|
.It Xo
|
||||||
.Nm zfs
|
.Nm zfs
|
||||||
.Cm send
|
.Cm send
|
||||||
.Op Fl DLPRbcehnpvw
|
.Op Fl DLPbcehnpsvw
|
||||||
.Op Fl X Ar dataset Ns Oo , Ns Ar dataset Oc Ns …
|
.Op Fl R Op Fl X Ar dataset Ns Oo , Ns Ar dataset Oc Ns …
|
||||||
.Op Oo Fl I Ns | Ns Fl i Oc Ar snapshot
|
.Op Oo Fl I Ns | Ns Fl i Oc Ar snapshot
|
||||||
.Ar snapshot
|
.Ar snapshot
|
||||||
.Xc
|
.Xc
|
||||||
|
@ -143,22 +143,15 @@ flag is used to send encrypted datasets, then
|
||||||
.Fl w
|
.Fl w
|
||||||
must also be specified.
|
must also be specified.
|
||||||
.It Fl X , -exclude Ar dataset Ns Oo , Ns Ar dataset Oc Ns …
|
.It Fl X , -exclude Ar dataset Ns Oo , Ns Ar dataset Oc Ns …
|
||||||
When the
|
With
|
||||||
.Fl R
|
.Fl R ,
|
||||||
flag is given,
|
|
||||||
.Fl X
|
.Fl X
|
||||||
can be used to specify a list of datasets to be excluded from the
|
specifies a set of datasets (and, hence, their descendants),
|
||||||
data stream.
|
to be excluded from the send stream.
|
||||||
The
|
The root dataset may not be excluded.
|
||||||
.Fl X
|
.Fl X Ar a Fl X Ar b
|
||||||
option can be used multiple times, or the list of datasets can be
|
is equivalent to
|
||||||
specified as a comma-separated list, or both.
|
.Fl X Ar a , Ns Ar b .
|
||||||
.Ar dataset
|
|
||||||
must not be the pool's root dataset, and all descendant datasets of
|
|
||||||
.Ar dataset
|
|
||||||
will be excluded from the send stream.
|
|
||||||
Requires
|
|
||||||
.Fl R .
|
|
||||||
.It Fl e , -embed
|
.It Fl e , -embed
|
||||||
Generate a more compact stream by using
|
Generate a more compact stream by using
|
||||||
.Sy WRITE_EMBEDDED
|
.Sy WRITE_EMBEDDED
|
||||||
|
|
Loading…
Reference in New Issue