Path: blob/main/sys/contrib/openzfs/tests/zfs-tests/cmd/libzfs_input_check.c
48529 views
// SPDX-License-Identifier: CDDL-1.01/*2* CDDL HEADER START3*4* This file and its contents are supplied under the terms of the5* Common Development and Distribution License ("CDDL"), version 1.0.6* You may only use this file in accordance with the terms of version7* 1.0 of the CDDL.8*9* A full copy of the text of the CDDL should have accompanied this10* source. A copy of the CDDL is also available via the Internet at11* http://www.illumos.org/license/CDDL.12*13* CDDL HEADER END14*/1516/*17* Copyright (c) 2018 by Delphix. All rights reserved.18*/1920#include <stdio.h>21#include <stdlib.h>22#include <string.h>23#include <libzfs_core.h>24#include <libzutil.h>2526#include <sys/nvpair.h>27#include <sys/vdev_impl.h>28#include <sys/zfs_ioctl.h>29#include <sys/zfs_bootenv.h>30#include <sys/fs/zfs.h>3132/*33* Test the nvpair inputs for the non-legacy zfs ioctl commands.34*/3536static boolean_t unexpected_failures;37static int zfs_fd;38static const char *active_test;3940/*41* Tracks which zfs_ioc_t commands were tested42*/43static boolean_t ioc_tested[ZFS_IOC_LAST - ZFS_IOC_FIRST];4445/*46* Legacy ioctls that are skipped (for now)47*/48static const zfs_ioc_t ioc_skip[] = {49ZFS_IOC_POOL_CREATE,50ZFS_IOC_POOL_DESTROY,51ZFS_IOC_POOL_IMPORT,52ZFS_IOC_POOL_EXPORT,53ZFS_IOC_POOL_CONFIGS,54ZFS_IOC_POOL_STATS,55ZFS_IOC_POOL_TRYIMPORT,56ZFS_IOC_POOL_SCAN,57ZFS_IOC_POOL_FREEZE,58ZFS_IOC_POOL_UPGRADE,59ZFS_IOC_POOL_GET_HISTORY,6061ZFS_IOC_VDEV_ADD,62ZFS_IOC_VDEV_REMOVE,63ZFS_IOC_VDEV_SET_STATE,64ZFS_IOC_VDEV_ATTACH,65ZFS_IOC_VDEV_DETACH,66ZFS_IOC_VDEV_SETPATH,67ZFS_IOC_VDEV_SETFRU,6869ZFS_IOC_OBJSET_STATS,70ZFS_IOC_OBJSET_ZPLPROPS,71ZFS_IOC_DATASET_LIST_NEXT,72ZFS_IOC_SNAPSHOT_LIST_NEXT,73ZFS_IOC_SET_PROP,74ZFS_IOC_DESTROY,75ZFS_IOC_RENAME,76ZFS_IOC_RECV,77ZFS_IOC_SEND,78ZFS_IOC_INJECT_FAULT,79ZFS_IOC_CLEAR_FAULT,80ZFS_IOC_INJECT_LIST_NEXT,81ZFS_IOC_ERROR_LOG,82ZFS_IOC_CLEAR,83ZFS_IOC_PROMOTE,84ZFS_IOC_DSOBJ_TO_DSNAME,85ZFS_IOC_OBJ_TO_PATH,86ZFS_IOC_POOL_SET_PROPS,87ZFS_IOC_POOL_GET_PROPS,88ZFS_IOC_SET_FSACL,89ZFS_IOC_GET_FSACL,90ZFS_IOC_SHARE,91ZFS_IOC_INHERIT_PROP,92ZFS_IOC_SMB_ACL,93ZFS_IOC_USERSPACE_ONE,94ZFS_IOC_USERSPACE_MANY,95ZFS_IOC_USERSPACE_UPGRADE,96ZFS_IOC_OBJSET_RECVD_PROPS,97ZFS_IOC_VDEV_SPLIT,98ZFS_IOC_NEXT_OBJ,99ZFS_IOC_DIFF,100ZFS_IOC_TMP_SNAPSHOT,101ZFS_IOC_OBJ_TO_STATS,102ZFS_IOC_SPACE_WRITTEN,103ZFS_IOC_POOL_REGUID,104ZFS_IOC_SEND_PROGRESS,105ZFS_IOC_EVENTS_NEXT,106ZFS_IOC_EVENTS_CLEAR,107ZFS_IOC_EVENTS_SEEK,108ZFS_IOC_NEXTBOOT,109ZFS_IOC_JAIL,110ZFS_IOC_UNJAIL,111};112113114#define IOC_INPUT_TEST(ioc, name, req, opt, err) \115IOC_INPUT_TEST_IMPL(ioc, name, req, opt, err, B_FALSE)116117#define IOC_INPUT_TEST_WILD(ioc, name, req, opt, err) \118IOC_INPUT_TEST_IMPL(ioc, name, req, opt, err, B_TRUE)119120#define IOC_INPUT_TEST_IMPL(ioc, name, req, opt, err, wild) \121do { \122active_test = __func__ + 5; \123ioc_tested[ioc - ZFS_IOC_FIRST] = B_TRUE; \124lzc_ioctl_test(ioc, name, req, opt, err, wild); \125} while (0)126127/*128* run a zfs ioctl command, verify expected results and log failures129*/130static void131lzc_ioctl_run(zfs_ioc_t ioc, const char *name, nvlist_t *innvl, int expected)132{133zfs_cmd_t zc = {"\0"};134char *packed = NULL;135const char *variant;136size_t size = 0;137int error = 0;138139switch (expected) {140case ZFS_ERR_IOC_ARG_UNAVAIL:141variant = "unsupported input";142break;143case ZFS_ERR_IOC_ARG_REQUIRED:144variant = "missing input";145break;146case ZFS_ERR_IOC_ARG_BADTYPE:147variant = "invalid input type";148break;149default:150variant = "valid input";151break;152}153154packed = fnvlist_pack(innvl, &size);155(void) strlcpy(zc.zc_name, name, sizeof (zc.zc_name));156zc.zc_name[sizeof (zc.zc_name) - 1] = '\0';157zc.zc_nvlist_src = (uint64_t)(uintptr_t)packed;158zc.zc_nvlist_src_size = size;159zc.zc_nvlist_dst_size = MAX(size * 2, 128 * 1024);160zc.zc_nvlist_dst = (uint64_t)(uintptr_t)malloc(zc.zc_nvlist_dst_size);161162if (lzc_ioctl_fd(zfs_fd, ioc, &zc) != 0)163error = errno;164165if (error != expected) {166unexpected_failures = B_TRUE;167(void) fprintf(stderr, "%s: Unexpected result with %s, "168"error %d (expecting %d)\n",169active_test, variant, error, expected);170}171172fnvlist_pack_free(packed, size);173free((void *)(uintptr_t)zc.zc_nvlist_dst);174}175176/*177* Test each ioc for the following ioctl input errors:178* ZFS_ERR_IOC_ARG_UNAVAIL an input argument is not supported by kernel179* ZFS_ERR_IOC_ARG_REQUIRED a required input argument is missing180* ZFS_ERR_IOC_ARG_BADTYPE an input argument has an invalid type181*/182static int183lzc_ioctl_test(zfs_ioc_t ioc, const char *name, nvlist_t *required,184nvlist_t *optional, int expected_error, boolean_t wildcard)185{186nvlist_t *input = fnvlist_alloc();187nvlist_t *future = fnvlist_alloc();188int error = 0;189190if (required != NULL) {191for (nvpair_t *pair = nvlist_next_nvpair(required, NULL);192pair != NULL; pair = nvlist_next_nvpair(required, pair)) {193fnvlist_add_nvpair(input, pair);194}195}196if (optional != NULL) {197for (nvpair_t *pair = nvlist_next_nvpair(optional, NULL);198pair != NULL; pair = nvlist_next_nvpair(optional, pair)) {199fnvlist_add_nvpair(input, pair);200}201}202203/*204* Generic input run with 'optional' nvlist pair205*/206if (!wildcard)207fnvlist_add_nvlist(input, "optional", future);208lzc_ioctl_run(ioc, name, input, expected_error);209if (!wildcard)210fnvlist_remove(input, "optional");211212/*213* Bogus input value214*/215if (!wildcard) {216fnvlist_add_string(input, "bogus_input", "bogus");217lzc_ioctl_run(ioc, name, input, ZFS_ERR_IOC_ARG_UNAVAIL);218fnvlist_remove(input, "bogus_input");219}220221/*222* Missing required inputs223*/224if (required != NULL) {225nvlist_t *empty = fnvlist_alloc();226lzc_ioctl_run(ioc, name, empty, ZFS_ERR_IOC_ARG_REQUIRED);227nvlist_free(empty);228}229230/*231* Wrong nvpair type232*/233if (required != NULL || optional != NULL) {234/*235* switch the type of one of the input pairs236*/237for (nvpair_t *pair = nvlist_next_nvpair(input, NULL);238pair != NULL; pair = nvlist_next_nvpair(input, pair)) {239char pname[MAXNAMELEN];240data_type_t ptype;241242strlcpy(pname, nvpair_name(pair), sizeof (pname));243pname[sizeof (pname) - 1] = '\0';244ptype = nvpair_type(pair);245fnvlist_remove_nvpair(input, pair);246247switch (ptype) {248case DATA_TYPE_STRING:249fnvlist_add_uint64(input, pname, 42);250break;251default:252fnvlist_add_string(input, pname, "bogus");253break;254}255}256lzc_ioctl_run(ioc, name, input, ZFS_ERR_IOC_ARG_BADTYPE);257}258259nvlist_free(future);260nvlist_free(input);261262return (error);263}264265static void266test_pool_sync(const char *pool)267{268nvlist_t *required = fnvlist_alloc();269270fnvlist_add_boolean_value(required, "force", B_TRUE);271272IOC_INPUT_TEST(ZFS_IOC_POOL_SYNC, pool, required, NULL, 0);273274nvlist_free(required);275}276277static void278test_pool_reopen(const char *pool)279{280nvlist_t *optional = fnvlist_alloc();281282fnvlist_add_boolean_value(optional, "scrub_restart", B_FALSE);283284IOC_INPUT_TEST(ZFS_IOC_POOL_REOPEN, pool, NULL, optional, 0);285286nvlist_free(optional);287}288289static void290test_pool_checkpoint(const char *pool)291{292IOC_INPUT_TEST(ZFS_IOC_POOL_CHECKPOINT, pool, NULL, NULL, 0);293}294295static void296test_pool_discard_checkpoint(const char *pool)297{298int err = lzc_pool_checkpoint(pool);299if (err == 0 || err == ZFS_ERR_CHECKPOINT_EXISTS)300IOC_INPUT_TEST(ZFS_IOC_POOL_DISCARD_CHECKPOINT, pool, NULL,301NULL, 0);302}303304static void305test_log_history(const char *pool)306{307nvlist_t *required = fnvlist_alloc();308309fnvlist_add_string(required, "message", "input check");310311IOC_INPUT_TEST(ZFS_IOC_LOG_HISTORY, pool, required, NULL, 0);312313nvlist_free(required);314}315316static void317test_create(const char *pool)318{319char dataset[MAXNAMELEN + 32];320321(void) snprintf(dataset, sizeof (dataset), "%s/create-fs", pool);322323nvlist_t *required = fnvlist_alloc();324nvlist_t *optional = fnvlist_alloc();325nvlist_t *props = fnvlist_alloc();326327fnvlist_add_int32(required, "type", DMU_OST_ZFS);328fnvlist_add_uint64(props, "recordsize", 8192);329fnvlist_add_nvlist(optional, "props", props);330331IOC_INPUT_TEST(ZFS_IOC_CREATE, dataset, required, optional, 0);332333nvlist_free(required);334nvlist_free(optional);335}336337static void338test_snapshot(const char *pool, const char *snapshot)339{340nvlist_t *required = fnvlist_alloc();341nvlist_t *optional = fnvlist_alloc();342nvlist_t *snaps = fnvlist_alloc();343nvlist_t *props = fnvlist_alloc();344345fnvlist_add_boolean(snaps, snapshot);346fnvlist_add_nvlist(required, "snaps", snaps);347348fnvlist_add_string(props, "org.openzfs:launch", "September 17th, 2013");349fnvlist_add_nvlist(optional, "props", props);350351IOC_INPUT_TEST(ZFS_IOC_SNAPSHOT, pool, required, optional, 0);352353nvlist_free(props);354nvlist_free(snaps);355nvlist_free(optional);356nvlist_free(required);357}358359static void360test_space_snaps(const char *snapshot)361{362nvlist_t *required = fnvlist_alloc();363fnvlist_add_string(required, "firstsnap", snapshot);364365IOC_INPUT_TEST(ZFS_IOC_SPACE_SNAPS, snapshot, required, NULL, 0);366367nvlist_free(required);368}369370static void371test_destroy_snaps(const char *pool, const char *snapshot)372{373nvlist_t *required = fnvlist_alloc();374nvlist_t *snaps = fnvlist_alloc();375376fnvlist_add_boolean(snaps, snapshot);377fnvlist_add_nvlist(required, "snaps", snaps);378379IOC_INPUT_TEST(ZFS_IOC_DESTROY_SNAPS, pool, required, NULL, 0);380381nvlist_free(snaps);382nvlist_free(required);383}384385386static void387test_bookmark(const char *pool, const char *snapshot, const char *bookmark)388{389nvlist_t *required = fnvlist_alloc();390391fnvlist_add_string(required, bookmark, snapshot);392393IOC_INPUT_TEST_WILD(ZFS_IOC_BOOKMARK, pool, required, NULL, 0);394395nvlist_free(required);396}397398static void399test_get_bookmarks(const char *dataset)400{401nvlist_t *optional = fnvlist_alloc();402403fnvlist_add_boolean(optional, "guid");404fnvlist_add_boolean(optional, "createtxg");405fnvlist_add_boolean(optional, "creation");406407IOC_INPUT_TEST_WILD(ZFS_IOC_GET_BOOKMARKS, dataset, NULL, optional, 0);408409nvlist_free(optional);410}411412static void413test_destroy_bookmarks(const char *pool, const char *bookmark)414{415nvlist_t *required = fnvlist_alloc();416417fnvlist_add_boolean(required, bookmark);418419IOC_INPUT_TEST_WILD(ZFS_IOC_DESTROY_BOOKMARKS, pool, required, NULL, 0);420421nvlist_free(required);422}423424static void425test_clone(const char *snapshot, const char *clone)426{427nvlist_t *required = fnvlist_alloc();428nvlist_t *optional = fnvlist_alloc();429nvlist_t *props = fnvlist_alloc();430431fnvlist_add_string(required, "origin", snapshot);432433IOC_INPUT_TEST(ZFS_IOC_CLONE, clone, required, NULL, 0);434435nvlist_free(props);436nvlist_free(optional);437nvlist_free(required);438}439440static void441test_rollback(const char *dataset, const char *snapshot)442{443nvlist_t *optional = fnvlist_alloc();444445fnvlist_add_string(optional, "target", snapshot);446447IOC_INPUT_TEST(ZFS_IOC_ROLLBACK, dataset, NULL, optional, B_FALSE);448449nvlist_free(optional);450}451452static void453test_hold(const char *pool, const char *snapshot)454{455nvlist_t *required = fnvlist_alloc();456nvlist_t *optional = fnvlist_alloc();457nvlist_t *holds = fnvlist_alloc();458459fnvlist_add_string(holds, snapshot, "libzfs_check_hold");460fnvlist_add_nvlist(required, "holds", holds);461fnvlist_add_int32(optional, "cleanup_fd", zfs_fd);462463IOC_INPUT_TEST(ZFS_IOC_HOLD, pool, required, optional, 0);464465nvlist_free(holds);466nvlist_free(optional);467nvlist_free(required);468}469470static void471test_get_holds(const char *snapshot)472{473IOC_INPUT_TEST(ZFS_IOC_GET_HOLDS, snapshot, NULL, NULL, 0);474}475476static void477test_release(const char *pool, const char *snapshot)478{479nvlist_t *required = fnvlist_alloc();480nvlist_t *release = fnvlist_alloc();481482fnvlist_add_boolean(release, "libzfs_check_hold");483fnvlist_add_nvlist(required, snapshot, release);484485IOC_INPUT_TEST_WILD(ZFS_IOC_RELEASE, pool, required, NULL, 0);486487nvlist_free(release);488nvlist_free(required);489}490491492static void493test_send_new(const char *snapshot, int fd)494{495nvlist_t *required = fnvlist_alloc();496nvlist_t *optional = fnvlist_alloc();497498fnvlist_add_int32(required, "fd", fd);499500fnvlist_add_boolean(optional, "largeblockok");501fnvlist_add_boolean(optional, "embedok");502fnvlist_add_boolean(optional, "compressok");503fnvlist_add_boolean(optional, "rawok");504505/*506* TODO - Resumable send is harder to set up. So we currently507* ignore testing for that variant.508*/509#if 0510fnvlist_add_string(optional, "fromsnap", from);511fnvlist_add_uint64(optional, "resume_object", resumeobj);512fnvlist_add_uint64(optional, "resume_offset", offset);513fnvlist_add_boolean(optional, "savedok");514#endif515IOC_INPUT_TEST(ZFS_IOC_SEND_NEW, snapshot, required, optional, 0);516517nvlist_free(optional);518nvlist_free(required);519}520521static void522test_recv_new(const char *dataset, int fd)523{524dmu_replay_record_t drr;525nvlist_t *required = fnvlist_alloc();526nvlist_t *optional = fnvlist_alloc();527nvlist_t *props = fnvlist_alloc();528char snapshot[MAXNAMELEN + 32];529ssize_t count;530531memset(&drr, 0, sizeof (dmu_replay_record_t));532533int cleanup_fd = open(ZFS_DEV, O_RDWR);534if (cleanup_fd == -1) {535(void) fprintf(stderr, "open(%s) failed: %s\n", ZFS_DEV,536strerror(errno));537exit(EXIT_FAILURE);538}539(void) snprintf(snapshot, sizeof (snapshot), "%s@replicant", dataset);540541count = pread(fd, &drr, sizeof (drr), 0);542if (count != sizeof (drr)) {543(void) fprintf(stderr, "could not read stream: %s\n",544strerror(errno));545}546547fnvlist_add_string(required, "snapname", snapshot);548fnvlist_add_byte_array(required, "begin_record", (uchar_t *)&drr,549sizeof (drr));550fnvlist_add_int32(required, "input_fd", fd);551552fnvlist_add_string(props, "org.openzfs:launch", "September 17th, 2013");553fnvlist_add_nvlist(optional, "localprops", props);554fnvlist_add_boolean(optional, "force");555fnvlist_add_boolean(optional, "heal");556fnvlist_add_int32(optional, "cleanup_fd", cleanup_fd);557558/*559* TODO - Resumable receive is harder to set up. So we currently560* ignore testing for one.561*/562#if 0563fnvlist_add_nvlist(optional, "props", recvdprops);564fnvlist_add_string(optional, "origin", origin);565fnvlist_add_boolean(optional, "resumable");566fnvlist_add_uint64(optional, "action_handle", *action_handle);567#endif568IOC_INPUT_TEST(ZFS_IOC_RECV_NEW, dataset, required, optional,569ENOTSUP);570571nvlist_free(props);572nvlist_free(optional);573nvlist_free(required);574575(void) close(cleanup_fd);576}577578static void579test_send_space(const char *snapshot1, const char *snapshot2)580{581nvlist_t *optional = fnvlist_alloc();582583fnvlist_add_string(optional, "from", snapshot1);584fnvlist_add_boolean(optional, "largeblockok");585fnvlist_add_boolean(optional, "embedok");586fnvlist_add_boolean(optional, "compressok");587fnvlist_add_boolean(optional, "rawok");588589IOC_INPUT_TEST(ZFS_IOC_SEND_SPACE, snapshot2, NULL, optional, 0);590591nvlist_free(optional);592}593594static void595test_remap(const char *dataset)596{597IOC_INPUT_TEST(ZFS_IOC_REMAP, dataset, NULL, NULL, 0);598}599600static void601test_channel_program(const char *pool)602{603const char *program =604"arg = ...\n"605"argv = arg[\"argv\"]\n"606"return argv[1]";607const char *const argv[1] = { "Hello World!" };608nvlist_t *required = fnvlist_alloc();609nvlist_t *optional = fnvlist_alloc();610nvlist_t *args = fnvlist_alloc();611612fnvlist_add_string(required, "program", program);613fnvlist_add_string_array(args, "argv", argv, 1);614fnvlist_add_nvlist(required, "arg", args);615616fnvlist_add_boolean_value(optional, "sync", B_TRUE);617fnvlist_add_uint64(optional, "instrlimit", 1000 * 1000);618fnvlist_add_uint64(optional, "memlimit", 8192 * 1024);619620IOC_INPUT_TEST(ZFS_IOC_CHANNEL_PROGRAM, pool, required, optional, 0);621622nvlist_free(args);623nvlist_free(optional);624nvlist_free(required);625}626627#define WRAPPING_KEY_LEN 32628629static void630test_load_key(const char *dataset)631{632nvlist_t *required = fnvlist_alloc();633nvlist_t *optional = fnvlist_alloc();634nvlist_t *hidden = fnvlist_alloc();635uint8_t keydata[WRAPPING_KEY_LEN] = {0};636637fnvlist_add_uint8_array(hidden, "wkeydata", keydata, sizeof (keydata));638fnvlist_add_nvlist(required, "hidden_args", hidden);639fnvlist_add_boolean(optional, "noop");640641IOC_INPUT_TEST(ZFS_IOC_LOAD_KEY, dataset, required, optional, EINVAL);642nvlist_free(hidden);643nvlist_free(optional);644nvlist_free(required);645}646647static void648test_change_key(const char *dataset)649{650IOC_INPUT_TEST(ZFS_IOC_CHANGE_KEY, dataset, NULL, NULL, EINVAL);651}652653static void654test_unload_key(const char *dataset)655{656IOC_INPUT_TEST(ZFS_IOC_UNLOAD_KEY, dataset, NULL, NULL, EACCES);657}658659static void660test_vdev_initialize(const char *pool)661{662nvlist_t *required = fnvlist_alloc();663nvlist_t *vdev_guids = fnvlist_alloc();664665fnvlist_add_uint64(vdev_guids, "path", 0xdeadbeefdeadbeef);666fnvlist_add_uint64(required, ZPOOL_INITIALIZE_COMMAND,667POOL_INITIALIZE_START);668fnvlist_add_nvlist(required, ZPOOL_INITIALIZE_VDEVS, vdev_guids);669670IOC_INPUT_TEST(ZFS_IOC_POOL_INITIALIZE, pool, required, NULL, EINVAL);671nvlist_free(vdev_guids);672nvlist_free(required);673}674675static void676test_vdev_trim(const char *pool)677{678nvlist_t *required = fnvlist_alloc();679nvlist_t *optional = fnvlist_alloc();680nvlist_t *vdev_guids = fnvlist_alloc();681682fnvlist_add_uint64(vdev_guids, "path", 0xdeadbeefdeadbeef);683fnvlist_add_uint64(required, ZPOOL_TRIM_COMMAND, POOL_TRIM_START);684fnvlist_add_nvlist(required, ZPOOL_TRIM_VDEVS, vdev_guids);685fnvlist_add_uint64(optional, ZPOOL_TRIM_RATE, 1ULL << 30);686fnvlist_add_boolean_value(optional, ZPOOL_TRIM_SECURE, B_TRUE);687688IOC_INPUT_TEST(ZFS_IOC_POOL_TRIM, pool, required, optional, EINVAL);689nvlist_free(vdev_guids);690nvlist_free(optional);691nvlist_free(required);692}693694/* Test with invalid values */695static void696test_scrub(const char *pool)697{698nvlist_t *required = fnvlist_alloc();699fnvlist_add_uint64(required, "scan_type", POOL_SCAN_FUNCS + 1);700fnvlist_add_uint64(required, "scan_command", POOL_SCRUB_FLAGS_END + 1);701IOC_INPUT_TEST(ZFS_IOC_POOL_SCRUB, pool, required, NULL, EINVAL);702nvlist_free(required);703}704705static int706zfs_destroy(const char *dataset)707{708zfs_cmd_t zc = {"\0"};709int err;710711(void) strlcpy(zc.zc_name, dataset, sizeof (zc.zc_name));712zc.zc_name[sizeof (zc.zc_name) - 1] = '\0';713err = lzc_ioctl_fd(zfs_fd, ZFS_IOC_DESTROY, &zc);714715return (err == 0 ? 0 : errno);716}717718static void719test_redact(const char *snapshot1, const char *snapshot2)720{721nvlist_t *required = fnvlist_alloc();722nvlist_t *snapnv = fnvlist_alloc();723char bookmark[MAXNAMELEN + 32];724725fnvlist_add_string(required, "bookname", "testbookmark");726fnvlist_add_boolean(snapnv, snapshot2);727fnvlist_add_nvlist(required, "snapnv", snapnv);728729IOC_INPUT_TEST(ZFS_IOC_REDACT, snapshot1, required, NULL, 0);730731nvlist_free(snapnv);732nvlist_free(required);733734strlcpy(bookmark, snapshot1, sizeof (bookmark));735*strchr(bookmark, '@') = '\0';736strlcat(bookmark, "#testbookmark", sizeof (bookmark) -737strlen(bookmark));738zfs_destroy(bookmark);739}740741static void742test_get_bookmark_props(const char *bookmark)743{744IOC_INPUT_TEST(ZFS_IOC_GET_BOOKMARK_PROPS, bookmark, NULL, NULL, 0);745}746747static void748test_wait(const char *pool)749{750nvlist_t *required = fnvlist_alloc();751nvlist_t *optional = fnvlist_alloc();752753fnvlist_add_int32(required, "wait_activity", 2);754fnvlist_add_uint64(optional, "wait_tag", 0xdeadbeefdeadbeef);755756IOC_INPUT_TEST(ZFS_IOC_WAIT, pool, required, optional, EINVAL);757758nvlist_free(required);759nvlist_free(optional);760}761762static void763test_wait_fs(const char *dataset)764{765nvlist_t *required = fnvlist_alloc();766767fnvlist_add_int32(required, "wait_activity", 2);768769IOC_INPUT_TEST(ZFS_IOC_WAIT_FS, dataset, required, NULL, EINVAL);770771nvlist_free(required);772}773774static void775test_get_bootenv(const char *pool)776{777IOC_INPUT_TEST(ZFS_IOC_GET_BOOTENV, pool, NULL, NULL, 0);778}779780static void781test_set_bootenv(const char *pool)782{783nvlist_t *required = fnvlist_alloc();784785fnvlist_add_uint64(required, "version", VB_RAW);786fnvlist_add_string(required, GRUB_ENVMAP, "test");787788IOC_INPUT_TEST_WILD(ZFS_IOC_SET_BOOTENV, pool, required, NULL, 0);789790nvlist_free(required);791}792793static void794zfs_ioc_input_tests(const char *pool)795{796char filepath[] = "/tmp/ioc_test_file_XXXXXX";797char dataset[ZFS_MAX_DATASET_NAME_LEN];798char snapbase[ZFS_MAX_DATASET_NAME_LEN + 32];799char snapshot[ZFS_MAX_DATASET_NAME_LEN + 32];800char bookmark[ZFS_MAX_DATASET_NAME_LEN + 32];801char backup[ZFS_MAX_DATASET_NAME_LEN];802char clone[ZFS_MAX_DATASET_NAME_LEN];803char clonesnap[ZFS_MAX_DATASET_NAME_LEN + 32];804int tmpfd, err;805806/*807* Setup names and create a working dataset808*/809(void) snprintf(dataset, sizeof (dataset), "%s/test-fs", pool);810(void) snprintf(snapbase, sizeof (snapbase), "%s@snapbase", dataset);811(void) snprintf(snapshot, sizeof (snapshot), "%s@snapshot", dataset);812(void) snprintf(bookmark, sizeof (bookmark), "%s#bookmark", dataset);813(void) snprintf(clone, sizeof (clone), "%s/test-fs-clone", pool);814(void) snprintf(clonesnap, sizeof (clonesnap), "%s@snap", clone);815(void) snprintf(backup, sizeof (backup), "%s/backup", pool);816817err = lzc_create(dataset, LZC_DATSET_TYPE_ZFS, NULL, NULL, -1);818if (err) {819(void) fprintf(stderr, "could not create '%s': %s\n",820dataset, strerror(errno));821exit(2);822}823824tmpfd = mkstemp(filepath);825if (tmpfd < 0) {826(void) fprintf(stderr, "could not create '%s': %s\n",827filepath, strerror(errno));828exit(2);829}830831/*832* run a test for each ioctl833* Note that some test build on previous test operations834*/835test_pool_sync(pool);836test_pool_reopen(pool);837test_pool_checkpoint(pool);838test_pool_discard_checkpoint(pool);839test_log_history(pool);840841test_create(dataset);842test_snapshot(pool, snapbase);843test_snapshot(pool, snapshot);844845test_space_snaps(snapshot);846test_send_space(snapbase, snapshot);847test_send_new(snapshot, tmpfd);848test_recv_new(backup, tmpfd);849850test_bookmark(pool, snapshot, bookmark);851test_get_bookmarks(dataset);852test_get_bookmark_props(bookmark);853test_destroy_bookmarks(pool, bookmark);854855test_hold(pool, snapshot);856test_get_holds(snapshot);857test_release(pool, snapshot);858859test_clone(snapshot, clone);860test_snapshot(pool, clonesnap);861test_redact(snapshot, clonesnap);862zfs_destroy(clonesnap);863zfs_destroy(clone);864865test_rollback(dataset, snapshot);866test_destroy_snaps(pool, snapshot);867test_destroy_snaps(pool, snapbase);868869test_remap(dataset);870test_channel_program(pool);871872test_load_key(dataset);873test_change_key(dataset);874test_unload_key(dataset);875876test_vdev_initialize(pool);877test_vdev_trim(pool);878879test_wait(pool);880test_wait_fs(dataset);881882test_set_bootenv(pool);883test_get_bootenv(pool);884885test_scrub(pool);886887/*888* cleanup889*/890zfs_cmd_t zc = {"\0"};891892nvlist_t *snaps = fnvlist_alloc();893fnvlist_add_boolean(snaps, snapshot);894(void) lzc_destroy_snaps(snaps, B_FALSE, NULL);895nvlist_free(snaps);896897(void) zfs_destroy(dataset);898(void) zfs_destroy(backup);899900(void) close(tmpfd);901(void) unlink(filepath);902903/*904* All the unused slots should yield ZFS_ERR_IOC_CMD_UNAVAIL905*/906for (int i = 0; i < ARRAY_SIZE(ioc_skip); i++) {907if (ioc_tested[ioc_skip[i] - ZFS_IOC_FIRST])908(void) fprintf(stderr, "cmd %d tested, not skipped!\n",909(int)(ioc_skip[i] - ZFS_IOC_FIRST));910911ioc_tested[ioc_skip[i] - ZFS_IOC_FIRST] = B_TRUE;912}913914(void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));915zc.zc_name[sizeof (zc.zc_name) - 1] = '\0';916917for (unsigned ioc = ZFS_IOC_FIRST; ioc < ZFS_IOC_LAST; ioc++) {918unsigned cmd = ioc - ZFS_IOC_FIRST;919920if (ioc_tested[cmd])921continue;922923if (lzc_ioctl_fd(zfs_fd, ioc, &zc) != 0 &&924errno != ZFS_ERR_IOC_CMD_UNAVAIL) {925(void) fprintf(stderr, "cmd %d is missing a test case "926"(%d)\n", cmd, errno);927}928}929}930931enum zfs_ioc_ref {932#ifdef __FreeBSD__933ZFS_IOC_BASE = 0,934#else935ZFS_IOC_BASE = ('Z' << 8),936#endif937ZFS_IOC_PLATFORM_BASE = ZFS_IOC_BASE + 0x80,938};939940/*941* Canonical reference check of /dev/zfs ioctl numbers.942* These cannot change and new ioctl numbers must be appended.943*/944static boolean_t945validate_ioc_values(void)946{947boolean_t result = B_TRUE;948949#define CHECK(expr) do { \950if (!(expr)) { \951result = B_FALSE; \952fprintf(stderr, "(%s) === FALSE\n", #expr); \953} \954} while (0)955956CHECK(ZFS_IOC_BASE + 0 == ZFS_IOC_POOL_CREATE);957CHECK(ZFS_IOC_BASE + 1 == ZFS_IOC_POOL_DESTROY);958CHECK(ZFS_IOC_BASE + 2 == ZFS_IOC_POOL_IMPORT);959CHECK(ZFS_IOC_BASE + 3 == ZFS_IOC_POOL_EXPORT);960CHECK(ZFS_IOC_BASE + 4 == ZFS_IOC_POOL_CONFIGS);961CHECK(ZFS_IOC_BASE + 5 == ZFS_IOC_POOL_STATS);962CHECK(ZFS_IOC_BASE + 6 == ZFS_IOC_POOL_TRYIMPORT);963CHECK(ZFS_IOC_BASE + 7 == ZFS_IOC_POOL_SCAN);964CHECK(ZFS_IOC_BASE + 8 == ZFS_IOC_POOL_FREEZE);965CHECK(ZFS_IOC_BASE + 9 == ZFS_IOC_POOL_UPGRADE);966CHECK(ZFS_IOC_BASE + 10 == ZFS_IOC_POOL_GET_HISTORY);967CHECK(ZFS_IOC_BASE + 11 == ZFS_IOC_VDEV_ADD);968CHECK(ZFS_IOC_BASE + 12 == ZFS_IOC_VDEV_REMOVE);969CHECK(ZFS_IOC_BASE + 13 == ZFS_IOC_VDEV_SET_STATE);970CHECK(ZFS_IOC_BASE + 14 == ZFS_IOC_VDEV_ATTACH);971CHECK(ZFS_IOC_BASE + 15 == ZFS_IOC_VDEV_DETACH);972CHECK(ZFS_IOC_BASE + 16 == ZFS_IOC_VDEV_SETPATH);973CHECK(ZFS_IOC_BASE + 17 == ZFS_IOC_VDEV_SETFRU);974CHECK(ZFS_IOC_BASE + 18 == ZFS_IOC_OBJSET_STATS);975CHECK(ZFS_IOC_BASE + 19 == ZFS_IOC_OBJSET_ZPLPROPS);976CHECK(ZFS_IOC_BASE + 20 == ZFS_IOC_DATASET_LIST_NEXT);977CHECK(ZFS_IOC_BASE + 21 == ZFS_IOC_SNAPSHOT_LIST_NEXT);978CHECK(ZFS_IOC_BASE + 22 == ZFS_IOC_SET_PROP);979CHECK(ZFS_IOC_BASE + 23 == ZFS_IOC_CREATE);980CHECK(ZFS_IOC_BASE + 24 == ZFS_IOC_DESTROY);981CHECK(ZFS_IOC_BASE + 25 == ZFS_IOC_ROLLBACK);982CHECK(ZFS_IOC_BASE + 26 == ZFS_IOC_RENAME);983CHECK(ZFS_IOC_BASE + 27 == ZFS_IOC_RECV);984CHECK(ZFS_IOC_BASE + 28 == ZFS_IOC_SEND);985CHECK(ZFS_IOC_BASE + 29 == ZFS_IOC_INJECT_FAULT);986CHECK(ZFS_IOC_BASE + 30 == ZFS_IOC_CLEAR_FAULT);987CHECK(ZFS_IOC_BASE + 31 == ZFS_IOC_INJECT_LIST_NEXT);988CHECK(ZFS_IOC_BASE + 32 == ZFS_IOC_ERROR_LOG);989CHECK(ZFS_IOC_BASE + 33 == ZFS_IOC_CLEAR);990CHECK(ZFS_IOC_BASE + 34 == ZFS_IOC_PROMOTE);991CHECK(ZFS_IOC_BASE + 35 == ZFS_IOC_SNAPSHOT);992CHECK(ZFS_IOC_BASE + 36 == ZFS_IOC_DSOBJ_TO_DSNAME);993CHECK(ZFS_IOC_BASE + 37 == ZFS_IOC_OBJ_TO_PATH);994CHECK(ZFS_IOC_BASE + 38 == ZFS_IOC_POOL_SET_PROPS);995CHECK(ZFS_IOC_BASE + 39 == ZFS_IOC_POOL_GET_PROPS);996CHECK(ZFS_IOC_BASE + 40 == ZFS_IOC_SET_FSACL);997CHECK(ZFS_IOC_BASE + 41 == ZFS_IOC_GET_FSACL);998CHECK(ZFS_IOC_BASE + 42 == ZFS_IOC_SHARE);999CHECK(ZFS_IOC_BASE + 43 == ZFS_IOC_INHERIT_PROP);1000CHECK(ZFS_IOC_BASE + 44 == ZFS_IOC_SMB_ACL);1001CHECK(ZFS_IOC_BASE + 45 == ZFS_IOC_USERSPACE_ONE);1002CHECK(ZFS_IOC_BASE + 46 == ZFS_IOC_USERSPACE_MANY);1003CHECK(ZFS_IOC_BASE + 47 == ZFS_IOC_USERSPACE_UPGRADE);1004CHECK(ZFS_IOC_BASE + 48 == ZFS_IOC_HOLD);1005CHECK(ZFS_IOC_BASE + 49 == ZFS_IOC_RELEASE);1006CHECK(ZFS_IOC_BASE + 50 == ZFS_IOC_GET_HOLDS);1007CHECK(ZFS_IOC_BASE + 51 == ZFS_IOC_OBJSET_RECVD_PROPS);1008CHECK(ZFS_IOC_BASE + 52 == ZFS_IOC_VDEV_SPLIT);1009CHECK(ZFS_IOC_BASE + 53 == ZFS_IOC_NEXT_OBJ);1010CHECK(ZFS_IOC_BASE + 54 == ZFS_IOC_DIFF);1011CHECK(ZFS_IOC_BASE + 55 == ZFS_IOC_TMP_SNAPSHOT);1012CHECK(ZFS_IOC_BASE + 56 == ZFS_IOC_OBJ_TO_STATS);1013CHECK(ZFS_IOC_BASE + 57 == ZFS_IOC_SPACE_WRITTEN);1014CHECK(ZFS_IOC_BASE + 58 == ZFS_IOC_SPACE_SNAPS);1015CHECK(ZFS_IOC_BASE + 59 == ZFS_IOC_DESTROY_SNAPS);1016CHECK(ZFS_IOC_BASE + 60 == ZFS_IOC_POOL_REGUID);1017CHECK(ZFS_IOC_BASE + 61 == ZFS_IOC_POOL_REOPEN);1018CHECK(ZFS_IOC_BASE + 62 == ZFS_IOC_SEND_PROGRESS);1019CHECK(ZFS_IOC_BASE + 63 == ZFS_IOC_LOG_HISTORY);1020CHECK(ZFS_IOC_BASE + 64 == ZFS_IOC_SEND_NEW);1021CHECK(ZFS_IOC_BASE + 65 == ZFS_IOC_SEND_SPACE);1022CHECK(ZFS_IOC_BASE + 66 == ZFS_IOC_CLONE);1023CHECK(ZFS_IOC_BASE + 67 == ZFS_IOC_BOOKMARK);1024CHECK(ZFS_IOC_BASE + 68 == ZFS_IOC_GET_BOOKMARKS);1025CHECK(ZFS_IOC_BASE + 69 == ZFS_IOC_DESTROY_BOOKMARKS);1026CHECK(ZFS_IOC_BASE + 70 == ZFS_IOC_RECV_NEW);1027CHECK(ZFS_IOC_BASE + 71 == ZFS_IOC_POOL_SYNC);1028CHECK(ZFS_IOC_BASE + 72 == ZFS_IOC_CHANNEL_PROGRAM);1029CHECK(ZFS_IOC_BASE + 73 == ZFS_IOC_LOAD_KEY);1030CHECK(ZFS_IOC_BASE + 74 == ZFS_IOC_UNLOAD_KEY);1031CHECK(ZFS_IOC_BASE + 75 == ZFS_IOC_CHANGE_KEY);1032CHECK(ZFS_IOC_BASE + 76 == ZFS_IOC_REMAP);1033CHECK(ZFS_IOC_BASE + 77 == ZFS_IOC_POOL_CHECKPOINT);1034CHECK(ZFS_IOC_BASE + 78 == ZFS_IOC_POOL_DISCARD_CHECKPOINT);1035CHECK(ZFS_IOC_BASE + 79 == ZFS_IOC_POOL_INITIALIZE);1036CHECK(ZFS_IOC_BASE + 80 == ZFS_IOC_POOL_TRIM);1037CHECK(ZFS_IOC_BASE + 81 == ZFS_IOC_REDACT);1038CHECK(ZFS_IOC_BASE + 82 == ZFS_IOC_GET_BOOKMARK_PROPS);1039CHECK(ZFS_IOC_BASE + 83 == ZFS_IOC_WAIT);1040CHECK(ZFS_IOC_BASE + 84 == ZFS_IOC_WAIT_FS);1041CHECK(ZFS_IOC_BASE + 87 == ZFS_IOC_POOL_SCRUB);1042CHECK(ZFS_IOC_PLATFORM_BASE + 1 == ZFS_IOC_EVENTS_NEXT);1043CHECK(ZFS_IOC_PLATFORM_BASE + 2 == ZFS_IOC_EVENTS_CLEAR);1044CHECK(ZFS_IOC_PLATFORM_BASE + 3 == ZFS_IOC_EVENTS_SEEK);1045CHECK(ZFS_IOC_PLATFORM_BASE + 4 == ZFS_IOC_NEXTBOOT);1046CHECK(ZFS_IOC_PLATFORM_BASE + 5 == ZFS_IOC_JAIL);1047CHECK(ZFS_IOC_PLATFORM_BASE + 6 == ZFS_IOC_UNJAIL);1048CHECK(ZFS_IOC_PLATFORM_BASE + 7 == ZFS_IOC_SET_BOOTENV);1049CHECK(ZFS_IOC_PLATFORM_BASE + 8 == ZFS_IOC_GET_BOOTENV);10501051#undef CHECK10521053return (result);1054}10551056int1057main(int argc, const char *argv[])1058{1059if (argc != 2) {1060(void) fprintf(stderr, "usage: %s <pool>\n", argv[0]);1061exit(2);1062}10631064if (!validate_ioc_values()) {1065(void) fprintf(stderr, "WARNING: zfs_ioc_t has binary "1066"incompatible command values\n");1067exit(3);1068}10691070(void) libzfs_core_init();1071zfs_fd = open(ZFS_DEV, O_RDWR);1072if (zfs_fd < 0) {1073(void) fprintf(stderr, "open: %s\n", strerror(errno));1074libzfs_core_fini();1075exit(2);1076}10771078zfs_ioc_input_tests(argv[1]);10791080(void) close(zfs_fd);1081libzfs_core_fini();10821083return (unexpected_failures);1084}108510861087