func (pool *Pool) GetProperty(p Prop) (prop Property, err error) {
	if pool.list != nil {
		if p < PoolPropName || p > PoolNumProps {
			err = errors.New(fmt.Sprint("Unknown zpool property: ",
				PoolPropertyToName(p)))
			return
		}
		list := C.read_zpool_property(pool.list, C.int(p))
		if list == nil {
			err = LastError()
			return
		}
		defer C.free_properties(list)
		prop.Value = C.GoString(&(list.value[0]))
		prop.Source = C.GoString(&(list.source[0]))
		pool.Properties[p] = prop
		return
	}
	return prop, errors.New(msgPoolIsNil)
}
GetProperty reload and return single specified property. This also reloads requested
property in Properties map.
package zfs
import "C"
import (
	"errors"
	"fmt"
	"strconv"
	"time"
	"unsafe"
)
const (
	msgPoolIsNil = "Pool handle not initialized or its closed"
)
const (
	FENABLED  = "enabled"
	FDISABLED = "disabled"
)
type PoolProperties map[Prop]string
const (
	ZIOTypeNull = iota
	ZIOTypeRead
	ZIOTypeWrite
	ZIOTypeFree
	ZIOTypeClaim
	ZIOTypeIOCtl
	ZIOTypes
)
const (
	DSSNone      = iota  
	DSSScanning          
	DSSFinished          
	DSSCanceled          
	DSSNumStates         
)
const (
	PoolScanNone     = iota  
	PoolScanScrub            
	PoolScanResilver         
	PoolScanFuncs            
)
type PoolInitializeAction int
const (
	PoolInitializeStart   PoolInitializeAction = iota  
	PoolInitializeCancel                               
	PoolInitializeSuspend                              
)
type VDevStat struct {
	Timestamp      time.Duration     
	State          VDevState         
	Aux            VDevAux           
	Alloc          uint64            
	Space          uint64            
	DSpace         uint64            
	RSize          uint64            
	ESize          uint64            
	Ops            [ZIOTypes]uint64  
	Bytes          [ZIOTypes]uint64  
	ReadErrors     uint64            
	WriteErrors    uint64            
	ChecksumErrors uint64            
	SelfHealed     uint64            
	ScanRemoving   uint64            
	ScanProcessed  uint64            
	Fragmentation  uint64            
}
type PoolScanStat struct {
	Func      uint64  
	State     uint64  
	StartTime uint64  
	EndTime   uint64  
	ToExamine uint64  
	Examined  uint64  
	ToProcess uint64  
	Processed uint64  
	Errors    uint64  
	PassExam  uint64  
	PassStart uint64  
}
type VDevTree struct {
	Type     VDevType
	Devices  []VDevTree  
	Spares   []VDevTree
	L2Cache  []VDevTree
	Logs     *VDevTree
	GUID     uint64
	Parity   uint
	Path     string
	Name     string
	Stat     VDevStat
	ScanStat PoolScanStat
}
type ExportedPool struct {
	VDevs   VDevTree
	Name    string
	Comment string
	GUID    uint64
	State   PoolState
	Status  PoolStatus
}
type Pool struct {
	list       C.zpool_list_ptr
	Properties []Property
	Features   map[string]string
}
func PoolOpen(name string) (pool Pool, err error) {
	csName := C.CString(name)
	defer C.free(unsafe.Pointer(csName))
	pool.list = C.zpool_list_open(csName)
	if pool.list != nil {
		err = pool.ReloadProperties()
		return
	}
	err = LastError()
	return
}
func poolGetConfig(name string, nv C.nvlist_ptr) (vdevs VDevTree, err error) {
	var dtype C.char_ptr
	var vs C.vdev_stat_ptr
	var ps C.pool_scan_stat_ptr
	var children C.vdev_children_ptr
	if dtype = C.get_vdev_type(nv); dtype == nil {
		err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_TYPE)
		return
	}
	vdevs.Name = name
	vdevs.Type = VDevType(C.GoString(dtype))
	if vdevs.Type == VDevTypeMissing || vdevs.Type == VDevTypeHole {
		return
	}
	vdevs.GUID = uint64(C.get_vdev_guid(nv))
	if vs = C.get_vdev_stats(nv); vs == nil {
		err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_VDEV_STATS)
		return
	}
	vdevs.Stat.Timestamp = time.Duration(vs.vs_timestamp)
	vdevs.Stat.State = VDevState(vs.vs_state)
	vdevs.Stat.Aux = VDevAux(vs.vs_aux)
	vdevs.Stat.Alloc = uint64(vs.vs_alloc)
	vdevs.Stat.Space = uint64(vs.vs_space)
	vdevs.Stat.DSpace = uint64(vs.vs_dspace)
	vdevs.Stat.RSize = uint64(vs.vs_rsize)
	vdevs.Stat.ESize = uint64(vs.vs_esize)
	for z := 0; z < ZIOTypes; z++ {
		vdevs.Stat.Ops[z] = uint64(vs.vs_ops[z])
		vdevs.Stat.Bytes[z] = uint64(vs.vs_bytes[z])
	}
	vdevs.Stat.ReadErrors = uint64(vs.vs_read_errors)
	vdevs.Stat.WriteErrors = uint64(vs.vs_write_errors)
	vdevs.Stat.ChecksumErrors = uint64(vs.vs_checksum_errors)
	vdevs.Stat.SelfHealed = uint64(vs.vs_self_healed)
	vdevs.Stat.ScanRemoving = uint64(vs.vs_scan_removing)
	vdevs.Stat.ScanProcessed = uint64(vs.vs_scan_processed)
	vdevs.Stat.Fragmentation = uint64(vs.vs_fragmentation)
	if ps = C.get_vdev_scan_stats(nv); ps != nil {
		vdevs.ScanStat.Func = uint64(ps.pss_func)
		vdevs.ScanStat.State = uint64(ps.pss_state)
		vdevs.ScanStat.StartTime = uint64(ps.pss_start_time)
		vdevs.ScanStat.EndTime = uint64(ps.pss_end_time)
		vdevs.ScanStat.ToExamine = uint64(ps.pss_to_examine)
		vdevs.ScanStat.Examined = uint64(ps.pss_examined)
		vdevs.ScanStat.ToProcess = uint64(ps.pss_to_process)
		vdevs.ScanStat.Processed = uint64(ps.pss_processed)
		vdevs.ScanStat.Errors = uint64(ps.pss_errors)
		vdevs.ScanStat.PassExam = uint64(ps.pss_pass_exam)
		vdevs.ScanStat.PassStart = uint64(ps.pss_pass_start)
	}
	children = C.get_vdev_children(nv)
	if children != nil {
		defer C.free(unsafe.Pointer(children))
		vdevs.Devices = make([]VDevTree, 0, children.count)
	}
	path := C.get_vdev_path(nv)
	if path != nil {
		vdevs.Path = C.GoString(path)
	}
	for c := C.uint_t(0); children != nil && c < children.count; c++ {
		var islog = C.uint64_t(C.B_FALSE)
		islog = C.get_vdev_is_log(C.nvlist_array_at(children.first, c))
		vname := C.zpool_vdev_name(C.libzfsHandle, nil, C.nvlist_array_at(children.first, c),
			C.B_TRUE)
		var vdev VDevTree
		vdev, err = poolGetConfig(C.GoString(vname),
			C.nvlist_array_at(children.first, c))
		C.free(unsafe.Pointer(vname))
		if err != nil {
			return
		}
		if islog != C.B_FALSE {
			vdevs.Logs = &vdev
		} else {
			vdevs.Devices = append(vdevs.Devices, vdev)
		}
	}
	return
}
func poolGetSpares(name string, nv C.nvlist_ptr) (vdevs []VDevTree, err error) {
	var spares C.vdev_children_ptr
	spares = C.get_vdev_spares(nv)
	if spares != nil {
		defer C.free(unsafe.Pointer(spares))
		vdevs = make([]VDevTree, 0, spares.count)
	}
	for c := C.uint_t(0); spares != nil && c < spares.count; c++ {
		vname := C.zpool_vdev_name(C.libzfsHandle, nil, C.nvlist_array_at(spares.first, c),
			C.B_TRUE)
		var vdev VDevTree
		vdev, err = poolGetConfig(C.GoString(vname),
			C.nvlist_array_at(spares.first, c))
		C.free(unsafe.Pointer(vname))
		if err != nil {
			return
		}
		vdevs = append(vdevs, vdev)
	}
	return
}
func poolGetL2Cache(name string, nv C.nvlist_ptr) (vdevs []VDevTree, err error) {
	var l2cache C.vdev_children_ptr
	l2cache = C.get_vdev_l2cache(nv)
	if l2cache != nil {
		defer C.free(unsafe.Pointer(l2cache))
		vdevs = make([]VDevTree, 0, l2cache.count)
	}
	for c := C.uint_t(0); l2cache != nil && c < l2cache.count; c++ {
		vname := C.zpool_vdev_name(C.libzfsHandle, nil, C.nvlist_array_at(l2cache.first, c),
			C.B_TRUE)
		var vdev VDevTree
		vdev, err = poolGetConfig(C.GoString(vname),
			C.nvlist_array_at(l2cache.first, c))
		C.free(unsafe.Pointer(vname))
		if err != nil {
			return
		}
		vdevs = append(vdevs, vdev)
	}
	return
}
func PoolImportSearch(searchpaths []string) (epools []ExportedPool, err error) {
	var config, nvroot C.nvlist_ptr
	var cname, msgid, comment C.char_ptr
	var reason C.zpool_status_t
	var errata C.zpool_errata_t
	config = nil
	var elem C.nvpair_ptr
	numofp := len(searchpaths)
	cpaths := C.alloc_cstrings(C.int(numofp))
	defer C.free(unsafe.Pointer(cpaths))
	for i, path := range searchpaths {
		csPath := C.CString(path)
		defer C.free(unsafe.Pointer(csPath))
		C.strings_setat(cpaths, C.int(i), csPath)
	}
	pools := C.go_zpool_search_import(C.libzfsHandle, C.int(numofp), cpaths, C.B_FALSE)
	defer C.nvlist_free(pools)
	elem = C.nvlist_next_nvpair(pools, elem)
	epools = make([]ExportedPool, 0, 1)
	for ; elem != nil; elem = C.nvlist_next_nvpair(pools, elem) {
		ep := ExportedPool{}
		if C.nvpair_value_nvlist(elem, (**C.struct_nvlist)(&config)) != 0 {
			err = LastError()
			return
		}
		ep.State = PoolState(C.get_zpool_state(config))
		if ep.State == PoolStateDestroyed {
			continue  
		}
		if cname = C.get_zpool_name(config); cname == nil {
			err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_POOL_NAME)
			return
		}
		ep.Name = C.GoString(cname)
		ep.GUID = uint64(C.get_zpool_guid(config))
		reason = C.zpool_import_status(config, (**C.char)(&msgid), &errata)
		ep.Status = PoolStatus(reason)
		if comment = C.get_zpool_comment(config); comment != nil {
			ep.Comment = C.GoString(comment)
		}
		if nvroot = C.get_zpool_vdev_tree(config); nvroot == nil {
			err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_VDEV_TREE)
			return
		}
		ep.VDevs, err = poolGetConfig(ep.Name, nvroot)
		epools = append(epools, ep)
	}
	return
}
func poolSearchImport(q string, searchpaths []string, guid bool) (name string,
	err error) {
	var config C.nvlist_ptr
	var cname C.char_ptr
	config = nil
	errPoolList := errors.New("Failed to list pools")
	var elem *C.nvpair_t
	numofp := len(searchpaths)
	cpaths := C.alloc_cstrings(C.int(numofp))
	defer C.free(unsafe.Pointer(cpaths))
	for i, path := range searchpaths {
		csPath := C.CString(path)
		defer C.free(unsafe.Pointer(csPath))
		C.strings_setat(cpaths, C.int(i), csPath)
	}
	pools := C.go_zpool_search_import(C.libzfsHandle, C.int(numofp), cpaths, C.B_FALSE)
	defer C.nvlist_free(pools)
	elem = C.nvlist_next_nvpair(pools, elem)
	for ; elem != nil; elem = C.nvlist_next_nvpair(pools, elem) {
		var cq *C.char
		var tconfig *C.nvlist_t
		retcode := C.nvpair_value_nvlist(elem, (**C.struct_nvlist)(&tconfig))
		if retcode != 0 {
			err = errPoolList
			return
		}
		if PoolState(C.get_zpool_state(tconfig)) == PoolStateDestroyed {
			continue  
		}
		if guid {
			sguid := fmt.Sprint(C.get_zpool_guid(tconfig))
			if q == sguid {
				config = tconfig
				break
			}
		} else {
			if cq = C.get_zpool_name(tconfig); cq == nil {
				err = errPoolList
				return
			}
			cname = cq
			name = C.GoString(cq)
			if q == name {
				config = tconfig
				break
			}
		}
	}
	if config == nil {
		err = fmt.Errorf("No pool found %s", q)
		return
	}
	if guid {
		if cname = C.get_zpool_name(config); cname == nil {
			err = errPoolList
			return
		}
		name = C.GoString(cname)
	}
	if retcode := C.zpool_import_props(C.libzfsHandle, config, cname,
		nil, C.ZFS_IMPORT_NORMAL|C.ZFS_IMPORT_ANY_HOST); retcode != 0 {
		err = fmt.Errorf("Import pool properties failed: %s", LastError().Error())
		return
	}
	return
}
func PoolImport(name string, searchpaths []string) (pool Pool, err error) {
	_, err = poolSearchImport(name, searchpaths, false)
	if err != nil {
		return
	}
	pool, err = PoolOpen(name)
	return
}
func PoolImportByGUID(guid string, searchpaths []string) (pool Pool, err error) {
	var name string
	name, err = poolSearchImport(guid, searchpaths, true)
	if err != nil {
		return
	}
	pool, err = PoolOpen(name)
	return
}
func PoolOpenAll() (pools []Pool, err error) {
	var pool Pool
	if pool.list = C.zpool_list_openall(); pool.list == nil {
		err = LastError()
		return
	}
	for pool.list != nil {
		err = pool.ReloadProperties()
		if err != nil {
			return
		}
		next := C.zpool_next(pool.list)
		pool.list.pnext = nil
		pools = append(pools, pool)
		pool.list = next
	}
	return
}
func PoolCloseAll(pools []Pool) {
	for _, p := range pools {
		p.Close()
	}
}
func PoolPropertyToName(p Prop) (name string) {
	if p == PoolNumProps {
		return "numofprops"
	}
	prop := C.zpool_prop_t(p)
	name = C.GoString(C.zpool_prop_to_name(prop))
	return
}
func PoolStateToName(state PoolState) (name string) {
	ps := C.pool_state_t(state)
	name = C.GoString(C.zpool_pool_state_to_name(ps))
	return
}
func (pool *Pool) RefreshStats() (err error) {
	if 0 != C.refresh_stats(pool.list) {
		return errors.New("error refreshing stats")
	}
	return nil
}
func (pool *Pool) ReloadProperties() (err error) {
	propList := C.read_zpool_properties(pool.list)
	if propList == nil {
		err = LastError()
		return
	}
	pool.Properties = make([]Property, PoolNumProps+1)
	next := propList
	for next != nil {
		pool.Properties[next.property] = Property{Value: C.GoString(&(next.value[0])), Source: C.GoString(&(next.source[0]))}
		next = C.next_property(next)
	}
	C.free_properties(propList)
	pool.Features = map[string]string{
		"async_destroy":      "disabled",
		"empty_bpobj":        "disabled",
		"lz4_compress":       "disabled",
		"spacemap_histogram": "disabled",
		"enabled_txg":        "disabled",
		"hole_birth":         "disabled",
		"extensible_dataset": "disabled",
		"embedded_data":      "disabled",
		"bookmarks":          "disabled",
		"filesystem_limits":  "disabled",
		"large_blocks":       "disabled"}
	for name := range pool.Features {
		_, ferr := pool.GetFeature(name)
		if ferr != nil {
		}
	}
	return
}