1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
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) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
24 */
25
26 #include <sys/zfs_ioctl.h>
27 #include <zfs_ioctl_compat.h>
28 #include "libzfs_core_compat.h"
29
30 extern int zfs_ioctl_version;
31
32 int
lzc_compat_pre(zfs_cmd_t * zc,zfs_ioc_t * ioc,nvlist_t ** source)33 lzc_compat_pre(zfs_cmd_t *zc, zfs_ioc_t *ioc, nvlist_t **source)
34 {
35 nvlist_t *nvl = NULL;
36 nvpair_t *pair, *hpair;
37 char *buf, *val;
38 zfs_ioc_t vecnum;
39 uint32_t type32;
40 int32_t cleanup_fd;
41 int error = 0;
42 int pos;
43
44 if (zfs_ioctl_version >= ZFS_IOCVER_LZC)
45 return (0);
46
47 vecnum = *ioc;
48
49 switch (vecnum) {
50 case ZFS_IOC_CREATE:
51 type32 = fnvlist_lookup_int32(*source, "type");
52 zc->zc_objset_type = (uint64_t)type32;
53 nvlist_lookup_nvlist(*source, "props", &nvl);
54 *source = nvl;
55 break;
56 case ZFS_IOC_CLONE:
57 buf = fnvlist_lookup_string(*source, "origin");
58 strlcpy(zc->zc_value, buf, MAXPATHLEN);
59 nvlist_lookup_nvlist(*source, "props", &nvl);
60 *ioc = ZFS_IOC_CREATE;
61 *source = nvl;
62 break;
63 case ZFS_IOC_SNAPSHOT:
64 nvl = fnvlist_lookup_nvlist(*source, "snaps");
65 pair = nvlist_next_nvpair(nvl, NULL);
66 if (pair != NULL) {
67 buf = nvpair_name(pair);
68 pos = strcspn(buf, "@");
69 strlcpy(zc->zc_name, buf, pos + 1);
70 strlcpy(zc->zc_value, buf + pos + 1, MAXPATHLEN);
71 } else
72 error = EINVAL;
73 /* old kernel cannot create multiple snapshots */
74 if (!error && nvlist_next_nvpair(nvl, pair) != NULL)
75 error = EOPNOTSUPP;
76 nvlist_free(nvl);
77 nvl = NULL;
78 nvlist_lookup_nvlist(*source, "props", &nvl);
79 *source = nvl;
80 break;
81 case ZFS_IOC_SPACE_SNAPS:
82 buf = fnvlist_lookup_string(*source, "firstsnap");
83 strlcpy(zc->zc_value, buf, MAXPATHLEN);
84 break;
85 case ZFS_IOC_DESTROY_SNAPS:
86 nvl = fnvlist_lookup_nvlist(*source, "snaps");
87 pair = nvlist_next_nvpair(nvl, NULL);
88 if (pair != NULL) {
89 buf = nvpair_name(pair);
90 pos = strcspn(buf, "@");
91 strlcpy(zc->zc_name, buf, pos + 1);
92 } else
93 error = EINVAL;
94 /* old kernel cannot atomically destroy multiple snaps */
95 if (!error && nvlist_next_nvpair(nvl, pair) != NULL)
96 error = EOPNOTSUPP;
97 *source = nvl;
98 break;
99 case ZFS_IOC_HOLD:
100 nvl = fnvlist_lookup_nvlist(*source, "holds");
101 pair = nvlist_next_nvpair(nvl, NULL);
102 if (pair != NULL) {
103 buf = nvpair_name(pair);
104 pos = strcspn(buf, "@");
105 strlcpy(zc->zc_name, buf, pos + 1);
106 strlcpy(zc->zc_value, buf + pos + 1, MAXPATHLEN);
107 if (nvpair_value_string(pair, &val) == 0)
108 strlcpy(zc->zc_string, val, MAXNAMELEN);
109 else
110 error = EINVAL;
111 } else
112 error = EINVAL;
113 /* old kernel cannot atomically create multiple holds */
114 if (!error && nvlist_next_nvpair(nvl, pair) != NULL)
115 error = EOPNOTSUPP;
116 nvlist_free(nvl);
117 if (nvlist_lookup_int32(*source, "cleanup_fd",
118 &cleanup_fd) == 0)
119 zc->zc_cleanup_fd = cleanup_fd;
120 else
121 zc->zc_cleanup_fd = -1;
122 break;
123 case ZFS_IOC_RELEASE:
124 pair = nvlist_next_nvpair(*source, NULL);
125 if (pair != NULL) {
126 buf = nvpair_name(pair);
127 pos = strcspn(buf, "@");
128 strlcpy(zc->zc_name, buf, pos + 1);
129 strlcpy(zc->zc_value, buf + pos + 1, MAXPATHLEN);
130 if (nvpair_value_nvlist(pair, &nvl) == 0) {
131 hpair = nvlist_next_nvpair(nvl, NULL);
132 if (hpair != NULL)
133 strlcpy(zc->zc_string,
134 nvpair_name(hpair), MAXNAMELEN);
135 else
136 error = EINVAL;
137 if (!error && nvlist_next_nvpair(nvl,
138 hpair) != NULL)
139 error = EOPNOTSUPP;
140 } else
141 error = EINVAL;
142 } else
143 error = EINVAL;
144 /* old kernel cannot atomically release multiple holds */
145 if (!error && nvlist_next_nvpair(nvl, pair) != NULL)
146 error = EOPNOTSUPP;
147 break;
148 }
149
150 return (error);
151 }
152
153 void
lzc_compat_post(zfs_cmd_t * zc,const zfs_ioc_t ioc)154 lzc_compat_post(zfs_cmd_t *zc, const zfs_ioc_t ioc)
155 {
156 if (zfs_ioctl_version >= ZFS_IOCVER_LZC)
157 return;
158
159 switch (ioc) {
160 case ZFS_IOC_CREATE:
161 case ZFS_IOC_CLONE:
162 case ZFS_IOC_SNAPSHOT:
163 case ZFS_IOC_SPACE_SNAPS:
164 case ZFS_IOC_DESTROY_SNAPS:
165 zc->zc_nvlist_dst_filled = B_FALSE;
166 break;
167 }
168 }
169
170 int
lzc_compat_outnvl(zfs_cmd_t * zc,const zfs_ioc_t ioc,nvlist_t ** outnvl)171 lzc_compat_outnvl(zfs_cmd_t *zc, const zfs_ioc_t ioc, nvlist_t **outnvl)
172 {
173 nvlist_t *nvl;
174
175 if (zfs_ioctl_version >= ZFS_IOCVER_LZC)
176 return (0);
177
178 switch (ioc) {
179 case ZFS_IOC_SPACE_SNAPS:
180 nvl = fnvlist_alloc();
181 fnvlist_add_uint64(nvl, "used", zc->zc_cookie);
182 fnvlist_add_uint64(nvl, "compressed", zc->zc_objset_type);
183 fnvlist_add_uint64(nvl, "uncompressed", zc->zc_perm_action);
184 *outnvl = nvl;
185 break;
186 }
187
188 return (0);
189 }
190