4084 zfs_handle_t *szhp;
4085 char name[ZFS_MAXNAMELEN];
4086 int rv = 0;
4087
4088 (void) snprintf(name, sizeof (name),
4089 "%s@%s", zhp->zfs_name, ha->snapname);
4090
4091 szhp = make_dataset_handle(zhp->zfs_hdl, name);
4092 if (szhp) {
4093 fnvlist_add_string(ha->nvl, name, ha->tag);
4094 zfs_close(szhp);
4095 }
4096
4097 if (ha->recursive)
4098 rv = zfs_iter_filesystems(zhp, zfs_hold_one, ha);
4099 zfs_close(zhp);
4100 return (rv);
4101 }
4102
4103 int
4104 zfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag,
4105 boolean_t recursive, boolean_t enoent_ok, int cleanup_fd)
4106 {
4107 int ret;
4108 struct holdarg ha;
4109 nvlist_t *errors;
4110 libzfs_handle_t *hdl = zhp->zfs_hdl;
4111 char errbuf[1024];
4112 nvpair_t *elem;
4113
4114 ha.nvl = fnvlist_alloc();
4115 ha.snapname = snapname;
4116 ha.tag = tag;
4117 ha.recursive = recursive;
4118 (void) zfs_hold_one(zfs_handle_dup(zhp), &ha);
4119 ret = lzc_hold(ha.nvl, cleanup_fd, &errors);
4120 fnvlist_free(ha.nvl);
4121
4122 if (ret == 0)
4123 return (0);
4124
4125 if (nvlist_next_nvpair(errors, NULL) == NULL) {
4126 /* no hold-specific errors */
4127 (void) snprintf(errbuf, sizeof (errbuf),
4128 dgettext(TEXT_DOMAIN, "cannot hold"));
4129 switch (ret) {
4130 case ENOTSUP:
4131 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4132 "pool must be upgraded"));
4133 (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
4134 break;
4135 case EINVAL:
4136 (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
4137 break;
4138 default:
4139 (void) zfs_standard_error(hdl, ret, errbuf);
4140 }
4141 }
4159 case EINVAL:
4160 (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
4161 break;
4162 case EEXIST:
4163 (void) zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf);
4164 break;
4165 case ENOENT:
4166 if (enoent_ok)
4167 return (ENOENT);
4168 /* FALLTHROUGH */
4169 default:
4170 (void) zfs_standard_error(hdl,
4171 fnvpair_value_int32(elem), errbuf);
4172 }
4173 }
4174
4175 fnvlist_free(errors);
4176 return (ret);
4177 }
4178
4179 struct releasearg {
4180 nvlist_t *nvl;
4181 const char *snapname;
4182 const char *tag;
4183 boolean_t recursive;
4184 };
4185
4186 static int
4187 zfs_release_one(zfs_handle_t *zhp, void *arg)
4188 {
4189 struct holdarg *ha = arg;
4190 zfs_handle_t *szhp;
4191 char name[ZFS_MAXNAMELEN];
4192 int rv = 0;
4193
4194 (void) snprintf(name, sizeof (name),
4195 "%s@%s", zhp->zfs_name, ha->snapname);
4196
4197 szhp = make_dataset_handle(zhp->zfs_hdl, name);
4198 if (szhp) {
4199 nvlist_t *holds = fnvlist_alloc();
4200 fnvlist_add_boolean(holds, ha->tag);
4201 fnvlist_add_nvlist(ha->nvl, name, holds);
4202 zfs_close(szhp);
4203 }
4204
4205 if (ha->recursive)
4206 rv = zfs_iter_filesystems(zhp, zfs_release_one, ha);
4207 zfs_close(zhp);
4208 return (rv);
4209 }
4210
4211 int
4212 zfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag,
4213 boolean_t recursive)
4214 {
4215 int ret;
4216 struct holdarg ha;
4217 nvlist_t *errors;
4218 nvpair_t *elem;
4219 libzfs_handle_t *hdl = zhp->zfs_hdl;
4220
4221 ha.nvl = fnvlist_alloc();
|
4084 zfs_handle_t *szhp;
4085 char name[ZFS_MAXNAMELEN];
4086 int rv = 0;
4087
4088 (void) snprintf(name, sizeof (name),
4089 "%s@%s", zhp->zfs_name, ha->snapname);
4090
4091 szhp = make_dataset_handle(zhp->zfs_hdl, name);
4092 if (szhp) {
4093 fnvlist_add_string(ha->nvl, name, ha->tag);
4094 zfs_close(szhp);
4095 }
4096
4097 if (ha->recursive)
4098 rv = zfs_iter_filesystems(zhp, zfs_hold_one, ha);
4099 zfs_close(zhp);
4100 return (rv);
4101 }
4102
4103 int
4104 zfs_hold_add(zfs_handle_t *zhp, const char *snapname, const char *tag,
4105 boolean_t enoent_ok, nvlist_t *holds)
4106 {
4107 zfs_handle_t *szhp;
4108 char name[ZFS_MAXNAMELEN];
4109 char errbuf[1024];
4110 int ret;
4111
4112 (void) snprintf(name, sizeof (name),
4113 "%s@%s", zhp->zfs_name, snapname);
4114
4115 szhp = make_dataset_handle(zhp->zfs_hdl, name);
4116 if (szhp) {
4117 fnvlist_add_string(holds, name, tag);
4118 zfs_close(szhp);
4119 return (0);
4120 }
4121
4122 ret = ENOENT;
4123 if (enoent_ok)
4124 return (ret);
4125
4126 (void) snprintf(errbuf, sizeof (errbuf),
4127 dgettext(TEXT_DOMAIN, "cannot hold snapshot '%s@%s'"),
4128 zhp->zfs_name, snapname);
4129 (void) zfs_standard_error(zhp->zfs_hdl, ret, errbuf);
4130
4131 return (ret);
4132 }
4133
4134 int
4135 zfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag,
4136 boolean_t recursive, boolean_t enoent_ok, int cleanup_fd)
4137 {
4138 int ret;
4139 struct holdarg ha;
4140
4141 ha.nvl = fnvlist_alloc();
4142 ha.snapname = snapname;
4143 ha.tag = tag;
4144 ha.recursive = recursive;
4145 (void) zfs_hold_one(zfs_handle_dup(zhp), &ha);
4146 ret = zfs_hold_apply(zhp, enoent_ok, cleanup_fd, ha.nvl);
4147 fnvlist_free(ha.nvl);
4148
4149 return (ret);
4150 }
4151
4152 int
4153 zfs_hold_apply(zfs_handle_t *zhp, boolean_t enoent_ok, int cleanup_fd, nvlist_t *holds)
4154 {
4155 int ret;
4156 nvlist_t *errors;
4157 libzfs_handle_t *hdl = zhp->zfs_hdl;
4158 char errbuf[1024];
4159 nvpair_t *elem;
4160
4161 ret = lzc_hold(holds, cleanup_fd, &errors);
4162
4163 if (ret == 0)
4164 return (0);
4165
4166 if (nvlist_next_nvpair(errors, NULL) == NULL) {
4167 /* no hold-specific errors */
4168 (void) snprintf(errbuf, sizeof (errbuf),
4169 dgettext(TEXT_DOMAIN, "cannot hold"));
4170 switch (ret) {
4171 case ENOTSUP:
4172 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4173 "pool must be upgraded"));
4174 (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
4175 break;
4176 case EINVAL:
4177 (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
4178 break;
4179 default:
4180 (void) zfs_standard_error(hdl, ret, errbuf);
4181 }
4182 }
4200 case EINVAL:
4201 (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
4202 break;
4203 case EEXIST:
4204 (void) zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf);
4205 break;
4206 case ENOENT:
4207 if (enoent_ok)
4208 return (ENOENT);
4209 /* FALLTHROUGH */
4210 default:
4211 (void) zfs_standard_error(hdl,
4212 fnvpair_value_int32(elem), errbuf);
4213 }
4214 }
4215
4216 fnvlist_free(errors);
4217 return (ret);
4218 }
4219
4220 static int
4221 zfs_release_one(zfs_handle_t *zhp, void *arg)
4222 {
4223 struct holdarg *ha = arg;
4224 zfs_handle_t *szhp;
4225 char name[ZFS_MAXNAMELEN];
4226 int rv = 0;
4227
4228 (void) snprintf(name, sizeof (name),
4229 "%s@%s", zhp->zfs_name, ha->snapname);
4230
4231 szhp = make_dataset_handle(zhp->zfs_hdl, name);
4232 if (szhp) {
4233 nvlist_t *holds = fnvlist_alloc();
4234 fnvlist_add_boolean(holds, ha->tag);
4235 fnvlist_add_nvlist(ha->nvl, name, holds);
4236 fnvlist_free(holds);
4237 zfs_close(szhp);
4238 }
4239
4240 if (ha->recursive)
4241 rv = zfs_iter_filesystems(zhp, zfs_release_one, ha);
4242 zfs_close(zhp);
4243 return (rv);
4244 }
4245
4246 int
4247 zfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag,
4248 boolean_t recursive)
4249 {
4250 int ret;
4251 struct holdarg ha;
4252 nvlist_t *errors;
4253 nvpair_t *elem;
4254 libzfs_handle_t *hdl = zhp->zfs_hdl;
4255
4256 ha.nvl = fnvlist_alloc();
|