8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2012 by Delphix. All rights reserved.
25 * Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved.
26 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
27 * Copyright (c) 2013 Martin Matuska. All rights reserved.
28 */
29
30 #include <ctype.h>
31 #include <errno.h>
32 #include <libintl.h>
33 #include <math.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <strings.h>
37 #include <unistd.h>
38 #include <stddef.h>
39 #include <zone.h>
40 #include <fcntl.h>
41 #include <sys/mntent.h>
42 #include <sys/mount.h>
43 #include <priv.h>
44 #include <pwd.h>
45 #include <grp.h>
46 #include <stddef.h>
47 #include <ucred.h>
4065 return (ret);
4066 zua++;
4067 zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t);
4068 }
4069 }
4070
4071 return (0);
4072 }
4073
4074 struct holdarg {
4075 nvlist_t *nvl;
4076 const char *snapname;
4077 const char *tag;
4078 boolean_t recursive;
4079 };
4080
4081 static int
4082 zfs_hold_one(zfs_handle_t *zhp, void *arg)
4083 {
4084 struct holdarg *ha = arg;
4085 zfs_handle_t *szhp;
4086 char name[ZFS_MAXNAMELEN];
4087 int rv = 0;
4088
4089 (void) snprintf(name, sizeof (name),
4090 "%s@%s", zhp->zfs_name, ha->snapname);
4091
4092 szhp = make_dataset_handle(zhp->zfs_hdl, name);
4093 if (szhp) {
4094 fnvlist_add_string(ha->nvl, name, ha->tag);
4095 zfs_close(szhp);
4096 }
4097
4098 if (ha->recursive)
4099 rv = zfs_iter_filesystems(zhp, zfs_hold_one, ha);
4100 zfs_close(zhp);
4101 return (rv);
4102 }
4103
4104 int
4105 zfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag,
4106 boolean_t recursive, boolean_t enoent_ok, int cleanup_fd)
4107 {
4108 int ret;
4109 struct holdarg ha;
4110 nvlist_t *errors;
4111 libzfs_handle_t *hdl = zhp->zfs_hdl;
4112 char errbuf[1024];
4113 nvpair_t *elem;
4114
4115 ha.nvl = fnvlist_alloc();
4116 ha.snapname = snapname;
4117 ha.tag = tag;
4118 ha.recursive = recursive;
4119 (void) zfs_hold_one(zfs_handle_dup(zhp), &ha);
4120
4121 if (nvlist_next_nvpair(ha.nvl, NULL) == NULL) {
4122 fnvlist_free(ha.nvl);
4123 ret = ENOENT;
4124 if (!enoent_ok) {
4125 (void) snprintf(errbuf, sizeof (errbuf),
4126 dgettext(TEXT_DOMAIN,
4127 "cannot hold snapshot '%s@%s'"),
4128 zhp->zfs_name, snapname);
4129 (void) zfs_standard_error(hdl, ret, errbuf);
4130 }
4131 return (ret);
4132 }
4133
4134 ret = lzc_hold(ha.nvl, cleanup_fd, &errors);
4135 fnvlist_free(ha.nvl);
4136
4137 if (ret == 0)
4138 return (0);
4139
4140 if (nvlist_next_nvpair(errors, NULL) == NULL) {
4141 /* no hold-specific errors */
4142 (void) snprintf(errbuf, sizeof (errbuf),
4143 dgettext(TEXT_DOMAIN, "cannot hold"));
4144 switch (ret) {
4145 case ENOTSUP:
4146 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4147 "pool must be upgraded"));
4148 (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
4149 break;
4150 case EINVAL:
4151 (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
4152 break;
4153 default:
4154 (void) zfs_standard_error(hdl, ret, errbuf);
4155 }
4156 }
4157
4158 for (elem = nvlist_next_nvpair(errors, NULL);
4160 elem = nvlist_next_nvpair(errors, elem)) {
4161 (void) snprintf(errbuf, sizeof (errbuf),
4162 dgettext(TEXT_DOMAIN,
4163 "cannot hold snapshot '%s'"), nvpair_name(elem));
4164 switch (fnvpair_value_int32(elem)) {
4165 case E2BIG:
4166 /*
4167 * Temporary tags wind up having the ds object id
4168 * prepended. So even if we passed the length check
4169 * above, it's still possible for the tag to wind
4170 * up being slightly too long.
4171 */
4172 (void) zfs_error(hdl, EZFS_TAGTOOLONG, errbuf);
4173 break;
4174 case EINVAL:
4175 (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
4176 break;
4177 case EEXIST:
4178 (void) zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf);
4179 break;
4180 case ENOENT:
4181 if (enoent_ok)
4182 return (ENOENT);
4183 /* FALLTHROUGH */
4184 default:
4185 (void) zfs_standard_error(hdl,
4186 fnvpair_value_int32(elem), errbuf);
4187 }
4188 }
4189
4190 fnvlist_free(errors);
4191 return (ret);
4192 }
4193
4194 struct releasearg {
4195 nvlist_t *nvl;
4196 const char *snapname;
4197 const char *tag;
4198 boolean_t recursive;
4199 };
4200
4201 static int
4202 zfs_release_one(zfs_handle_t *zhp, void *arg)
4203 {
4204 struct holdarg *ha = arg;
4205 zfs_handle_t *szhp;
4206 char name[ZFS_MAXNAMELEN];
4207 int rv = 0;
4208
4209 (void) snprintf(name, sizeof (name),
4210 "%s@%s", zhp->zfs_name, ha->snapname);
4211
4212 szhp = make_dataset_handle(zhp->zfs_hdl, name);
4213 if (szhp) {
4214 nvlist_t *holds = fnvlist_alloc();
4215 fnvlist_add_boolean(holds, ha->tag);
4216 fnvlist_add_nvlist(ha->nvl, name, holds);
4217 zfs_close(szhp);
4218 }
4219
4220 if (ha->recursive)
4221 rv = zfs_iter_filesystems(zhp, zfs_release_one, ha);
4222 zfs_close(zhp);
4223 return (rv);
4224 }
4225
4226 int
4227 zfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag,
4228 boolean_t recursive)
4229 {
4230 int ret;
4231 struct holdarg ha;
4232 nvlist_t *errors;
4233 nvpair_t *elem;
4234 libzfs_handle_t *hdl = zhp->zfs_hdl;
4235 char errbuf[1024];
4236
4237 ha.nvl = fnvlist_alloc();
4238 ha.snapname = snapname;
4239 ha.tag = tag;
4240 ha.recursive = recursive;
4241 (void) zfs_release_one(zfs_handle_dup(zhp), &ha);
4242
4243 if (nvlist_next_nvpair(ha.nvl, NULL) == NULL) {
4244 fnvlist_free(ha.nvl);
4245 ret = ENOENT;
4246 (void) snprintf(errbuf, sizeof (errbuf),
4247 dgettext(TEXT_DOMAIN,
4248 "cannot release hold from snapshot '%s@%s'"),
4249 zhp->zfs_name, snapname);
4250 (void) zfs_standard_error(hdl, ret, errbuf);
4251 return (ret);
4252 }
4253
4254 ret = lzc_release(ha.nvl, &errors);
4255 fnvlist_free(ha.nvl);
4256
4257 if (ret == 0)
4258 return (0);
4259
4260 if (nvlist_next_nvpair(errors, NULL) == NULL) {
4261 /* no hold-specific errors */
4262 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
4263 "cannot release"));
4264 switch (errno) {
4265 case ENOTSUP:
4266 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4267 "pool must be upgraded"));
4268 (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
4269 break;
4270 default:
4271 (void) zfs_standard_error_fmt(hdl, errno, errbuf);
4272 }
4273 }
4274
4275 for (elem = nvlist_next_nvpair(errors, NULL);
4276 elem != NULL;
4277 elem = nvlist_next_nvpair(errors, elem)) {
4278 (void) snprintf(errbuf, sizeof (errbuf),
|
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2012 by Delphix. All rights reserved.
25 * Copyright (c) 2012 DEY Storage Systems, Inc. All rights reserved.
26 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
27 * Copyright (c) 2013 Martin Matuska. All rights reserved.
28 * Copyright (c) 2013 Steven Hartland. All rights reserved.
29 */
30
31 #include <ctype.h>
32 #include <errno.h>
33 #include <libintl.h>
34 #include <math.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <strings.h>
38 #include <unistd.h>
39 #include <stddef.h>
40 #include <zone.h>
41 #include <fcntl.h>
42 #include <sys/mntent.h>
43 #include <sys/mount.h>
44 #include <priv.h>
45 #include <pwd.h>
46 #include <grp.h>
47 #include <stddef.h>
48 #include <ucred.h>
4066 return (ret);
4067 zua++;
4068 zc.zc_nvlist_dst_size -= sizeof (zfs_useracct_t);
4069 }
4070 }
4071
4072 return (0);
4073 }
4074
4075 struct holdarg {
4076 nvlist_t *nvl;
4077 const char *snapname;
4078 const char *tag;
4079 boolean_t recursive;
4080 };
4081
4082 static int
4083 zfs_hold_one(zfs_handle_t *zhp, void *arg)
4084 {
4085 struct holdarg *ha = arg;
4086 char name[ZFS_MAXNAMELEN];
4087 int rv = 0;
4088
4089 (void) snprintf(name, sizeof (name),
4090 "%s@%s", zhp->zfs_name, ha->snapname);
4091
4092 if (lzc_exists(name))
4093 fnvlist_add_string(ha->nvl, name, ha->tag);
4094
4095 if (ha->recursive)
4096 rv = zfs_iter_filesystems(zhp, zfs_hold_one, ha);
4097 zfs_close(zhp);
4098 return (rv);
4099 }
4100
4101 int
4102 zfs_hold(zfs_handle_t *zhp, const char *snapname, const char *tag,
4103 boolean_t recursive, int cleanup_fd)
4104 {
4105 int ret;
4106 struct holdarg ha;
4107
4108 ha.nvl = fnvlist_alloc();
4109 ha.snapname = snapname;
4110 ha.tag = tag;
4111 ha.recursive = recursive;
4112 (void) zfs_hold_one(zfs_handle_dup(zhp), &ha);
4113
4114 if (nvlist_next_nvpair(ha.nvl, NULL) == NULL) {
4115 char errbuf[1024];
4116
4117 fnvlist_free(ha.nvl);
4118 ret = ENOENT;
4119 (void) snprintf(errbuf, sizeof (errbuf),
4120 dgettext(TEXT_DOMAIN,
4121 "cannot hold snapshot '%s@%s'"),
4122 zhp->zfs_name, snapname);
4123 (void) zfs_standard_error(zhp->zfs_hdl, ret, errbuf);
4124 return (ret);
4125 }
4126
4127 ret = zfs_hold_nvl(zhp, cleanup_fd, ha.nvl);
4128 fnvlist_free(ha.nvl);
4129
4130 return (ret);
4131 }
4132
4133 int
4134 zfs_hold_nvl(zfs_handle_t *zhp, int cleanup_fd, nvlist_t *holds)
4135 {
4136 int ret;
4137 nvlist_t *errors;
4138 libzfs_handle_t *hdl = zhp->zfs_hdl;
4139 char errbuf[1024];
4140 nvpair_t *elem;
4141
4142 errors = NULL;
4143 ret = lzc_hold(holds, cleanup_fd, &errors);
4144
4145 if (ret == 0) {
4146 /* There may be errors even in the success case. */
4147 fnvlist_free(errors);
4148 return (0);
4149 }
4150
4151 if (nvlist_next_nvpair(errors, NULL) == NULL) {
4152 /* no hold-specific errors */
4153 (void) snprintf(errbuf, sizeof (errbuf),
4154 dgettext(TEXT_DOMAIN, "cannot hold"));
4155 switch (ret) {
4156 case ENOTSUP:
4157 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4158 "pool must be upgraded"));
4159 (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
4160 break;
4161 case EINVAL:
4162 (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
4163 break;
4164 default:
4165 (void) zfs_standard_error(hdl, ret, errbuf);
4166 }
4167 }
4168
4169 for (elem = nvlist_next_nvpair(errors, NULL);
4171 elem = nvlist_next_nvpair(errors, elem)) {
4172 (void) snprintf(errbuf, sizeof (errbuf),
4173 dgettext(TEXT_DOMAIN,
4174 "cannot hold snapshot '%s'"), nvpair_name(elem));
4175 switch (fnvpair_value_int32(elem)) {
4176 case E2BIG:
4177 /*
4178 * Temporary tags wind up having the ds object id
4179 * prepended. So even if we passed the length check
4180 * above, it's still possible for the tag to wind
4181 * up being slightly too long.
4182 */
4183 (void) zfs_error(hdl, EZFS_TAGTOOLONG, errbuf);
4184 break;
4185 case EINVAL:
4186 (void) zfs_error(hdl, EZFS_BADTYPE, errbuf);
4187 break;
4188 case EEXIST:
4189 (void) zfs_error(hdl, EZFS_REFTAG_HOLD, errbuf);
4190 break;
4191 default:
4192 (void) zfs_standard_error(hdl,
4193 fnvpair_value_int32(elem), errbuf);
4194 }
4195 }
4196
4197 fnvlist_free(errors);
4198 return (ret);
4199 }
4200
4201 static int
4202 zfs_release_one(zfs_handle_t *zhp, void *arg)
4203 {
4204 struct holdarg *ha = arg;
4205 char name[ZFS_MAXNAMELEN];
4206 int rv = 0;
4207
4208 (void) snprintf(name, sizeof (name),
4209 "%s@%s", zhp->zfs_name, ha->snapname);
4210
4211 if (lzc_exists(name)) {
4212 nvlist_t *holds = fnvlist_alloc();
4213 fnvlist_add_boolean(holds, ha->tag);
4214 fnvlist_add_nvlist(ha->nvl, name, holds);
4215 fnvlist_free(holds);
4216 }
4217
4218 if (ha->recursive)
4219 rv = zfs_iter_filesystems(zhp, zfs_release_one, ha);
4220 zfs_close(zhp);
4221 return (rv);
4222 }
4223
4224 int
4225 zfs_release(zfs_handle_t *zhp, const char *snapname, const char *tag,
4226 boolean_t recursive)
4227 {
4228 int ret;
4229 struct holdarg ha;
4230 nvlist_t *errors;
4231 nvpair_t *elem;
4232 libzfs_handle_t *hdl = zhp->zfs_hdl;
4233 char errbuf[1024];
4234
4235 ha.nvl = fnvlist_alloc();
4236 ha.snapname = snapname;
4237 ha.tag = tag;
4238 ha.recursive = recursive;
4239 (void) zfs_release_one(zfs_handle_dup(zhp), &ha);
4240
4241 if (nvlist_next_nvpair(ha.nvl, NULL) == NULL) {
4242 fnvlist_free(ha.nvl);
4243 ret = ENOENT;
4244 (void) snprintf(errbuf, sizeof (errbuf),
4245 dgettext(TEXT_DOMAIN,
4246 "cannot release hold from snapshot '%s@%s'"),
4247 zhp->zfs_name, snapname);
4248 (void) zfs_standard_error(hdl, ret, errbuf);
4249 return (ret);
4250 }
4251
4252 errors = NULL;
4253 ret = lzc_release(ha.nvl, &errors);
4254 fnvlist_free(ha.nvl);
4255
4256 if (ret == 0) {
4257 /* There may be errors even in the success case. */
4258 fnvlist_free(errors);
4259 return (0);
4260 }
4261
4262 if (nvlist_next_nvpair(errors, NULL) == NULL) {
4263 /* no hold-specific errors */
4264 (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
4265 "cannot release"));
4266 switch (errno) {
4267 case ENOTSUP:
4268 zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
4269 "pool must be upgraded"));
4270 (void) zfs_error(hdl, EZFS_BADVERSION, errbuf);
4271 break;
4272 default:
4273 (void) zfs_standard_error_fmt(hdl, errno, errbuf);
4274 }
4275 }
4276
4277 for (elem = nvlist_next_nvpair(errors, NULL);
4278 elem != NULL;
4279 elem = nvlist_next_nvpair(errors, elem)) {
4280 (void) snprintf(errbuf, sizeof (errbuf),
|