diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c index 902512f997cc..07c51f1c47f9 100644 --- a/lib/libzfs/libzfs_sendrecv.c +++ b/lib/libzfs/libzfs_sendrecv.c @@ -2783,8 +2783,6 @@ parse_overrides(libzfs_handle_t *hdl, nvlist_t *props, nvlist_t *poprops, goto error; } - /* TODO: check properties that cannot be received */ - /* second pass: process "-o" properties */ nvp = NULL; while ((nvp = nvlist_next_nvpair(nvl_voprops, nvp)) != NULL) { @@ -3836,6 +3834,50 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, return (err); } +/* + * Check properties we were asked to override (both -o|-x) + */ +static int +zfs_receive_checkprops(libzfs_handle_t *hdl, nvlist_t *props, + const char *errbuf) +{ + nvpair_t *nvp; + int err = 0; + const char *name; + + nvp = NULL; + while ((nvp = nvlist_next_nvpair(props, nvp)) != NULL && err == 0) { + zfs_prop_t prop; + name = nvpair_name(nvp); + + prop = zfs_name_to_prop(name); + if (prop == ZPROP_INVAL) + continue; + /* + * "origin" is readonly but is used to receive datasets as + * clones so we don't raise an error here + */ + if (prop == ZFS_PROP_ORIGIN) + continue; + + // cannot override readonly properties + if (zfs_prop_readonly(prop) == B_TRUE) { + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "cannot override received property '%s'"), name); + err = 1; + } + // also cannot override specific settable properties + if (prop == ZFS_PROP_VERSION || + prop == ZFS_PROP_VOLSIZE) { + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "cannot override received property '%s'"), name); + err = 1; + } + } + + return (err); +} + static int zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap, const char *originsnap, recvflags_t *flags, int infd, const char *sendfs, @@ -3853,6 +3895,11 @@ zfs_receive_impl(libzfs_handle_t *hdl, const char *tosnap, (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN, "cannot receive")); + /* check properties that cannot be received */ + if (zfs_receive_checkprops(hdl, override_props, errbuf) != 0) { + return (zfs_error(hdl, EZFS_BADPROP, errbuf)); + } + if (flags->isprefix && !zfs_dataset_exists(hdl, tosnap, ZFS_TYPE_DATASET)) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "specified fs " diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_014_pos.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_014_pos.ksh index 8287cfa8c432..f44442627bde 100755 --- a/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_014_pos.ksh +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_014_pos.ksh @@ -148,6 +148,8 @@ log_mustnot eval "$ZFS recv $dest -x atime=off < $streamfile_full" log_mustnot eval "$ZFS recv $dest -o atime=off -x atime < $streamfile_full" log_mustnot eval "$ZFS recv $dest -o atime=off -o atime=on < $streamfile_full" log_mustnot eval "$ZFS recv $dest -x atime -x atime < $streamfile_full" +log_mustnot eval "$ZFS recv $dest -o version=1 < $streamfile_full" +log_mustnot eval "$ZFS recv $dest -x normalization < $streamfile_full" # 5.2 Verify -o property=value works on streams without properties. log_must eval "$ZFS recv -o compression=on -o '$userprop:dest1'='$userval' "\