4064 return (ret);
4065 zua++;
4066 zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t);
4067 }
4068 }
4069
4070 return (0);
4071 }
4072
4073 struct holdarg {
4074 nvlist_t *nvl;
4075 const char *snapname;
4076 const char *tag;
4077 boolean_t recursive;
4078 };
4079
4080 static int
4081 zfs_hold_one(zfs_handle_t *zhp, void *arg)
4082 {
4083 struct holdarg *ha = arg;
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 }
4142
4143 for (elem = nvlist_next_nvpair(errors, NULL);
4145 elem = nvlist_next_nvpair(errors, elem)) {
4146 (void) snprintf(errbuf, sizeof (errbuf),
4147 dgettext(TEXT_DOMAIN,
4148 "cannot hold snapshot '%s'"), nvpair_name(elem));
4149 switch (fnvpair_value_int32(elem)) {
4150 case E2BIG:
4151 /*
4152 * Temporary tags wind up having the ds object id
4153 * prepended. So even if we passed the length check
4154 * above, it's still possible for the tag to wind
4155 * up being slightly too long.
4156 */
4157 (void) zfs_error(hdl, EZFS_TAGTOOLONG, errbuf);
4158 break;
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();
4222 ha.snapname = snapname;
4223 ha.tag = tag;
4224 ha.recursive = recursive;
4225 (void) zfs_release_one(zfs_handle_dup(zhp), &ha);
4226 ret = lzc_release(ha.nvl, &errors);
4227 fnvlist_free(ha.nvl);
4228
4229 if (ret == 0)
4230 return (0);
4231
4232 if (nvlist_next_nvpair(errors, NULL) == NULL) {
4233 /* no hold-specific errors */
4234 char errbuf[1024];
4235
4236 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
4237 "cannot release"));
4238 switch (errno) {
4239 case ENOTSUP:
4240 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4241 "pool must be upgraded"));
4242 (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
4243 break;
4244 default:
4245 (void) zfs_standard_error_fmt(hdl, errno, errbuf);
4246 }
4247 }
4248
4249 for (elem = nvlist_next_nvpair(errors, NULL);
4250 elem != NULL;
|
4064 return (ret);
4065 zua++;
4066 zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t);
4067 }
4068 }
4069
4070 return (0);
4071 }
4072
4073 struct holdarg {
4074 nvlist_t *nvl;
4075 const char *snapname;
4076 const char *tag;
4077 boolean_t recursive;
4078 };
4079
4080 static int
4081 zfs_hold_one(zfs_handle_t *zhp, void *arg)
4082 {
4083 struct holdarg *ha = arg;
4084 char name[ZFS_MAXNAMELEN];
4085 int rv = 0;
4086
4087 (void) snprintf(name, sizeof (name),
4088 "%s@%s", zhp->zfs_name, ha->snapname);
4089
4090 if (lzc_exists(name))
4091 fnvlist_add_string(ha->nvl, name, ha->tag);
4092
4093 if (ha->recursive)
4094 rv = zfs_iter_filesystems(zhp, zfs_hold_one, ha);
4095 zfs_close(zhp);
4096 return (rv);
4097 }
4098
4099 int
4100 zfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag,
4101 boolean_t recursive, int cleanup_fd)
4102 {
4103 int ret;
4104 struct holdarg ha;
4105
4106 ha.nvl = fnvlist_alloc();
4107 ha.snapname = snapname;
4108 ha.tag = tag;
4109 ha.recursive = recursive;
4110 (void) zfs_hold_one(zfs_handle_dup(zhp), &ha);
4111 ret = zfs_hold_nvl(zhp, cleanup_fd, ha.nvl);
4112 fnvlist_free(ha.nvl);
4113
4114 return (ret);
4115 }
4116
4117 int
4118 zfs_hold_nvl(zfs_handle_t *zhp, int cleanup_fd, nvlist_t *holds)
4119 {
4120 int ret;
4121 nvlist_t *errors;
4122 libzfs_handle_t *hdl = zhp->zfs_hdl;
4123 char errbuf[1024];
4124 nvpair_t *elem;
4125
4126 errors = NULL;
4127 ret = lzc_hold(holds, cleanup_fd, &errors);
4128
4129 if (ret == 0) {
4130 /* There may be errors even in the success case. */
4131 fnvlist_free(errors);
4132 return (0);
4133 }
4134
4135 if (nvlist_next_nvpair(errors, NULL) == NULL) {
4136 /* no hold-specific errors */
4137 (void) snprintf(errbuf, sizeof (errbuf),
4138 dgettext(TEXT_DOMAIN, "cannot hold"));
4139 switch (ret) {
4140 case ENOTSUP:
4141 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4142 "pool must be upgraded"));
4143 (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
4144 break;
4145 case EINVAL:
4146 (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
4147 break;
4148 default:
4149 (void) zfs_standard_error(hdl, ret, errbuf);
4150 }
4151 }
4152
4153 for (elem = nvlist_next_nvpair(errors, NULL);
4155 elem = nvlist_next_nvpair(errors, elem)) {
4156 (void) snprintf(errbuf, sizeof (errbuf),
4157 dgettext(TEXT_DOMAIN,
4158 "cannot hold snapshot '%s'"), nvpair_name(elem));
4159 switch (fnvpair_value_int32(elem)) {
4160 case E2BIG:
4161 /*
4162 * Temporary tags wind up having the ds object id
4163 * prepended. So even if we passed the length check
4164 * above, it's still possible for the tag to wind
4165 * up being slightly too long.
4166 */
4167 (void) zfs_error(hdl, EZFS_TAGTOOLONG, errbuf);
4168 break;
4169 case EINVAL:
4170 (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
4171 break;
4172 case EEXIST:
4173 (void) zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf);
4174 break;
4175 default:
4176 (void) zfs_standard_error(hdl,
4177 fnvpair_value_int32(elem), errbuf);
4178 }
4179 }
4180
4181 fnvlist_free(errors);
4182 return (ret);
4183 }
4184
4185 static int
4186 zfs_release_one(zfs_handle_t *zhp, void *arg)
4187 {
4188 struct holdarg *ha = arg;
4189 char name[ZFS_MAXNAMELEN];
4190 int rv = 0;
4191
4192 (void) snprintf(name, sizeof (name),
4193 "%s@%s", zhp->zfs_name, ha->snapname);
4194
4195 if (lzc_exists(name)) {
4196 nvlist_t *holds = fnvlist_alloc();
4197 fnvlist_add_boolean(holds, ha->tag);
4198 fnvlist_add_nvlist(ha->nvl, name, holds);
4199 fnvlist_free(holds);
4200 }
4201
4202 if (ha->recursive)
4203 rv = zfs_iter_filesystems(zhp, zfs_release_one, ha);
4204 zfs_close(zhp);
4205 return (rv);
4206 }
4207
4208 int
4209 zfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag,
4210 boolean_t recursive)
4211 {
4212 int ret;
4213 struct holdarg ha;
4214 nvlist_t *errors;
4215 nvpair_t *elem;
4216 libzfs_handle_t *hdl = zhp->zfs_hdl;
4217
4218 ha.nvl = fnvlist_alloc();
4219 ha.snapname = snapname;
4220 ha.tag = tag;
4221 ha.recursive = recursive;
4222 (void) zfs_release_one(zfs_handle_dup(zhp), &ha);
4223 errors = NULL;
4224 ret = lzc_release(ha.nvl, &errors);
4225 fnvlist_free(ha.nvl);
4226
4227 if (ret == 0) {
4228 /* There may be errors even in the success case. */
4229 fnvlist_free(errors);
4230 return (0);
4231 }
4232
4233 if (nvlist_next_nvpair(errors, NULL) == NULL) {
4234 /* no hold-specific errors */
4235 char errbuf[1024];
4236
4237 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
4238 "cannot release"));
4239 switch (errno) {
4240 case ENOTSUP:
4241 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4242 "pool must be upgraded"));
4243 (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
4244 break;
4245 default:
4246 (void) zfs_standard_error_fmt(hdl, errno, errbuf);
4247 }
4248 }
4249
4250 for (elem = nvlist_next_nvpair(errors, NULL);
4251 elem != NULL;
|