diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index 44440dc3d..9d48b2b32 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -327,15 +327,15 @@ get_usage(zfs_help_t idx) case HELP_ROLLBACK: return (gettext("\trollback [-rRf] \n")); case HELP_SEND: - return (gettext("\tsend [-DLPbcehnpsvw] " + return (gettext("\tsend [-DLPbcehnpsVvw] " "[-i|-I snapshot]\n" "\t [-R [-X dataset[,dataset]...]] \n" - "\tsend [-DnvPLecw] [-i snapshot|bookmark] " + "\tsend [-DnVvPLecw] [-i snapshot|bookmark] " "\n" - "\tsend [-DnPpvLec] [-i bookmark|snapshot] " + "\tsend [-DnPpVvLec] [-i bookmark|snapshot] " "--redact \n" - "\tsend [-nvPe] -t \n" - "\tsend [-Pnv] --saved filesystem\n")); + "\tsend [-nVvPe] -t \n" + "\tsend [-PnVv] --saved filesystem\n")); case HELP_SET: return (gettext("\tset ... " " ...\n")); @@ -4388,6 +4388,7 @@ zfs_do_send(int argc, char **argv) {"props", no_argument, NULL, 'p'}, {"parsable", no_argument, NULL, 'P'}, {"dedup", no_argument, NULL, 'D'}, + {"proctitle", no_argument, NULL, 'V'}, {"verbose", no_argument, NULL, 'v'}, {"dryrun", no_argument, NULL, 'n'}, {"large-block", no_argument, NULL, 'L'}, @@ -4403,7 +4404,7 @@ zfs_do_send(int argc, char **argv) }; /* check options */ - while ((c = getopt_long(argc, argv, ":i:I:RsDpvnPLeht:cwbd:SX:", + while ((c = getopt_long(argc, argv, ":i:I:RsDpVvnPLeht:cwbd:SX:", long_options, NULL)) != -1) { switch (c) { case 'X': @@ -4452,6 +4453,9 @@ zfs_do_send(int argc, char **argv) case 'P': flags.parsable = B_TRUE; break; + case 'V': + flags.progressastitle = B_TRUE; + break; case 'v': flags.verbosity++; flags.progress = B_TRUE; @@ -8668,6 +8672,7 @@ main(int argc, char **argv) int i = 0; const char *cmdname; char **newargv; + extern char **environ; (void) setlocale(LC_ALL, ""); (void) setlocale(LC_NUMERIC, "C"); @@ -8725,6 +8730,8 @@ main(int argc, char **argv) libzfs_print_on_error(g_zfs, B_TRUE); + zfs_setproctitle_init(argc, argv, environ); + /* * Many commands modify input strings for string parsing reasons. * We create a copy to protect the original argv. diff --git a/include/libzfs.h b/include/libzfs.h index e56374922..05b4dfe35 100644 --- a/include/libzfs.h +++ b/include/libzfs.h @@ -740,6 +740,9 @@ typedef struct sendflags { /* show progress (ie. -v) */ boolean_t progress; + /* show progress as process title (ie. -V) */ + boolean_t progressastitle; + /* large blocks (>128K) are permitted */ boolean_t largeblock; diff --git a/include/libzutil.h b/include/libzutil.h index e285183e0..4d4bddaad 100644 --- a/include/libzutil.h +++ b/include/libzutil.h @@ -182,6 +182,13 @@ _LIBZUTIL_H int printf_color(const char *color, const char *format, ...); _LIBZUTIL_H const char *zfs_basename(const char *path); _LIBZUTIL_H ssize_t zfs_dirnamelen(const char *path); +#ifdef __linux__ +_LIBZUTIL_H void zfs_setproctitle_init(int argc, char *argv[], char *envp[]); +_LIBZUTIL_H void zfs_setproctitle(const char *fmt, ...); +#else +#define zfs_setproctitle(fmt, ...) setproctitle(fmt, ##__VA_ARGS__) +#define zfs_setproctitle_init(x, y, z) ((void)0) +#endif /* * These functions are used by the ZFS libraries and cmd/zpool code, but are diff --git a/lib/libzfs/libzfs.abi b/lib/libzfs/libzfs.abi index e5115e973..004930e34 100644 --- a/lib/libzfs/libzfs.abi +++ b/lib/libzfs/libzfs.abi @@ -416,6 +416,8 @@ + + @@ -3834,6 +3836,11 @@ + + + + + @@ -4525,6 +4532,12 @@ + + + + + + diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c index c79c636e1..7aebd85f8 100644 --- a/lib/libzfs/libzfs_sendrecv.c +++ b/lib/libzfs/libzfs_sendrecv.c @@ -83,6 +83,8 @@ typedef struct progress_arg { boolean_t pa_parsable; boolean_t pa_estimate; int pa_verbosity; + boolean_t pa_astitle; + uint64_t pa_size; } progress_arg_t; static int @@ -733,6 +735,7 @@ typedef struct send_dump_data { boolean_t seenfrom, seento, replicate, doall, fromorigin; boolean_t dryrun, parsable, progress, embed_data, std_out; boolean_t large_block, compress, raw, holds; + boolean_t progressastitle; int outfd; boolean_t err; nvlist_t *fss; @@ -931,12 +934,13 @@ send_progress_thread(void *arg) zfs_handle_t *zhp = pa->pa_zhp; uint64_t bytes; uint64_t blocks; + uint64_t total = pa->pa_size / 100; char buf[16]; time_t t; struct tm tm; int err; - if (!pa->pa_parsable) { + if (!pa->pa_parsable && pa->pa_verbosity != 0) { (void) fprintf(stderr, "TIME %s %sSNAPSHOT %s\n", pa->pa_estimate ? "BYTES" : " SENT", @@ -959,6 +963,17 @@ send_progress_thread(void *arg) (void) time(&t); localtime_r(&t, &tm); + if (pa->pa_astitle) { + char buf_bytes[16]; + char buf_size[16]; + int pct; + zfs_nicenum(bytes, buf_bytes, sizeof (buf_bytes)); + zfs_nicenum(pa->pa_size, buf_size, sizeof (buf_size)); + pct = (total > 0) ? bytes / total : 100; + zfs_setproctitle("sending %s (%d%%: %s/%s)", + zhp->zfs_name, MIN(pct, 100), buf_bytes, buf_size); + } + if (pa->pa_verbosity >= 2 && pa->pa_parsable) { (void) fprintf(stderr, "%02d:%02d:%02d\t%llu\t%llu\t%s\n", @@ -975,7 +990,7 @@ send_progress_thread(void *arg) (void) fprintf(stderr, "%02d:%02d:%02d\t%llu\t%s\n", tm.tm_hour, tm.tm_min, tm.tm_sec, (u_longlong_t)bytes, zhp->zfs_name); - } else { + } else if (pa->pa_verbosity != 0) { zfs_nicebytes(bytes, buf, sizeof (buf)); (void) fprintf(stderr, "%02d:%02d:%02d %5s %s\n", tm.tm_hour, tm.tm_min, tm.tm_sec, @@ -1183,12 +1198,14 @@ dump_snapshot(zfs_handle_t *zhp, void *arg) * If progress reporting is requested, spawn a new thread to * poll ZFS_IOC_SEND_PROGRESS at a regular interval. */ - if (sdd->progress) { + if (sdd->progress || sdd->progressastitle) { pa.pa_zhp = zhp; pa.pa_fd = sdd->outfd; pa.pa_parsable = sdd->parsable; pa.pa_estimate = B_FALSE; pa.pa_verbosity = sdd->verbosity; + pa.pa_size = sdd->size; + pa.pa_astitle = sdd->progressastitle; if ((err = pthread_create(&tid, NULL, send_progress_thread, &pa)) != 0) { @@ -1200,7 +1217,7 @@ dump_snapshot(zfs_handle_t *zhp, void *arg) err = dump_ioctl(zhp, sdd->prevsnap, sdd->prevsnap_obj, fromorigin, sdd->outfd, flags, sdd->debugnv); - if (sdd->progress && + if ((sdd->progress || sdd->progressastitle) && send_progress_thread_exit(zhp->zfs_hdl, tid)) return (-1); } @@ -1536,7 +1553,7 @@ lzc_flags_from_sendflags(const sendflags_t *flags) static int estimate_size(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags, uint64_t resumeobj, uint64_t resumeoff, uint64_t bytes, - const char *redactbook, char *errbuf) + const char *redactbook, char *errbuf, uint64_t *sizep) { uint64_t size; FILE *fout = flags->dryrun ? stdout : stderr; @@ -1544,7 +1561,7 @@ estimate_size(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags, int err = 0; pthread_t ptid; - if (flags->progress) { + if (flags->progress || flags->progressastitle) { pa.pa_zhp = zhp; pa.pa_fd = fd; pa.pa_parsable = flags->parsable; @@ -1563,10 +1580,15 @@ estimate_size(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags, err = lzc_send_space_resume_redacted(zhp->zfs_name, from, lzc_flags_from_sendflags(flags), resumeobj, resumeoff, bytes, redactbook, fd, &size); + *sizep = size; - if (flags->progress && send_progress_thread_exit(zhp->zfs_hdl, ptid)) + if ((flags->progress || flags->progressastitle) && + send_progress_thread_exit(zhp->zfs_hdl, ptid)) return (-1); + if (!flags->progress && !flags->parsable) + return (err); + if (err != 0) { zfs_error_aux(zhp->zfs_hdl, "%s", strerror(err)); return (zfs_error(zhp->zfs_hdl, EZFS_BADBACKUP, @@ -1743,6 +1765,7 @@ zfs_send_resume_impl_cb_impl(libzfs_handle_t *hdl, sendflags_t *flags, uint64_t *redact_snap_guids = NULL; int num_redact_snaps = 0; char *redact_book = NULL; + uint64_t size = 0; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot resume send")); @@ -1828,7 +1851,7 @@ zfs_send_resume_impl_cb_impl(libzfs_handle_t *hdl, sendflags_t *flags, enum lzc_send_flags lzc_flags = lzc_flags_from_sendflags(flags) | lzc_flags_from_resume_nvl(resume_nvl); - if (flags->verbosity != 0) { + if (flags->verbosity != 0 || flags->progressastitle) { /* * Some of these may have come from the resume token, set them * here for size estimate purposes. @@ -1845,7 +1868,7 @@ zfs_send_resume_impl_cb_impl(libzfs_handle_t *hdl, sendflags_t *flags, if (lzc_flags & LZC_SEND_FLAG_SAVED) tmpflags.saved = B_TRUE; error = estimate_size(zhp, fromname, outfd, &tmpflags, - resumeobj, resumeoff, bytes, redact_book, errbuf); + resumeobj, resumeoff, bytes, redact_book, errbuf, &size); } if (!flags->dryrun) { @@ -1855,12 +1878,14 @@ zfs_send_resume_impl_cb_impl(libzfs_handle_t *hdl, sendflags_t *flags, * If progress reporting is requested, spawn a new thread to * poll ZFS_IOC_SEND_PROGRESS at a regular interval. */ - if (flags->progress) { + if (flags->progress || flags->progressastitle) { pa.pa_zhp = zhp; pa.pa_fd = outfd; pa.pa_parsable = flags->parsable; pa.pa_estimate = B_FALSE; pa.pa_verbosity = flags->verbosity; + pa.pa_size = size; + pa.pa_astitle = flags->progressastitle; error = pthread_create(&tid, NULL, send_progress_thread, &pa); @@ -1877,8 +1902,11 @@ zfs_send_resume_impl_cb_impl(libzfs_handle_t *hdl, sendflags_t *flags, if (redact_book != NULL) free(redact_book); - if (flags->progress && send_progress_thread_exit(hdl, tid)) + if ((flags->progressastitle || flags->progress) && + send_progress_thread_exit(hdl, tid)) { + zfs_close(zhp); return (-1); + } char errbuf[ERRBUFLEN]; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, @@ -2313,6 +2341,7 @@ zfs_send_cb_impl(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap, sdd.verbosity = flags->verbosity; sdd.parsable = flags->parsable; sdd.progress = flags->progress; + sdd.progressastitle = flags->progressastitle; sdd.dryrun = flags->dryrun; sdd.large_block = flags->largeblock; sdd.embed_data = flags->embed_data; @@ -2562,6 +2591,7 @@ zfs_send_one_cb_impl(zfs_handle_t *zhp, const char *from, int fd, char *name = zhp->zfs_name; pthread_t ptid; progress_arg_t pa = { 0 }; + uint64_t size = 0; char errbuf[ERRBUFLEN]; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, @@ -2644,9 +2674,9 @@ zfs_send_one_cb_impl(zfs_handle_t *zhp, const char *from, int fd, /* * Perform size estimate if verbose was specified. */ - if (flags->verbosity != 0) { + if (flags->verbosity != 0 || flags->progressastitle) { err = estimate_size(zhp, from, fd, flags, 0, 0, 0, redactbook, - errbuf); + errbuf, &size); if (err != 0) return (err); } @@ -2658,12 +2688,14 @@ zfs_send_one_cb_impl(zfs_handle_t *zhp, const char *from, int fd, * If progress reporting is requested, spawn a new thread to poll * ZFS_IOC_SEND_PROGRESS at a regular interval. */ - if (flags->progress) { + if (flags->progress || flags->progressastitle) { pa.pa_zhp = zhp; pa.pa_fd = fd; pa.pa_parsable = flags->parsable; pa.pa_estimate = B_FALSE; pa.pa_verbosity = flags->verbosity; + pa.pa_size = size; + pa.pa_astitle = flags->progressastitle; err = pthread_create(&ptid, NULL, send_progress_thread, &pa); @@ -2677,7 +2709,8 @@ zfs_send_one_cb_impl(zfs_handle_t *zhp, const char *from, int fd, err = lzc_send_redacted(name, from, fd, lzc_flags_from_sendflags(flags), redactbook); - if (flags->progress && send_progress_thread_exit(hdl, ptid)) + if ((flags->progress || flags->progressastitle) && + send_progress_thread_exit(hdl, ptid)) return (-1); if (err == 0 && (flags->props || flags->holds || flags->backup)) { diff --git a/lib/libzutil/Makefile.am b/lib/libzutil/Makefile.am index ecdf94050..519906235 100644 --- a/lib/libzutil/Makefile.am +++ b/lib/libzutil/Makefile.am @@ -17,6 +17,7 @@ libzutil_la_SOURCES = \ if BUILD_LINUX libzutil_la_SOURCES += \ + %D%/os/linux/zutil_setproctitle.c \ %D%/os/linux/zutil_device_path_os.c \ %D%/os/linux/zutil_import_os.c endif diff --git a/lib/libzutil/os/linux/zutil_setproctitle.c b/lib/libzutil/os/linux/zutil_setproctitle.c new file mode 100644 index 000000000..4a6d12cf7 --- /dev/null +++ b/lib/libzutil/os/linux/zutil_setproctitle.c @@ -0,0 +1,299 @@ +/* + * Copyright © 2013 Guillem Jover + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct { + /* Original value. */ + const char *arg0; + + /* Title space available. */ + char *base, *end; + + /* Pointer to original nul character within base. */ + char *nul; + + boolean_t warned; + boolean_t reset; + int error; +} SPT; + +#define LIBBSD_IS_PATHNAME_SEPARATOR(c) ((c) == '/') +#define SPT_MAXTITLE 255 + +extern const char *__progname; + +static const char * +getprogname(void) +{ + return (__progname); +} + +static void +setprogname(const char *progname) +{ + size_t i; + + for (i = strlen(progname); i > 0; i--) { + if (LIBBSD_IS_PATHNAME_SEPARATOR(progname[i - 1])) { + __progname = progname + i; + return; + } + } + __progname = progname; +} + + +static inline size_t +spt_min(size_t a, size_t b) +{ + return ((a < b) ? a : b); +} + +/* + * For discussion on the portability of the various methods, see + * https://lists.freebsd.org/pipermail/freebsd-stable/2008-June/043136.html + */ +static int +spt_clearenv(void) +{ + char **tmp; + + tmp = malloc(sizeof (*tmp)); + if (tmp == NULL) + return (errno); + + tmp[0] = NULL; + environ = tmp; + + return (0); +} + +static int +spt_copyenv(int envc, char *envp[]) +{ + char **envcopy; + char *eq; + int envsize; + int i, error; + + if (environ != envp) + return (0); + + /* + * Make a copy of the old environ array of pointers, in case + * clearenv() or setenv() is implemented to free the internal + * environ array, because we will need to access the old environ + * contents to make the new copy. + */ + envsize = (envc + 1) * sizeof (char *); + envcopy = malloc(envsize); + if (envcopy == NULL) + return (errno); + memcpy(envcopy, envp, envsize); + + error = spt_clearenv(); + if (error) { + environ = envp; + free(envcopy); + return (error); + } + + for (i = 0; envcopy[i]; i++) { + eq = strchr(envcopy[i], '='); + if (eq == NULL) + continue; + + *eq = '\0'; + if (setenv(envcopy[i], eq + 1, 1) < 0) + error = errno; + *eq = '='; + + if (error) { + environ = envp; + free(envcopy); + return (error); + } + } + + /* + * Dispose of the shallow copy, now that we've finished transfering + * the old environment. + */ + free(envcopy); + + return (0); +} + +static int +spt_copyargs(int argc, char *argv[]) +{ + char *tmp; + int i; + + for (i = 1; i < argc || (i >= argc && argv[i]); i++) { + if (argv[i] == NULL) + continue; + + tmp = strdup(argv[i]); + if (tmp == NULL) + return (errno); + + argv[i] = tmp; + } + + return (0); +} + +void +zfs_setproctitle_init(int argc, char *argv[], char *envp[]) +{ + char *base, *end, *nul, *tmp; + int i, envc, error; + + /* Try to make sure we got called with main() arguments. */ + if (argc < 0) + return; + + base = argv[0]; + if (base == NULL) + return; + + nul = base + strlen(base); + end = nul + 1; + + for (i = 0; i < argc || (i >= argc && argv[i]); i++) { + if (argv[i] == NULL || argv[i] != end) + continue; + + end = argv[i] + strlen(argv[i]) + 1; + } + + for (i = 0; envp[i]; i++) { + if (envp[i] != end) + continue; + + end = envp[i] + strlen(envp[i]) + 1; + } + envc = i; + + SPT.arg0 = strdup(argv[0]); + if (SPT.arg0 == NULL) { + SPT.error = errno; + return; + } + + tmp = strdup(getprogname()); + if (tmp == NULL) { + SPT.error = errno; + return; + } + setprogname(tmp); + + error = spt_copyenv(envc, envp); + if (error) { + SPT.error = error; + return; + } + + error = spt_copyargs(argc, argv); + if (error) { + SPT.error = error; + return; + } + + SPT.nul = nul; + SPT.base = base; + SPT.end = end; +} + +void +zfs_setproctitle(const char *fmt, ...) +{ + /* Use buffer in case argv[0] is passed. */ + char buf[SPT_MAXTITLE + 1]; + va_list ap; + char *nul; + int len; + if (SPT.base == NULL) { + if (!SPT.warned) { + warnx("setproctitle not initialized, please" + "call zfs_setproctitle_init()"); + SPT.warned = B_TRUE; + } + return; + } + + if (fmt) { + if (fmt[0] == '-') { + /* Skip program name prefix. */ + fmt++; + len = 0; + } else { + /* Print program name heading for grep. */ + snprintf(buf, sizeof (buf), "%s: ", getprogname()); + len = strlen(buf); + } + + va_start(ap, fmt); + len += vsnprintf(buf + len, sizeof (buf) - len, fmt, ap); + va_end(ap); + } else { + len = snprintf(buf, sizeof (buf), "%s", SPT.arg0); + } + + if (len <= 0) { + SPT.error = errno; + return; + } + + if (!SPT.reset) { + memset(SPT.base, 0, SPT.end - SPT.base); + SPT.reset = B_TRUE; + } else { + memset(SPT.base, 0, spt_min(sizeof (buf), SPT.end - SPT.base)); + } + + len = spt_min(len, spt_min(sizeof (buf), SPT.end - SPT.base) - 1); + memcpy(SPT.base, buf, len); + nul = SPT.base + len; + + if (nul < SPT.nul) { + *SPT.nul = '.'; + } else if (nul == SPT.nul && nul + 1 < SPT.end) { + *SPT.nul = ' '; + *++nul = '\0'; + } +} diff --git a/man/man8/zfs-send.8 b/man/man8/zfs-send.8 index 83f4e81da..8cc6ae6ad 100644 --- a/man/man8/zfs-send.8 +++ b/man/man8/zfs-send.8 @@ -29,7 +29,7 @@ .\" Copyright 2018 Nexenta Systems, Inc. .\" Copyright 2019 Joyent, Inc. .\" -.Dd March 16, 2022 +.Dd January 12, 2023 .Dt ZFS-SEND 8 .Os . @@ -39,29 +39,29 @@ .Sh SYNOPSIS .Nm zfs .Cm send -.Op Fl DLPbcehnpsvw +.Op Fl DLPVbcehnpsvw .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 .Ar snapshot .Nm zfs .Cm send -.Op Fl DLPcensvw +.Op Fl DLPVcensvw .Op Fl i Ar snapshot Ns | Ns Ar bookmark .Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot .Nm zfs .Cm send .Fl -redact Ar redaction_bookmark -.Op Fl DLPcenpv +.Op Fl DLPVcenpv .Op Fl i Ar snapshot Ns | Ns Ar bookmark .Ar snapshot .Nm zfs .Cm send -.Op Fl Penv +.Op Fl PVenv .Fl t .Ar receive_resume_token .Nm zfs .Cm send -.Op Fl Pnv +.Op Fl PVnv .Fl S Ar filesystem .Nm zfs .Cm redact @@ -73,7 +73,7 @@ .It Xo .Nm zfs .Cm send -.Op Fl DLPbcehnpsvw +.Op Fl DLPVbcehnpsvw .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 .Ar snapshot @@ -142,6 +142,8 @@ If the flag is used to send encrypted datasets, then .Fl w must also be specified. +.It Fl V , -proctitle +Set the process title to a per-second report of how much data has been sent. .It Fl X , -exclude Ar dataset Ns Oo , Ns Ar dataset Oc Ns … With .Fl R , @@ -302,7 +304,7 @@ You will be able to receive your streams on future versions of ZFS. .It Xo .Nm zfs .Cm send -.Op Fl DLPcenvw +.Op Fl DLPVcenvw .Op Fl i Ar snapshot Ns | Ns Ar bookmark .Ar filesystem Ns | Ns Ar volume Ns | Ns Ar snapshot .Xc @@ -436,7 +438,7 @@ This information includes a per-second report of how much data has been sent. .Nm zfs .Cm send .Fl -redact Ar redaction_bookmark -.Op Fl DLPcenpv +.Op Fl DLPVcenpv .Op Fl i Ar snapshot Ns | Ns Ar bookmark .Ar snapshot .Xc @@ -530,7 +532,7 @@ raw sends and redacted sends cannot be combined at this time. .It Xo .Nm zfs .Cm send -.Op Fl Penv +.Op Fl PVenv .Fl t .Ar receive_resume_token .Xc @@ -545,7 +547,7 @@ for more details. .It Xo .Nm zfs .Cm send -.Op Fl Pnv +.Op Fl PVnv .Op Fl i Ar snapshot Ns | Ns Ar bookmark .Fl S .Ar filesystem diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_006_pos.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_006_pos.ksh index c5dfb8939..d7ee161eb 100755 --- a/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_006_pos.ksh +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_send/zfs_send_006_pos.ksh @@ -119,33 +119,33 @@ full_size=$(zfs send $full_snapshot 2>&1 | wc -c) incremental_size=$(zfs send $incremental_snapshot 2>&1 | wc -c) incremental_send=$(zfs send -i $full_snapshot $incremental_snapshot 2>&1 | wc -c) -log_note "verify zfs send -nv" -options="-nv" +log_note "verify zfs send -nvV" +options="-nvV" refer_size=$(get_prop refer $full_snapshot) estimate_size=$(get_estimate_size $full_snapshot $options) log_must verify_size_estimates $options $full_size -log_note "verify zfs send -Pnv" -options="-Pnv" +log_note "verify zfs send -PnvV" +options="-PnvV" estimate_size=$(get_estimate_size $full_snapshot $options) log_must verify_size_estimates $options $full_size -log_note "verify zfs send -nv for multiple snapshot send" -options="-nv" +log_note "verify zfs send -nvV for multiple snapshot send" +options="-nvV" refer_size=$(get_prop refer $incremental_snapshot) estimate_size=$(get_estimate_size $incremental_snapshot $options) log_must verify_size_estimates $options $incremental_size -log_note "verify zfs send -vPn for multiple snapshot send" -options="-vPn" +log_note "verify zfs send -vVPn for multiple snapshot send" +options="-vVPn" estimate_size=$(get_estimate_size $incremental_snapshot $options) log_must verify_size_estimates $options $incremental_size -log_note "verify zfs send -inv for incremental send" -options="-nvi" +log_note "verify zfs send -invV for incremental send" +options="-nvVi" refer_size=$(get_prop refer $incremental_snapshot) deduct_size=$(get_prop refer $full_snapshot) refer_size=$(echo "$refer_size - $deduct_size" | bc) @@ -155,8 +155,8 @@ log_must verify_size_estimates $options $incremental_send estimate_size=$(get_estimate_size $incremental_snapshot $options $full_bookmark) log_must verify_size_estimates $options $incremental_send -log_note "verify zfs send -ivPn for incremental send" -options="-vPni" +log_note "verify zfs send -ivVPn for incremental send" +options="-vVPni" estimate_size=$(get_estimate_size $incremental_snapshot $options $full_snapshot) log_must verify_size_estimates $options $incremental_send @@ -186,16 +186,16 @@ for ds in $datasets; do datasetexists $ds@snap64 || log_fail "Create $ds@snap64 snapshot fail." done recursive_size=$(zfs send -R $full_snapshot 2>&1 | wc -c) -log_note "verify zfs send -Rnv for recursive send" -options="-Rnv" +log_note "verify zfs send -RnvV for recursive send" +options="-RnvV" refer_size=$(get_prop refer $full_snapshot) refer_size=$(echo "$refer_size * 3" | bc) estimate_size=$(get_estimate_size $full_snapshot $options) log_must verify_size_estimates $options $recursive_size -log_note "verify zfs send -RvPn for recursive send" -options="-RvPn" +log_note "verify zfs send -RvVPn for recursive send" +options="-RvVPn" estimate_size=$(get_estimate_size $full_snapshot $options) log_must verify_size_estimates $options $recursive_size