1248435Smm/*
2248435Smm * CDDL HEADER START
3248435Smm *
4248435Smm * The contents of this file are subject to the terms of the
5248435Smm * Common Development and Distribution License (the "License").
6248435Smm * You may not use this file except in compliance with the License.
7248435Smm *
8248435Smm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9248435Smm * or http://www.opensolaris.org/os/licensing.
10248435Smm * See the License for the specific language governing permissions
11248435Smm * and limitations under the License.
12248435Smm *
13248435Smm * When distributing Covered Code, include this CDDL HEADER in each
14248435Smm * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15248435Smm * If applicable, add the following below this CDDL HEADER, with the
16248435Smm * fields enclosed by brackets "[]" replaced with your own identifying
17248435Smm * information: Portions Copyright [yyyy] [name of copyright owner]
18248435Smm *
19248435Smm * CDDL HEADER END
20248435Smm */
21248435Smm
22248435Smm/*
23248435Smm * Copyright (c) 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
24248435Smm */
25248435Smm
26248435Smm#include <sys/zfs_ioctl.h>
27248445Smm#include <zfs_ioctl_compat.h>
28248445Smm#include "libzfs_core_compat.h"
29248435Smm
30248461Smmextern int zfs_ioctl_version;
31248435Smm
32248435Smmint
33248435Smmlzc_compat_pre(zfs_cmd_t *zc, zfs_ioc_t *ioc, nvlist_t **source)
34248435Smm{
35248435Smm	nvlist_t *nvl = NULL;
36248498Smm	nvpair_t *pair, *hpair;
37248498Smm	char *buf, *val;
38248435Smm	zfs_ioc_t vecnum;
39248435Smm	uint32_t type32;
40248498Smm	int32_t cleanup_fd;
41248435Smm	int error = 0;
42248435Smm	int pos;
43248435Smm
44248461Smm	if (zfs_ioctl_version >= ZFS_IOCVER_LZC)
45248435Smm		return (0);
46248435Smm
47248435Smm	vecnum = *ioc;
48248435Smm
49248435Smm	switch (vecnum) {
50248435Smm	case ZFS_IOC_CREATE:
51248435Smm		type32 = fnvlist_lookup_int32(*source, "type");
52248435Smm		zc->zc_objset_type = (uint64_t)type32;
53248435Smm		nvlist_lookup_nvlist(*source, "props", &nvl);
54248435Smm		*source = nvl;
55248435Smm	break;
56248435Smm	case ZFS_IOC_CLONE:
57248435Smm		buf = fnvlist_lookup_string(*source, "origin");
58248435Smm		strlcpy(zc->zc_value, buf, MAXPATHLEN);
59248435Smm		nvlist_lookup_nvlist(*source, "props", &nvl);
60248435Smm		*ioc = ZFS_IOC_CREATE;
61248435Smm		*source = nvl;
62248435Smm	break;
63248435Smm	case ZFS_IOC_SNAPSHOT:
64248435Smm		nvl = fnvlist_lookup_nvlist(*source, "snaps");
65248435Smm		pair = nvlist_next_nvpair(nvl, NULL);
66248435Smm		if (pair != NULL) {
67248435Smm			buf = nvpair_name(pair);
68248435Smm			pos = strcspn(buf, "@");
69248435Smm			strlcpy(zc->zc_name, buf, pos + 1);
70248435Smm			strlcpy(zc->zc_value, buf + pos + 1, MAXPATHLEN);
71248435Smm		} else
72248498Smm			error = EINVAL;
73248435Smm		/* old kernel cannot create multiple snapshots */
74248435Smm		if (!error && nvlist_next_nvpair(nvl, pair) != NULL)
75248435Smm			error = EOPNOTSUPP;
76248435Smm		nvlist_free(nvl);
77248435Smm		nvl = NULL;
78248435Smm		nvlist_lookup_nvlist(*source, "props", &nvl);
79248435Smm		*source = nvl;
80248435Smm	break;
81248435Smm	case ZFS_IOC_SPACE_SNAPS:
82248435Smm		buf = fnvlist_lookup_string(*source, "firstsnap");
83248435Smm		strlcpy(zc->zc_value, buf, MAXPATHLEN);
84248435Smm	break;
85248435Smm	case ZFS_IOC_DESTROY_SNAPS:
86248435Smm		nvl = fnvlist_lookup_nvlist(*source, "snaps");
87248435Smm		pair = nvlist_next_nvpair(nvl, NULL);
88248435Smm		if (pair != NULL) {
89248435Smm			buf = nvpair_name(pair);
90248435Smm			pos = strcspn(buf, "@");
91248435Smm			strlcpy(zc->zc_name, buf, pos + 1);
92248498Smm		} else
93248498Smm			error = EINVAL;
94248498Smm		/* old kernel cannot atomically destroy multiple snaps */
95248498Smm		if (!error && nvlist_next_nvpair(nvl, pair) != NULL)
96248498Smm			error = EOPNOTSUPP;
97248435Smm		*source = nvl;
98248435Smm	break;
99248498Smm	case ZFS_IOC_HOLD:
100248498Smm		nvl = fnvlist_lookup_nvlist(*source, "holds");
101248498Smm		pair = nvlist_next_nvpair(nvl, NULL);
102248498Smm		if (pair != NULL) {
103248498Smm			buf = nvpair_name(pair);
104248498Smm			pos = strcspn(buf, "@");
105248498Smm			strlcpy(zc->zc_name, buf, pos + 1);
106248498Smm			strlcpy(zc->zc_value, buf + pos + 1, MAXPATHLEN);
107248498Smm			if (nvpair_value_string(pair, &val) == 0)
108248498Smm				strlcpy(zc->zc_string, val, MAXNAMELEN);
109248498Smm			else
110248498Smm				error = EINVAL;
111248498Smm		} else
112248498Smm			error = EINVAL;
113248498Smm		/* old kernel cannot atomically create multiple holds */
114248498Smm		if (!error && nvlist_next_nvpair(nvl, pair) != NULL)
115248498Smm			error = EOPNOTSUPP;
116248498Smm		nvlist_free(nvl);
117248498Smm		if (nvlist_lookup_int32(*source, "cleanup_fd",
118248498Smm		    &cleanup_fd) == 0)
119248498Smm			zc->zc_cleanup_fd = cleanup_fd;
120248498Smm		else
121248498Smm			zc->zc_cleanup_fd = -1;
122248498Smm	break;
123248498Smm	case ZFS_IOC_RELEASE:
124248498Smm		pair = nvlist_next_nvpair(*source, NULL);
125248498Smm		if (pair != NULL) {
126248498Smm			buf = nvpair_name(pair);
127248498Smm			pos = strcspn(buf, "@");
128248498Smm			strlcpy(zc->zc_name, buf, pos + 1);
129248498Smm			strlcpy(zc->zc_value, buf + pos + 1, MAXPATHLEN);
130248498Smm			if (nvpair_value_nvlist(pair, &nvl) == 0) {
131248498Smm				hpair = nvlist_next_nvpair(nvl, NULL);
132248498Smm				if (hpair != NULL)
133248498Smm					strlcpy(zc->zc_string,
134248498Smm					    nvpair_name(hpair), MAXNAMELEN);
135248498Smm				else
136248498Smm					error = EINVAL;
137248498Smm				if (!error && nvlist_next_nvpair(nvl,
138248498Smm				    hpair) != NULL)
139248498Smm					error = EOPNOTSUPP;
140248498Smm			} else
141248498Smm				error = EINVAL;
142248498Smm		} else
143248498Smm			error = EINVAL;
144248498Smm		/* old kernel cannot atomically release multiple holds */
145248498Smm		if (!error && nvlist_next_nvpair(nvl, pair) != NULL)
146248498Smm			error = EOPNOTSUPP;
147248498Smm	break;
148248435Smm	}
149248435Smm
150248435Smm	return (error);
151248435Smm}
152248435Smm
153248435Smmvoid
154248435Smmlzc_compat_post(zfs_cmd_t *zc, const zfs_ioc_t ioc)
155248435Smm{
156248461Smm	if (zfs_ioctl_version >= ZFS_IOCVER_LZC)
157248435Smm		return;
158248435Smm
159248435Smm	switch (ioc) {
160248435Smm	case ZFS_IOC_CREATE:
161248435Smm	case ZFS_IOC_CLONE:
162248435Smm	case ZFS_IOC_SNAPSHOT:
163248435Smm	case ZFS_IOC_SPACE_SNAPS:
164248435Smm	case ZFS_IOC_DESTROY_SNAPS:
165248435Smm		zc->zc_nvlist_dst_filled = B_FALSE;
166248435Smm	break;
167248435Smm	}
168248435Smm}
169248435Smm
170248435Smmint
171248435Smmlzc_compat_outnvl(zfs_cmd_t *zc, const zfs_ioc_t ioc, nvlist_t **outnvl)
172248435Smm{
173248435Smm	nvlist_t *nvl;
174248435Smm
175248461Smm	if (zfs_ioctl_version >= ZFS_IOCVER_LZC)
176248435Smm		return (0);
177248435Smm
178248435Smm	switch (ioc) {
179248435Smm	case ZFS_IOC_SPACE_SNAPS:
180248435Smm		nvl = fnvlist_alloc();
181248435Smm		fnvlist_add_uint64(nvl, "used", zc->zc_cookie);
182248435Smm		fnvlist_add_uint64(nvl, "compressed", zc->zc_objset_type);
183248435Smm		fnvlist_add_uint64(nvl, "uncompressed", zc->zc_perm_action);
184248435Smm		*outnvl = nvl;
185248435Smm	break;
186248435Smm	}
187248435Smm
188248435Smm	return (0);
189248435Smm}
190