diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index 7191fbdf47..dabf0eb80b 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -315,14 +315,14 @@ get_usage(zfs_help_t idx) case HELP_ROLLBACK: return (gettext("\trollback [-rRf] \n")); case HELP_SEND: - return (gettext("\tsend [-DnPpRvLecwhb] [-[i|I] snapshot] " + return (gettext("\tsend [-DnPpRVvLecwhb] [-[i|I] snapshot] " "\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")); @@ -4437,6 +4437,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'}, @@ -4451,7 +4452,7 @@ zfs_do_send(int argc, char **argv) }; /* check options */ - while ((c = getopt_long(argc, argv, ":i:I:RsDpvnPLeht:cwbd:S", + while ((c = getopt_long(argc, argv, ":i:I:RsDpVvnPLeht:cwbd:S", long_options, NULL)) != -1) { switch (c) { case 'i': @@ -4486,6 +4487,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; @@ -8664,6 +8668,7 @@ main(int argc, char **argv) int i = 0; char *cmdname; char **newargv; + extern char **environ; (void) setlocale(LC_ALL, ""); (void) setlocale(LC_NUMERIC, "C"); @@ -8723,6 +8728,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 182f3f63e4..214a188f94 100644 --- a/include/libzfs.h +++ b/include/libzfs.h @@ -693,6 +693,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 36f8474e15..8e081fff60 100644 --- a/include/libzutil.h +++ b/include/libzutil.h @@ -167,6 +167,14 @@ void color_start(const char *color); void color_end(void); int printf_color(const char *color, char *format, ...); +#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 * not exported in the ABI. diff --git a/lib/libzfs/libzfs.abi b/lib/libzfs/libzfs.abi index 605826f70e..51c77ab34a 100644 --- a/lib/libzfs/libzfs.abi +++ b/lib/libzfs/libzfs.abi @@ -6104,7 +6104,7 @@ - + @@ -6136,24 +6136,27 @@ - + - + - + - + - + - + + + + @@ -6734,6 +6737,11 @@ + + + + + diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c index 6a53571e3a..439d20a7a3 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 @@ -712,6 +714,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; @@ -904,6 +907,7 @@ 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; @@ -922,7 +926,7 @@ send_progress_thread(void *arg) return ((void *)(uintptr_t)err); } - if (firstloop && !pa->pa_parsable) { + if (firstloop && !pa->pa_parsable && pa->pa_verbosity != 0) { (void) fprintf(stderr, "TIME %s %sSNAPSHOT %s\n", pa->pa_estimate ? "BYTES" : " SENT", @@ -934,6 +938,17 @@ send_progress_thread(void *arg) (void) time(&t); tm = localtime(&t); + 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", @@ -950,7 +965,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, @@ -1114,12 +1129,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) { @@ -1131,7 +1148,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) { void *status = NULL; (void) pthread_cancel(tid); (void) pthread_join(tid, &status); @@ -1462,7 +1479,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; @@ -1470,7 +1487,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; @@ -1489,8 +1506,9 @@ 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) { + if (flags->progress || flags->progressastitle) { void *status = NULL; (void) pthread_cancel(ptid); (void) pthread_join(ptid, &status); @@ -1505,6 +1523,9 @@ estimate_size(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags, } } + 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, @@ -1638,6 +1659,7 @@ zfs_send_resume_impl(libzfs_handle_t *hdl, sendflags_t *flags, int outfd, 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")); @@ -1731,7 +1753,7 @@ zfs_send_resume_impl(libzfs_handle_t *hdl, sendflags_t *flags, int outfd, } } - 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. @@ -1748,7 +1770,7 @@ zfs_send_resume_impl(libzfs_handle_t *hdl, sendflags_t *flags, int outfd, 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) { @@ -1758,12 +1780,14 @@ zfs_send_resume_impl(libzfs_handle_t *hdl, sendflags_t *flags, int outfd, * 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); @@ -1780,7 +1804,7 @@ zfs_send_resume_impl(libzfs_handle_t *hdl, sendflags_t *flags, int outfd, if (redact_book != NULL) free(redact_book); - if (flags->progress) { + if (flags->progress || flags->progress) { void *status = NULL; (void) pthread_cancel(tid); (void) pthread_join(tid, &status); @@ -1790,6 +1814,7 @@ zfs_send_resume_impl(libzfs_handle_t *hdl, sendflags_t *flags, int outfd, (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "progress thread exited nonzero")); + zfs_close(zhp); return (zfs_standard_error(hdl, error, errbuf)); } } @@ -2199,6 +2224,7 @@ zfs_send(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; @@ -2410,6 +2436,7 @@ zfs_send_one(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags, char *name = zhp->zfs_name; pthread_t ptid; progress_arg_t pa = { 0 }; + uint64_t size = 0; char errbuf[1024]; (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, @@ -2492,9 +2519,9 @@ zfs_send_one(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags, /* * 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); } @@ -2506,12 +2533,14 @@ zfs_send_one(zfs_handle_t *zhp, const char *from, int fd, 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 = 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); @@ -2525,7 +2554,7 @@ zfs_send_one(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags, err = lzc_send_redacted(name, from, fd, lzc_flags_from_sendflags(flags), redactbook); - if (flags->progress) { + if (flags->progress || flags->progressastitle) { void *status = NULL; (void) pthread_cancel(ptid); (void) pthread_join(ptid, &status); diff --git a/lib/libzfs_core/libzfs_core.abi b/lib/libzfs_core/libzfs_core.abi index c15cb3afbf..1b03a5c42e 100644 --- a/lib/libzfs_core/libzfs_core.abi +++ b/lib/libzfs_core/libzfs_core.abi @@ -272,6 +272,8 @@ + + @@ -3340,6 +3342,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/libzutil/Makefile.am b/lib/libzutil/Makefile.am index f55b7798f1..0ddc241d6d 100644 --- a/lib/libzutil/Makefile.am +++ b/lib/libzutil/Makefile.am @@ -18,6 +18,7 @@ USER_C = \ if BUILD_LINUX USER_C += \ + os/linux/zutil_setproctitle.c \ os/linux/zutil_device_path_os.c \ os/linux/zutil_import_os.c \ os/linux/zutil_compat.c diff --git a/lib/libzutil/os/linux/zutil_setproctitle.c b/lib/libzutil/os/linux/zutil_setproctitle.c new file mode 100644 index 0000000000..4a6d12cf70 --- /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 688bd03397..3280a1e361 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 April 15, 2021 +.Dd January 12, 2023 .Dt ZFS-SEND 8 .Os . @@ -39,28 +39,28 @@ .Sh SYNOPSIS .Nm zfs .Cm send -.Op Fl DLPRbcehnpsvw +.Op Fl DLPVRbcehnpsvw .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 @@ -72,7 +72,7 @@ .It Xo .Nm zfs .Cm send -.Op Fl DLPRbcehnpvw +.Op Fl DLPVRbcehnpvw .Op Oo Fl I Ns | Ns Fl i Oc Ar snapshot .Ar snapshot .Xc @@ -140,6 +140,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 e , -embed Generate a more compact stream by using .Sy WRITE_EMBEDDED @@ -285,7 +287,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 @@ -417,7 +419,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 @@ -511,7 +513,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 @@ -526,7 +528,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 42628a0512..3023ea47ee 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