Allow 'zfs holds -r' to recurse over a file system or volume to find holds

Previously, the parameters of 'zfs holds' could only be snapshots

Add -d <depth> flag to limit depth of recursion
Add -p flag to print literal values, rather than interpreted values
Add -H flag to suppress header output and use tabs rather than whitespace

Reviewed by:	mahrens, smh, dteske
Approved by:	bapt (mentor)
MFC after:	3 weeks
Relnotes:	yes
Sponsored by:	ScaleEngine Inc.
Differential Revision:	https://reviews.freebsd.org/D3994
This commit is contained in:
Allan Jude 2015-10-26 17:07:22 +00:00
parent 546df339f0
commit cd684494e5
2 changed files with 55 additions and 28 deletions

View File

@ -31,7 +31,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd September 14, 2015
.Dd October 24, 2015
.Dt ZFS 8
.Os
.Sh NAME
@ -272,8 +272,10 @@
.Ar tag snapshot Ns ...
.Nm
.Cm holds
.Op Fl r
.Ar snapshot Ns ...
.Op Fl Hp
.Op Fl r Ns | Ns Fl d Ar depth
.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot Ns
.Ns ...
.Nm
.Cm release
.Op Fl r
@ -3159,15 +3161,26 @@ snapshots of all descendent file systems.
.It Xo
.Nm
.Cm holds
.Op Fl r
.Ar snapshot Ns ...
.Op Fl Hp
.Op Fl r Ns | Ns Fl d Ar depth
.Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot Ns
.Ns ...
.Xc
.Pp
Lists all existing user references for the given snapshot or snapshots.
Lists all existing user references for the given dataset or datasets.
.Bl -tag -width indent
.It Fl H
Used for scripting mode. Do not print headers and separate fields by a single
tab instead of arbitrary white space.
.It Fl p
Display numbers in parsable (exact) values.
.It Fl r
Lists the holds that are set on the named descendent snapshots, in addition to
listing the holds on the named snapshot.
Lists the holds that are set on the descendent snapshots of the named datasets
or snapshots, in addition to listing the holds on the named snapshots, if any.
.It Fl d Ar depth
Recursively display any holds on the named snapshots, or descendent snapshots of
the named datasets or snapshots, limiting the recursion to
.Ar depth .
.El
.It Xo
.Nm

View File

@ -329,7 +329,8 @@ get_usage(zfs_help_t idx)
case HELP_HOLD:
return (gettext("\thold [-r] <tag> <snapshot> ...\n"));
case HELP_HOLDS:
return (gettext("\tholds [-r] <snapshot> ...\n"));
return (gettext("\tholds [-Hp] [-r|-d depth] "
"<filesystem|volume|snapshot> ...\n"));
case HELP_RELEASE:
return (gettext("\trelease [-r] <tag> <snapshot> ...\n"));
case HELP_DIFF:
@ -5543,7 +5544,8 @@ typedef struct holds_cbdata {
*
*/
static void
print_holds(boolean_t scripted, size_t nwidth, size_t tagwidth, nvlist_t *nvl)
print_holds(boolean_t scripted, boolean_t literal, size_t nwidth,
size_t tagwidth, nvlist_t *nvl)
{
int i;
nvpair_t *nvp = NULL;
@ -5576,10 +5578,14 @@ print_holds(boolean_t scripted, size_t nwidth, size_t tagwidth, nvlist_t *nvl)
size_t sepnum = scripted ? 1 : 2;
(void) nvpair_value_uint64(nvp2, &val);
time = (time_t)val;
(void) localtime_r(&time, &t);
(void) strftime(tsbuf, DATETIME_BUF_LEN,
gettext(STRFTIME_FMT_STR), &t);
if (literal)
snprintf(tsbuf, DATETIME_BUF_LEN, "%llu", val);
else {
time = (time_t)val;
(void) localtime_r(&time, &t);
(void) strftime(tsbuf, DATETIME_BUF_LEN,
gettext(STRFTIME_FMT_STR), &t);
}
(void) printf("%-*s%*c%-*s%*c%s\n", nwidth, zname,
sepnum, sep, tagwidth, tagname, sepnum, sep, tsbuf);
@ -5600,7 +5606,7 @@ holds_callback(zfs_handle_t *zhp, void *data)
const char *zname = zfs_get_name(zhp);
size_t znamelen = strnlen(zname, ZFS_MAXNAMELEN);
if (cbp->cb_recursive) {
if (cbp->cb_recursive && cbp->cb_snapname != NULL) {
const char *snapname;
char *delim = strchr(zname, '@');
if (delim == NULL)
@ -5628,9 +5634,12 @@ holds_callback(zfs_handle_t *zhp, void *data)
}
/*
* zfs holds [-r] <snap> ...
* zfs holds [-Hp] [-r | -d max] <dataset|snap> ...
*
* -r Recursively hold
* -H Suppress header output
* -p Output literal values
* -r Recursively search for holds
* -d max Limit depth of recursive search
*/
static int
zfs_do_holds(int argc, char **argv)
@ -5639,8 +5648,9 @@ zfs_do_holds(int argc, char **argv)
int c;
int i;
boolean_t scripted = B_FALSE;
boolean_t literal = B_FALSE;
boolean_t recursive = B_FALSE;
const char *opts = "rH";
const char *opts = "d:rHp";
nvlist_t *nvl;
int types = ZFS_TYPE_SNAPSHOT;
@ -5653,12 +5663,19 @@ zfs_do_holds(int argc, char **argv)
/* check options */
while ((c = getopt(argc, argv, opts)) != -1) {
switch (c) {
case 'd':
limit = parse_depth(optarg, &flags);
recursive = B_TRUE;
break;
case 'r':
recursive = B_TRUE;
break;
case 'H':
scripted = B_TRUE;
break;
case 'p':
literal = B_TRUE;
break;
case '?':
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
optopt);
@ -5684,18 +5701,14 @@ zfs_do_holds(int argc, char **argv)
for (i = 0; i < argc; ++i) {
char *snapshot = argv[i];
const char *delim;
const char *snapname;
const char *snapname = NULL;
delim = strchr(snapshot, '@');
if (delim == NULL) {
(void) fprintf(stderr,
gettext("'%s' is not a snapshot\n"), snapshot);
++errors;
continue;
if (delim != NULL) {
snapname = delim + 1;
if (recursive)
snapshot[delim - snapshot] = '\0';
}
snapname = delim + 1;
if (recursive)
snapshot[delim - snapshot] = '\0';
cb.cb_recursive = recursive;
cb.cb_snapname = snapname;
@ -5713,7 +5726,8 @@ zfs_do_holds(int argc, char **argv)
/*
* 2. print holds data
*/
print_holds(scripted, cb.cb_max_namelen, cb.cb_max_taglen, nvl);
print_holds(scripted, literal, cb.cb_max_namelen, cb.cb_max_taglen,
nvl);
if (nvlist_empty(nvl))
(void) printf(gettext("no datasets available\n"));