Last active
October 3, 2017 10:02
-
-
Save Laeeth/6ca193d82926fd5b2289e75d9a47dc49 to your computer and use it in GitHub Desktop.
First steps towards creating dlang binding for libzfs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module kaleidic.api.libzfs; | |
/** | |
LibZFS - ported to the D programming language by Jonathan Davis and Laeeth Isharc | |
(c) Kaleidic Associates 2017 | |
License - CDDL | |
*/ | |
/** | |
Remove redundant / make sure we translate imports | |
#include <libnvpair.h> | |
#include <sys/fs/zfs.h> | |
#include <ucred.h> | |
#include <libzfs_core.h> | |
#include <libnvpair.h> | |
*/ | |
alias boolean_t = uint; // check me | |
int libzfs_core_init(); | |
void libzfs_core_fini(); | |
enum lzc_dataset_type | |
{ | |
LZC_DATSET_TYPE_ZFS = 2, | |
LZC_DATSET_TYPE_ZVOL | |
} | |
int lzc_snapshot(nvlist_t *, nvlist_t *, nvlist_t **); | |
int lzc_create(const(char)* , enum lzc_dataset_type, nvlist_t *, ubyte *, uint); | |
int lzc_clone(const(char)* , const(char)* , nvlist_t *); | |
int lzc_promote(const(char)* , char *, int); | |
int lzc_destroy_snaps(nvlist_t *, boolean_t, nvlist_t **); | |
int lzc_bookmark(nvlist_t *, nvlist_t **); | |
int lzc_get_bookmarks(const(char)* , nvlist_t *, nvlist_t **); | |
int lzc_destroy_bookmarks(nvlist_t *, nvlist_t **); | |
int lzc_load_key(const(char)* , boolean_t, ubyte *, uint); | |
int lzc_unload_key(const(char)* ); | |
int lzc_change_key(const(char)* , ulong, nvlist_t *, ubyte *, uint); | |
int lzc_snaprange_space(const(char)* , const(char)* , ulong *); | |
int lzc_hold(nvlist_t *, int, nvlist_t **); | |
int lzc_release(nvlist_t *, nvlist_t **); | |
int lzc_get_holds(const(char)* , nvlist_t **); | |
alias LZCSendFlags = lzc_send_flags; | |
enum lzc_send_flags | |
{ | |
LZC_SEND_FLAG_EMBED_DATA = 1 << 0, | |
LZC_SEND_FLAG_LARGE_BLOCK = 1 << 1, | |
LZC_SEND_FLAG_COMPRESS = 1 << 2, | |
LZC_SEND_FLAG_RAW = 1 << 3, | |
} | |
int lzc_send(const(char)* , const(char)* , int, lzc_send_flags); | |
int lzc_send_resume(const(char)* , const(char)* , int, lzc_send_flags, ulong, ulong); | |
int lzc_send_space(const(char)* , const(char)* , lzc_send_flags, ulong *); | |
struct dmu_replay_record {} | |
int lzc_receive(const(char)* , nvlist_t *, const(char)* , boolean_t, boolean_t, int); | |
int lzc_receive_resumable(const(char)* , nvlist_t *, const(char)* , boolean_t, boolean_t, int); | |
int lzc_receive_with_header(const(char)* , nvlist_t *, const(char)* , boolean_t, boolean_t, boolean_t, int, const struct dmu_replay_record *); | |
int lzc_receive_one(const(char)* , nvlist_t *, const(char)* , boolean_t, boolean_t, boolean_t, int, const struct dmu_replay_record *, int, ulong *, ulong *, ulong *, nvlist_t **); | |
int lzc_receive_with_cmdprops(const(char)* , nvlist_t *, nvlist_t *, const(char)* , boolean_t, boolean_t, boolean_t, int, const struct dmu_replay_record *, int, ulong *, ulong *, ulong *, nvlist_t **); | |
boolean_t lzc_exists(const(char)* ); | |
int lzc_rollback(const(char)* , char *, int); | |
int lzc_rollback_to(const(char)* , const(char)* ); | |
int lzc_sync(const(char)* , nvlist_t *, nvlist_t **); | |
/* | |
* Miscellaneous ZFS constants | |
*/ | |
enum ZFS_MAXPROPLEN = MAXPATHLEN; | |
enum ZPOOL_MAXPROPLEN = MAXPATHLEN; | |
/* | |
* Default device paths | |
*/ | |
enum DISK_ROOT ="/dev"; | |
enum UDISK_ROOT ="/dev/disk"; | |
enum ZVOL_ROOT ="/dev/zvol"; | |
/* | |
* Default wait time for a device name to be created. | |
*/ | |
enum DISK_LABEL_WAIT (30 * 1000) /* 30 seconds */ | |
enum IMPORT_ORDER_PREFERRED_1 1 | |
enum IMPORT_ORDER_PREFERRED_2 2 | |
enum IMPORT_ORDER_SCAN_OFFSET 10 | |
enum IMPORT_ORDER_DEFAULT 100 | |
enum DEFAULT_IMPORT_PATH_SIZE 9 | |
extern(C) char *zpool_default_import_path[DEFAULT_IMPORT_PATH_SIZE]; | |
/* | |
* libzfs errors | |
*/ | |
enum ZFSError | |
{ | |
EZFS_SUCCESS = 0, /* no error -- success */ | |
EZFS_NOMEM = 2000, /* out of memory */ | |
EZFS_BADPROP, /* invalid property value */ | |
EZFS_PROPREADONLY, /* cannot set readonly property */ | |
EZFS_PROPTYPE, /* property does not apply to dataset type */ | |
EZFS_PROPNONINHERIT, /* property is not inheritable */ | |
EZFS_PROPSPACE, /* bad quota or reservation */ | |
EZFS_BADTYPE, /* dataset is not of appropriate type */ | |
EZFS_BUSY, /* pool or dataset is busy */ | |
EZFS_EXISTS, /* pool or dataset already exists */ | |
EZFS_NOENT, /* no such pool or dataset */ | |
EZFS_BADSTREAM, /* bad backup stream */ | |
EZFS_DSREADONLY, /* dataset is readonly */ | |
EZFS_VOLTOOBIG, /* volume is too large for 32-bit system */ | |
EZFS_INVALIDNAME, /* invalid dataset name */ | |
EZFS_BADRESTORE, /* unable to restore to destination */ | |
EZFS_BADBACKUP, /* backup failed */ | |
EZFS_BADTARGET, /* bad attach/detach/replace target */ | |
EZFS_NODEVICE, /* no such device in pool */ | |
EZFS_BADDEV, /* invalid device to add */ | |
EZFS_NOREPLICAS, /* no valid replicas */ | |
EZFS_RESILVERING, /* currently resilvering */ | |
EZFS_BADVERSION, /* unsupported version */ | |
EZFS_POOLUNAVAIL, /* pool is currently unavailable */ | |
EZFS_DEVOVERFLOW, /* too many devices in one vdev */ | |
EZFS_BADPATH, /* must be an absolute path */ | |
EZFS_CROSSTARGET, /* rename or clone across pool or dataset */ | |
EZFS_ZONED, /* used improperly in local zone */ | |
EZFS_MOUNTFAILED, /* failed to mount dataset */ | |
EZFS_UMOUNTFAILED, /* failed to unmount dataset */ | |
EZFS_UNSHARENFSFAILED, /* unshare(1M) failed */ | |
EZFS_SHARENFSFAILED, /* share(1M) failed */ | |
EZFS_PERM, /* permission denied */ | |
EZFS_NOSPC, /* out of space */ | |
EZFS_FAULT, /* bad address */ | |
EZFS_IO, /* I/O error */ | |
EZFS_INTR, /* signal received */ | |
EZFS_ISSPARE, /* device is a hot spare */ | |
EZFS_INVALCONFIG, /* invalid vdev configuration */ | |
EZFS_RECURSIVE, /* recursive dependency */ | |
EZFS_NOHISTORY, /* no history object */ | |
EZFS_POOLPROPS, /* couldn't retrieve pool props */ | |
EZFS_POOL_NOTSUP, /* ops not supported for this type of pool */ | |
EZFS_POOL_INVALARG, /* invalid argument for this pool operation */ | |
EZFS_NAMETOOLONG, /* dataset name is too long */ | |
EZFS_OPENFAILED, /* open of device failed */ | |
EZFS_NOCAP, /* couldn't get capacity */ | |
EZFS_LABELFAILED, /* write of label failed */ | |
EZFS_BADWHO, /* invalid permission who */ | |
EZFS_BADPERM, /* invalid permission */ | |
EZFS_BADPERMSET, /* invalid permission set name */ | |
EZFS_NODELEGATION, /* delegated administration is disabled */ | |
EZFS_UNSHARESMBFAILED, /* failed to unshare over smb */ | |
EZFS_SHARESMBFAILED, /* failed to share over smb */ | |
EZFS_BADCACHE, /* bad cache file */ | |
EZFS_ISL2CACHE, /* device is for the level 2 ARC */ | |
EZFS_VDEVNOTSUP, /* unsupported vdev type */ | |
EZFS_NOTSUP, /* ops not supported on this dataset */ | |
EZFS_ACTIVE_SPARE, /* pool has active shared spare devices */ | |
EZFS_UNPLAYED_LOGS, /* log device has unplayed logs */ | |
EZFS_REFTAG_RELE, /* snapshot release: tag not found */ | |
EZFS_REFTAG_HOLD, /* snapshot hold: tag already exists */ | |
EZFS_TAGTOOLONG, /* snapshot hold/rele: tag too long */ | |
EZFS_PIPEFAILED, /* pipe create failed */ | |
EZFS_THREADCREATEFAILED, /* thread create failed */ | |
EZFS_POSTSPLIT_ONLINE, /* onlining a disk after splitting it */ | |
EZFS_SCRUBBING, /* currently scrubbing */ | |
EZFS_NO_SCRUB, /* no active scrub */ | |
EZFS_DIFF, /* general failure of zfs diff */ | |
EZFS_DIFFDATA, /* bad zfs diff data */ | |
EZFS_POOLREADONLY, /* pool is in read-only mode */ | |
EZFS_SCRUB_PAUSED, /* scrub currently paused */ | |
EZFS_ACTIVE_POOL, /* pool is imported on a different system */ | |
EZFS_CRYPTOFAILED, /* failed to setup encryption */ | |
EZFS_UNKNOWN | |
} | |
/* | |
* The following data structures are all part | |
* of the zfs_allow_t data structure which is | |
* used for printing 'allow' permissions. | |
* It is a linked list of zfs_allow_t's which | |
* then contain avl tree's for user/group/sets/... | |
* and each one of the entries in those trees have | |
* avl tree's for the permissions they belong to and | |
* whether they are local,descendent or local+descendent | |
* permissions. The AVL trees are used primarily for | |
* sorting purposes, but also so that we can quickly find | |
* a given user and or permission. | |
*/ | |
struct zfs_perm_node | |
{ | |
avl_node_t z_node; | |
char[MAXPATHLEN] z_pname; | |
} | |
struct zfs_allow_node | |
{ | |
avl_node_t z_node; | |
char z_key[MAXPATHLEN]; /* name, such as joe */ | |
avl_tree_t z_localdescend; /* local+descendent perms */ | |
avl_tree_t z_local; /* local permissions */ | |
avl_tree_t z_descend; /* descendent permissions */ | |
} | |
struct zfs_allow | |
{ | |
struct zfs_allow *z_next; | |
char z_setpoint[MAXPATHLEN]; | |
avl_tree_t z_sets; | |
avl_tree_t z_crperms; | |
avl_tree_t z_user; | |
avl_tree_t z_group; | |
avl_tree_t z_everyone; | |
} | |
/* | |
* Library initialization | |
*/ | |
extern(C) libzfs_handle *libzfs_init(); | |
extern(C) void libzfs_fini(libzfs_handle *); | |
extern(C) libzfs_handle *zpool_get_handle(zpool_handle *); | |
extern(C) libzfs_handle *zfs_get_handle(zfs_handle *); | |
extern(C) void libzfs_print_on_error(libzfs_handle *, boolean_t); | |
extern(C) void zfs_save_arguments(int argc, char **, char *, int); | |
extern(C) int zpool_log_history(libzfs_handle *, const(char)* ); | |
extern(C) int libzfs_errno(libzfs_handle *); | |
extern(C) const(char)* libzfs_error_init(int); | |
extern(C) const(char)* libzfs_error_action(libzfs_handle *); | |
extern(C) const(char)* libzfs_error_description(libzfs_handle *); | |
extern(C) int zfs_standard_error(libzfs_handle *, int, const(char)* ); | |
extern(C) void libzfs_mnttab_init(libzfs_handle *); | |
extern(C) void libzfs_mnttab_fini(libzfs_handle *); | |
extern(C) void libzfs_mnttab_cache(libzfs_handle *, boolean_t); | |
extern(C) int libzfs_mnttab_find(libzfs_handle *, const(char)* , struct mnttab *); | |
extern(C) void libzfs_mnttab_add(libzfs_handle *, const(char)* , const(char)* , const(char)* ); | |
extern(C) void libzfs_mnttab_remove(libzfs_handle *, const(char)* ); | |
/* | |
* Basic handle functions | |
*/ | |
extern(C) zpool_handle *zpool_open(libzfs_handle *, const(char)* ); | |
extern(C) zpool_handle *zpool_open_canfail(libzfs_handle *, const(char)* ); | |
extern(C) void zpool_close(zpool_handle *); | |
extern(C) const(char)* zpool_get_name(zpool_handle *); | |
extern(C) int zpool_get_state(zpool_handle *); | |
extern(C) char *zpool_state_to_name(vdev_state_t, vdev_aux_t); | |
extern(C) const(char)* zpool_pool_state_to_name(pool_state_t); | |
extern(C) void zpool_free_handles(libzfs_handle *); | |
/* | |
* Iterate over all active pools in the system. | |
*/ | |
alias zpool_iter_f = int funciton(zpool_handle *, void *); | |
extern(C) int zpool_iter(libzfs_handle *, zpool_iter_f, void *); | |
extern(C) boolean_t zpool_skip_pool(const(char)* ); | |
/* | |
* Functions to create and destroy pools | |
*/ | |
extern(C) int zpool_create(libzfs_handle *, const(char)* , nvlist_t *, nvlist_t *, nvlist_t *); | |
extern(C) int zpool_destroy(zpool_handle *, const(char)* ); | |
extern(C) int zpool_add(zpool_handle *, nvlist_t *); | |
struct splitflags { | |
/* do not split, but return the config that would be split off */ | |
int dryrun : 1; | |
/* after splitting, import the pool */ | |
int import : 1; | |
int name_flags; | |
} | |
/* | |
* Functions to manipulate pool and vdev state | |
*/ | |
extern(C) int zpool_scan(zpool_handle *, pool_scan_func_t, pool_scrub_cmd_t); | |
extern(C) int zpool_clear(zpool_handle *, const(char)* , nvlist_t *); | |
extern(C) int zpool_reguid(zpool_handle *); | |
extern(C) int zpool_reopen(zpool_handle *); | |
extern(C) int zpool_sync_one(zpool_handle *, void *); | |
extern(C) int zpool_vdev_online(zpool_handle *, const(char)* , int, | |
vdev_state_t *); | |
extern(C) int zpool_vdev_offline(zpool_handle *, const(char)* , boolean_t); | |
extern(C) int zpool_vdev_attach(zpool_handle *, const(char)* , const(char)* , nvlist_t *, int); | |
extern(C) int zpool_vdev_detach(zpool_handle *, const(char)* ); | |
extern(C) int zpool_vdev_remove(zpool_handle *, const(char)* ); | |
extern(C) int zpool_vdev_split(zpool_handle *, char *, nvlist_t **, nvlist_t *, splitflags_t); | |
extern(C) int zpool_vdev_fault(zpool_handle *, ulong, vdev_aux_t); | |
extern(C) int zpool_vdev_degrade(zpool_handle *, ulong, vdev_aux_t); | |
extern(C) int zpool_vdev_clear(zpool_handle *, ulong); | |
extern(C) nvlist_t *zpool_find_vdev(zpool_handle *, const(char)* , boolean_t *, boolean_t *, boolean_t *); | |
extern(C) nvlist_t *zpool_find_vdev_by_physpath(zpool_handle *, const(char)* , boolean_t *, boolean_t *, boolean_t *); | |
extern(C) int zpool_label_disk_wait(char *, int); | |
extern(C) int zpool_label_disk(libzfs_handle *, zpool_handle *, char *); | |
extern(C) ulong zpool_vdev_path_to_guid(zpool_handle *zhp, const(char)* path); | |
int zfs_dev_is_dm(char *dev_name); | |
int zfs_dev_is_whole_disk(char *dev_name); | |
char *zfs_get_underlying_path(char *dev_name); | |
char *zfs_get_enclosure_sysfs_path(char *dev_name); | |
/* | |
* Functions to manage pool properties | |
*/ | |
extern(C) int zpool_set_prop(zpool_handle *, const(char)* , const(char)* ); | |
extern(C) int zpool_get_prop(zpool_handle *, zpool_prop_t, char *, size_t proplen, zprop_source_t *, boolean_t literal); | |
extern(C) ulong zpool_get_prop_int(zpool_handle *, zpool_prop_t, zprop_source_t *); | |
extern(C) const(char)* zpool_prop_to_name(zpool_prop_t); | |
extern(C) const(char)* zpool_prop_values(zpool_prop_t); | |
/* | |
* Pool health statistics. | |
*/ | |
enum zpool_status_t | |
{ | |
/* | |
* The following correspond to faults as defined in the (fault.fs.zfs.*) | |
* event namespace. Each is associated with a corresponding message ID. | |
*/ | |
ZPOOL_STATUS_CORRUPT_CACHE, /* corrupt /kernel/drv/zpool.cache */ | |
ZPOOL_STATUS_MISSING_DEV_R, /* missing device with replicas */ | |
ZPOOL_STATUS_MISSING_DEV_NR, /* missing device with no replicas */ | |
ZPOOL_STATUS_CORRUPT_LABEL_R, /* bad device label with replicas */ | |
ZPOOL_STATUS_CORRUPT_LABEL_NR, /* bad device label with no replicas */ | |
ZPOOL_STATUS_BAD_GUID_SUM, /* sum of device guids didn't match */ | |
ZPOOL_STATUS_CORRUPT_POOL, /* pool metadata is corrupted */ | |
ZPOOL_STATUS_CORRUPT_DATA, /* data errors in user (meta)data */ | |
ZPOOL_STATUS_FAILING_DEV, /* device experiencing errors */ | |
ZPOOL_STATUS_VERSION_NEWER, /* newer on-disk version */ | |
ZPOOL_STATUS_HOSTID_MISMATCH, /* last accessed by another system */ | |
ZPOOL_STATUS_HOSTID_ACTIVE, /* currently active on another system */ | |
ZPOOL_STATUS_HOSTID_REQUIRED, /* multihost=on and hostid=0 */ | |
ZPOOL_STATUS_IO_FAILURE_WAIT, /* failed I/O, failmode 'wait' */ | |
ZPOOL_STATUS_IO_FAILURE_CONTINUE, /* failed I/O, failmode 'continue' */ | |
ZPOOL_STATUS_BAD_LOG, /* cannot read log chain(s) */ | |
ZPOOL_STATUS_ERRATA, /* informational errata available */ | |
/* | |
* If the pool has unsupported features but can still be opened in | |
* read-only mode, its status is ZPOOL_STATUS_UNSUP_FEAT_WRITE. If the | |
* pool has unsupported features but cannot be opened at all, its | |
* status is ZPOOL_STATUS_UNSUP_FEAT_READ. | |
*/ | |
ZPOOL_STATUS_UNSUP_FEAT_READ, /* unsupported features for read */ | |
ZPOOL_STATUS_UNSUP_FEAT_WRITE, /* unsupported features for write */ | |
/* | |
* These faults have no corresponding message ID. At the time we are | |
* checking the status, the original reason for the FMA fault (I/O or | |
* checksum errors) has been lost. | |
*/ | |
ZPOOL_STATUS_FAULTED_DEV_R, /* faulted device with replicas */ | |
ZPOOL_STATUS_FAULTED_DEV_NR, /* faulted device with no replicas */ | |
/* | |
* The following are not faults per se, but still an error possibly | |
* requiring administrative attention. There is no corresponding | |
* message ID. | |
*/ | |
ZPOOL_STATUS_VERSION_OLDER, /* older legacy on-disk version */ | |
ZPOOL_STATUS_FEAT_DISABLED, /* supported features are disabled */ | |
ZPOOL_STATUS_RESILVERING, /* device being resilvered */ | |
ZPOOL_STATUS_OFFLINE_DEV, /* device offline */ | |
ZPOOL_STATUS_REMOVED_DEV, /* removed device */ | |
/* | |
* Finally, the following indicates a healthy pool. | |
*/ | |
ZPOOL_STATUS_OK | |
} | |
extern(C) zpool_status_t zpool_get_status(zpool_handle *, char **, | |
zpool_errata_t *); | |
extern(C) zpool_status_t zpool_import_status(nvlist_t *, char **, | |
zpool_errata_t *); | |
extern(C) void zpool_dump_ddt(const ddt_stat_t *dds, const ddt_histogram_t *ddh); | |
/* | |
* Statistics and configuration functions. | |
*/ | |
extern(C) nvlist_t *zpool_get_config(zpool_handle *, nvlist_t **); | |
extern(C) nvlist_t *zpool_get_features(zpool_handle *); | |
extern(C) int zpool_refresh_stats(zpool_handle *, boolean_t *); | |
extern(C) int zpool_get_errlog(zpool_handle *, nvlist_t **); | |
/* | |
* Import and export functions | |
*/ | |
extern(C) int zpool_export(zpool_handle *, boolean_t, const(char)* ); | |
extern(C) int zpool_export_force(zpool_handle *, const(char)* ); | |
extern(C) int zpool_import(libzfs_handle *, nvlist_t *, const(char)* , | |
char *altroot); | |
extern(C) int zpool_import_props(libzfs_handle *, nvlist_t *, const(char)* , | |
nvlist_t *, int); | |
extern(C) void zpool_print_unsup_feat(nvlist_t *config); | |
/* | |
* Search for pools to import | |
*/ | |
struct importargs | |
{ | |
char **path; /* a list of paths to search */ | |
int paths; /* number of paths to search */ | |
char *poolname; /* name of a pool to find */ | |
ulong guid; /* guid of a pool to find */ | |
char *cachefile; /* cachefile to use for import */ | |
int can_be_active : 1; /* can the pool be active? */ | |
int unique : 1; /* does 'poolname' already exist? */ | |
int exists : 1; /* set on return if pool already exists */ | |
int scan : 1; /* prefer scanning to libblkid cache */ | |
} | |
extern(C) nvlist_t *zpool_search_import(libzfs_handle *, importargs_t *); | |
extern(C) int zpool_tryimport(libzfs_handle *hdl, char *target, nvlist_t **configp, importargs_t *args); | |
/* legacy pool search routines */ | |
extern(C) nvlist_t *zpool_find_import(libzfs_handle *, int, char **); | |
extern(C) nvlist_t *zpool_find_import_cached(libzfs_handle *, const(char)* , char *, ulong); | |
/* | |
* Miscellaneous pool functions | |
*/ | |
struct zfs_cmd; | |
extern(C) const(char)* zfs_history_event_names[]; | |
enum VdevName | |
{ | |
VDEV_NAME_PATH = 1 << 0, | |
VDEV_NAME_GUID = 1 << 1, | |
VDEV_NAME_FOLLOW_LINKS = 1 << 2, | |
VDEV_NAME_TYPE_ID = 1 << 3, | |
} | |
extern(C) char *zpool_vdev_name(libzfs_handle *, zpool_handle *, nvlist_t *, int name_flags); | |
extern(C) int zpool_upgrade(zpool_handle *, ulong); | |
extern(C) int zpool_get_history(zpool_handle *, nvlist_t **); | |
extern(C) int zpool_history_unpack(char *, ulong, ulong *, nvlist_t ***, uint *); | |
extern(C) int zpool_events_next(libzfs_handle *, nvlist_t **, int *, unsigned, int); | |
extern(C) int zpool_events_clear(libzfs_handle *, int *); | |
extern(C) int zpool_events_seek(libzfs_handle *, ulong, int); | |
extern(C) void zpool_obj_to_path(zpool_handle *, ulong, ulong, char *, size_t len); | |
extern(C) int zfs_ioctl(libzfs_handle *, int, struct zfs_cmd *); | |
extern(C) int zpool_get_physpath(zpool_handle *, char *, size_t); | |
extern(C) void zpool_explain_recover(libzfs_handle *, const(char)* , int, | |
nvlist_t *); | |
/* | |
* Basic handle manipulations. These functions do not create or destroy the | |
* underlying datasets, only the references to them. | |
*/ | |
extern(C) zfs_handle *zfs_open(libzfs_handle *, const(char)* , int); | |
extern(C) zfs_handle *zfs_handle_dup(zfs_handle *); | |
extern(C) void zfs_close(zfs_handle *); | |
extern(C) zfs_type_t zfs_get_type(const zfs_handle *); | |
extern(C) const(char)* zfs_get_name(const zfs_handle *); | |
extern(C) zpool_handle *zfs_get_pool_handle(const zfs_handle *); | |
extern(C) const(char)* zfs_get_pool_name(const zfs_handle *); | |
/* | |
* Property management functions. Some functions are shared with the kernel, | |
* and are found in sys/fs/zfs.h. | |
*/ | |
/* | |
* zfs dataset property management | |
*/ | |
extern(C) const(char)* zfs_prop_default_string(zfs_prop_t); | |
extern(C) ulong zfs_prop_default_numeric(zfs_prop_t); | |
extern(C) const(char)* zfs_prop_column_name(zfs_prop_t); | |
extern(C) boolean_t zfs_prop_align_right(zfs_prop_t); | |
extern(C) nvlist_t *zfs_valid_proplist(libzfs_handle *, zfs_type_t, nvlist_t *, ulong, zfs_handle *, zpool_handle *, boolean_t, const(char)* ); | |
extern(C) const(char)* zfs_prop_to_name(zfs_prop_t); | |
extern(C) int zfs_prop_set(zfs_handle *, const(char)* , const(char)* ); | |
extern(C) int zfs_prop_set_list(zfs_handle *, nvlist_t *); | |
extern(C) int zfs_prop_get(zfs_handle *, zfs_prop_t, char *, size_t, zprop_source_t *, char *, size_t, boolean_t); | |
extern(C) int zfs_prop_get_recvd(zfs_handle *, const(char)* , char *, size_t, boolean_t); | |
extern(C) int zfs_prop_get_numeric(zfs_handle *, zfs_prop_t, ulong *, | |
zprop_source_t *, char *, size_t); | |
extern(C) int zfs_prop_get_userquota_int(zfs_handle *zhp, const(char)* propname, ulong *propvalue); | |
extern(C) int zfs_prop_get_userquota(zfs_handle *zhp, const(char)* propname, char *propbuf, int proplen, boolean_t literal); | |
extern(C) int zfs_prop_get_written_int(zfs_handle *zhp, const(char)* propname, ulong *propvalue); | |
extern(C) int zfs_prop_get_written(zfs_handle *zhp, const(char)* propname, char *propbuf, int proplen, boolean_t literal); | |
extern(C) int zfs_prop_get_feature(zfs_handle *zhp, const(char)* propname, char *buf, size_t len); | |
extern(C) ulong getprop_uint64(zfs_handle *, zfs_prop_t, char **); | |
extern(C) ulong zfs_prop_get_int(zfs_handle *, zfs_prop_t); | |
extern(C) int zfs_prop_inherit(zfs_handle *, const(char)* , boolean_t); | |
extern(C) const(char)* zfs_prop_values(zfs_prop_t); | |
extern(C) int zfs_prop_is_string(zfs_prop_t prop); | |
extern(C) nvlist_t *zfs_get_user_props(zfs_handle *); | |
extern(C) nvlist_t *zfs_get_recvd_props(zfs_handle *); | |
extern(C) nvlist_t *zfs_get_clones_nvl(zfs_handle *); | |
/* | |
* zfs encryption management | |
*/ | |
extern(C) int zfs_crypto_get_encryption_root(zfs_handle *, boolean_t *, char *); | |
extern(C) int zfs_crypto_create(libzfs_handle *, char *, nvlist_t *, nvlist_t *, ubyte **, uint *); | |
extern(C) int zfs_crypto_clone_check(libzfs_handle *, zfs_handle *, char *, nvlist_t *); | |
extern(C) int zfs_crypto_attempt_load_keys(libzfs_handle *, char *); | |
extern(C) int zfs_crypto_load_key(zfs_handle *, boolean_t, char *); | |
extern(C) int zfs_crypto_unload_key(zfs_handle *); | |
extern(C) int zfs_crypto_rewrap(zfs_handle *, nvlist_t *, boolean_t); | |
struct zprop_list | |
{ | |
int pl_prop; | |
char *pl_user_prop; | |
struct zprop_list *pl_next; | |
boolean_t pl_all; | |
size_t pl_width; | |
size_t pl_recvd_width; | |
boolean_t pl_fixed; | |
} | |
extern(C) int zfs_expand_proplist(zfs_handle *, zprop_list_t **, boolean_t, | |
boolean_t); | |
extern(C) void zfs_prune_proplist(zfs_handle *, ubyte *); | |
enum ZFS_MOUNTPOINT_NONE= "none"; | |
enum ZFS_MOUNTPOINT_LEGACY= "legacy"; | |
enum ZFS_FEATURE_DISABLED ="disabled"; | |
enum ZFS_FEATURE_ENABLED ="enabled"; | |
enum ZFS_FEATURE_ACTIVE ="active"; | |
enum ZFS_UNSUPPORTED_INACTIVE ="inactive"; | |
enum ZFS_UNSUPPORTED_READONLY ="readonly"; | |
/* | |
* zpool property management | |
*/ | |
extern(C) int zpool_expand_proplist(zpool_handle *, zprop_list_t **); | |
extern(C) int zpool_prop_get_feature(zpool_handle *, const(char)* , char *, | |
size_t); | |
extern(C) const(char)* zpool_prop_default_string(zpool_prop_t); | |
extern(C) ulong zpool_prop_default_numeric(zpool_prop_t); | |
extern(C) const(char)* zpool_prop_column_name(zpool_prop_t); | |
extern(C) boolean_t zpool_prop_align_right(zpool_prop_t); | |
/* | |
* Functions shared by zfs and zpool property management. | |
*/ | |
extern(C) int zprop_iter(zprop_func func, void *cb, boolean_t show_all, | |
boolean_t ordered, zfs_type_t type); | |
extern(C) int zprop_get_list(libzfs_handle *, char *, zprop_list_t **, | |
zfs_type_t); | |
extern(C) void zprop_free_list(zprop_list_t *); | |
enum ZFS_GET_NCOLS 5 | |
enum zfs_get_column_t | |
{ | |
GET_COL_NONE, | |
GET_COL_NAME, | |
GET_COL_PROPERTY, | |
GET_COL_VALUE, | |
GET_COL_RECVD, | |
GET_COL_SOURCE | |
} | |
/// Functions for printing zfs or zpool properties | |
struct zprop_get_cbdata | |
{ | |
int cb_sources; | |
zfs_get_column_t[ZFS_GET_NCOLS] cb_columns; | |
int cb_colwidths[ZFS_GET_NCOLS + 1]; | |
boolean_t cb_scripted; | |
boolean_t cb_literal; | |
boolean_t cb_first; | |
zprop_list_t *cb_proplist; | |
zfs_type_t cb_type; | |
} | |
void zprop_print_one_property(const(char)* , zprop_get_cbdata_t *, const(char)* , const(char)* , zprop_source_t, const(char)* , const(char)* ); | |
/* | |
* Iterator functions. | |
*/ | |
alias zfs_iter_f = int(zfs_handle *, void *); | |
extern(C) int zfs_iter_root(libzfs_handle *, zfs_iter_f, void *); | |
extern(C) int zfs_iter_children(zfs_handle *, zfs_iter_f, void *); | |
extern(C) int zfs_iter_dependents(zfs_handle *, boolean_t, zfs_iter_f, void *); | |
extern(C) int zfs_iter_filesystems(zfs_handle *, zfs_iter_f, void *); | |
extern(C) int zfs_iter_snapshots(zfs_handle *, boolean_t, zfs_iter_f, void *); | |
extern(C) int zfs_iter_snapshots_sorted(zfs_handle *, zfs_iter_f, void *); | |
extern(C) int zfs_iter_snapspec(zfs_handle *, const(char)* , zfs_iter_f, void *); | |
extern(C) int zfs_iter_bookmarks(zfs_handle *, zfs_iter_f, void *); | |
struct get_all_cb | |
{ | |
zfs_handle **cb_handles; | |
size_t cb_alloc; | |
size_t cb_used; | |
boolean_t cb_verbose; | |
int (*cb_getone)(zfs_handle *, void *); | |
} | |
extern(C) void libzfs_add_handle(get_all_cb_t *, zfs_handle *); | |
extern(C) int libzfs_dataset_cmp(const void *, const void *); | |
/* | |
* Functions to create and destroy datasets. | |
*/ | |
extern(C) int zfs_create(libzfs_handle *, const(char)* , zfs_type_t, nvlist_t *); | |
extern(C) int zfs_create_ancestors(libzfs_handle *, const(char)* ); | |
extern(C) int zfs_destroy(zfs_handle *, boolean_t); | |
extern(C) int zfs_destroy_snaps(zfs_handle *, char *, boolean_t); | |
extern(C) int zfs_destroy_snaps_nvl(libzfs_handle *, nvlist_t *, boolean_t); | |
extern(C) int zfs_clone(zfs_handle *, const(char)* , nvlist_t *); | |
extern(C) int zfs_snapshot(libzfs_handle *, const(char)* , boolean_t, nvlist_t *); | |
extern(C) int zfs_snapshot_nvl(libzfs_handle *hdl, nvlist_t *snaps, | |
nvlist_t *props); | |
extern(C) int zfs_rollback(zfs_handle *, zfs_handle *, boolean_t); | |
extern(C) int zfs_rename(zfs_handle *, const(char)* , boolean_t, boolean_t); | |
struct sendflags | |
{ | |
/* print informational messages (ie, -v was specified) */ | |
boolean_t verbose; | |
/* recursive send (ie, -R) */ | |
boolean_t replicate; | |
/* for incrementals, do all intermediate snapshots */ | |
boolean_t doall; | |
/* if dataset is a clone, do incremental from its origin */ | |
boolean_t fromorigin; | |
/* do deduplication */ | |
boolean_t dedup; | |
/* send properties (ie, -p) */ | |
boolean_t props; | |
/* do not send (no-op, ie. -n) */ | |
boolean_t dryrun; | |
/* parsable verbose output (ie. -P) */ | |
boolean_t parsable; | |
/* show progress (ie. -v) */ | |
boolean_t progress; | |
/* large blocks (>128K) are permitted */ | |
boolean_t largeblock; | |
/* WRITE_EMBEDDED records of type DATA are permitted */ | |
boolean_t embed_data; | |
/* compressed WRITE records are permitted */ | |
boolean_t compress; | |
/* raw encrypted records are permitted */ | |
boolean_t raw; | |
} | |
alias snapfilter_cb_t = boolean_t function(zfs_handle *, void *); | |
extern(C) int zfs_send(zfs_handle *, const(char)* , const(char)* , sendflags_t *, int, snapfilter_cb_t, void *, nvlist_t **); | |
extern(C) int zfs_send_one(zfs_handle *, const(char)* , int, lzc_send_flags); | |
extern(C) int zfs_send_resume(libzfs_handle *, sendflags_t *, int outfd, const(char)* ); | |
extern(C) nvlist_t *zfs_send_resume_token_to_nvlist(libzfs_handle *hdl, const(char)* token); | |
extern(C) int zfs_promote(zfs_handle *); | |
extern(C) int zfs_hold(zfs_handle *, const(char)* , const(char)* , boolean_t, int); | |
extern(C) int zfs_hold_nvl(zfs_handle *, int, nvlist_t *); | |
extern(C) int zfs_release(zfs_handle *, const(char)* , const(char)* , boolean_t); | |
extern(C) int zfs_get_holds(zfs_handle *, nvlist_t **); | |
extern(C) ulong zvol_volsize_to_reservation(ulong, nvlist_t *); | |
alias zfs_userspace_cb_t = int function(void *arg, const(char)* domain, uid_t rid, ulong space); | |
extern(C) int zfs_userspace(zfs_handle *, zfs_userquota_prop_t, zfs_userspace_cb_t, void *); | |
extern(C) int zfs_get_fsacl(zfs_handle *, nvlist_t **); | |
extern(C) int zfs_set_fsacl(zfs_handle *, boolean_t, nvlist_t *); | |
struct recvflags | |
{ | |
/* print informational messages (ie, -v was specified) */ | |
boolean_t verbose; | |
/* the destination is a prefix, not the exact fs (ie, -d) */ | |
boolean_t isprefix; | |
/* | |
* Only the tail of the sent snapshot path is appended to the | |
* destination to determine the received snapshot name (ie, -e). | |
*/ | |
boolean_t istail; | |
/* do not actually do the recv, just check if it would work (ie, -n) */ | |
boolean_t dryrun; | |
/* rollback/destroy filesystems as necessary (eg, -F) */ | |
boolean_t force; | |
/* set "canmount=off" on all modified filesystems */ | |
boolean_t canmountoff; | |
/* | |
* Mark the file systems as "resumable" and do not destroy them if the | |
* receive is interrupted | |
*/ | |
boolean_t resumable; | |
/* byteswap flag is used internally; callers need not specify */ | |
boolean_t byteswap; | |
/* do not mount file systems as they are extracted (private) */ | |
boolean_t nomount; | |
} | |
extern(C) int zfs_receive(libzfs_handle *, const(char)* , nvlist_t *, recvflags_t *, int, avl_tree_t *); | |
enum diff_flags { | |
ZFS_DIFF_PARSEABLE = 0x1, | |
ZFS_DIFF_TIMESTAMP = 0x2, | |
ZFS_DIFF_CLASSIFY = 0x4 | |
} | |
extern(C) int zfs_show_diffs(zfs_handle *, int, const(char)* , const(char)* , int); | |
/* | |
* Miscellaneous functions. | |
*/ | |
extern(C) const(char)* zfs_type_to_name(zfs_type_t); | |
extern(C) void zfs_refresh_properties(zfs_handle *); | |
extern(C) int zfs_name_valid(const(char)* , zfs_type_t); | |
extern(C) zfs_handle *zfs_path_to_zhandle(libzfs_handle *, char *, zfs_type_t); | |
extern(C) int zfs_parent_name(zfs_handle *, char *, size_t); | |
extern(C) boolean_t zfs_dataset_exists(libzfs_handle *, const(char)* , zfs_type_t); | |
extern(C) int zfs_spa_version(zfs_handle *, int *); | |
extern(C) boolean_t zfs_bookmark_exists(const(char)* path); | |
extern(C) int zfs_append_partition(char *path, size_t max_len); | |
extern(C) int zfs_resolve_shortname(const(char)* name, char *path, size_t pathlen); | |
extern(C) int zfs_strcmp_pathname(char *name, char *cmp_name, int wholedisk); | |
extern(C) int zfs_path_order(char *path, int *order); | |
/* | |
* Mount support functions. | |
*/ | |
extern(C) boolean_t is_mounted(libzfs_handle *, const(char)* special, char **); | |
extern(C) boolean_t zfs_is_mounted(zfs_handle *, char **); | |
extern(C) int zfs_mount(zfs_handle *, const(char)* , int); | |
extern(C) int zfs_unmount(zfs_handle *, const(char)* , int); | |
extern(C) int zfs_unmountall(zfs_handle *, int); | |
/// Share support functions. | |
extern(C) boolean_t zfs_is_shared(zfs_handle *); | |
extern(C) int zfs_share(zfs_handle *); | |
extern(C) int zfs_unshare(zfs_handle *); | |
/* | |
* Protocol-specific share support functions. | |
*/ | |
extern(C) boolean_t zfs_is_shared_nfs(zfs_handle *, char **); | |
extern(C) boolean_t zfs_is_shared_smb(zfs_handle *, char **); | |
extern(C) int zfs_share_nfs(zfs_handle *); | |
extern(C) int zfs_share_smb(zfs_handle *); | |
extern(C) int zfs_shareall(zfs_handle *); | |
extern(C) int zfs_unshare_nfs(zfs_handle *, const(char)* ); | |
extern(C) int zfs_unshare_smb(zfs_handle *, const(char)* ); | |
extern(C) int zfs_unshareall_nfs(zfs_handle *); | |
extern(C) int zfs_unshareall_smb(zfs_handle *); | |
extern(C) int zfs_unshareall_bypath(zfs_handle *, const(char)* ); | |
extern(C) int zfs_unshareall_bytype(zfs_handle *, const(char)* , const(char)* ); | |
extern(C) int zfs_unshareall(zfs_handle *); | |
extern(C) int zfs_deleg_share_nfs(libzfs_handle *, char *, char *, char *, void *, void *, int, zfs_share_op_t); | |
/* | |
* Formats for iostat numbers. Examples: "12K", "30ms", "4B", "2321234", "-". | |
* | |
* ZFS_NICENUM_1024: Print kilo, mega, tera, peta, exa.. | |
* ZFS_NICENUM_BYTES: Print single bytes ("13B"), kilo, mega, tera... | |
* ZFS_NICENUM_TIME: Print nanosecs, microsecs, millisecs, seconds... | |
* ZFS_NICENUM_RAW: Print the raw number without any formatting | |
* ZFS_NICENUM_RAWTIME: Same as RAW, but print dashes ('-') for zero. | |
*/ | |
enum zfs_nicenum_format | |
{ | |
ZFS_NICENUM_1024 = 0, | |
ZFS_NICENUM_BYTES = 1, | |
ZFS_NICENUM_TIME = 2, | |
ZFS_NICENUM_RAW = 3, | |
ZFS_NICENUM_RAWTIME = 4 | |
} | |
/* | |
* Utility function to convert a number to a human-readable form. | |
*/ | |
extern(C) void zfs_nicenum(ulong, char *, size_t); | |
extern(C) void zfs_nicenum_format(ulong num, char *buf, size_t buflen, enum zfs_nicenum_format type); | |
extern(C) void zfs_nicetime(ulong, char *, size_t); | |
extern(C) void zfs_nicebytes(ulong, char *, size_t); | |
extern(C) int zfs_nicestrtonum(libzfs_handle *, const(char)* , ulong *); | |
/* | |
* Utility functions to run an extern(C) al process. | |
*/ | |
enum STDOUT_VERBOSE=0x01; | |
enum STDERR_VERBOSE= 0x02; | |
enum NO_DEFAULT_PATH= 0x04; /* Don't use $PATH to lookup the command */ | |
int libzfs_run_process(const(char)* , char **, int flags); | |
int libzfs_run_process_get_stdout(const(char)* path, char *argv[], char *env[], char **lines[], int *lines_cnt); | |
int libzfs_run_process_get_stdout_nopath(const(char)* path, char *argv[], char *env[], char **lines[], int *lines_cnt); | |
void libzfs_free_str_array(char **strs, int count); | |
int libzfs_envvar_is_set(char *envvar); | |
/// Given a device or file, determine if it is part of a pool. | |
extern(C) int zpool_in_use(libzfs_handle *, int, pool_state_t *, char **, boolean_t *); | |
/// Label manipulation. | |
extern(C) int zpool_read_label(int, nvlist_t **, int *); | |
extern(C) int zpool_clear_label(int); | |
/// Management interfaces for SMB ACL files | |
int zfs_smb_acl_add(libzfs_handle *, char *, char *, char *); | |
int zfs_smb_acl_remove(libzfs_handle *, char *, char *, char *); | |
int zfs_smb_acl_purge(libzfs_handle *, char *, char *); | |
int zfs_smb_acl_rename(libzfs_handle *, char *, char *, char *, char *); | |
/// Enable and disable datasets within a pool by mounting/unmounting and sharing/unsharing them. | |
extern(C) int zpool_enable_datasets(zpool_handle *, const(char)* , int); | |
extern(C) int zpool_disable_datasets(zpool_handle *, boolean_t); | |
/// Mappings between vdev and FRU. | |
extern(C) void libzfs_fru_refresh(libzfs_handle *); | |
extern(C) const(char)* libzfs_fru_lookup(libzfs_handle *, const(char)* ); | |
extern(C) const(char)* libzfs_fru_devpath(libzfs_handle *, const(char)* ); | |
extern(C) boolean_t libzfs_fru_compare(libzfs_handle *, const(char)* , const(char)* ); | |
extern(C) boolean_t libzfs_fru_notself(libzfs_handle *, const(char)* ); | |
extern(C) int zpool_fru_set(zpool_handle *, ulong, const(char)* ); | |
/// Support for Linux libudev derived persistent device strings | |
extern(C) boolean_t is_mpath_whole_disk(const(char)* ); | |
extern(C) void update_vdev_config_dev_strs(nvlist_t *); | |
extern(C) char *zfs_strip_partition(char *); | |
extern(C) char *zfs_strip_partition_path(char *); | |
struct udev_device {} | |
extern(C) boolean_t udev_is_mpath(struct udev_device *dev); | |
extern(C) int zfs_device_get_devid(struct udev_device *, char *, size_t); | |
extern(C) int zfs_device_get_physical(struct udev_device *, char *, size_t); | |
int libzfs_core_init(); | |
void libzfs_core_fini(); | |
/// NB: this type should be kept binary compatible with dmu_objset_type_t. | |
enum lzc_dataset_type | |
{ | |
LZC_DATSET_TYPE_ZFS = 2, | |
LZC_DATSET_TYPE_ZVOL | |
} | |
int lzc_snapshot(nvlist_t *, nvlist_t *, nvlist_t **); | |
int lzc_create(const(char)* , enum lzc_dataset_type, nvlist_t *, ubyte *, uint); | |
int lzc_clone(const(char)* , const(char)* , nvlist_t *); | |
int lzc_promote(const(char)* , char *, int); | |
int lzc_destroy_snaps(nvlist_t *, boolean_t, nvlist_t **); | |
int lzc_bookmark(nvlist_t *, nvlist_t **); | |
int lzc_get_bookmarks(const(char)* , nvlist_t *, nvlist_t **); | |
int lzc_destroy_bookmarks(nvlist_t *, nvlist_t **); | |
int lzc_load_key(const(char)* , boolean_t, ubyte *, uint); | |
int lzc_unload_key(const(char)* ); | |
int lzc_change_key(const(char)* , ulong, nvlist_t *, ubyte *, uint); | |
int lzc_snaprange_space(const(char)* , const(char)* , ulong *); | |
int lzc_hold(nvlist_t *, int, nvlist_t **); | |
int lzc_release(nvlist_t *, nvlist_t **); | |
int lzc_get_holds(const(char)* , nvlist_t **); | |
lzc_send_flags | |
{ | |
LZC_SEND_FLAG_EMBED_DATA = 1 << 0, | |
LZC_SEND_FLAG_LARGE_BLOCK = 1 << 1, | |
LZC_SEND_FLAG_COMPRESS = 1 << 2, | |
LZC_SEND_FLAG_RAW = 1 << 3, | |
} | |
int lzc_send(const(char)* , const(char)* , int, lzc_send_flags); | |
int lzc_send_resume(const(char)* , const(char)* , int, lzc_send_flags, ulong, ulong); | |
int lzc_send_space(const(char)* , const(char)* , lzc_send_flags, ulong *); | |
struct dmu_replay_record; | |
int lzc_receive(const(char)* , nvlist_t *, const(char)* , boolean_t, boolean_t, int); | |
int lzc_receive_resumable(const(char)* , nvlist_t *, const(char)* , boolean_t, boolean_t, int); | |
int lzc_receive_with_header(const(char)* , nvlist_t *, const(char)* , boolean_t, boolean_t, boolean_t, int, const struct dmu_replay_record *); | |
int lzc_receive_one(const(char)* , nvlist_t *, const(char)* , boolean_t, boolean_t, boolean_t, int, const struct dmu_replay_record *, int, ulong *, ulong *, ulong *, nvlist_t **); | |
int lzc_receive_with_cmdprops(const(char)* , nvlist_t *, nvlist_t *, const(char)* , boolean_t, boolean_t, boolean_t, int, const struct dmu_replay_record *, int, ulong *, ulong *, ulong *, nvlist_t **); | |
boolean_t lzc_exists(const(char)* ); | |
int lzc_rollback(const(char)* , char *, int); | |
int lzc_rollback_to(const(char)* , const(char)* ); | |
int lzc_sync(const(char)* , nvlist_t *, nvlist_t **); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package zfs_test | |
package zfs_test | |
import ( | |
"fmt" | |
"testing" | |
"github.com/bicomsystems/go-libzfs" | |
) | |
/* ------------------------------------------------------------------------- */ | |
// HELPERS: | |
var TSTDatasetPath = TSTPoolName + "/DATASET" | |
var TSTVolumePath = TSTDatasetPath + "/VOLUME" | |
var TSTDatasetPathSnap = TSTDatasetPath + "@test" | |
func printDatasets(ds []zfs.Dataset) error { | |
for _, d := range ds { | |
path, err := d.Path() | |
if err != nil { | |
return err | |
} | |
p, err := d.GetProperty(zfs.DatasetPropType) | |
if err != nil { | |
return err | |
} | |
fmt.Printf(" %30s | %10s\n", path, p.Value) | |
if len(d.Children) > 0 { | |
printDatasets(d.Children) | |
} | |
} | |
return nil | |
} | |
/* ------------------------------------------------------------------------- */ | |
// TESTS: | |
func zfsTestDatasetCreate(t *testing.T) { | |
// reinit names used in case TESTPOOL was in conflict | |
TSTDatasetPath = TSTPoolName + "/DATASET" | |
TSTVolumePath = TSTDatasetPath + "/VOLUME" | |
TSTDatasetPathSnap = TSTDatasetPath + "@test" | |
println("TEST DatasetCreate(", TSTDatasetPath, ") (filesystem) ... ") | |
props := make(map[zfs.Prop]zfs.Property) | |
d, err := zfs.DatasetCreate(TSTDatasetPath, zfs.DatasetTypeFilesystem, props) | |
if err != nil { | |
t.Error(err) | |
return | |
} | |
d.Close() | |
print("PASS\n\n") | |
strSize := "536870912" // 512M | |
println("TEST DatasetCreate(", TSTVolumePath, ") (volume) ... ") | |
props[zfs.DatasetPropVolsize] = zfs.Property{Value: strSize} | |
// In addition I explicitly choose some more properties to be set. | |
props[zfs.DatasetPropVolblocksize] = zfs.Property{Value: "4096"} | |
props[zfs.DatasetPropReservation] = zfs.Property{Value: strSize} | |
d, err = zfs.DatasetCreate(TSTVolumePath, zfs.DatasetTypeVolume, props) | |
if err != nil { | |
t.Error(err) | |
return | |
} | |
d.Close() | |
print("PASS\n\n") | |
} | |
func zfsTestDatasetOpen(t *testing.T) { | |
println("TEST DatasetOpen(", TSTDatasetPath, ") ... ") | |
d, err := zfs.DatasetOpen(TSTDatasetPath) | |
if err != nil { | |
t.Error(err) | |
return | |
} | |
defer d.Close() | |
print("PASS\n\n") | |
println("TEST Set/GetUserProperty(prop, value string) ... ") | |
var p zfs.Property | |
// Test set/get user property | |
if err = d.SetUserProperty("go-libzfs:test", "yes"); err != nil { | |
t.Error(err) | |
return | |
} | |
if p, err = d.GetUserProperty("go-libzfs:test"); err != nil { | |
t.Error(err) | |
return | |
} | |
println("go-libzfs:test", " = ", | |
p.Value) | |
print("PASS\n\n") | |
} | |
func zfsTestDatasetOpenAll(t *testing.T) { | |
println("TEST DatasetOpenAll()/DatasetCloseAll() ... ") | |
ds, err := zfs.DatasetOpenAll() | |
if err != nil { | |
t.Error(err) | |
return | |
} | |
if err = printDatasets(ds); err != nil { | |
zfs.DatasetCloseAll(ds) | |
t.Error(err) | |
return | |
} | |
zfs.DatasetCloseAll(ds) | |
print("PASS\n\n") | |
} | |
func zfsTestDatasetSnapshot(t *testing.T) { | |
println("TEST DatasetSnapshot(", TSTDatasetPath, ", true, ...) ... ") | |
props := make(map[zfs.Prop]zfs.Property) | |
d, err := zfs.DatasetSnapshot(TSTDatasetPathSnap, true, props) | |
if err != nil { | |
t.Error(err) | |
return | |
} | |
defer d.Close() | |
print("PASS\n\n") | |
} | |
func zfsTestDatasetDestroy(t *testing.T) { | |
println("TEST DATASET Destroy( ", TSTDatasetPath, " ) ... ") | |
d, err := zfs.DatasetOpen(TSTDatasetPath) | |
if err != nil { | |
t.Error(err) | |
return | |
} | |
defer d.Close() | |
if err = d.DestroyRecursive(); err != nil { | |
t.Error(err) | |
return | |
} | |
print("PASS\n\n") | |
} | |
/* ------------------------------------------------------------------------- */ | |
// EXAMPLES: | |
// Example of creating ZFS volume | |
func ExampleDatasetCreate() { | |
// Create map to represent ZFS dataset properties. This is equivalent to | |
// list of properties you can get from ZFS CLI tool, and some more | |
// internally used by libzfs. | |
props := make(map[zfs.Prop]zfs.Property) | |
// I choose to create (block) volume 1GiB in size. Size is just ZFS dataset | |
// property and this is done as map of strings. So, You have to either | |
// specify size as base 10 number in string, or use strconv package or | |
// similar to convert in to string (base 10) from numeric type. | |
strSize := "1073741824" | |
props[zfs.DatasetPropVolsize] = zfs.Property{Value: strSize} | |
// In addition I explicitly choose some more properties to be set. | |
props[zfs.DatasetPropVolblocksize] = zfs.Property{Value: "4096"} | |
props[zfs.DatasetPropReservation] = zfs.Property{Value: strSize} | |
// Lets create desired volume | |
d, err := zfs.DatasetCreate("TESTPOOL/VOLUME1", zfs.DatasetTypeVolume, props) | |
if err != nil { | |
println(err.Error()) | |
return | |
} | |
// Dataset have to be closed for memory cleanup | |
defer d.Close() | |
println("Created zfs volume TESTPOOL/VOLUME1") | |
} | |
func ExampleDatasetOpen() { | |
// Open dataset and read its available space | |
d, err := zfs.DatasetOpen("TESTPOOL/DATASET1") | |
if err != nil { | |
panic(err.Error()) | |
} | |
defer d.Close() | |
var p zfs.Property | |
if p, err = d.GetProperty(zfs.DatasetPropAvailable); err != nil { | |
panic(err.Error()) | |
} | |
println(zfs.DatasetPropertyToName(zfs.DatasetPropAvailable), " = ", | |
p.Value) | |
} | |
func ExampleDatasetOpenAll() { | |
datasets, err := zfs.DatasetOpenAll() | |
if err != nil { | |
panic(err.Error()) | |
} | |
defer zfs.DatasetCloseAll(datasets) | |
// Print out path and type of root datasets | |
for _, d := range datasets { | |
path, err := d.Path() | |
if err != nil { | |
panic(err.Error()) | |
} | |
p, err := d.GetProperty(zfs.DatasetPropType) | |
if err != nil { | |
panic(err.Error()) | |
} | |
fmt.Printf("%30s | %10s\n", path, p.Value) | |
} | |
} | |
import ( | |
"fmt" | |
"io/ioutil" | |
"os" | |
"testing" | |
"github.com/bicomsystems/go-libzfs" | |
) | |
/* ------------------------------------------------------------------------- */ | |
// HELPERS: | |
var TSTPoolName = "TESTPOOL" | |
var TSTPoolGUID string | |
auto CreateTmpSparse(prefix string, size int64) (path string, err error) { | |
sf, err := ioutil.TempFile("/tmp", prefix) | |
if err != nil { | |
return | |
} | |
defer sf.Close() | |
if err = sf.Truncate(size); err != nil { | |
return | |
} | |
path = sf.Name() | |
return | |
} | |
var s1path, s2path, s3path string | |
// This will create sparse files in tmp directory, | |
// for purpose of creating test pool. | |
auto createTestpoolVdisks() (err error) { | |
if s1path, err = CreateTmpSparse("zfs_test_", 0x140000000); err != nil { | |
return | |
} | |
if s2path, err = CreateTmpSparse("zfs_test_", 0x140000000); err != nil { | |
// try cleanup | |
os.Remove(s1path) | |
return | |
} | |
if s3path, err = CreateTmpSparse("zfs_test_", 0x140000000); err != nil { | |
// try cleanup | |
os.Remove(s1path) | |
os.Remove(s2path) | |
return | |
} | |
return | |
} | |
// Cleanup sparse files used for tests | |
auto cleanupVDisks() { | |
// try cleanup | |
os.Remove(s1path) | |
os.Remove(s2path) | |
os.Remove(s3path) | |
} | |
/* ------------------------------------------------------------------------- */ | |
// TESTS: | |
// Create 3 sparse file in /tmp directory each 5G size, and use them to create | |
// mirror TESTPOOL with one spare "disk" | |
auto zpoolTestPoolCreate(t *testing.T) { | |
println("TEST PoolCreate ... ") | |
// first check if pool with same name already exist | |
// we don't want conflict | |
for { | |
p, err := zfs.PoolOpen(TSTPoolName) | |
if err != nil { | |
break | |
} | |
p.Close() | |
TSTPoolName += "0" | |
} | |
var err error | |
if err = createTestpoolVdisks(); err != nil { | |
t.Error(err) | |
return | |
} | |
disks := [2]string{s1path, s2path} | |
var vdevs, mdevs, sdevs []zfs.VDevTree | |
for _, d := range disks { | |
mdevs = append(mdevs, | |
zfs.VDevTree{Type: zfs.VDevTypeFile, Path: d}) | |
} | |
sdevs = []zfs.VDevTree{ | |
{Type: zfs.VDevTypeFile, Path: s3path}} | |
vdevs = []zfs.VDevTree{ | |
zfs.VDevTree{Type: zfs.VDevTypeMirror, Devices: mdevs}, | |
zfs.VDevTree{Type: zfs.VDevTypeSpare, Devices: sdevs}, | |
} | |
props := make(map[zfs.Prop]string) | |
fsprops := make(map[zfs.Prop]string) | |
features := make(map[string]string) | |
fsprops[zfs.DatasetPropMountpoint] = "none" | |
features["async_destroy"] = zfs.FENABLED | |
features["empty_bpobj"] = zfs.FENABLED | |
features["lz4_compress"] = zfs.FENABLED | |
pool, err := zfs.PoolCreate(TSTPoolName, vdevs, features, props, fsprops) | |
if err != nil { | |
t.Error(err) | |
// try cleanup | |
os.Remove(s1path) | |
os.Remove(s2path) | |
os.Remove(s3path) | |
return | |
} | |
defer pool.Close() | |
pguid, _ := pool.GetProperty(zfs.PoolPropGUID) | |
TSTPoolGUID = pguid.Value | |
print("PASS\n\n") | |
} | |
// Open and list all pools and them state on the system | |
// Then list properties of last pool in the list | |
auto zpoolTestPoolOpenAll(t *testing.T) { | |
println("TEST PoolOpenAll() ... ") | |
var pname string | |
pools, err := zfs.PoolOpenAll() | |
if err != nil { | |
t.Error(err) | |
return | |
} | |
println("\tThere is ", len(pools), " ZFS pools.") | |
for _, p := range pools { | |
pname, err = p.Name() | |
if err != nil { | |
t.Error(err) | |
p.Close() | |
return | |
} | |
pstate, err := p.State() | |
if err != nil { | |
t.Error(err) | |
p.Close() | |
return | |
} | |
println("\tPool: ", pname, " state: ", pstate) | |
p.Close() | |
} | |
print("PASS\n\n") | |
} | |
auto zpoolTestPoolDestroy(t *testing.T) { | |
println("TEST POOL Destroy( ", TSTPoolName, " ) ... ") | |
p, err := zfs.PoolOpen(TSTPoolName) | |
if err != nil { | |
t.Error(err) | |
return | |
} | |
defer p.Close() | |
if err = p.Destroy("Test of pool destroy (" + TSTPoolName + ")"); err != nil { | |
t.Error(err.Error()) | |
return | |
} | |
print("PASS\n\n") | |
} | |
auto zpoolTestFailPoolOpen(t *testing.T) { | |
println("TEST open of non existing pool ... ") | |
pname := "fail to open this pool" | |
p, err := zfs.PoolOpen(pname) | |
if err != nil { | |
print("PASS\n\n") | |
return | |
} | |
t.Error("PoolOpen pass when it should fail") | |
p.Close() | |
} | |
auto zpoolTestExport(t *testing.T) { | |
println("TEST POOL Export( ", TSTPoolName, " ) ... ") | |
p, err := zfs.PoolOpen(TSTPoolName) | |
if err != nil { | |
t.Error(err) | |
return | |
} | |
p.Export(false, "Test exporting pool") | |
defer p.Close() | |
print("PASS\n\n") | |
} | |
auto zpoolTestExportForce(t *testing.T) { | |
println("TEST POOL ExportForce( ", TSTPoolName, " ) ... ") | |
p, err := zfs.PoolOpen(TSTPoolName) | |
if err != nil { | |
t.Error(err) | |
return | |
} | |
p.ExportForce("Test force exporting pool") | |
defer p.Close() | |
print("PASS\n\n") | |
} | |
auto zpoolTestImport(t *testing.T) { | |
println("TEST POOL Import( ", TSTPoolName, " ) ... ") | |
p, err := zfs.PoolImport(TSTPoolName, []string{"/tmp"}) | |
if err != nil { | |
t.Error(err) | |
return | |
} | |
defer p.Close() | |
print("PASS\n\n") | |
} | |
auto zpoolTestImportByGUID(t *testing.T) { | |
println("TEST POOL ImportByGUID( ", TSTPoolGUID, " ) ... ") | |
p, err := zfs.PoolImportByGUID(TSTPoolGUID, []string{"/tmp"}) | |
if err != nil { | |
t.Error(err) | |
return | |
} | |
defer p.Close() | |
print("PASS\n\n") | |
} | |
auto printVDevTree(vt zfs.VDevTree, pref string) { | |
first := pref + vt.Name | |
fmt.Printf("%-30s | %-10s | %-10s | %s\n", first, vt.Type, | |
vt.Stat.State.String(), vt.Path) | |
for _, v := range vt.Devices { | |
printVDevTree(v, " "+pref) | |
} | |
} | |
auto zpoolTestPoolImportSearch(t *testing.T) { | |
println("TEST PoolImportSearch") | |
pools, err := zfs.PoolImportSearch([]string{"/tmp"}) | |
if err != nil { | |
t.Error(err.Error()) | |
return | |
} | |
for _, p := range pools { | |
println() | |
println("---------------------------------------------------------------") | |
println("pool: ", p.Name) | |
println("guid: ", p.GUID) | |
println("state: ", p.State.String()) | |
fmt.Printf("%-30s | %-10s | %-10s | %s\n", "NAME", "TYPE", "STATE", "PATH") | |
println("---------------------------------------------------------------") | |
printVDevTree(p.VDevs, "") | |
} | |
print("PASS\n\n") | |
} | |
auto zpoolTestPoolProp(t *testing.T) { | |
println("TEST PoolProp on ", TSTPoolName, " ... ") | |
if pool, err := zfs.PoolOpen(TSTPoolName); err == nil { | |
defer pool.Close() | |
// Turn on snapshot listing for pool | |
pool.SetProperty(zfs.PoolPropListsnaps, "on") | |
// Verify change is succesfull | |
if pool.Properties[zfs.PoolPropListsnaps].Value != "on" { | |
t.Error(fmt.Errorf("Update of pool property failed")) | |
return | |
} | |
// Test fetching property | |
propHealth, err := pool.GetProperty(zfs.PoolPropHealth) | |
if err != nil { | |
t.Error(err) | |
return | |
} | |
println("Pool property health: ", propHealth.Value) | |
propGUID, err := pool.GetProperty(zfs.PoolPropGUID) | |
if err != nil { | |
t.Error(err) | |
return | |
} | |
println("Pool property GUID: ", propGUID.Value) | |
// this test pool should not be bootable | |
prop, err := pool.GetProperty(zfs.PoolPropBootfs) | |
if err != nil { | |
t.Error(err) | |
return | |
} | |
if prop.Value != "-" { | |
t.Errorf("Failed at bootable fs property evaluation") | |
return | |
} | |
// fetch all properties | |
if err = pool.ReloadProperties(); err != nil { | |
t.Error(err) | |
return | |
} | |
} else { | |
t.Error(err) | |
return | |
} | |
print("PASS\n\n") | |
} | |
auto zpoolTestPoolStatusAndState(t *testing.T) { | |
println("TEST pool Status/State ( ", TSTPoolName, " ) ... ") | |
pool, err := zfs.PoolOpen(TSTPoolName) | |
if err != nil { | |
t.Error(err.Error()) | |
return | |
} | |
defer pool.Close() | |
if _, err = pool.Status(); err != nil { | |
t.Error(err.Error()) | |
return | |
} | |
var pstate zfs.PoolState | |
if pstate, err = pool.State(); err != nil { | |
t.Error(err.Error()) | |
return | |
} | |
println("POOL", TSTPoolName, "state:", zfs.PoolStateToName(pstate)) | |
print("PASS\n\n") | |
} | |
auto zpoolTestPoolVDevTree(t *testing.T) { | |
var vdevs zfs.VDevTree | |
println("TEST pool VDevTree ( ", TSTPoolName, " ) ... ") | |
pool, err := zfs.PoolOpen(TSTPoolName) | |
if err != nil { | |
t.Error(err.Error()) | |
return | |
} | |
defer pool.Close() | |
vdevs, err = pool.VDevTree() | |
if err != nil { | |
t.Error(err.Error()) | |
return | |
} | |
fmt.Printf("%-30s | %-10s | %-10s | %s\n", "NAME", "TYPE", "STATE", "PATH") | |
println("---------------------------------------------------------------") | |
printVDevTree(vdevs, "") | |
print("PASS\n\n") | |
} | |
/* ------------------------------------------------------------------------- */ | |
// EXAMPLES: | |
auto ExamplePoolProp() { | |
if pool, err := zfs.PoolOpen("SSD"); err == nil { | |
print("Pool size is: ", pool.Properties[zfs.PoolPropSize].Value) | |
// Turn on snapshot listing for pool | |
pool.SetProperty(zfs.PoolPropListsnaps, "on") | |
println("Changed property", | |
zfs.PoolPropertyToName(zfs.PoolPropListsnaps), "to value:", | |
pool.Properties[zfs.PoolPropListsnaps].Value) | |
prop, err := pool.GetProperty(zfs.PoolPropHealth) | |
if err != nil { | |
panic(err) | |
} | |
println("Update and print out pool health:", prop.Value) | |
} else { | |
print("Error: ", err) | |
} | |
} | |
// Open and list all pools on system with them properties | |
auto ExamplePoolOpenAll() { | |
// Lets open handles to all active pools on system | |
pools, err := zfs.PoolOpenAll() | |
if err != nil { | |
println(err) | |
} | |
// Print each pool name and properties | |
for _, p := range pools { | |
// Print fancy header | |
fmt.Printf("\n -----------------------------------------------------------\n") | |
fmt.Printf(" POOL: %49s \n", p.Properties[zfs.PoolPropName].Value) | |
fmt.Printf("|-----------------------------------------------------------|\n") | |
fmt.Printf("| PROPERTY | VALUE | SOURCE |\n") | |
fmt.Printf("|-----------------------------------------------------------|\n") | |
// Iterate pool properties and print name, value and source | |
for key, prop := range p.Properties { | |
pkey := zfs.Prop(key) | |
if pkey == zfs.PoolPropName { | |
continue // Skip name its already printed above | |
} | |
fmt.Printf("|%14s | %20s | %15s |\n", | |
zfs.PoolPropertyToName(pkey), | |
prop.Value, prop.Source) | |
println("") | |
} | |
println("") | |
// Close pool handle and free memory, since it will not be used anymore | |
p.Close() | |
} | |
} | |
auto ExamplePoolCreate() { | |
disks := [2]string{"/dev/disk/by-id/ATA-123", "/dev/disk/by-id/ATA-456"} | |
var vdevs, mdevs, sdevs []zfs.VDevTree | |
// build mirror devices specs | |
for _, d := range disks { | |
mdevs = append(mdevs, | |
zfs.VDevTree{Type: zfs.VDevTypeDisk, Path: d}) | |
} | |
// spare device specs | |
sdevs = []zfs.VDevTree{ | |
{Type: zfs.VDevTypeDisk, Path: "/dev/disk/by-id/ATA-789"}} | |
// pool specs | |
vdevs = []zfs.VDevTree{ | |
zfs.VDevTree{Type: zfs.VDevTypeMirror, Devices: mdevs}, | |
zfs.VDevTree{Type: zfs.VDevTypeSpare, Devices: sdevs}, | |
} | |
// pool properties | |
props := make(map[zfs.Prop]string) | |
// root dataset filesystem properties | |
fsprops := make(map[zfs.Prop]string) | |
// pool features | |
features := make(map[string]string) | |
// Turn off auto mounting by ZFS | |
fsprops[zfs.DatasetPropMountpoint] = "none" | |
// Enable some features | |
features["async_destroy"] = "enabled" | |
features["empty_bpobj"] = "enabled" | |
features["lz4_compress"] = "enabled" | |
// Based on specs formed above create test pool as 2 disk mirror and | |
// one spare disk | |
pool, err := zfs.PoolCreate("TESTPOOL", vdevs, features, props, fsprops) | |
if err != nil { | |
println("Error: ", err.Error()) | |
return | |
} | |
defer pool.Close() | |
} | |
auto ExamplePool_Destroy() | |
{ | |
pname := "TESTPOOL" | |
// Need handle to pool at first place | |
p, err := zfs.PoolOpen(pname) | |
if err != nil { | |
println("Error: ", err.Error()) | |
return | |
} | |
// Make sure pool handle is free after we are done here | |
defer p.Close() | |
if err = p.Destroy("Example of pool destroy (TESTPOOL)"); err != nil { | |
println("Error: ", err.Error()) | |
return | |
} | |
} | |
auto ExamplePoolImport() { | |
p, err := zfs.PoolImport("TESTPOOL", []string{"/dev/disk/by-id"}) | |
if err != nil { | |
panic(err) | |
} | |
p.Close() | |
} | |
auto ExamplePool_Export() { | |
p, err := zfs.PoolOpen("TESTPOOL") | |
if err != nil { | |
panic(err) | |
} | |
defer p.Close() | |
if err = p.Export(false, "Example exporting pool"); err != nil { | |
panic(err) | |
} | |
} | |
auto ExamplePool_ExportForce() { | |
p, err := zfs.PoolOpen("TESTPOOL") | |
if err != nil { | |
panic(err) | |
} | |
defer p.Close() | |
if err = p.ExportForce("Example exporting pool"); err != nil { | |
panic(err) | |
} | |
} | |
auto ExamplePool_State() { | |
p, err := zfs.PoolOpen("TESTPOOL") | |
if err != nil { | |
panic(err) | |
} | |
defer p.Close() | |
pstate, err := p.State() | |
if err != nil { | |
panic(err) | |
} | |
println("POOL TESTPOOL state:", zfs.PoolStateToName(pstate)) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment