1 /*
2 * CDDL HEADER START
3 *
4 * This file and its contents are supplied under the terms of the
5 * Common Development and Distribution License ("CDDL"), version 1.0.
6 * You may only use this file in accordance with the terms of version
7 * 1.0 of the CDDL.
8 *
9 * A full copy of the text of the CDDL should have accompanied this
10 * source. A copy of the CDDL is also available via the Internet at
11 * http://www.illumos.org/license/CDDL.
12 *
13 * CDDL HEADER END
14 */
15
16 /*
17 * Copyright (c) 2018 by Delphix. All rights reserved.
18 * Copyright 2020 Joyent, Inc.
19 */
20
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <strings.h>
27 #include <libzfs_core.h>
28 #include <unistd.h>
29
30 #include <sys/nvpair.h>
31 #include <sys/vdev_impl.h>
32 #include <sys/zfs_ioctl.h>
33 #include <sys/zfs_bootenv.h>
34
35 /*
36 * Test the nvpair inputs for the non-legacy zfs ioctl commands.
37 */
38
39 boolean_t unexpected_failures;
40 int zfs_fd;
41 const char *active_test;
42
43 /*
44 * Tracks which zfs_ioc_t commands were tested
45 */
46 boolean_t ioc_tested[256];
47
48 /*
49 * Legacy ioctls that are skipped (for now)
50 */
51 static unsigned ioc_skip[] = {
52 ZFS_IOC_POOL_CREATE,
53 ZFS_IOC_POOL_DESTROY,
54 ZFS_IOC_POOL_IMPORT,
55 ZFS_IOC_POOL_EXPORT,
56 ZFS_IOC_POOL_CONFIGS,
57 ZFS_IOC_POOL_STATS,
58 ZFS_IOC_POOL_TRYIMPORT,
59 ZFS_IOC_POOL_SCAN,
60 ZFS_IOC_POOL_FREEZE,
61 ZFS_IOC_POOL_UPGRADE,
62 ZFS_IOC_POOL_GET_HISTORY,
63
64 ZFS_IOC_VDEV_ADD,
65 ZFS_IOC_VDEV_REMOVE,
66 ZFS_IOC_VDEV_SET_STATE,
67 ZFS_IOC_VDEV_ATTACH,
68 ZFS_IOC_VDEV_DETACH,
69 ZFS_IOC_VDEV_SETPATH,
70 ZFS_IOC_VDEV_SETFRU,
71
72 ZFS_IOC_OBJSET_STATS,
73 ZFS_IOC_OBJSET_ZPLPROPS,
74 ZFS_IOC_DATASET_LIST_NEXT,
75 ZFS_IOC_SNAPSHOT_LIST_NEXT,
76 ZFS_IOC_SET_PROP,
77 ZFS_IOC_DESTROY,
78 ZFS_IOC_RENAME,
79 ZFS_IOC_RECV,
80 ZFS_IOC_SEND,
81 ZFS_IOC_INJECT_FAULT,
82 ZFS_IOC_CLEAR_FAULT,
83 ZFS_IOC_INJECT_LIST_NEXT,
84 ZFS_IOC_ERROR_LOG,
85 ZFS_IOC_CLEAR,
86 ZFS_IOC_PROMOTE,
87 ZFS_IOC_DSOBJ_TO_DSNAME,
88 ZFS_IOC_OBJ_TO_PATH,
89 ZFS_IOC_POOL_SET_PROPS,
90 ZFS_IOC_POOL_GET_PROPS,
91 ZFS_IOC_SET_FSACL,
92 ZFS_IOC_GET_FSACL,
93 ZFS_IOC_SHARE,
94 ZFS_IOC_INHERIT_PROP,
95 ZFS_IOC_SMB_ACL,
96 ZFS_IOC_USERSPACE_ONE,
97 ZFS_IOC_USERSPACE_MANY,
98 ZFS_IOC_USERSPACE_UPGRADE,
99 ZFS_IOC_OBJSET_RECVD_PROPS,
100 ZFS_IOC_VDEV_SPLIT,
101 ZFS_IOC_NEXT_OBJ,
102 ZFS_IOC_DIFF,
103 ZFS_IOC_TMP_SNAPSHOT,
104 ZFS_IOC_OBJ_TO_STATS,
105 ZFS_IOC_SPACE_WRITTEN,
106 ZFS_IOC_POOL_REGUID,
107 ZFS_IOC_SEND_PROGRESS,
108
109 #ifndef __sun
110 ZFS_IOC_EVENTS_NEXT,
111 ZFS_IOC_EVENTS_CLEAR,
112 ZFS_IOC_EVENTS_SEEK,
113 ZFS_IOC_NEXTBOOT,
114 ZFS_IOC_JAIL,
115 ZFS_IOC_UNJAIL,
116 #else
117 /* This is still a legacy ioctl in illumos */
118 ZFS_IOC_POOL_REOPEN,
119 #endif
120 };
121
122
123 #define IOC_INPUT_TEST(ioc, name, req, opt, err) \
124 IOC_INPUT_TEST_IMPL(ioc, name, req, opt, err, B_FALSE)
125
126 #define IOC_INPUT_TEST_WILD(ioc, name, req, opt, err) \
127 IOC_INPUT_TEST_IMPL(ioc, name, req, opt, err, B_TRUE)
128
129 #define IOC_INPUT_TEST_IMPL(ioc, name, req, opt, err, wild) \
130 do { \
131 active_test = __func__ + 5; \
132 ioc_tested[ioc - ZFS_IOC_FIRST] = B_TRUE; \
133 (void) lzc_ioctl_test(ioc, name, req, opt, err, wild); \
134 } while (0)
135
136 /*
137 * run a zfs ioctl command, verify expected results and log failures
138 */
139 static void
lzc_ioctl_run(zfs_ioc_t ioc,const char * name,nvlist_t * innvl,int expected)140 lzc_ioctl_run(zfs_ioc_t ioc, const char *name, nvlist_t *innvl, int expected)
141 {
142 zfs_cmd_t zc = {"\0"};
143 char *packed = NULL;
144 const char *variant;
145 size_t size = 0;
146 int error = 0;
147
148 switch (expected) {
149 case ZFS_ERR_IOC_ARG_UNAVAIL:
150 variant = "unsupported input";
151 break;
152 case ZFS_ERR_IOC_ARG_REQUIRED:
153 variant = "missing input";
154 break;
155 case ZFS_ERR_IOC_ARG_BADTYPE:
156 variant = "invalid input type";
157 break;
158 default:
159 variant = "valid input";
160 break;
161 }
162
163 packed = fnvlist_pack(innvl, &size);
164 (void) strncpy(zc.zc_name, name, sizeof (zc.zc_name));
165 zc.zc_name[sizeof (zc.zc_name) - 1] = '\0';
166 zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed;
167 zc.zc_nvlist_src_size = size;
168 zc.zc_nvlist_dst_size = MAX(size * 2, 128 * 1024);
169 zc.zc_nvlist_dst = (uint64_t)(uintptr_t)malloc(zc.zc_nvlist_dst_size);
170
171 if (ioctl(zfs_fd, ioc, &zc) != 0)
172 error = errno;
173
174 if (error != expected) {
175 unexpected_failures = B_TRUE;
176 (void) fprintf(stderr, "%s: Unexpected result with %s, "
177 "error %d (expecting %d)\n",
178 active_test, variant, error, expected);
179 }
180
181 fnvlist_pack_free(packed, size);
182 free((void *)(uintptr_t)zc.zc_nvlist_dst);
183 }
184
185 /*
186 * Test each ioc for the following ioctl input errors:
187 * ZFS_ERR_IOC_ARG_UNAVAIL an input argument is not supported by kernel
188 * ZFS_ERR_IOC_ARG_REQUIRED a required input argument is missing
189 * ZFS_ERR_IOC_ARG_BADTYPE an input argument has an invalid type
190 */
191 static int
lzc_ioctl_test(zfs_ioc_t ioc,const char * name,nvlist_t * required,nvlist_t * optional,int expected_error,boolean_t wildcard)192 lzc_ioctl_test(zfs_ioc_t ioc, const char *name, nvlist_t *required,
193 nvlist_t *optional, int expected_error, boolean_t wildcard)
194 {
195 nvlist_t *input = fnvlist_alloc();
196 nvlist_t *future = fnvlist_alloc();
197 int error = 0;
198
199 if (required != NULL) {
200 for (nvpair_t *pair = nvlist_next_nvpair(required, NULL);
201 pair != NULL; pair = nvlist_next_nvpair(required, pair)) {
202 fnvlist_add_nvpair(input, pair);
203 }
204 }
205 if (optional != NULL) {
206 for (nvpair_t *pair = nvlist_next_nvpair(optional, NULL);
207 pair != NULL; pair = nvlist_next_nvpair(optional, pair)) {
208 fnvlist_add_nvpair(input, pair);
209 }
210 }
211
212 /*
213 * Generic input run with 'optional' nvlist pair
214 */
215 if (!wildcard)
216 fnvlist_add_nvlist(input, "optional", future);
217 lzc_ioctl_run(ioc, name, input, expected_error);
218 if (!wildcard)
219 fnvlist_remove(input, "optional");
220
221 /*
222 * Bogus input value
223 */
224 if (!wildcard) {
225 fnvlist_add_string(input, "bogus_input", "bogus");
226 lzc_ioctl_run(ioc, name, input, ZFS_ERR_IOC_ARG_UNAVAIL);
227 fnvlist_remove(input, "bogus_input");
228 }
229
230 /*
231 * Missing required inputs
232 */
233 if (required != NULL) {
234 nvlist_t *empty = fnvlist_alloc();
235 lzc_ioctl_run(ioc, name, empty, ZFS_ERR_IOC_ARG_REQUIRED);
236 nvlist_free(empty);
237 }
238
239 /*
240 * Wrong nvpair type
241 */
242 if (required != NULL || optional != NULL) {
243 /*
244 * switch the type of one of the input pairs
245 */
246 for (nvpair_t *pair = nvlist_next_nvpair(input, NULL);
247 pair != NULL; pair = nvlist_next_nvpair(input, pair)) {
248 char pname[MAXNAMELEN];
249 data_type_t ptype;
250
251 (void) strncpy(pname, nvpair_name(pair),
252 sizeof (pname));
253 pname[sizeof (pname) - 1] = '\0';
254 ptype = nvpair_type(pair);
255 fnvlist_remove_nvpair(input, pair);
256
257 switch (ptype) {
258 case DATA_TYPE_STRING:
259 fnvlist_add_uint64(input, pname, 42);
260 break;
261 default:
262 fnvlist_add_string(input, pname, "bogus");
263 break;
264 }
265 }
266 lzc_ioctl_run(ioc, name, input, ZFS_ERR_IOC_ARG_BADTYPE);
267 }
268
269 nvlist_free(future);
270 nvlist_free(input);
271
272 return (error);
273 }
274
275 static void
test_pool_sync(const char * pool)276 test_pool_sync(const char *pool)
277 {
278 nvlist_t *required = fnvlist_alloc();
279
280 fnvlist_add_boolean_value(required, "force", B_TRUE);
281
282 IOC_INPUT_TEST(ZFS_IOC_POOL_SYNC, pool, required, NULL, 0);
283
284 nvlist_free(required);
285 }
286
287 #ifndef sun
288 static void
test_pool_reopen(const char * pool)289 test_pool_reopen(const char *pool)
290 {
291 nvlist_t *required = fnvlist_alloc();
292
293 fnvlist_add_boolean_value(required, "scrub_restart", B_FALSE);
294
295 IOC_INPUT_TEST(ZFS_IOC_POOL_REOPEN, pool, required, NULL, 0);
296
297 nvlist_free(required);
298 }
299 #endif
300
301 static void
test_pool_checkpoint(const char * pool)302 test_pool_checkpoint(const char *pool)
303 {
304 IOC_INPUT_TEST(ZFS_IOC_POOL_CHECKPOINT, pool, NULL, NULL, 0);
305 }
306
307 static void
test_pool_discard_checkpoint(const char * pool)308 test_pool_discard_checkpoint(const char *pool)
309 {
310 int err = lzc_pool_checkpoint(pool);
311 if (err == 0 || err == ZFS_ERR_CHECKPOINT_EXISTS)
312 IOC_INPUT_TEST(ZFS_IOC_POOL_DISCARD_CHECKPOINT, pool, NULL,
313 NULL, 0);
314 }
315
316 static void
test_log_history(const char * pool)317 test_log_history(const char *pool)
318 {
319 nvlist_t *required = fnvlist_alloc();
320
321 fnvlist_add_string(required, "message", "input check");
322
323 IOC_INPUT_TEST(ZFS_IOC_LOG_HISTORY, pool, required, NULL, 0);
324
325 nvlist_free(required);
326 }
327
328 static void
test_create(const char * pool)329 test_create(const char *pool)
330 {
331 char dataset[MAXNAMELEN + 32];
332
333 (void) snprintf(dataset, sizeof (dataset), "%s/create-fs", pool);
334
335 nvlist_t *required = fnvlist_alloc();
336 nvlist_t *optional = fnvlist_alloc();
337 nvlist_t *props = fnvlist_alloc();
338
339 fnvlist_add_int32(required, "type", DMU_OST_ZFS);
340 fnvlist_add_uint64(props, "recordsize", 8192);
341 fnvlist_add_nvlist(optional, "props", props);
342
343 IOC_INPUT_TEST(ZFS_IOC_CREATE, dataset, required, optional, 0);
344
345 nvlist_free(required);
346 nvlist_free(optional);
347 }
348
349 static void
test_snapshot(const char * pool,const char * snapshot)350 test_snapshot(const char *pool, const char *snapshot)
351 {
352 nvlist_t *required = fnvlist_alloc();
353 nvlist_t *optional = fnvlist_alloc();
354 nvlist_t *snaps = fnvlist_alloc();
355 nvlist_t *props = fnvlist_alloc();
356
357 fnvlist_add_boolean(snaps, snapshot);
358 fnvlist_add_nvlist(required, "snaps", snaps);
359
360 fnvlist_add_string(props, "org.openzfs:launch", "September 17th, 2013");
361 fnvlist_add_nvlist(optional, "props", props);
362
363 IOC_INPUT_TEST(ZFS_IOC_SNAPSHOT, pool, required, optional, 0);
364
365 nvlist_free(props);
366 nvlist_free(snaps);
367 nvlist_free(optional);
368 nvlist_free(required);
369 }
370
371 static void
test_space_snaps(const char * snapshot)372 test_space_snaps(const char *snapshot)
373 {
374 nvlist_t *required = fnvlist_alloc();
375 fnvlist_add_string(required, "firstsnap", snapshot);
376
377 IOC_INPUT_TEST(ZFS_IOC_SPACE_SNAPS, snapshot, required, NULL, 0);
378
379 nvlist_free(required);
380 }
381
382 static void
test_destroy_snaps(const char * pool,const char * snapshot)383 test_destroy_snaps(const char *pool, const char *snapshot)
384 {
385 nvlist_t *required = fnvlist_alloc();
386 nvlist_t *snaps = fnvlist_alloc();
387
388 fnvlist_add_boolean(snaps, snapshot);
389 fnvlist_add_nvlist(required, "snaps", snaps);
390
391 IOC_INPUT_TEST(ZFS_IOC_DESTROY_SNAPS, pool, required, NULL, 0);
392
393 nvlist_free(snaps);
394 nvlist_free(required);
395 }
396
397
398 static void
test_bookmark(const char * pool,const char * snapshot,const char * bookmark)399 test_bookmark(const char *pool, const char *snapshot, const char *bookmark)
400 {
401 nvlist_t *required = fnvlist_alloc();
402
403 fnvlist_add_string(required, bookmark, snapshot);
404
405 IOC_INPUT_TEST_WILD(ZFS_IOC_BOOKMARK, pool, required, NULL, 0);
406
407 nvlist_free(required);
408 }
409
410 static void
test_get_bookmarks(const char * dataset)411 test_get_bookmarks(const char *dataset)
412 {
413 nvlist_t *optional = fnvlist_alloc();
414
415 fnvlist_add_boolean(optional, "guid");
416 fnvlist_add_boolean(optional, "createtxg");
417 fnvlist_add_boolean(optional, "creation");
418
419 IOC_INPUT_TEST_WILD(ZFS_IOC_GET_BOOKMARKS, dataset, NULL, optional, 0);
420
421 nvlist_free(optional);
422 }
423
424 static void
test_destroy_bookmarks(const char * pool,const char * bookmark)425 test_destroy_bookmarks(const char *pool, const char *bookmark)
426 {
427 nvlist_t *required = fnvlist_alloc();
428
429 fnvlist_add_boolean(required, bookmark);
430
431 IOC_INPUT_TEST_WILD(ZFS_IOC_DESTROY_BOOKMARKS, pool, required, NULL, 0);
432
433 nvlist_free(required);
434 }
435
436 static void
test_clone(const char * snapshot,const char * clone)437 test_clone(const char *snapshot, const char *clone)
438 {
439 nvlist_t *required = fnvlist_alloc();
440 nvlist_t *optional = fnvlist_alloc();
441 nvlist_t *props = fnvlist_alloc();
442
443 fnvlist_add_string(required, "origin", snapshot);
444
445 IOC_INPUT_TEST(ZFS_IOC_CLONE, clone, required, NULL, 0);
446
447 nvlist_free(props);
448 nvlist_free(optional);
449 nvlist_free(required);
450 }
451
452 static void
test_rollback(const char * dataset,const char * snapshot)453 test_rollback(const char *dataset, const char *snapshot)
454 {
455 nvlist_t *optional = fnvlist_alloc();
456
457 fnvlist_add_string(optional, "target", snapshot);
458
459 IOC_INPUT_TEST(ZFS_IOC_ROLLBACK, dataset, NULL, optional, B_FALSE);
460
461 nvlist_free(optional);
462 }
463
464 static void
test_hold(const char * pool,const char * snapshot)465 test_hold(const char *pool, const char *snapshot)
466 {
467 nvlist_t *required = fnvlist_alloc();
468 nvlist_t *optional = fnvlist_alloc();
469 nvlist_t *holds = fnvlist_alloc();
470
471 fnvlist_add_string(holds, snapshot, "libzfs_check_hold");
472 fnvlist_add_nvlist(required, "holds", holds);
473 fnvlist_add_int32(optional, "cleanup_fd", zfs_fd);
474
475 IOC_INPUT_TEST(ZFS_IOC_HOLD, pool, required, optional, 0);
476
477 nvlist_free(holds);
478 nvlist_free(optional);
479 nvlist_free(required);
480 }
481
482 static void
test_get_holds(const char * snapshot)483 test_get_holds(const char *snapshot)
484 {
485 IOC_INPUT_TEST(ZFS_IOC_GET_HOLDS, snapshot, NULL, NULL, 0);
486 }
487
488 static void
test_release(const char * pool,const char * snapshot)489 test_release(const char *pool, const char *snapshot)
490 {
491 nvlist_t *required = fnvlist_alloc();
492 nvlist_t *release = fnvlist_alloc();
493
494 fnvlist_add_boolean(release, "libzfs_check_hold");
495 fnvlist_add_nvlist(required, snapshot, release);
496
497 IOC_INPUT_TEST_WILD(ZFS_IOC_RELEASE, pool, required, NULL, 0);
498
499 nvlist_free(release);
500 nvlist_free(required);
501 }
502
503
504 static void
test_send_new(const char * snapshot,int fd)505 test_send_new(const char *snapshot, int fd)
506 {
507 nvlist_t *required = fnvlist_alloc();
508 nvlist_t *optional = fnvlist_alloc();
509
510 fnvlist_add_int32(required, "fd", fd);
511
512 fnvlist_add_boolean(optional, "largeblockok");
513 fnvlist_add_boolean(optional, "embedok");
514 fnvlist_add_boolean(optional, "compressok");
515 fnvlist_add_boolean(optional, "rawok");
516
517 /*
518 * TODO - Resumable send is harder to set up. So we currently
519 * ignore testing for that variant.
520 */
521 #if 0
522 fnvlist_add_string(optional, "fromsnap", from);
523 fnvlist_add_uint64(optional, "resume_object", resumeobj);
524 fnvlist_add_uint64(optional, "resume_offset", offset);
525 #endif
526 IOC_INPUT_TEST(ZFS_IOC_SEND_NEW, snapshot, required, optional, 0);
527
528 nvlist_free(optional);
529 nvlist_free(required);
530 }
531
532 #ifndef __sun
533 static void
test_recv_new(const char * dataset,int fd)534 test_recv_new(const char *dataset, int fd)
535 {
536 dmu_replay_record_t drr = { 0 };
537 nvlist_t *required = fnvlist_alloc();
538 nvlist_t *optional = fnvlist_alloc();
539 nvlist_t *props = fnvlist_alloc();
540 char snapshot[MAXNAMELEN + 32];
541 ssize_t count;
542
543 int cleanup_fd = open(ZFS_DEV, O_RDWR);
544
545 (void) snprintf(snapshot, sizeof (snapshot), "%s@replicant", dataset);
546
547 count = pread(fd, &drr, sizeof (drr), 0);
548 if (count != sizeof (drr)) {
549 (void) fprintf(stderr, "could not read stream: %s\n",
550 strerror(errno));
551 }
552
553 fnvlist_add_string(required, "snapname", snapshot);
554 fnvlist_add_byte_array(required, "begin_record", (uchar_t *)&drr,
555 sizeof (drr));
556 fnvlist_add_int32(required, "input_fd", fd);
557
558 fnvlist_add_string(props, "org.openzfs:launch", "September 17th, 2013");
559 fnvlist_add_nvlist(optional, "localprops", props);
560 fnvlist_add_boolean(optional, "force");
561 fnvlist_add_int32(optional, "cleanup_fd", cleanup_fd);
562
563 /*
564 * TODO - Resumable receive is harder to set up. So we currently
565 * ignore testing for one.
566 */
567 #if 0
568 fnvlist_add_nvlist(optional, "props", recvdprops);
569 fnvlist_add_string(optional, "origin", origin);
570 fnvlist_add_boolean(optional, "resumable");
571 fnvlist_add_uint64(optional, "action_handle", *action_handle);
572 #endif
573 IOC_INPUT_TEST(ZFS_IOC_RECV_NEW, dataset, required, optional, EBADE);
574
575 nvlist_free(props);
576 nvlist_free(optional);
577 nvlist_free(required);
578
579 (void) close(cleanup_fd);
580 }
581 #endif
582
583 static void
test_send_space(const char * snapshot1,const char * snapshot2)584 test_send_space(const char *snapshot1, const char *snapshot2)
585 {
586 nvlist_t *optional = fnvlist_alloc();
587
588 fnvlist_add_string(optional, "from", snapshot1);
589 fnvlist_add_boolean(optional, "largeblockok");
590 fnvlist_add_boolean(optional, "embedok");
591 fnvlist_add_boolean(optional, "compressok");
592 fnvlist_add_boolean(optional, "rawok");
593
594 IOC_INPUT_TEST(ZFS_IOC_SEND_SPACE, snapshot2, NULL, optional, 0);
595
596 nvlist_free(optional);
597 }
598
599 static void
test_remap(const char * dataset)600 test_remap(const char *dataset)
601 {
602 IOC_INPUT_TEST(ZFS_IOC_REMAP, dataset, NULL, NULL, 0);
603 }
604
605 static void
test_channel_program(const char * pool)606 test_channel_program(const char *pool)
607 {
608 const char *program =
609 "arg = ...\n"
610 "argv = arg[\"argv\"]\n"
611 "return argv[1]";
612 char *const argv[1] = { "Hello World!" };
613 nvlist_t *required = fnvlist_alloc();
614 nvlist_t *optional = fnvlist_alloc();
615 nvlist_t *args = fnvlist_alloc();
616
617 fnvlist_add_string(required, "program", program);
618 fnvlist_add_string_array(args, "argv", argv, 1);
619 fnvlist_add_nvlist(required, "arg", args);
620
621 fnvlist_add_boolean_value(optional, "sync", B_TRUE);
622 fnvlist_add_uint64(optional, "instrlimit", 1000 * 1000);
623 fnvlist_add_uint64(optional, "memlimit", 8192 * 1024);
624
625 IOC_INPUT_TEST(ZFS_IOC_CHANNEL_PROGRAM, pool, required, optional, 0);
626
627 nvlist_free(args);
628 nvlist_free(optional);
629 nvlist_free(required);
630 }
631
632 #define WRAPPING_KEY_LEN 32
633
634 static void
test_load_key(const char * dataset)635 test_load_key(const char *dataset)
636 {
637 nvlist_t *required = fnvlist_alloc();
638 nvlist_t *optional = fnvlist_alloc();
639 nvlist_t *hidden = fnvlist_alloc();
640 uint8_t keydata[WRAPPING_KEY_LEN] = {0};
641
642 fnvlist_add_uint8_array(hidden, "wkeydata", keydata, sizeof (keydata));
643 fnvlist_add_nvlist(required, "hidden_args", hidden);
644 fnvlist_add_boolean(optional, "noop");
645
646 IOC_INPUT_TEST(ZFS_IOC_LOAD_KEY, dataset, required, optional, EINVAL);
647 nvlist_free(hidden);
648 nvlist_free(optional);
649 nvlist_free(required);
650 }
651
652 static void
test_change_key(const char * dataset)653 test_change_key(const char *dataset)
654 {
655 IOC_INPUT_TEST(ZFS_IOC_CHANGE_KEY, dataset, NULL, NULL, EINVAL);
656 }
657
658 static void
test_unload_key(const char * dataset)659 test_unload_key(const char *dataset)
660 {
661 IOC_INPUT_TEST(ZFS_IOC_UNLOAD_KEY, dataset, NULL, NULL, EACCES);
662 }
663
664 static void
test_vdev_initialize(const char * pool)665 test_vdev_initialize(const char *pool)
666 {
667 nvlist_t *required = fnvlist_alloc();
668 nvlist_t *vdev_guids = fnvlist_alloc();
669
670 fnvlist_add_uint64(vdev_guids, "path", 0xdeadbeefdeadbeef);
671 fnvlist_add_uint64(required, ZPOOL_INITIALIZE_COMMAND,
672 POOL_INITIALIZE_START);
673 fnvlist_add_nvlist(required, ZPOOL_INITIALIZE_VDEVS, vdev_guids);
674
675 IOC_INPUT_TEST(ZFS_IOC_POOL_INITIALIZE, pool, required, NULL, EINVAL);
676 nvlist_free(vdev_guids);
677 nvlist_free(required);
678 }
679
680 static void
test_vdev_trim(const char * pool)681 test_vdev_trim(const char *pool)
682 {
683 nvlist_t *required = fnvlist_alloc();
684 nvlist_t *optional = fnvlist_alloc();
685 nvlist_t *vdev_guids = fnvlist_alloc();
686
687 fnvlist_add_uint64(vdev_guids, "path", 0xdeadbeefdeadbeef);
688 fnvlist_add_uint64(required, ZPOOL_TRIM_COMMAND, POOL_TRIM_START);
689 fnvlist_add_nvlist(required, ZPOOL_TRIM_VDEVS, vdev_guids);
690 fnvlist_add_uint64(optional, ZPOOL_TRIM_RATE, 1ULL << 30);
691 fnvlist_add_boolean_value(optional, ZPOOL_TRIM_SECURE, B_TRUE);
692
693 IOC_INPUT_TEST(ZFS_IOC_POOL_TRIM, pool, required, optional, EINVAL);
694 nvlist_free(vdev_guids);
695 nvlist_free(optional);
696 nvlist_free(required);
697 }
698
699 static int
zfs_destroy(const char * dataset)700 zfs_destroy(const char *dataset)
701 {
702 zfs_cmd_t zc = {"\0"};
703 int err;
704
705 (void) strncpy(zc.zc_name, dataset, sizeof (zc.zc_name));
706 zc.zc_name[sizeof (zc.zc_name) - 1] = '\0';
707 zc.zc_objset_type = DMU_OST_ZFS;
708 err = ioctl(zfs_fd, ZFS_IOC_DESTROY, &zc);
709
710 return (err == 0 ? 0 : errno);
711 }
712
713 static void
test_get_bootenv(const char * pool)714 test_get_bootenv(const char *pool)
715 {
716 IOC_INPUT_TEST(ZFS_IOC_GET_BOOTENV, pool, NULL, NULL, 0);
717 }
718
719 static void
test_set_bootenv(const char * pool)720 test_set_bootenv(const char *pool)
721 {
722 nvlist_t *required = fnvlist_alloc();
723
724 fnvlist_add_uint64(required, "version", VB_RAW);
725 fnvlist_add_string(required, GRUB_ENVMAP, "test");
726
727 IOC_INPUT_TEST_WILD(ZFS_IOC_SET_BOOTENV, pool, required, NULL, 0);
728
729 nvlist_free(required);
730 }
731
732 static void
zfs_ioc_input_tests(const char * pool)733 zfs_ioc_input_tests(const char *pool)
734 {
735 char filepath[] = "/tmp/ioc_test_file_XXXXXX";
736 char dataset[ZFS_MAX_DATASET_NAME_LEN];
737 char snapbase[ZFS_MAX_DATASET_NAME_LEN + 32];
738 char snapshot[ZFS_MAX_DATASET_NAME_LEN + 32];
739 char bookmark[ZFS_MAX_DATASET_NAME_LEN + 32];
740 char backup[ZFS_MAX_DATASET_NAME_LEN];
741 char clone[ZFS_MAX_DATASET_NAME_LEN];
742 int tmpfd, err;
743
744 /*
745 * Setup names and create a working dataset
746 */
747 (void) snprintf(dataset, sizeof (dataset), "%s/test-fs", pool);
748 (void) snprintf(snapbase, sizeof (snapbase), "%s@snapbase", dataset);
749 (void) snprintf(snapshot, sizeof (snapshot), "%s@snapshot", dataset);
750 (void) snprintf(bookmark, sizeof (bookmark), "%s#bookmark", dataset);
751 (void) snprintf(clone, sizeof (clone), "%s/test-fs-clone", pool);
752 (void) snprintf(backup, sizeof (backup), "%s/backup", pool);
753
754 err = lzc_create(dataset, LZC_DATSET_TYPE_ZFS, NULL, NULL, 0);
755 if (err) {
756 (void) fprintf(stderr, "could not create '%s': %s\n",
757 dataset, strerror(errno));
758 exit(2);
759 }
760
761 tmpfd = mkstemp(filepath);
762 if (tmpfd < 0) {
763 (void) fprintf(stderr, "could not create '%s': %s\n",
764 filepath, strerror(errno));
765 exit(2);
766 }
767
768 /*
769 * run a test for each ioctl
770 * Note that some test build on previous test operations
771 */
772 test_pool_sync(pool);
773 #ifndef __sun
774 test_pool_reopen(pool);
775 #endif
776 test_pool_checkpoint(pool);
777 test_pool_discard_checkpoint(pool);
778 test_log_history(pool);
779
780 test_create(dataset);
781 test_snapshot(pool, snapbase);
782 test_snapshot(pool, snapshot);
783
784 test_space_snaps(snapshot);
785 test_send_space(snapbase, snapshot);
786 test_send_new(snapshot, tmpfd);
787 #ifndef __sun
788 test_recv_new(backup, tmpfd);
789 #endif
790
791 test_bookmark(pool, snapshot, bookmark);
792 test_get_bookmarks(dataset);
793 test_destroy_bookmarks(pool, bookmark);
794
795 test_hold(pool, snapshot);
796 test_get_holds(snapshot);
797 test_release(pool, snapshot);
798
799 test_clone(snapshot, clone);
800 (void) zfs_destroy(clone);
801
802 test_rollback(dataset, snapshot);
803 test_destroy_snaps(pool, snapshot);
804 test_destroy_snaps(pool, snapbase);
805
806 test_remap(dataset);
807 test_channel_program(pool);
808
809 test_load_key(dataset);
810 test_change_key(dataset);
811 test_unload_key(dataset);
812
813 test_vdev_initialize(pool);
814 test_vdev_trim(pool);
815
816 test_set_bootenv(pool);
817 test_get_bootenv(pool);
818
819 /*
820 * cleanup
821 */
822 zfs_cmd_t zc = {"\0"};
823
824 nvlist_t *snaps = fnvlist_alloc();
825 fnvlist_add_boolean(snaps, snapshot);
826 (void) lzc_destroy_snaps(snaps, B_FALSE, NULL);
827 nvlist_free(snaps);
828
829 (void) zfs_destroy(dataset);
830 (void) zfs_destroy(backup);
831
832 (void) close(tmpfd);
833 (void) unlink(filepath);
834
835 /*
836 * All the unused slots should yield ZFS_ERR_IOC_CMD_UNAVAIL
837 */
838 for (int i = 0; i < ARRAY_SIZE(ioc_skip); i++) {
839 if (ioc_tested[ioc_skip[i] - ZFS_IOC_FIRST])
840 (void) fprintf(stderr, "cmd %d tested, not skipped!\n",
841 (int)(ioc_skip[i] - ZFS_IOC_FIRST));
842
843 ioc_tested[ioc_skip[i] - ZFS_IOC_FIRST] = B_TRUE;
844 }
845
846 (void) strncpy(zc.zc_name, pool, sizeof (zc.zc_name));
847 zc.zc_name[sizeof (zc.zc_name) - 1] = '\0';
848
849 for (unsigned ioc = ZFS_IOC_FIRST; ioc < ZFS_IOC_LAST; ioc++) {
850 unsigned cmd = ioc - ZFS_IOC_FIRST;
851
852 if (ioc_tested[cmd])
853 continue;
854
855 if (ioctl(zfs_fd, ioc, &zc) != 0 &&
856 errno != ZFS_ERR_IOC_CMD_UNAVAIL) {
857 (void) fprintf(stderr, "cmd %d is missing a test case "
858 "(%d)\n", cmd, errno);
859 }
860 }
861 }
862
863 enum zfs_ioc_ref {
864 #ifdef __FreeBSD__
865 ZFS_IOC_BASE = 0,
866 #else
867 ZFS_IOC_BASE = ('Z' << 8),
868 #endif
869 ZFS_IOC_PLATFORM_BASE = ZFS_IOC_BASE + 0x80,
870 };
871
872 /*
873 * Canonical reference check of /dev/zfs ioctl numbers.
874 * These cannot change and new ioctl numbers must be appended.
875 */
876 boolean_t
validate_ioc_values(void)877 validate_ioc_values(void)
878 {
879 boolean_t result = B_TRUE;
880
881 #define CHECK(expr) do { \
882 if (!(expr)) { \
883 result = B_FALSE; \
884 fprintf(stderr, "(%s) === FALSE\n", #expr); \
885 } \
886 } while (0)
887
888 CHECK(ZFS_IOC_BASE + 0 == ZFS_IOC_POOL_CREATE);
889 CHECK(ZFS_IOC_BASE + 1 == ZFS_IOC_POOL_DESTROY);
890 CHECK(ZFS_IOC_BASE + 2 == ZFS_IOC_POOL_IMPORT);
891 CHECK(ZFS_IOC_BASE + 3 == ZFS_IOC_POOL_EXPORT);
892 CHECK(ZFS_IOC_BASE + 4 == ZFS_IOC_POOL_CONFIGS);
893 CHECK(ZFS_IOC_BASE + 5 == ZFS_IOC_POOL_STATS);
894 CHECK(ZFS_IOC_BASE + 6 == ZFS_IOC_POOL_TRYIMPORT);
895 CHECK(ZFS_IOC_BASE + 7 == ZFS_IOC_POOL_SCAN);
896 CHECK(ZFS_IOC_BASE + 8 == ZFS_IOC_POOL_FREEZE);
897 CHECK(ZFS_IOC_BASE + 9 == ZFS_IOC_POOL_UPGRADE);
898 CHECK(ZFS_IOC_BASE + 10 == ZFS_IOC_POOL_GET_HISTORY);
899 CHECK(ZFS_IOC_BASE + 11 == ZFS_IOC_VDEV_ADD);
900 CHECK(ZFS_IOC_BASE + 12 == ZFS_IOC_VDEV_REMOVE);
901 CHECK(ZFS_IOC_BASE + 13 == ZFS_IOC_VDEV_SET_STATE);
902 CHECK(ZFS_IOC_BASE + 14 == ZFS_IOC_VDEV_ATTACH);
903 CHECK(ZFS_IOC_BASE + 15 == ZFS_IOC_VDEV_DETACH);
904 CHECK(ZFS_IOC_BASE + 16 == ZFS_IOC_VDEV_SETPATH);
905 CHECK(ZFS_IOC_BASE + 17 == ZFS_IOC_VDEV_SETFRU);
906 CHECK(ZFS_IOC_BASE + 18 == ZFS_IOC_OBJSET_STATS);
907 CHECK(ZFS_IOC_BASE + 19 == ZFS_IOC_OBJSET_ZPLPROPS);
908 CHECK(ZFS_IOC_BASE + 20 == ZFS_IOC_DATASET_LIST_NEXT);
909 CHECK(ZFS_IOC_BASE + 21 == ZFS_IOC_SNAPSHOT_LIST_NEXT);
910 CHECK(ZFS_IOC_BASE + 22 == ZFS_IOC_SET_PROP);
911 CHECK(ZFS_IOC_BASE + 23 == ZFS_IOC_CREATE);
912 CHECK(ZFS_IOC_BASE + 24 == ZFS_IOC_DESTROY);
913 CHECK(ZFS_IOC_BASE + 25 == ZFS_IOC_ROLLBACK);
914 CHECK(ZFS_IOC_BASE + 26 == ZFS_IOC_RENAME);
915 CHECK(ZFS_IOC_BASE + 27 == ZFS_IOC_RECV);
916 CHECK(ZFS_IOC_BASE + 28 == ZFS_IOC_SEND);
917 CHECK(ZFS_IOC_BASE + 29 == ZFS_IOC_INJECT_FAULT);
918 CHECK(ZFS_IOC_BASE + 30 == ZFS_IOC_CLEAR_FAULT);
919 CHECK(ZFS_IOC_BASE + 31 == ZFS_IOC_INJECT_LIST_NEXT);
920 CHECK(ZFS_IOC_BASE + 32 == ZFS_IOC_ERROR_LOG);
921 CHECK(ZFS_IOC_BASE + 33 == ZFS_IOC_CLEAR);
922 CHECK(ZFS_IOC_BASE + 34 == ZFS_IOC_PROMOTE);
923 CHECK(ZFS_IOC_BASE + 35 == ZFS_IOC_SNAPSHOT);
924 CHECK(ZFS_IOC_BASE + 36 == ZFS_IOC_DSOBJ_TO_DSNAME);
925 CHECK(ZFS_IOC_BASE + 37 == ZFS_IOC_OBJ_TO_PATH);
926 CHECK(ZFS_IOC_BASE + 38 == ZFS_IOC_POOL_SET_PROPS);
927 CHECK(ZFS_IOC_BASE + 39 == ZFS_IOC_POOL_GET_PROPS);
928 CHECK(ZFS_IOC_BASE + 40 == ZFS_IOC_SET_FSACL);
929 CHECK(ZFS_IOC_BASE + 41 == ZFS_IOC_GET_FSACL);
930 CHECK(ZFS_IOC_BASE + 42 == ZFS_IOC_SHARE);
931 CHECK(ZFS_IOC_BASE + 43 == ZFS_IOC_INHERIT_PROP);
932 CHECK(ZFS_IOC_BASE + 44 == ZFS_IOC_SMB_ACL);
933 CHECK(ZFS_IOC_BASE + 45 == ZFS_IOC_USERSPACE_ONE);
934 CHECK(ZFS_IOC_BASE + 46 == ZFS_IOC_USERSPACE_MANY);
935 CHECK(ZFS_IOC_BASE + 47 == ZFS_IOC_USERSPACE_UPGRADE);
936 CHECK(ZFS_IOC_BASE + 48 == ZFS_IOC_HOLD);
937 CHECK(ZFS_IOC_BASE + 49 == ZFS_IOC_RELEASE);
938 CHECK(ZFS_IOC_BASE + 50 == ZFS_IOC_GET_HOLDS);
939 CHECK(ZFS_IOC_BASE + 51 == ZFS_IOC_OBJSET_RECVD_PROPS);
940 CHECK(ZFS_IOC_BASE + 52 == ZFS_IOC_VDEV_SPLIT);
941 CHECK(ZFS_IOC_BASE + 53 == ZFS_IOC_NEXT_OBJ);
942 CHECK(ZFS_IOC_BASE + 54 == ZFS_IOC_DIFF);
943 CHECK(ZFS_IOC_BASE + 55 == ZFS_IOC_TMP_SNAPSHOT);
944 CHECK(ZFS_IOC_BASE + 56 == ZFS_IOC_OBJ_TO_STATS);
945 CHECK(ZFS_IOC_BASE + 57 == ZFS_IOC_SPACE_WRITTEN);
946 CHECK(ZFS_IOC_BASE + 58 == ZFS_IOC_SPACE_SNAPS);
947 CHECK(ZFS_IOC_BASE + 59 == ZFS_IOC_DESTROY_SNAPS);
948 CHECK(ZFS_IOC_BASE + 60 == ZFS_IOC_POOL_REGUID);
949 CHECK(ZFS_IOC_BASE + 61 == ZFS_IOC_POOL_REOPEN);
950 CHECK(ZFS_IOC_BASE + 62 == ZFS_IOC_SEND_PROGRESS);
951 CHECK(ZFS_IOC_BASE + 63 == ZFS_IOC_LOG_HISTORY);
952 CHECK(ZFS_IOC_BASE + 64 == ZFS_IOC_SEND_NEW);
953 CHECK(ZFS_IOC_BASE + 65 == ZFS_IOC_SEND_SPACE);
954 CHECK(ZFS_IOC_BASE + 66 == ZFS_IOC_CLONE);
955 CHECK(ZFS_IOC_BASE + 67 == ZFS_IOC_BOOKMARK);
956 CHECK(ZFS_IOC_BASE + 68 == ZFS_IOC_GET_BOOKMARKS);
957 CHECK(ZFS_IOC_BASE + 69 == ZFS_IOC_DESTROY_BOOKMARKS);
958 #ifndef __sun
959 CHECK(ZFS_IOC_BASE + 71 == ZFS_IOC_RECV_NEW);
960 #endif
961 CHECK(ZFS_IOC_BASE + 70 == ZFS_IOC_POOL_SYNC);
962 CHECK(ZFS_IOC_BASE + 71 == ZFS_IOC_CHANNEL_PROGRAM);
963 CHECK(ZFS_IOC_BASE + 72 == ZFS_IOC_LOAD_KEY);
964 CHECK(ZFS_IOC_BASE + 73 == ZFS_IOC_UNLOAD_KEY);
965 CHECK(ZFS_IOC_BASE + 74 == ZFS_IOC_CHANGE_KEY);
966 CHECK(ZFS_IOC_BASE + 75 == ZFS_IOC_REMAP);
967 CHECK(ZFS_IOC_BASE + 76 == ZFS_IOC_POOL_CHECKPOINT);
968
969 #ifndef __sun
970 CHECK(ZFS_IOC_BASE + 78 == ZFS_IOC_POOL_DISCARD_CHECKPOINT);
971 CHECK(ZFS_IOC_PLATFORM_BASE + 1 == ZFS_IOC_EVENTS_NEXT);
972 CHECK(ZFS_IOC_PLATFORM_BASE + 2 == ZFS_IOC_EVENTS_CLEAR);
973 CHECK(ZFS_IOC_PLATFORM_BASE + 3 == ZFS_IOC_EVENTS_SEEK);
974 #else
975 CHECK(ZFS_IOC_BASE + 77 == ZFS_IOC_POOL_DISCARD_CHECKPOINT);
976 CHECK(ZFS_IOC_BASE + 78 == ZFS_IOC_POOL_INITIALIZE);
977 CHECK(ZFS_IOC_BASE + 79 == ZFS_IOC_POOL_TRIM);
978 CHECK(ZFS_IOC_BASE + 80 == ZFS_IOC_REDACT);
979 CHECK(ZFS_IOC_BASE + 81 == ZFS_IOC_GET_BOOKMARK_PROPS);
980 #endif
981 CHECK(ZFS_IOC_PLATFORM_BASE + 7 == ZFS_IOC_SET_BOOTENV);
982 CHECK(ZFS_IOC_PLATFORM_BASE + 8 == ZFS_IOC_GET_BOOTENV);
983
984 #undef CHECK
985
986 return (result);
987 }
988
989 int
main(int argc,const char * argv[])990 main(int argc, const char *argv[])
991 {
992 if (argc != 2) {
993 (void) fprintf(stderr, "usage: %s <pool>\n", argv[0]);
994 exit(2);
995 }
996
997 if (!validate_ioc_values()) {
998 (void) fprintf(stderr, "WARNING: zfs_ioc_t has binary "
999 "incompatible command values\n");
1000 exit(3);
1001 }
1002
1003 (void) libzfs_core_init();
1004 zfs_fd = open(ZFS_DEV, O_RDWR|O_EXCL);
1005 if (zfs_fd < 0) {
1006 (void) fprintf(stderr, "open: %s\n", strerror(errno));
1007 libzfs_core_fini();
1008 exit(2);
1009 }
1010
1011 zfs_ioc_input_tests(argv[1]);
1012
1013 (void) close(zfs_fd);
1014 libzfs_core_fini();
1015
1016 return (unexpected_failures);
1017 }
1018