zfs_ioctl_compat.c revision 289362
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 * Copyright 2013 Xin Li <delphij@FreeBSD.org>. All rights reserved.
23 * Copyright 2013 Martin Matuska <mm@FreeBSD.org>. All rights reserved.
24 * Portions Copyright 2005, 2010, Oracle and/or its affiliates.
25 * All rights reserved.
26 * Use is subject to license terms.
27 */
28
29#include <sys/types.h>
30#include <sys/param.h>
31#include <sys/cred.h>
32#include <sys/dmu.h>
33#include <sys/zio.h>
34#include <sys/nvpair.h>
35#include <sys/dsl_deleg.h>
36#include <sys/zfs_ioctl.h>
37#include "zfs_namecheck.h"
38#include "zfs_ioctl_compat.h"
39
40static int zfs_version_ioctl = ZFS_IOCVER_CURRENT;
41SYSCTL_DECL(_vfs_zfs_version);
42SYSCTL_INT(_vfs_zfs_version, OID_AUTO, ioctl, CTLFLAG_RD, &zfs_version_ioctl,
43    0, "ZFS_IOCTL_VERSION");
44
45/*
46 * FreeBSD zfs_cmd compatibility with older binaries
47 * appropriately remap/extend the zfs_cmd_t structure
48 */
49void
50zfs_cmd_compat_get(zfs_cmd_t *zc, caddr_t addr, const int cflag)
51{
52	zfs_cmd_v15_t *zc_c;
53	zfs_cmd_v28_t *zc28_c;
54	zfs_cmd_deadman_t *zcdm_c;
55	zfs_cmd_zcmd_t *zcmd_c;
56	zfs_cmd_edbp_t *edbp_c;
57
58	switch (cflag) {
59	case ZFS_CMD_COMPAT_EDBP:
60		edbp_c = (void *)addr;
61		/* zc */
62		strlcpy(zc->zc_name, edbp_c->zc_name, MAXPATHLEN);
63		strlcpy(zc->zc_value, edbp_c->zc_value, MAXPATHLEN * 2);
64		strlcpy(zc->zc_string, edbp_c->zc_string, MAXPATHLEN);
65
66#define ZCMD_COPY(field) zc->field = edbp_c->field
67		ZCMD_COPY(zc_nvlist_src);
68		ZCMD_COPY(zc_nvlist_src_size);
69		ZCMD_COPY(zc_nvlist_dst);
70		ZCMD_COPY(zc_nvlist_dst_size);
71		ZCMD_COPY(zc_nvlist_dst_filled);
72		ZCMD_COPY(zc_pad2);
73		ZCMD_COPY(zc_history);
74		ZCMD_COPY(zc_guid);
75		ZCMD_COPY(zc_nvlist_conf);
76		ZCMD_COPY(zc_nvlist_conf_size);
77		ZCMD_COPY(zc_cookie);
78		ZCMD_COPY(zc_objset_type);
79		ZCMD_COPY(zc_perm_action);
80		ZCMD_COPY(zc_history_len);
81		ZCMD_COPY(zc_history_offset);
82		ZCMD_COPY(zc_obj);
83		ZCMD_COPY(zc_iflags);
84		ZCMD_COPY(zc_share);
85		ZCMD_COPY(zc_jailid);
86		ZCMD_COPY(zc_objset_stats);
87		ZCMD_COPY(zc_inject_record);
88		ZCMD_COPY(zc_defer_destroy);
89		ZCMD_COPY(zc_flags);
90		ZCMD_COPY(zc_action_handle);
91		ZCMD_COPY(zc_cleanup_fd);
92		ZCMD_COPY(zc_simple);
93		zc->zc_resumable = B_FALSE;
94		ZCMD_COPY(zc_sendobj);
95		ZCMD_COPY(zc_fromobj);
96		ZCMD_COPY(zc_createtxg);
97		ZCMD_COPY(zc_stat);
98#undef ZCMD_COPY
99		break;
100
101	case ZFS_CMD_COMPAT_ZCMD:
102		zcmd_c = (void *)addr;
103		/* zc */
104		strlcpy(zc->zc_name, zcmd_c->zc_name, MAXPATHLEN);
105		strlcpy(zc->zc_value, zcmd_c->zc_value, MAXPATHLEN * 2);
106		strlcpy(zc->zc_string, zcmd_c->zc_string, MAXPATHLEN);
107
108#define ZCMD_COPY(field) zc->field = zcmd_c->field
109		ZCMD_COPY(zc_nvlist_src);
110		ZCMD_COPY(zc_nvlist_src_size);
111		ZCMD_COPY(zc_nvlist_dst);
112		ZCMD_COPY(zc_nvlist_dst_size);
113		ZCMD_COPY(zc_nvlist_dst_filled);
114		ZCMD_COPY(zc_pad2);
115		ZCMD_COPY(zc_history);
116		ZCMD_COPY(zc_guid);
117		ZCMD_COPY(zc_nvlist_conf);
118		ZCMD_COPY(zc_nvlist_conf_size);
119		ZCMD_COPY(zc_cookie);
120		ZCMD_COPY(zc_objset_type);
121		ZCMD_COPY(zc_perm_action);
122		ZCMD_COPY(zc_history_len);
123		ZCMD_COPY(zc_history_offset);
124		ZCMD_COPY(zc_obj);
125		ZCMD_COPY(zc_iflags);
126		ZCMD_COPY(zc_share);
127		ZCMD_COPY(zc_jailid);
128		ZCMD_COPY(zc_objset_stats);
129		ZCMD_COPY(zc_inject_record);
130
131		/* boolean_t -> uint32_t */
132		zc->zc_defer_destroy = (uint32_t)(zcmd_c->zc_defer_destroy);
133		zc->zc_flags = 0;
134
135		ZCMD_COPY(zc_action_handle);
136		ZCMD_COPY(zc_cleanup_fd);
137		ZCMD_COPY(zc_simple);
138		zc->zc_resumable = B_FALSE;
139		ZCMD_COPY(zc_sendobj);
140		ZCMD_COPY(zc_fromobj);
141		ZCMD_COPY(zc_createtxg);
142		ZCMD_COPY(zc_stat);
143#undef ZCMD_COPY
144
145		break;
146
147	case ZFS_CMD_COMPAT_DEADMAN:
148		zcdm_c = (void *)addr;
149		/* zc */
150		strlcpy(zc->zc_name, zcdm_c->zc_name, MAXPATHLEN);
151		strlcpy(zc->zc_value, zcdm_c->zc_value, MAXPATHLEN * 2);
152		strlcpy(zc->zc_string, zcdm_c->zc_string, MAXPATHLEN);
153		zc->zc_guid = zcdm_c->zc_guid;
154		zc->zc_nvlist_conf = zcdm_c->zc_nvlist_conf;
155		zc->zc_nvlist_conf_size = zcdm_c->zc_nvlist_conf_size;
156		zc->zc_nvlist_src = zcdm_c->zc_nvlist_src;
157		zc->zc_nvlist_src_size = zcdm_c->zc_nvlist_src_size;
158		zc->zc_nvlist_dst = zcdm_c->zc_nvlist_dst;
159		zc->zc_nvlist_dst_size = zcdm_c->zc_nvlist_dst_size;
160		zc->zc_cookie = zcdm_c->zc_cookie;
161		zc->zc_objset_type = zcdm_c->zc_objset_type;
162		zc->zc_perm_action = zcdm_c->zc_perm_action;
163		zc->zc_history = zcdm_c->zc_history;
164		zc->zc_history_len = zcdm_c->zc_history_len;
165		zc->zc_history_offset = zcdm_c->zc_history_offset;
166		zc->zc_obj = zcdm_c->zc_obj;
167		zc->zc_iflags = zcdm_c->zc_iflags;
168		zc->zc_share = zcdm_c->zc_share;
169		zc->zc_jailid = zcdm_c->zc_jailid;
170		zc->zc_objset_stats = zcdm_c->zc_objset_stats;
171		zc->zc_defer_destroy = zcdm_c->zc_defer_destroy;
172		(void)zcdm_c->zc_temphold;
173		zc->zc_action_handle = zcdm_c->zc_action_handle;
174		zc->zc_cleanup_fd = zcdm_c->zc_cleanup_fd;
175		zc->zc_simple = zcdm_c->zc_simple;
176		zc->zc_resumable = B_FALSE;
177		zc->zc_sendobj = zcdm_c->zc_sendobj;
178		zc->zc_fromobj = zcdm_c->zc_fromobj;
179		zc->zc_createtxg = zcdm_c->zc_createtxg;
180		zc->zc_stat = zcdm_c->zc_stat;
181
182		/* zc_inject_record doesn't change in libzfs_core */
183		zcdm_c->zc_inject_record = zc->zc_inject_record;
184
185		/* we always assume zc_nvlist_dst_filled is true */
186		zc->zc_nvlist_dst_filled = B_TRUE;
187		break;
188
189	case ZFS_CMD_COMPAT_V28:
190		zc28_c = (void *)addr;
191
192		/* zc */
193		strlcpy(zc->zc_name, zc28_c->zc_name, MAXPATHLEN);
194		strlcpy(zc->zc_value, zc28_c->zc_value, MAXPATHLEN * 2);
195		strlcpy(zc->zc_string, zc28_c->zc_string, MAXPATHLEN);
196		zc->zc_guid = zc28_c->zc_guid;
197		zc->zc_nvlist_conf = zc28_c->zc_nvlist_conf;
198		zc->zc_nvlist_conf_size = zc28_c->zc_nvlist_conf_size;
199		zc->zc_nvlist_src = zc28_c->zc_nvlist_src;
200		zc->zc_nvlist_src_size = zc28_c->zc_nvlist_src_size;
201		zc->zc_nvlist_dst = zc28_c->zc_nvlist_dst;
202		zc->zc_nvlist_dst_size = zc28_c->zc_nvlist_dst_size;
203		zc->zc_cookie = zc28_c->zc_cookie;
204		zc->zc_objset_type = zc28_c->zc_objset_type;
205		zc->zc_perm_action = zc28_c->zc_perm_action;
206		zc->zc_history = zc28_c->zc_history;
207		zc->zc_history_len = zc28_c->zc_history_len;
208		zc->zc_history_offset = zc28_c->zc_history_offset;
209		zc->zc_obj = zc28_c->zc_obj;
210		zc->zc_iflags = zc28_c->zc_iflags;
211		zc->zc_share = zc28_c->zc_share;
212		zc->zc_jailid = zc28_c->zc_jailid;
213		zc->zc_objset_stats = zc28_c->zc_objset_stats;
214		zc->zc_defer_destroy = zc28_c->zc_defer_destroy;
215		(void)zc28_c->zc_temphold;
216		zc->zc_action_handle = zc28_c->zc_action_handle;
217		zc->zc_cleanup_fd = zc28_c->zc_cleanup_fd;
218		zc->zc_simple = zc28_c->zc_simple;
219		zc->zc_resumable = B_FALSE;
220		zc->zc_sendobj = zc28_c->zc_sendobj;
221		zc->zc_fromobj = zc28_c->zc_fromobj;
222		zc->zc_createtxg = zc28_c->zc_createtxg;
223		zc->zc_stat = zc28_c->zc_stat;
224
225		/* zc->zc_inject_record */
226		zc->zc_inject_record.zi_objset =
227		    zc28_c->zc_inject_record.zi_objset;
228		zc->zc_inject_record.zi_object =
229		    zc28_c->zc_inject_record.zi_object;
230		zc->zc_inject_record.zi_start =
231		    zc28_c->zc_inject_record.zi_start;
232		zc->zc_inject_record.zi_end =
233		    zc28_c->zc_inject_record.zi_end;
234		zc->zc_inject_record.zi_guid =
235		    zc28_c->zc_inject_record.zi_guid;
236		zc->zc_inject_record.zi_level =
237		    zc28_c->zc_inject_record.zi_level;
238		zc->zc_inject_record.zi_error =
239		    zc28_c->zc_inject_record.zi_error;
240		zc->zc_inject_record.zi_type =
241		    zc28_c->zc_inject_record.zi_type;
242		zc->zc_inject_record.zi_freq =
243		    zc28_c->zc_inject_record.zi_freq;
244		zc->zc_inject_record.zi_failfast =
245		    zc28_c->zc_inject_record.zi_failfast;
246		strlcpy(zc->zc_inject_record.zi_func,
247		    zc28_c->zc_inject_record.zi_func, MAXNAMELEN);
248		zc->zc_inject_record.zi_iotype =
249		    zc28_c->zc_inject_record.zi_iotype;
250		zc->zc_inject_record.zi_duration =
251		    zc28_c->zc_inject_record.zi_duration;
252		zc->zc_inject_record.zi_timer =
253		    zc28_c->zc_inject_record.zi_timer;
254		zc->zc_inject_record.zi_cmd = ZINJECT_UNINITIALIZED;
255		zc->zc_inject_record.zi_pad = 0;
256		break;
257
258	case ZFS_CMD_COMPAT_V15:
259		zc_c = (void *)addr;
260
261		/* zc */
262		strlcpy(zc->zc_name, zc_c->zc_name, MAXPATHLEN);
263		strlcpy(zc->zc_value, zc_c->zc_value, MAXPATHLEN);
264		strlcpy(zc->zc_string, zc_c->zc_string, MAXPATHLEN);
265		zc->zc_guid = zc_c->zc_guid;
266		zc->zc_nvlist_conf = zc_c->zc_nvlist_conf;
267		zc->zc_nvlist_conf_size = zc_c->zc_nvlist_conf_size;
268		zc->zc_nvlist_src = zc_c->zc_nvlist_src;
269		zc->zc_nvlist_src_size = zc_c->zc_nvlist_src_size;
270		zc->zc_nvlist_dst = zc_c->zc_nvlist_dst;
271		zc->zc_nvlist_dst_size = zc_c->zc_nvlist_dst_size;
272		zc->zc_cookie = zc_c->zc_cookie;
273		zc->zc_objset_type = zc_c->zc_objset_type;
274		zc->zc_perm_action = zc_c->zc_perm_action;
275		zc->zc_history = zc_c->zc_history;
276		zc->zc_history_len = zc_c->zc_history_len;
277		zc->zc_history_offset = zc_c->zc_history_offset;
278		zc->zc_obj = zc_c->zc_obj;
279		zc->zc_share = zc_c->zc_share;
280		zc->zc_jailid = zc_c->zc_jailid;
281		zc->zc_objset_stats = zc_c->zc_objset_stats;
282
283		/* zc->zc_inject_record */
284		zc->zc_inject_record.zi_objset =
285		    zc_c->zc_inject_record.zi_objset;
286		zc->zc_inject_record.zi_object =
287		    zc_c->zc_inject_record.zi_object;
288		zc->zc_inject_record.zi_start =
289		    zc_c->zc_inject_record.zi_start;
290		zc->zc_inject_record.zi_end =
291		    zc_c->zc_inject_record.zi_end;
292		zc->zc_inject_record.zi_guid =
293		    zc_c->zc_inject_record.zi_guid;
294		zc->zc_inject_record.zi_level =
295		    zc_c->zc_inject_record.zi_level;
296		zc->zc_inject_record.zi_error =
297		    zc_c->zc_inject_record.zi_error;
298		zc->zc_inject_record.zi_type =
299		    zc_c->zc_inject_record.zi_type;
300		zc->zc_inject_record.zi_freq =
301		    zc_c->zc_inject_record.zi_freq;
302		zc->zc_inject_record.zi_failfast =
303		    zc_c->zc_inject_record.zi_failfast;
304		break;
305	}
306}
307
308void
309zfs_cmd_compat_put(zfs_cmd_t *zc, caddr_t addr, const int request,
310    const int cflag)
311{
312	zfs_cmd_v15_t *zc_c;
313	zfs_cmd_v28_t *zc28_c;
314	zfs_cmd_deadman_t *zcdm_c;
315	zfs_cmd_zcmd_t *zcmd_c;
316	zfs_cmd_edbp_t *edbp_c;
317
318	switch (cflag) {
319	case ZFS_CMD_COMPAT_EDBP:
320		edbp_c = (void *)addr;
321		strlcpy(edbp_c->zc_name, zc->zc_name, MAXPATHLEN);
322		strlcpy(edbp_c->zc_value, zc->zc_value, MAXPATHLEN * 2);
323		strlcpy(edbp_c->zc_string, zc->zc_string, MAXPATHLEN);
324
325#define ZCMD_COPY(field) edbp_c->field = zc->field
326		ZCMD_COPY(zc_nvlist_src);
327		ZCMD_COPY(zc_nvlist_src_size);
328		ZCMD_COPY(zc_nvlist_dst);
329		ZCMD_COPY(zc_nvlist_dst_size);
330		ZCMD_COPY(zc_nvlist_dst_filled);
331		ZCMD_COPY(zc_pad2);
332		ZCMD_COPY(zc_history);
333		ZCMD_COPY(zc_guid);
334		ZCMD_COPY(zc_nvlist_conf);
335		ZCMD_COPY(zc_nvlist_conf_size);
336		ZCMD_COPY(zc_cookie);
337		ZCMD_COPY(zc_objset_type);
338		ZCMD_COPY(zc_perm_action);
339		ZCMD_COPY(zc_history_len);
340		ZCMD_COPY(zc_history_offset);
341		ZCMD_COPY(zc_obj);
342		ZCMD_COPY(zc_iflags);
343		ZCMD_COPY(zc_share);
344		ZCMD_COPY(zc_jailid);
345		ZCMD_COPY(zc_objset_stats);
346		ZCMD_COPY(zc_inject_record);
347		ZCMD_COPY(zc_defer_destroy);
348		ZCMD_COPY(zc_flags);
349		ZCMD_COPY(zc_action_handle);
350		ZCMD_COPY(zc_cleanup_fd);
351		ZCMD_COPY(zc_simple);
352		ZCMD_COPY(zc_sendobj);
353		ZCMD_COPY(zc_fromobj);
354		ZCMD_COPY(zc_createtxg);
355		ZCMD_COPY(zc_stat);
356#undef ZCMD_COPY
357		break;
358
359	case ZFS_CMD_COMPAT_ZCMD:
360		zcmd_c = (void *)addr;
361		/* zc */
362		strlcpy(zcmd_c->zc_name, zc->zc_name, MAXPATHLEN);
363		strlcpy(zcmd_c->zc_value, zc->zc_value, MAXPATHLEN * 2);
364		strlcpy(zcmd_c->zc_string, zc->zc_string, MAXPATHLEN);
365
366#define ZCMD_COPY(field) zcmd_c->field = zc->field
367		ZCMD_COPY(zc_nvlist_src);
368		ZCMD_COPY(zc_nvlist_src_size);
369		ZCMD_COPY(zc_nvlist_dst);
370		ZCMD_COPY(zc_nvlist_dst_size);
371		ZCMD_COPY(zc_nvlist_dst_filled);
372		ZCMD_COPY(zc_pad2);
373		ZCMD_COPY(zc_history);
374		ZCMD_COPY(zc_guid);
375		ZCMD_COPY(zc_nvlist_conf);
376		ZCMD_COPY(zc_nvlist_conf_size);
377		ZCMD_COPY(zc_cookie);
378		ZCMD_COPY(zc_objset_type);
379		ZCMD_COPY(zc_perm_action);
380		ZCMD_COPY(zc_history_len);
381		ZCMD_COPY(zc_history_offset);
382		ZCMD_COPY(zc_obj);
383		ZCMD_COPY(zc_iflags);
384		ZCMD_COPY(zc_share);
385		ZCMD_COPY(zc_jailid);
386		ZCMD_COPY(zc_objset_stats);
387		ZCMD_COPY(zc_inject_record);
388
389		/* boolean_t -> uint32_t */
390		zcmd_c->zc_defer_destroy = (uint32_t)(zc->zc_defer_destroy);
391		zcmd_c->zc_temphold = 0;
392
393		ZCMD_COPY(zc_action_handle);
394		ZCMD_COPY(zc_cleanup_fd);
395		ZCMD_COPY(zc_simple);
396		ZCMD_COPY(zc_sendobj);
397		ZCMD_COPY(zc_fromobj);
398		ZCMD_COPY(zc_createtxg);
399		ZCMD_COPY(zc_stat);
400#undef ZCMD_COPY
401
402		break;
403
404	case ZFS_CMD_COMPAT_DEADMAN:
405		zcdm_c = (void *)addr;
406
407		strlcpy(zcdm_c->zc_name, zc->zc_name, MAXPATHLEN);
408		strlcpy(zcdm_c->zc_value, zc->zc_value, MAXPATHLEN * 2);
409		strlcpy(zcdm_c->zc_string, zc->zc_string, MAXPATHLEN);
410		zcdm_c->zc_guid = zc->zc_guid;
411		zcdm_c->zc_nvlist_conf = zc->zc_nvlist_conf;
412		zcdm_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size;
413		zcdm_c->zc_nvlist_src = zc->zc_nvlist_src;
414		zcdm_c->zc_nvlist_src_size = zc->zc_nvlist_src_size;
415		zcdm_c->zc_nvlist_dst = zc->zc_nvlist_dst;
416		zcdm_c->zc_nvlist_dst_size = zc->zc_nvlist_dst_size;
417		zcdm_c->zc_cookie = zc->zc_cookie;
418		zcdm_c->zc_objset_type = zc->zc_objset_type;
419		zcdm_c->zc_perm_action = zc->zc_perm_action;
420		zcdm_c->zc_history = zc->zc_history;
421		zcdm_c->zc_history_len = zc->zc_history_len;
422		zcdm_c->zc_history_offset = zc->zc_history_offset;
423		zcdm_c->zc_obj = zc->zc_obj;
424		zcdm_c->zc_iflags = zc->zc_iflags;
425		zcdm_c->zc_share = zc->zc_share;
426		zcdm_c->zc_jailid = zc->zc_jailid;
427		zcdm_c->zc_objset_stats = zc->zc_objset_stats;
428		zcdm_c->zc_defer_destroy = zc->zc_defer_destroy;
429		zcdm_c->zc_temphold = 0;
430		zcdm_c->zc_action_handle = zc->zc_action_handle;
431		zcdm_c->zc_cleanup_fd = zc->zc_cleanup_fd;
432		zcdm_c->zc_simple = zc->zc_simple;
433		zcdm_c->zc_sendobj = zc->zc_sendobj;
434		zcdm_c->zc_fromobj = zc->zc_fromobj;
435		zcdm_c->zc_createtxg = zc->zc_createtxg;
436		zcdm_c->zc_stat = zc->zc_stat;
437
438		/* zc_inject_record doesn't change in libzfs_core */
439		zc->zc_inject_record = zcdm_c->zc_inject_record;
440#ifndef _KERNEL
441		if (request == ZFS_IOC_RECV)
442			strlcpy(zcdm_c->zc_top_ds,
443			    zc->zc_value + strlen(zc->zc_value) + 1,
444			    (MAXPATHLEN * 2) - strlen(zc->zc_value) - 1);
445#endif
446		break;
447
448	case ZFS_CMD_COMPAT_V28:
449		zc28_c = (void *)addr;
450
451		strlcpy(zc28_c->zc_name, zc->zc_name, MAXPATHLEN);
452		strlcpy(zc28_c->zc_value, zc->zc_value, MAXPATHLEN * 2);
453		strlcpy(zc28_c->zc_string, zc->zc_string, MAXPATHLEN);
454		zc28_c->zc_guid = zc->zc_guid;
455		zc28_c->zc_nvlist_conf = zc->zc_nvlist_conf;
456		zc28_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size;
457		zc28_c->zc_nvlist_src = zc->zc_nvlist_src;
458		zc28_c->zc_nvlist_src_size = zc->zc_nvlist_src_size;
459		zc28_c->zc_nvlist_dst = zc->zc_nvlist_dst;
460		zc28_c->zc_nvlist_dst_size = zc->zc_nvlist_dst_size;
461		zc28_c->zc_cookie = zc->zc_cookie;
462		zc28_c->zc_objset_type = zc->zc_objset_type;
463		zc28_c->zc_perm_action = zc->zc_perm_action;
464		zc28_c->zc_history = zc->zc_history;
465		zc28_c->zc_history_len = zc->zc_history_len;
466		zc28_c->zc_history_offset = zc->zc_history_offset;
467		zc28_c->zc_obj = zc->zc_obj;
468		zc28_c->zc_iflags = zc->zc_iflags;
469		zc28_c->zc_share = zc->zc_share;
470		zc28_c->zc_jailid = zc->zc_jailid;
471		zc28_c->zc_objset_stats = zc->zc_objset_stats;
472		zc28_c->zc_defer_destroy = zc->zc_defer_destroy;
473		zc28_c->zc_temphold = 0;
474		zc28_c->zc_action_handle = zc->zc_action_handle;
475		zc28_c->zc_cleanup_fd = zc->zc_cleanup_fd;
476		zc28_c->zc_simple = zc->zc_simple;
477		zc28_c->zc_sendobj = zc->zc_sendobj;
478		zc28_c->zc_fromobj = zc->zc_fromobj;
479		zc28_c->zc_createtxg = zc->zc_createtxg;
480		zc28_c->zc_stat = zc->zc_stat;
481#ifndef _KERNEL
482		if (request == ZFS_IOC_RECV)
483			strlcpy(zc28_c->zc_top_ds,
484			    zc->zc_value + strlen(zc->zc_value) + 1,
485			    MAXPATHLEN * 2 - strlen(zc->zc_value) - 1);
486#endif
487		/* zc_inject_record */
488		zc28_c->zc_inject_record.zi_objset =
489		    zc->zc_inject_record.zi_objset;
490		zc28_c->zc_inject_record.zi_object =
491		    zc->zc_inject_record.zi_object;
492		zc28_c->zc_inject_record.zi_start =
493		    zc->zc_inject_record.zi_start;
494		zc28_c->zc_inject_record.zi_end =
495		    zc->zc_inject_record.zi_end;
496		zc28_c->zc_inject_record.zi_guid =
497		    zc->zc_inject_record.zi_guid;
498		zc28_c->zc_inject_record.zi_level =
499		    zc->zc_inject_record.zi_level;
500		zc28_c->zc_inject_record.zi_error =
501		    zc->zc_inject_record.zi_error;
502		zc28_c->zc_inject_record.zi_type =
503		    zc->zc_inject_record.zi_type;
504		zc28_c->zc_inject_record.zi_freq =
505		    zc->zc_inject_record.zi_freq;
506		zc28_c->zc_inject_record.zi_failfast =
507		    zc->zc_inject_record.zi_failfast;
508		strlcpy(zc28_c->zc_inject_record.zi_func,
509		    zc->zc_inject_record.zi_func, MAXNAMELEN);
510		zc28_c->zc_inject_record.zi_iotype =
511		    zc->zc_inject_record.zi_iotype;
512		zc28_c->zc_inject_record.zi_duration =
513		    zc->zc_inject_record.zi_duration;
514		zc28_c->zc_inject_record.zi_timer =
515		    zc->zc_inject_record.zi_timer;
516		break;
517
518	case ZFS_CMD_COMPAT_V15:
519		zc_c = (void *)addr;
520
521		/* zc */
522		strlcpy(zc_c->zc_name, zc->zc_name, MAXPATHLEN);
523		strlcpy(zc_c->zc_value, zc->zc_value, MAXPATHLEN);
524		strlcpy(zc_c->zc_string, zc->zc_string, MAXPATHLEN);
525		zc_c->zc_guid = zc->zc_guid;
526		zc_c->zc_nvlist_conf = zc->zc_nvlist_conf;
527		zc_c->zc_nvlist_conf_size = zc->zc_nvlist_conf_size;
528		zc_c->zc_nvlist_src = zc->zc_nvlist_src;
529		zc_c->zc_nvlist_src_size = zc->zc_nvlist_src_size;
530		zc_c->zc_nvlist_dst = zc->zc_nvlist_dst;
531		zc_c->zc_nvlist_dst_size = zc->zc_nvlist_dst_size;
532		zc_c->zc_cookie = zc->zc_cookie;
533		zc_c->zc_objset_type = zc->zc_objset_type;
534		zc_c->zc_perm_action = zc->zc_perm_action;
535		zc_c->zc_history = zc->zc_history;
536		zc_c->zc_history_len = zc->zc_history_len;
537		zc_c->zc_history_offset = zc->zc_history_offset;
538		zc_c->zc_obj = zc->zc_obj;
539		zc_c->zc_share = zc->zc_share;
540		zc_c->zc_jailid = zc->zc_jailid;
541		zc_c->zc_objset_stats = zc->zc_objset_stats;
542
543		/* zc_inject_record */
544		zc_c->zc_inject_record.zi_objset =
545		    zc->zc_inject_record.zi_objset;
546		zc_c->zc_inject_record.zi_object =
547		    zc->zc_inject_record.zi_object;
548		zc_c->zc_inject_record.zi_start =
549		    zc->zc_inject_record.zi_start;
550		zc_c->zc_inject_record.zi_end =
551		    zc->zc_inject_record.zi_end;
552		zc_c->zc_inject_record.zi_guid =
553		    zc->zc_inject_record.zi_guid;
554		zc_c->zc_inject_record.zi_level =
555		    zc->zc_inject_record.zi_level;
556		zc_c->zc_inject_record.zi_error =
557		    zc->zc_inject_record.zi_error;
558		zc_c->zc_inject_record.zi_type =
559		    zc->zc_inject_record.zi_type;
560		zc_c->zc_inject_record.zi_freq =
561		    zc->zc_inject_record.zi_freq;
562		zc_c->zc_inject_record.zi_failfast =
563		    zc->zc_inject_record.zi_failfast;
564
565		break;
566	}
567}
568
569static int
570zfs_ioctl_compat_get_nvlist(uint64_t nvl, size_t size, int iflag,
571    nvlist_t **nvp)
572{
573	char *packed;
574	int error;
575	nvlist_t *list = NULL;
576
577	/*
578	 * Read in and unpack the user-supplied nvlist.
579	 */
580	if (size == 0)
581		return (EINVAL);
582
583#ifdef _KERNEL
584	packed = kmem_alloc(size, KM_SLEEP);
585	if ((error = ddi_copyin((void *)(uintptr_t)nvl, packed, size,
586	    iflag)) != 0) {
587		kmem_free(packed, size);
588		return (error);
589	}
590#else
591	packed = (void *)(uintptr_t)nvl;
592#endif
593
594	error = nvlist_unpack(packed, size, &list, 0);
595
596#ifdef _KERNEL
597	kmem_free(packed, size);
598#endif
599
600	if (error != 0)
601		return (error);
602
603	*nvp = list;
604	return (0);
605}
606
607static int
608zfs_ioctl_compat_put_nvlist(zfs_cmd_t *zc, nvlist_t *nvl)
609{
610	char *packed = NULL;
611	int error = 0;
612	size_t size;
613
614	VERIFY(nvlist_size(nvl, &size, NV_ENCODE_NATIVE) == 0);
615
616#ifdef _KERNEL
617	packed = kmem_alloc(size, KM_SLEEP);
618	VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
619	    KM_SLEEP) == 0);
620
621	if (ddi_copyout(packed,
622	    (void *)(uintptr_t)zc->zc_nvlist_dst, size, zc->zc_iflags) != 0)
623		error = EFAULT;
624	kmem_free(packed, size);
625#else
626	packed = (void *)(uintptr_t)zc->zc_nvlist_dst;
627	VERIFY(nvlist_pack(nvl, &packed, &size, NV_ENCODE_NATIVE,
628	    0) == 0);
629#endif
630
631	zc->zc_nvlist_dst_size = size;
632	return (error);
633}
634
635static void
636zfs_ioctl_compat_fix_stats_nvlist(nvlist_t *nvl)
637{
638	nvlist_t **child;
639	nvlist_t *nvroot = NULL;
640	vdev_stat_t *vs;
641	uint_t c, children, nelem;
642
643	if (nvlist_lookup_nvlist_array(nvl, ZPOOL_CONFIG_CHILDREN,
644	    &child, &children) == 0) {
645		for (c = 0; c < children; c++) {
646			zfs_ioctl_compat_fix_stats_nvlist(child[c]);
647		}
648	}
649
650	if (nvlist_lookup_nvlist(nvl, ZPOOL_CONFIG_VDEV_TREE,
651	    &nvroot) == 0)
652		zfs_ioctl_compat_fix_stats_nvlist(nvroot);
653#ifdef _KERNEL
654	if ((nvlist_lookup_uint64_array(nvl, ZPOOL_CONFIG_VDEV_STATS,
655#else
656	if ((nvlist_lookup_uint64_array(nvl, "stats",
657#endif
658
659	    (uint64_t **)&vs, &nelem) == 0)) {
660		nvlist_add_uint64_array(nvl,
661#ifdef _KERNEL
662		    "stats",
663#else
664		    ZPOOL_CONFIG_VDEV_STATS,
665#endif
666		    (uint64_t *)vs, nelem);
667#ifdef _KERNEL
668		nvlist_remove(nvl, ZPOOL_CONFIG_VDEV_STATS,
669#else
670		nvlist_remove(nvl, "stats",
671#endif
672		    DATA_TYPE_UINT64_ARRAY);
673	}
674}
675
676static int
677zfs_ioctl_compat_fix_stats(zfs_cmd_t *zc, const int nc)
678{
679	nvlist_t *nv, *nvp = NULL;
680	nvpair_t *elem;
681	int error;
682
683	if ((error = zfs_ioctl_compat_get_nvlist(zc->zc_nvlist_dst,
684	    zc->zc_nvlist_dst_size, zc->zc_iflags, &nv)) != 0)
685		return (error);
686
687	if (nc == 5) { /* ZFS_IOC_POOL_STATS */
688		elem = NULL;
689		while ((elem = nvlist_next_nvpair(nv, elem)) != NULL) {
690			if (nvpair_value_nvlist(elem, &nvp) == 0)
691				zfs_ioctl_compat_fix_stats_nvlist(nvp);
692		}
693		elem = NULL;
694	} else
695		zfs_ioctl_compat_fix_stats_nvlist(nv);
696
697	error = zfs_ioctl_compat_put_nvlist(zc, nv);
698
699	nvlist_free(nv);
700
701	return (error);
702}
703
704static int
705zfs_ioctl_compat_pool_get_props(zfs_cmd_t *zc)
706{
707	nvlist_t *nv, *nva = NULL;
708	int error;
709
710	if ((error = zfs_ioctl_compat_get_nvlist(zc->zc_nvlist_dst,
711	    zc->zc_nvlist_dst_size, zc->zc_iflags, &nv)) != 0)
712		return (error);
713
714#ifdef _KERNEL
715	if (nvlist_lookup_nvlist(nv, "allocated", &nva) == 0) {
716		nvlist_add_nvlist(nv, "used", nva);
717		nvlist_remove(nv, "allocated", DATA_TYPE_NVLIST);
718	}
719
720	if (nvlist_lookup_nvlist(nv, "free", &nva) == 0) {
721		nvlist_add_nvlist(nv, "available", nva);
722		nvlist_remove(nv, "free", DATA_TYPE_NVLIST);
723	}
724#else
725	if (nvlist_lookup_nvlist(nv, "used", &nva) == 0) {
726		nvlist_add_nvlist(nv, "allocated", nva);
727		nvlist_remove(nv, "used", DATA_TYPE_NVLIST);
728	}
729
730	if (nvlist_lookup_nvlist(nv, "available", &nva) == 0) {
731		nvlist_add_nvlist(nv, "free", nva);
732		nvlist_remove(nv, "available", DATA_TYPE_NVLIST);
733	}
734#endif
735
736	error = zfs_ioctl_compat_put_nvlist(zc, nv);
737
738	nvlist_free(nv);
739
740	return (error);
741}
742
743#ifndef _KERNEL
744int
745zcmd_ioctl_compat(int fd, int request, zfs_cmd_t *zc, const int cflag)
746{
747	int nc, ret;
748	void *zc_c;
749	unsigned long ncmd;
750	zfs_iocparm_t zp;
751
752	switch (cflag) {
753	case ZFS_CMD_COMPAT_NONE:
754		ncmd = _IOWR('Z', request, struct zfs_iocparm);
755		zp.zfs_cmd = (uint64_t)zc;
756		zp.zfs_cmd_size = sizeof(zfs_cmd_t);
757		zp.zfs_ioctl_version = ZFS_IOCVER_CURRENT;
758		return (ioctl(fd, ncmd, &zp));
759	case ZFS_CMD_COMPAT_EDBP:
760		ncmd = _IOWR('Z', request, struct zfs_iocparm);
761		zp.zfs_cmd = (uint64_t)zc;
762		zp.zfs_cmd_size = sizeof(zfs_cmd_edbp_t);
763		zp.zfs_ioctl_version = ZFS_IOCVER_EDBP;
764		return (ioctl(fd, ncmd, &zp));
765	case ZFS_CMD_COMPAT_ZCMD:
766		ncmd = _IOWR('Z', request, struct zfs_iocparm);
767		zp.zfs_cmd = (uint64_t)zc;
768		zp.zfs_cmd_size = sizeof(zfs_cmd_zcmd_t);
769		zp.zfs_ioctl_version = ZFS_IOCVER_ZCMD;
770		return (ioctl(fd, ncmd, &zp));
771	case ZFS_CMD_COMPAT_LZC:
772		ncmd = _IOWR('Z', request, struct zfs_cmd);
773		return (ioctl(fd, ncmd, zc));
774	case ZFS_CMD_COMPAT_DEADMAN:
775		zc_c = malloc(sizeof(zfs_cmd_deadman_t));
776		ncmd = _IOWR('Z', request, struct zfs_cmd_deadman);
777		break;
778	case ZFS_CMD_COMPAT_V28:
779		zc_c = malloc(sizeof(zfs_cmd_v28_t));
780		ncmd = _IOWR('Z', request, struct zfs_cmd_v28);
781		break;
782	case ZFS_CMD_COMPAT_V15:
783		nc = zfs_ioctl_v28_to_v15[request];
784		zc_c = malloc(sizeof(zfs_cmd_v15_t));
785		ncmd = _IOWR('Z', nc, struct zfs_cmd_v15);
786		break;
787	default:
788		return (EINVAL);
789	}
790
791	if (ZFS_IOCREQ(ncmd) == ZFS_IOC_COMPAT_FAIL)
792		return (ENOTSUP);
793
794	zfs_cmd_compat_put(zc, (caddr_t)zc_c, request, cflag);
795
796	ret = ioctl(fd, ncmd, zc_c);
797	if (cflag == ZFS_CMD_COMPAT_V15 &&
798	    nc == ZFS_IOC_POOL_IMPORT)
799		ret = ioctl(fd, _IOWR('Z', ZFS_IOC_POOL_CONFIGS,
800		    struct zfs_cmd_v15), zc_c);
801	zfs_cmd_compat_get(zc, (caddr_t)zc_c, cflag);
802	free(zc_c);
803
804	if (cflag == ZFS_CMD_COMPAT_V15) {
805		switch (nc) {
806		case ZFS_IOC_POOL_IMPORT:
807		case ZFS_IOC_POOL_CONFIGS:
808		case ZFS_IOC_POOL_STATS:
809		case ZFS_IOC_POOL_TRYIMPORT:
810			zfs_ioctl_compat_fix_stats(zc, nc);
811			break;
812		case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */
813			zfs_ioctl_compat_pool_get_props(zc);
814			break;
815		}
816	}
817
818	return (ret);
819}
820#else /* _KERNEL */
821int
822zfs_ioctl_compat_pre(zfs_cmd_t *zc, int *vec, const int cflag)
823{
824	int error = 0;
825
826	/* are we creating a clone? */
827	if (*vec == ZFS_IOC_CREATE && zc->zc_value[0] != '\0')
828		*vec = ZFS_IOC_CLONE;
829
830	if (cflag == ZFS_CMD_COMPAT_V15) {
831		switch (*vec) {
832
833		case 7: /* ZFS_IOC_POOL_SCRUB (v15) */
834			zc->zc_cookie = POOL_SCAN_SCRUB;
835			break;
836		}
837	}
838
839	return (error);
840}
841
842void
843zfs_ioctl_compat_post(zfs_cmd_t *zc, int vec, const int cflag)
844{
845	if (cflag == ZFS_CMD_COMPAT_V15) {
846		switch (vec) {
847		case ZFS_IOC_POOL_CONFIGS:
848		case ZFS_IOC_POOL_STATS:
849		case ZFS_IOC_POOL_TRYIMPORT:
850			zfs_ioctl_compat_fix_stats(zc, vec);
851			break;
852		case 41: /* ZFS_IOC_POOL_GET_PROPS (v15) */
853			zfs_ioctl_compat_pool_get_props(zc);
854			break;
855		}
856	}
857}
858
859nvlist_t *
860zfs_ioctl_compat_innvl(zfs_cmd_t *zc, nvlist_t * innvl, const int vec,
861    const int cflag)
862{
863	nvlist_t *nvl, *tmpnvl, *hnvl;
864	nvpair_t *elem;
865	char *poolname, *snapname;
866	int err;
867
868	if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC ||
869	    cflag == ZFS_CMD_COMPAT_ZCMD || cflag == ZFS_CMD_COMPAT_EDBP)
870		goto out;
871
872	switch (vec) {
873	case ZFS_IOC_CREATE:
874		nvl = fnvlist_alloc();
875		fnvlist_add_int32(nvl, "type", zc->zc_objset_type);
876		if (innvl != NULL) {
877			fnvlist_add_nvlist(nvl, "props", innvl);
878			nvlist_free(innvl);
879		}
880		return (nvl);
881	break;
882	case ZFS_IOC_CLONE:
883		nvl = fnvlist_alloc();
884		fnvlist_add_string(nvl, "origin", zc->zc_value);
885		if (innvl != NULL) {
886			fnvlist_add_nvlist(nvl, "props", innvl);
887			nvlist_free(innvl);
888		}
889		return (nvl);
890	break;
891	case ZFS_IOC_SNAPSHOT:
892		if (innvl == NULL)
893			goto out;
894		nvl = fnvlist_alloc();
895		fnvlist_add_nvlist(nvl, "props", innvl);
896		tmpnvl = fnvlist_alloc();
897		snapname = kmem_asprintf("%s@%s", zc->zc_name, zc->zc_value);
898		fnvlist_add_boolean(tmpnvl, snapname);
899		kmem_free(snapname, strlen(snapname + 1));
900		/* check if we are doing a recursive snapshot */
901		if (zc->zc_cookie)
902			dmu_get_recursive_snaps_nvl(zc->zc_name, zc->zc_value,
903			    tmpnvl);
904		fnvlist_add_nvlist(nvl, "snaps", tmpnvl);
905		fnvlist_free(tmpnvl);
906		nvlist_free(innvl);
907		/* strip dataset part from zc->zc_name */
908		zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
909		return (nvl);
910	break;
911	case ZFS_IOC_SPACE_SNAPS:
912		nvl = fnvlist_alloc();
913		fnvlist_add_string(nvl, "firstsnap", zc->zc_value);
914		if (innvl != NULL)
915			nvlist_free(innvl);
916		return (nvl);
917	break;
918	case ZFS_IOC_DESTROY_SNAPS:
919		if (innvl == NULL && cflag == ZFS_CMD_COMPAT_DEADMAN)
920			goto out;
921		nvl = fnvlist_alloc();
922		if (innvl != NULL) {
923			fnvlist_add_nvlist(nvl, "snaps", innvl);
924		} else {
925			/*
926			 * We are probably called by even older binaries,
927			 * allocate and populate nvlist with recursive
928			 * snapshots
929			 */
930			if (zfs_component_namecheck(zc->zc_value, NULL,
931			    NULL) == 0) {
932				tmpnvl = fnvlist_alloc();
933				if (dmu_get_recursive_snaps_nvl(zc->zc_name,
934				    zc->zc_value, tmpnvl) == 0)
935					fnvlist_add_nvlist(nvl, "snaps",
936					    tmpnvl);
937				nvlist_free(tmpnvl);
938			}
939		}
940		if (innvl != NULL)
941			nvlist_free(innvl);
942		/* strip dataset part from zc->zc_name */
943		zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
944		return (nvl);
945	break;
946	case ZFS_IOC_HOLD:
947		nvl = fnvlist_alloc();
948		tmpnvl = fnvlist_alloc();
949		if (zc->zc_cleanup_fd != -1)
950			fnvlist_add_int32(nvl, "cleanup_fd",
951			    (int32_t)zc->zc_cleanup_fd);
952		if (zc->zc_cookie) {
953			hnvl = fnvlist_alloc();
954			if (dmu_get_recursive_snaps_nvl(zc->zc_name,
955			    zc->zc_value, hnvl) == 0) {
956				elem = NULL;
957				while ((elem = nvlist_next_nvpair(hnvl,
958				    elem)) != NULL) {
959					nvlist_add_string(tmpnvl,
960					    nvpair_name(elem), zc->zc_string);
961				}
962			}
963			nvlist_free(hnvl);
964		} else {
965			snapname = kmem_asprintf("%s@%s", zc->zc_name,
966			    zc->zc_value);
967			nvlist_add_string(tmpnvl, snapname, zc->zc_string);
968			kmem_free(snapname, strlen(snapname + 1));
969		}
970		fnvlist_add_nvlist(nvl, "holds", tmpnvl);
971		nvlist_free(tmpnvl);
972		if (innvl != NULL)
973			nvlist_free(innvl);
974		/* strip dataset part from zc->zc_name */
975		zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
976		return (nvl);
977	break;
978	case ZFS_IOC_RELEASE:
979		nvl = fnvlist_alloc();
980		tmpnvl = fnvlist_alloc();
981		if (zc->zc_cookie) {
982			hnvl = fnvlist_alloc();
983			if (dmu_get_recursive_snaps_nvl(zc->zc_name,
984			    zc->zc_value, hnvl) == 0) {
985				elem = NULL;
986				while ((elem = nvlist_next_nvpair(hnvl,
987				    elem)) != NULL) {
988					fnvlist_add_boolean(tmpnvl,
989					    zc->zc_string);
990					fnvlist_add_nvlist(nvl,
991					    nvpair_name(elem), tmpnvl);
992				}
993			}
994			nvlist_free(hnvl);
995		} else {
996			snapname = kmem_asprintf("%s@%s", zc->zc_name,
997			    zc->zc_value);
998			fnvlist_add_boolean(tmpnvl, zc->zc_string);
999			fnvlist_add_nvlist(nvl, snapname, tmpnvl);
1000			kmem_free(snapname, strlen(snapname + 1));
1001		}
1002		nvlist_free(tmpnvl);
1003		if (innvl != NULL)
1004			nvlist_free(innvl);
1005		/* strip dataset part from zc->zc_name */
1006		zc->zc_name[strcspn(zc->zc_name, "/@")] = '\0';
1007		return (nvl);
1008	break;
1009	}
1010out:
1011	return (innvl);
1012}
1013
1014nvlist_t *
1015zfs_ioctl_compat_outnvl(zfs_cmd_t *zc, nvlist_t * outnvl, const int vec,
1016    const int cflag)
1017{
1018	nvlist_t *tmpnvl;
1019
1020	if (cflag == ZFS_CMD_COMPAT_NONE || cflag == ZFS_CMD_COMPAT_LZC ||
1021	    cflag == ZFS_CMD_COMPAT_ZCMD || cflag == ZFS_CMD_COMPAT_EDBP)
1022		return (outnvl);
1023
1024	switch (vec) {
1025	case ZFS_IOC_SPACE_SNAPS:
1026		(void) nvlist_lookup_uint64(outnvl, "used", &zc->zc_cookie);
1027		(void) nvlist_lookup_uint64(outnvl, "compressed",
1028		    &zc->zc_objset_type);
1029		(void) nvlist_lookup_uint64(outnvl, "uncompressed",
1030		    &zc->zc_perm_action);
1031		nvlist_free(outnvl);
1032		/* return empty outnvl */
1033		tmpnvl = fnvlist_alloc();
1034		return (tmpnvl);
1035	break;
1036	case ZFS_IOC_CREATE:
1037	case ZFS_IOC_CLONE:
1038	case ZFS_IOC_HOLD:
1039	case ZFS_IOC_RELEASE:
1040		nvlist_free(outnvl);
1041		/* return empty outnvl */
1042		tmpnvl = fnvlist_alloc();
1043		return (tmpnvl);
1044	break;
1045	}
1046
1047	return (outnvl);
1048}
1049#endif /* KERNEL */
1050