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 }
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;
|
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 ret = lzc_hold(holds, cleanup_fd, &errors);
4127
4128 if (ret == 0)
4129 return (0);
4130
4131 if (nvlist_next_nvpair(errors, NULL) == NULL) {
4132 /* no hold-specific errors */
4133 (void) snprintf(errbuf, sizeof (errbuf),
4134 dgettext(TEXT_DOMAIN, "cannot hold"));
4135 switch (ret) {
4136 case ENOTSUP:
4137 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4138 "pool must be upgraded"));
4139 (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
4140 break;
4141 case EINVAL:
4142 (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
4143 break;
4144 default:
4145 (void) zfs_standard_error(hdl, ret, errbuf);
4146 }
4147 }
4151 elem = nvlist_next_nvpair(errors, elem)) {
4152 (void) snprintf(errbuf, sizeof (errbuf),
4153 dgettext(TEXT_DOMAIN,
4154 "cannot hold snapshot '%s'"), nvpair_name(elem));
4155 switch (fnvpair_value_int32(elem)) {
4156 case E2BIG:
4157 /*
4158 * Temporary tags wind up having the ds object id
4159 * prepended. So even if we passed the length check
4160 * above, it's still possible for the tag to wind
4161 * up being slightly too long.
4162 */
4163 (void) zfs_error(hdl, EZFS_TAGTOOLONG, errbuf);
4164 break;
4165 case EINVAL:
4166 (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
4167 break;
4168 case EEXIST:
4169 (void) zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf);
4170 break;
4171 default:
4172 (void) zfs_standard_error(hdl,
4173 fnvpair_value_int32(elem), errbuf);
4174 }
4175 }
4176
4177 fnvlist_free(errors);
4178 return (ret);
4179 }
4180
4181 static int
4182 zfs_release_one(zfs_handle_t *zhp, void *arg)
4183 {
4184 struct holdarg *ha = arg;
4185 char name[ZFS_MAXNAMELEN];
4186 int rv = 0;
4187
4188 (void) snprintf(name, sizeof (name),
4189 "%s@%s", zhp->zfs_name, ha->snapname);
4190
4191 if (lzc_exists(name)) {
4192 nvlist_t *holds = fnvlist_alloc();
4193 fnvlist_add_boolean(holds, ha->tag);
4194 fnvlist_add_nvlist(ha->nvl, name, holds);
4195 fnvlist_free(holds);
4196 }
4197
4198 if (ha->recursive)
4199 rv = zfs_iter_filesystems(zhp, zfs_release_one, ha);
4200 zfs_close(zhp);
4201 return (rv);
4202 }
4203
4204 int
4205 zfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag,
4206 boolean_t recursive)
4207 {
4208 int ret;
4209 struct holdarg ha;
4210 nvlist_t *errors;
4211 nvpair_t *elem;
4212 libzfs_handle_t *hdl = zhp->zfs_hdl;
4213
4214 ha.nvl = fnvlist_alloc();
4215 ha.snapname = snapname;
|