libzfs_core_compat.c revision 248498
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
30extern int zfs_ioctl_version;
31
32int
33lzc_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
153void
154lzc_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
170int
171lzc_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