- Fix issue not building on go 1.8 , and some more improvements

This commit is contained in:
Faruk Kasumovic 2017-06-02 08:42:14 +02:00
parent fa91900915
commit 8fd0833477
10 changed files with 599 additions and 468 deletions

56
common.c Normal file
View File

@ -0,0 +1,56 @@
#include <libzfs.h>
#include <memory.h>
#include <string.h>
#include <stdio.h>
#include "common.h"
libzfs_handle_ptr libzfsHandle;
int go_libzfs_init() {
libzfsHandle = libzfs_init();
return 0;
}
int libzfs_last_error() {
return libzfs_errno(libzfsHandle);
}
const char *libzfs_last_error_str() {
return libzfs_error_description(libzfsHandle);
}
int libzfs_clear_last_error() {
zfs_standard_error(libzfsHandle, EZFS_SUCCESS, "success");
return 0;
}
property_list_t *new_property_list() {
property_list_t *r = malloc(sizeof(property_list_t));
memset(r, 0, sizeof(property_list_t));
return r;
}
void free_properties(property_list_t *root) {
if (root != 0) {
property_list_t *tmp = 0;
do {
tmp = root->pnext;
free(root);
root = tmp;
} while(tmp);
}
}
nvlist_ptr new_property_nvlist() {
nvlist_ptr props = NULL;
int r = nvlist_alloc(&props, NV_UNIQUE_NAME, 0);
if ( r != 0 ) {
return NULL;
}
return props;
}
int property_nvlist_add(nvlist_ptr list, const char *prop, const char *value) {
return nvlist_add_string(list, prop, value);
}

View File

@ -14,6 +14,7 @@ package zfs
#include <stdlib.h> #include <stdlib.h>
#include <libzfs.h> #include <libzfs.h>
#include "common.h"
#include "zpool.h" #include "zpool.h"
#include "zfs.h" #include "zfs.h"
*/ */
@ -26,10 +27,8 @@ import (
// VDevType type of device in the pool // VDevType type of device in the pool
type VDevType string type VDevType string
var libzfsHandle C.libzfs_handle_ptr
func init() { func init() {
libzfsHandle = C.libzfs_init() C.go_libzfs_init()
return return
} }
@ -256,17 +255,13 @@ const (
// LastError get last underlying libzfs error description if any // LastError get last underlying libzfs error description if any
func LastError() (err error) { func LastError() (err error) {
errno := C.libzfs_errno(libzfsHandle) return errors.New(C.GoString(C.libzfs_last_error_str()))
if errno == 0 {
return nil
}
return errors.New(C.GoString(C.libzfs_error_description(libzfsHandle)))
} }
// ClearLastError force clear of any last error set by undeliying libzfs // ClearLastError force clear of any last error set by undeliying libzfs
func ClearLastError() (err error) { func ClearLastError() (err error) {
err = LastError() err = LastError()
C.clear_last_error(libzfsHandle) C.libzfs_clear_last_error()
return return
} }

37
common.h Normal file
View File

@ -0,0 +1,37 @@
/* C wrappers around some zfs calls and C in general that should simplify
* using libzfs from go language, make go code shorter and more readable.
*/
#define INT_MAX_NAME 256
#define INT_MAX_VALUE 1024
#define ZAP_OLDMAXVALUELEN 1024
#define ZFS_MAX_DATASET_NAME_LEN 256
typedef struct property_list {
char value[INT_MAX_VALUE];
char source[ZFS_MAX_DATASET_NAME_LEN];
int property;
void *pnext;
} property_list_t;
typedef struct libzfs_handle* libzfs_handle_ptr;
typedef struct nvlist* nvlist_ptr;
typedef struct property_list *property_list_ptr;
typedef struct nvpair* nvpair_ptr;
typedef struct vdev_stat* vdev_stat_ptr;
typedef char* char_ptr;
extern libzfs_handle_ptr libzfsHandle;
int go_libzfs_init();
int libzfs_last_error();
const char *libzfs_last_error_str();
int libzfs_clear_last_error();
property_list_t *new_property_list();
void free_properties(property_list_t *root);
nvlist_ptr new_property_nvlist();
int property_nvlist_add(nvlist_ptr ptr, const char* prop, const char *value);

147
zfs.c
View File

@ -7,6 +7,7 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include "common.h"
#include "zpool.h" #include "zpool.h"
#include "zfs.h" #include "zfs.h"
@ -46,59 +47,144 @@ int dataset_list_callb(zfs_handle_t *dataset, void *data) {
return 0; return 0;
} }
int dataset_list_root(libzfs_handle_t *libzfs, dataset_list_t **first) { dataset_list_ptr dataset_list_root() {
int err = 0; int err = 0;
dataset_list_t *zlist = create_dataset_list_item(); dataset_list_t *zlist = create_dataset_list_item();
err = zfs_iter_root(libzfs, dataset_list_callb, &zlist); err = zfs_iter_root(libzfsHandle, dataset_list_callb, &zlist);
if ( zlist->zh ) { if ( err != 0 || zlist->zh == NULL) {
*first = zlist;
} else {
*first = 0;
dataset_list_free(zlist); dataset_list_free(zlist);
return NULL;
} }
return err; return zlist;
} }
dataset_list_t *dataset_next(dataset_list_t *dataset) { dataset_list_ptr dataset_next(dataset_list_t *dataset) {
return dataset->pnext; return dataset->pnext;
} }
int dataset_type(dataset_list_ptr dataset) {
int dataset_list_children(zfs_handle_t *zfs, dataset_list_t **first) { return zfs_get_type(dataset->zh);
int err = 0;
dataset_list_t *zlist = create_dataset_list_item();
err = zfs_iter_children(zfs, dataset_list_callb, &zlist);
if ( zlist->zh ) {
*first = zlist;
} else {
*first = 0;
dataset_list_free(zlist);
}
return err;
} }
int read_dataset_property(zfs_handle_t *zh, property_list_t *list, int prop) { dataset_list_ptr dataset_open(const char *path) {
dataset_list_ptr list = create_dataset_list_item();
list->zh = zfs_open(libzfsHandle, path, 0xF);
if (list->zh == NULL) {
dataset_list_free(list);
list = NULL;
}
return list;
}
int dataset_create(const char *path, zfs_type_t type, nvlist_ptr props) {
return zfs_create(libzfsHandle, path, type, props);
}
int dataset_destroy(dataset_list_ptr dataset, boolean_t defer) {
return zfs_destroy(dataset->zh, defer);
}
dataset_list_t *dataset_list_children(dataset_list_t *dataset) {
int err = 0;
dataset_list_t *zlist = create_dataset_list_item();
err = zfs_iter_children(dataset->zh, dataset_list_callb, &zlist);
if ( err != 0 || zlist->zh == NULL) {
dataset_list_free(zlist);
return NULL;
}
return zlist;
}
zpool_list_ptr dataset_get_pool(dataset_list_ptr dataset) {
zpool_list_ptr pool = create_zpool_list_item();
if(pool != NULL) {
pool->zph = zfs_get_pool_handle(dataset->zh);
}
return pool;
}
int dataset_prop_set(dataset_list_ptr dataset, zfs_prop_t prop, const char *value) {
return zfs_prop_set(dataset->zh, zfs_prop_to_name(prop), value);
}
int dataset_user_prop_set(dataset_list_ptr dataset, const char *prop, const char *value) {
return zfs_prop_set(dataset->zh, prop, value);
}
int dataset_clone(dataset_list_ptr dataset, const char *target, nvlist_ptr props) {
return zfs_clone(dataset->zh, target, props);
}
int dataset_snapshot(const char *path, boolean_t recur, nvlist_ptr props) {
return zfs_snapshot(libzfsHandle, path, recur, props);
}
int dataset_rollback(dataset_list_ptr dataset, dataset_list_ptr snapshot, boolean_t force) {
return zfs_rollback(dataset->zh, snapshot->zh, force);
}
int dataset_promote(dataset_list_ptr dataset) {
return zfs_promote(dataset->zh);
}
int dataset_rename(dataset_list_ptr dataset, const char* new_name, boolean_t recur, boolean_t force_unm) {
return zfs_rename(dataset->zh, new_name, recur, force_unm);
}
const char *dataset_is_mounted(dataset_list_ptr dataset){
char *mp;
if (0 != zfs_is_mounted(dataset->zh, &mp)) {
return NULL;
}
return mp;
}
int dataset_mount(dataset_list_ptr dataset, const char *options, int flags) {
return zfs_mount(dataset->zh, options, flags);
}
int dataset_unmount(dataset_list_ptr dataset, int flags) {
return zfs_unmount(dataset->zh, NULL, flags);
}
int dataset_unmountall(dataset_list_ptr dataset, int flags) {
return zfs_unmountall(dataset->zh, flags);
}
const char *dataset_get_name(dataset_list_ptr ds) {
return zfs_get_name(ds->zh);
}
//int read_dataset_property(zfs_handle_t *zh, property_list_t *list, int prop) {
property_list_t *read_dataset_property(dataset_list_t *dataset, int prop) {
int r = 0; int r = 0;
zprop_source_t source; zprop_source_t source;
char statbuf[INT_MAX_VALUE]; char statbuf[INT_MAX_VALUE];
property_list_ptr list;
list = new_property_list();
r = zfs_prop_get(zh, prop, r = zfs_prop_get(dataset->zh, prop,
list->value, INT_MAX_VALUE, &source, statbuf, INT_MAX_VALUE, 1); list->value, INT_MAX_VALUE, &source, statbuf, INT_MAX_VALUE, 1);
if (r == 0) { if (r == 0) {
// strcpy(list->name, zpool_prop_to_name(prop)); // strcpy(list->name, zpool_prop_to_name(prop));
zprop_source_tostr(list->source, source); zprop_source_tostr(list->source, source);
list->property = (int)prop;
} else {
free_properties(list);
list = NULL;
} }
list->property = (int)prop; return list;
return r;
} }
int read_user_property(zfs_handle_t *zh, property_list_t *list, const char *prop) { // int read_user_property(zfs_handle_t *zh, property_list_t *list, const char *prop) {
nvlist_t *user_props = zfs_get_user_props(zh); property_list_t *read_user_property(dataset_list_t *dataset, const char* prop) {
nvlist_t *user_props = zfs_get_user_props(dataset->zh);
nvlist_t *propval; nvlist_t *propval;
zprop_source_t sourcetype; zprop_source_t sourcetype;
char *strval; char *strval;
char *sourceval; char *sourceval;
// char source[ZFS_MAX_DATASET_NAME_LEN]; // char source[ZFS_MAX_DATASET_NAME_LEN];
property_list_ptr list = new_property_list();
if (nvlist_lookup_nvlist(user_props, if (nvlist_lookup_nvlist(user_props,
prop, &propval) != 0) { prop, &propval) != 0) {
@ -113,7 +199,7 @@ int read_user_property(zfs_handle_t *zh, property_list_t *list, const char *prop
ZPROP_SOURCE, &sourceval) == 0); ZPROP_SOURCE, &sourceval) == 0);
if (strcmp(sourceval, if (strcmp(sourceval,
zfs_get_name(zh)) == 0) { zfs_get_name(dataset->zh)) == 0) {
sourcetype = ZPROP_SRC_LOCAL; sourcetype = ZPROP_SRC_LOCAL;
(void) strncpy(list->source, (void) strncpy(list->source,
"local", sizeof (list->source)); "local", sizeof (list->source));
@ -130,12 +216,7 @@ int read_user_property(zfs_handle_t *zh, property_list_t *list, const char *prop
} }
(void) strncpy(list->value, (void) strncpy(list->value,
strval, sizeof (list->value)); strval, sizeof (list->value));
return 0; return list;
}
int clear_last_error(libzfs_handle_t *hdl) {
zfs_standard_error(hdl, EZFS_SUCCESS, "success");
return 0;
} }
char** alloc_cstrings(int size) { char** alloc_cstrings(int size) {

119
zfs.go
View File

@ -2,6 +2,7 @@ package zfs
// #include <stdlib.h> // #include <stdlib.h>
// #include <libzfs.h> // #include <libzfs.h>
// #include "common.h"
// #include "zpool.h" // #include "zpool.h"
// #include "zfs.h" // #include "zfs.h"
import "C" import "C"
@ -44,12 +45,11 @@ type Dataset struct {
} }
func (d *Dataset) openChildren() (err error) { func (d *Dataset) openChildren() (err error) {
var list C.dataset_list_ptr
d.Children = make([]Dataset, 0, 5) d.Children = make([]Dataset, 0, 5)
errcode := C.dataset_list_children(d.list.zh, unsafe.Pointer(&list)) list := C.dataset_list_children(d.list)
for list != nil { for list != nil {
dataset := Dataset{list: list} dataset := Dataset{list: list}
dataset.Type = DatasetType(C.zfs_get_type(dataset.list.zh)) dataset.Type = DatasetType(C.dataset_type(d.list))
dataset.Properties = make(map[Prop]Property) dataset.Properties = make(map[Prop]Property)
err = dataset.ReloadProperties() err = dataset.ReloadProperties()
if err != nil { if err != nil {
@ -58,10 +58,6 @@ func (d *Dataset) openChildren() (err error) {
d.Children = append(d.Children, dataset) d.Children = append(d.Children, dataset)
list = C.dataset_next(list) list = C.dataset_next(list)
} }
if errcode != 0 {
err = LastError()
return
}
for ci := range d.Children { for ci := range d.Children {
if err = d.Children[ci].openChildren(); err != nil { if err = d.Children[ci].openChildren(); err != nil {
return return
@ -74,9 +70,9 @@ func (d *Dataset) openChildren() (err error) {
// (file-systems, volumes or snapshots). // (file-systems, volumes or snapshots).
func DatasetOpenAll() (datasets []Dataset, err error) { func DatasetOpenAll() (datasets []Dataset, err error) {
var dataset Dataset var dataset Dataset
errcode := C.dataset_list_root(libzfsHandle, unsafe.Pointer(&dataset.list)) dataset.list = C.dataset_list_root()
for dataset.list != nil { for dataset.list != nil {
dataset.Type = DatasetType(C.zfs_get_type(dataset.list.zh)) dataset.Type = DatasetType(C.dataset_type(dataset.list))
err = dataset.ReloadProperties() err = dataset.ReloadProperties()
if err != nil { if err != nil {
return return
@ -84,10 +80,6 @@ func DatasetOpenAll() (datasets []Dataset, err error) {
datasets = append(datasets, dataset) datasets = append(datasets, dataset)
dataset.list = C.dataset_next(dataset.list) dataset.list = C.dataset_next(dataset.list)
} }
if errcode != 0 {
err = LastError()
return
}
for ci := range datasets { for ci := range datasets {
if err = datasets[ci].openChildren(); err != nil { if err = datasets[ci].openChildren(); err != nil {
return return
@ -106,22 +98,23 @@ func DatasetCloseAll(datasets []Dataset) {
// DatasetOpen open dataset and all of its recursive children datasets // DatasetOpen open dataset and all of its recursive children datasets
func DatasetOpen(path string) (d Dataset, err error) { func DatasetOpen(path string) (d Dataset, err error) {
d.list = C.create_dataset_list_item()
csPath := C.CString(path) csPath := C.CString(path)
d.list.zh = C.zfs_open(libzfsHandle, csPath, 0xF) d.list = C.dataset_open(csPath)
C.free(unsafe.Pointer(csPath)) C.free(unsafe.Pointer(csPath))
if d.list.zh == nil { if d.list == nil || d.list.zh == nil {
err = LastError() err = LastError()
if err == nil { if err == nil {
err = fmt.Errorf("dataset not found.") err = fmt.Errorf("dataset not found.")
} }
println("open failed")
return return
} }
d.Type = DatasetType(C.zfs_get_type(d.list.zh)) d.Type = DatasetType(C.dataset_type(d.list))
d.Properties = make(map[Prop]Property) d.Properties = make(map[Prop]Property)
err = d.ReloadProperties() err = d.ReloadProperties()
if err != nil { if err != nil {
println("reload properties failed")
return return
} }
err = d.openChildren() err = d.openChildren()
@ -131,16 +124,15 @@ func DatasetOpen(path string) (d Dataset, err error) {
func datasetPropertiesTonvlist(props map[Prop]Property) ( func datasetPropertiesTonvlist(props map[Prop]Property) (
cprops C.nvlist_ptr, err error) { cprops C.nvlist_ptr, err error) {
// convert properties to nvlist C type // convert properties to nvlist C type
r := C.nvlist_alloc(unsafe.Pointer(&cprops), C.NV_UNIQUE_NAME, 0) cprops = C.new_property_nvlist()
if r != 0 { if cprops == nil {
err = errors.New("Failed to allocate properties") err = errors.New("Failed to allocate properties")
return return
} }
for prop, value := range props { for prop, value := range props {
csValue := C.CString(value.Value) csValue := C.CString(value.Value)
r := C.nvlist_add_string( r := C.property_nvlist_add(
cprops, C.zfs_prop_to_name( cprops, C.zfs_prop_to_name(C.zfs_prop_t(prop)), csValue)
C.zfs_prop_t(prop)), csValue)
C.free(unsafe.Pointer(csValue)) C.free(unsafe.Pointer(csValue))
if r != 0 { if r != 0 {
err = errors.New("Failed to convert property") err = errors.New("Failed to convert property")
@ -161,13 +153,13 @@ func DatasetCreate(path string, dtype DatasetType,
defer C.nvlist_free(cprops) defer C.nvlist_free(cprops)
csPath := C.CString(path) csPath := C.CString(path)
errcode := C.zfs_create(libzfsHandle, csPath, errcode := C.dataset_create(csPath, C.zfs_type_t(dtype), cprops)
C.zfs_type_t(dtype), cprops)
C.free(unsafe.Pointer(csPath)) C.free(unsafe.Pointer(csPath))
if errcode != 0 { if errcode != 0 {
err = LastError() err = LastError()
return
} }
return return DatasetOpen(path)
} }
// Close close dataset and all its recursive children datasets (close handle // Close close dataset and all its recursive children datasets (close handle
@ -184,7 +176,8 @@ func (d *Dataset) Close() {
// Destroy destroys the dataset. The caller must make sure that the filesystem // Destroy destroys the dataset. The caller must make sure that the filesystem
// isn't mounted, and that there are no active dependents. Set Defer argument // isn't mounted, and that there are no active dependents. Set Defer argument
// to true to defer destruction for when dataset is not in use. // to true to defer destruction for when dataset is not in use. Call Close() to
// cleanup memory.
func (d *Dataset) Destroy(Defer bool) (err error) { func (d *Dataset) Destroy(Defer bool) (err error) {
if len(d.Children) > 0 { if len(d.Children) > 0 {
path, e := d.Path() path, e := d.Path()
@ -200,7 +193,7 @@ func (d *Dataset) Destroy(Defer bool) (err error) {
return return
} }
if d.list != nil { if d.list != nil {
if ec := C.zfs_destroy(d.list.zh, booleanT(Defer)); ec != 0 { if ec := C.dataset_destroy(d.list, booleanT(Defer)); ec != 0 {
err = LastError() err = LastError()
} }
} else { } else {
@ -232,9 +225,8 @@ func (d *Dataset) Pool() (p Pool, err error) {
err = errors.New(msgDatasetIsNil) err = errors.New(msgDatasetIsNil)
return return
} }
p.list = C.create_zpool_list_item() p.list = C.dataset_get_pool(d.list)
p.list.zph = C.zfs_get_pool_handle(d.list.zh) if p.list != nil && p.list.zph != nil {
if p.list != nil {
err = p.ReloadProperties() err = p.ReloadProperties()
return return
} }
@ -248,14 +240,10 @@ func (d *Dataset) ReloadProperties() (err error) {
err = errors.New(msgDatasetIsNil) err = errors.New(msgDatasetIsNil)
return return
} }
var plist C.property_list_ptr
d.Properties = make(map[Prop]Property) d.Properties = make(map[Prop]Property)
for prop := DatasetPropType; prop < DatasetNumProps; prop++ { for prop := DatasetPropType; prop < DatasetNumProps; prop++ {
plist = C.new_property_list() plist := C.read_dataset_property(d.list, C.int(prop))
errcode := C.read_dataset_property(d.list.zh, plist, C.int(prop)) if plist == nil {
if errcode != 0 {
C.free_properties(plist)
continue continue
} }
d.Properties[prop] = Property{Value: C.GoString(&(*plist).value[0]), d.Properties[prop] = Property{Value: C.GoString(&(*plist).value[0]),
@ -272,14 +260,12 @@ func (d *Dataset) GetProperty(p Prop) (prop Property, err error) {
err = errors.New(msgDatasetIsNil) err = errors.New(msgDatasetIsNil)
return return
} }
var plist C.property_list_ptr plist := C.read_dataset_property(d.list, C.int(p))
plist = C.new_property_list() if plist == nil {
defer C.free_properties(plist)
errcode := C.read_dataset_property(d.list.zh, plist, C.int(p))
if errcode != 0 {
err = LastError() err = LastError()
return return
} }
defer C.free_properties(plist)
prop = Property{Value: C.GoString(&(*plist).value[0]), prop = Property{Value: C.GoString(&(*plist).value[0]),
Source: C.GoString(&(*plist).source[0])} Source: C.GoString(&(*plist).source[0])}
d.Properties[p] = prop d.Properties[p] = prop
@ -291,16 +277,14 @@ func (d *Dataset) GetUserProperty(p string) (prop Property, err error) {
err = errors.New(msgDatasetIsNil) err = errors.New(msgDatasetIsNil)
return return
} }
var plist C.property_list_ptr
plist = C.new_property_list()
defer C.free_properties(plist)
csp := C.CString(p) csp := C.CString(p)
defer C.free(unsafe.Pointer(csp)) defer C.free(unsafe.Pointer(csp))
errcode := C.read_user_property(d.list.zh, plist, csp) plist := C.read_user_property(d.list, csp)
if errcode != 0 { if plist == nil {
err = LastError() err = LastError()
return return
} }
defer C.free_properties(plist)
prop = Property{Value: C.GoString(&(*plist).value[0]), prop = Property{Value: C.GoString(&(*plist).value[0]),
Source: C.GoString(&(*plist).source[0])} Source: C.GoString(&(*plist).source[0])}
return return
@ -315,8 +299,7 @@ func (d *Dataset) SetProperty(p Prop, value string) (err error) {
return return
} }
csValue := C.CString(value) csValue := C.CString(value)
errcode := C.zfs_prop_set(d.list.zh, C.zfs_prop_to_name( errcode := C.dataset_prop_set(d.list, C.zfs_prop_t(p), csValue)
C.zfs_prop_t(p)), csValue)
C.free(unsafe.Pointer(csValue)) C.free(unsafe.Pointer(csValue))
if errcode != 0 { if errcode != 0 {
err = LastError() err = LastError()
@ -335,7 +318,7 @@ func (d *Dataset) SetUserProperty(prop, value string) (err error) {
} }
csValue := C.CString(value) csValue := C.CString(value)
csProp := C.CString(prop) csProp := C.CString(prop)
errcode := C.zfs_prop_set(d.list.zh, csProp, csValue) errcode := C.dataset_user_prop_set(d.list, csProp, csValue)
C.free(unsafe.Pointer(csValue)) C.free(unsafe.Pointer(csValue))
C.free(unsafe.Pointer(csProp)) C.free(unsafe.Pointer(csProp))
if errcode != 0 { if errcode != 0 {
@ -358,7 +341,7 @@ func (d *Dataset) Clone(target string, props map[Prop]Property) (rd Dataset, err
defer C.nvlist_free(cprops) defer C.nvlist_free(cprops)
csTarget := C.CString(target) csTarget := C.CString(target)
defer C.free(unsafe.Pointer(csTarget)) defer C.free(unsafe.Pointer(csTarget))
if errc := C.zfs_clone(d.list.zh, csTarget, cprops); errc != 0 { if errc := C.dataset_clone(d.list, csTarget, cprops); errc != 0 {
err = LastError() err = LastError()
return return
} }
@ -375,7 +358,7 @@ func DatasetSnapshot(path string, recur bool, props map[Prop]Property) (rd Datas
defer C.nvlist_free(cprops) defer C.nvlist_free(cprops)
csPath := C.CString(path) csPath := C.CString(path)
defer C.free(unsafe.Pointer(csPath)) defer C.free(unsafe.Pointer(csPath))
if errc := C.zfs_snapshot(libzfsHandle, csPath, booleanT(recur), cprops); errc != 0 { if errc := C.dataset_snapshot(csPath, booleanT(recur), cprops); errc != 0 {
err = LastError() err = LastError()
return return
} }
@ -389,7 +372,7 @@ func (d *Dataset) Path() (path string, err error) {
err = errors.New(msgDatasetIsNil) err = errors.New(msgDatasetIsNil)
return return
} }
name := C.zfs_get_name(d.list.zh) name := C.dataset_get_name(d.list)
path = C.GoString(name) path = C.GoString(name)
return return
} }
@ -400,10 +383,11 @@ func (d *Dataset) Rollback(snap *Dataset, force bool) (err error) {
err = errors.New(msgDatasetIsNil) err = errors.New(msgDatasetIsNil)
return return
} }
if errc := C.zfs_rollback(d.list.zh, if errc := C.dataset_rollback(d.list, snap.list, booleanT(force)); errc != 0 {
snap.list.zh, booleanT(force)); errc != 0 {
err = LastError() err = LastError()
return
} }
d.ReloadProperties()
return return
} }
@ -413,9 +397,11 @@ func (d *Dataset) Promote() (err error) {
err = errors.New(msgDatasetIsNil) err = errors.New(msgDatasetIsNil)
return return
} }
if errc := C.zfs_promote(d.list.zh); errc != 0 { if errc := C.dataset_promote(d.list); errc != 0 {
err = LastError() err = LastError()
return
} }
d.ReloadProperties()
return return
} }
@ -428,10 +414,12 @@ func (d *Dataset) Rename(newName string, recur,
} }
csNewName := C.CString(newName) csNewName := C.CString(newName)
defer C.free(unsafe.Pointer(csNewName)) defer C.free(unsafe.Pointer(csNewName))
if errc := C.zfs_rename(d.list.zh, csNewName, if errc := C.dataset_rename(d.list, csNewName,
booleanT(recur), booleanT(forceUnmount)); errc != 0 { booleanT(recur), booleanT(forceUnmount)); errc != 0 {
err = LastError() err = LastError()
return
} }
d.ReloadProperties()
return return
} }
@ -439,16 +427,15 @@ func (d *Dataset) Rename(newName string, recur,
// sets in 'where' argument the current mountpoint, and returns true. Otherwise, // sets in 'where' argument the current mountpoint, and returns true. Otherwise,
// returns false. // returns false.
func (d *Dataset) IsMounted() (mounted bool, where string) { func (d *Dataset) IsMounted() (mounted bool, where string) {
var cw C.char_ptr
if d.list == nil { if d.list == nil {
return false, "" return
} }
m := C.zfs_is_mounted(d.list.zh, unsafe.Pointer(&cw)) mp := C.dataset_is_mounted(d.list)
// defer C.free(cw) // defer C.free(mp)
if m != 0 { if mounted = (mp != nil); mounted {
return true, C.GoString(cw) where = C.GoString(mp)
} }
return false, "" return
} }
// Mount the given filesystem. // Mount the given filesystem.
@ -459,7 +446,7 @@ func (d *Dataset) Mount(options string, flags int) (err error) {
} }
csOptions := C.CString(options) csOptions := C.CString(options)
defer C.free(unsafe.Pointer(csOptions)) defer C.free(unsafe.Pointer(csOptions))
if ec := C.zfs_mount(d.list.zh, csOptions, C.int(flags)); ec != 0 { if ec := C.dataset_mount(d.list, csOptions, C.int(flags)); ec != 0 {
err = LastError() err = LastError()
} }
return return
@ -471,7 +458,7 @@ func (d *Dataset) Unmount(flags int) (err error) {
err = errors.New(msgDatasetIsNil) err = errors.New(msgDatasetIsNil)
return return
} }
if ec := C.zfs_unmount(d.list.zh, nil, C.int(flags)); ec != 0 { if ec := C.dataset_unmount(d.list, C.int(flags)); ec != 0 {
err = LastError() err = LastError()
} }
return return
@ -484,7 +471,7 @@ func (d *Dataset) UnmountAll(flags int) (err error) {
err = errors.New(msgDatasetIsNil) err = errors.New(msgDatasetIsNil)
return return
} }
if ec := C.zfs_unmountall(d.list.zh, C.int(flags)); ec != 0 { if ec := C.dataset_unmountall(d.list, C.int(flags)); ec != 0 {
err = LastError() err = LastError()
} }
return return

26
zfs.h
View File

@ -18,14 +18,30 @@ dataset_list_t *create_dataset_list_item();
void dataset_list_close(dataset_list_t *list); void dataset_list_close(dataset_list_t *list);
void dataset_list_free(dataset_list_t *list); void dataset_list_free(dataset_list_t *list);
int dataset_list_root(libzfs_handle_t *libzfs, dataset_list_t **first); dataset_list_t* dataset_list_root();
int dataset_list_children(zfs_handle_t *zfs, dataset_list_t **first); dataset_list_t* dataset_list_children(dataset_list_t *dataset);
dataset_list_t *dataset_next(dataset_list_t *dataset); dataset_list_t *dataset_next(dataset_list_t *dataset);
int dataset_type(dataset_list_ptr dataset);
int read_dataset_property(zfs_handle_t *zh, property_list_t *list, int prop); dataset_list_ptr dataset_open(const char *path);
int read_user_property(zfs_handle_t *zh, property_list_t *list, const char* prop); int dataset_create(const char *path, zfs_type_t type, nvlist_ptr props);
int dataset_destroy(dataset_list_ptr dataset, boolean_t defer);
zpool_list_ptr dataset_get_pool(dataset_list_ptr dataset);
int dataset_prop_set(dataset_list_ptr dataset, zfs_prop_t prop, const char *value);
int dataset_user_prop_set(dataset_list_ptr dataset, const char *prop, const char *value);
int dataset_clone(dataset_list_ptr dataset, const char *target, nvlist_ptr props);
int dataset_snapshot(const char *path, boolean_t recur, nvlist_ptr props);
int dataset_rollback(dataset_list_ptr dataset, dataset_list_ptr snapshot, boolean_t force);
int dataset_promote(dataset_list_ptr dataset);
int dataset_rename(dataset_list_ptr dataset, const char* new_name, boolean_t recur, boolean_t force_unm);
const char* dataset_is_mounted(dataset_list_ptr dataset);
int dataset_mount(dataset_list_ptr dataset, const char *options, int flags);
int dataset_unmount(dataset_list_ptr dataset, int flags);
int dataset_unmountall(dataset_list_ptr dataset, int flags);
const char *dataset_get_name(dataset_list_ptr ds);
int clear_last_error(libzfs_handle_t *libzfs); property_list_t *read_dataset_property(dataset_list_t *dataset, int prop);
property_list_t *read_user_property(dataset_list_t *dataset, const char* prop);
char** alloc_cstrings(int size); char** alloc_cstrings(int size);
void strings_setat(char **a, int at, char *v); void strings_setat(char **a, int at, char *v);

449
zpool.c
View File

@ -7,6 +7,7 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include "common.h"
#include "zpool.h" #include "zpool.h"
char *sZPOOL_CONFIG_VERSION = ZPOOL_CONFIG_VERSION; char *sZPOOL_CONFIG_VERSION = ZPOOL_CONFIG_VERSION;
@ -109,26 +110,24 @@ int zpool_list_callb(zpool_handle_t *pool, void *data) {
return 0; return 0;
} }
int zpool_list(libzfs_handle_t *libzfs, zpool_list_t **first) { zpool_list_ptr zpool_list_openall() {
int err = 0; int err = 0;
zpool_list_t *zlist = create_zpool_list_item(); zpool_list_t *zlist = create_zpool_list_item();
err = zpool_iter(libzfs, zpool_list_callb, &zlist); err = zpool_iter(libzfsHandle, zpool_list_callb, &zlist);
if ( zlist->zph ) { if ( err != 0 || zlist->zph == NULL ) {
*first = zlist; zpool_list_free(zlist);
} else { zlist = NULL;
*first = 0;
free(zlist);
} }
return err; return zlist;
} }
zpool_list_t* zpool_list_open(libzfs_handle_t *libzfs, const char *name) { zpool_list_t* zpool_list_open(const char *name) {
zpool_list_t *zlist = create_zpool_list_item(); zpool_list_t *zlist = create_zpool_list_item();
zlist->zph = zpool_open(libzfs, name); zlist->zph = zpool_open(libzfsHandle, name);
if ( zlist->zph ) { if ( zlist->zph ) {
return zlist; return zlist;
} else { } else {
free(zlist); zpool_list_free(zlist);
} }
return 0; return 0;
} }
@ -137,26 +136,18 @@ zpool_list_t *zpool_next(zpool_list_t *pool) {
return pool->pnext; return pool->pnext;
} }
void zpool_list_free(zpool_list_t *list) {
zpool_list_ptr next;
while(list) {
next = list->pnext;
free(list);
list = next;
}
}
void zpool_list_close(zpool_list_t *pool) { void zpool_list_close(zpool_list_t *pool) {
zpool_close(pool->zph); zpool_close(pool->zph);
free(pool); zpool_list_free(pool);
}
property_list_t *new_property_list() {
property_list_t *r = malloc(sizeof(property_list_t));
memset(r, 0, sizeof(property_list_t));
return r;
}
void free_properties(property_list_t *root) {
if (root != 0) {
property_list_t *tmp = 0;
do {
tmp = root->pnext;
free(root);
root = tmp;
} while(tmp);
}
} }
property_list_t *next_property(property_list_t *list) { property_list_t *next_property(property_list_t *list) {
@ -191,161 +182,68 @@ void zprop_source_tostr(char *dst, zprop_source_t source) {
} }
int read_zpool_property(zpool_handle_t *zh, property_list_t *list, int prop) { property_list_ptr read_zpool_property(zpool_list_ptr pool, int prop) {
int r = 0; int r = 0;
zprop_source_t source; zprop_source_t source;
property_list_ptr list = new_property_list();
r = zpool_get_prop(zh, prop, r = zpool_get_prop(pool->zph, prop,
list->value, INT_MAX_VALUE, &source); list->value, INT_MAX_VALUE, &source);
if (r == 0) { if (r == 0) {
// strcpy(list->name, zpool_prop_to_name(prop)); // strcpy(list->name, zpool_prop_to_name(prop));
zprop_source_tostr(list->source, source); zprop_source_tostr(list->source, source);
} else {
free_properties(list);
return NULL;
} }
list->property = (int)prop; list->property = (int)prop;
return r; return list;
} }
int read_append_zpool_property(zpool_handle_t *zh, property_list_t **proot, property_list_ptr read_append_zpool_property(zpool_list_ptr pool, property_list_ptr proot, zpool_prop_t prop) {
zpool_prop_t prop) {
int r = 0; int r = 0;
property_list_t *newitem = NULL, *root = *proot; property_list_t *newitem = NULL;
newitem = new_property_list();
r = read_zpool_property(zh, newitem, prop); newitem = read_zpool_property(pool, prop);
// printf("p: %s %s %s\n", newitem->name, newitem->value, newitem->source); if (newitem == NULL) {
newitem->pnext = root; return proot;
*proot = root = newitem;
if (r != 0) {
free_properties(root);
*proot = NULL;
} }
return r; // printf("p: %s %s %s\n", newitem->name, newitem->value, newitem->source);
newitem->pnext = proot;
proot = newitem;
return proot;
} }
property_list_t *read_zpool_properties(zpool_handle_t *zh) { property_list_t *read_zpool_properties(zpool_list_ptr pool) {
// read pool name as first property // read pool name as first property
property_list_t *root = NULL, *list = NULL; property_list_t *root = NULL, *list = NULL;
int r = read_append_zpool_property(zh, &root, ZPOOL_PROP_NAME); root = read_append_zpool_property(pool, root, ZPOOL_PROP_NAME);
if (r != 0) { root = read_append_zpool_property(pool, root, ZPOOL_PROP_SIZE);
return 0; root = read_append_zpool_property(pool, root, ZPOOL_PROP_CAPACITY);
} root = read_append_zpool_property(pool, root, ZPOOL_PROP_ALTROOT);
root = read_append_zpool_property(pool, root, ZPOOL_PROP_HEALTH);
root = read_append_zpool_property(pool, root, ZPOOL_PROP_GUID);
root = read_append_zpool_property(pool, root, ZPOOL_PROP_VERSION);
root = read_append_zpool_property(pool, root, ZPOOL_PROP_BOOTFS);
root = read_append_zpool_property(pool, root, ZPOOL_PROP_DELEGATION);
root = read_append_zpool_property(pool, root, ZPOOL_PROP_AUTOREPLACE);
root = read_append_zpool_property(pool, root, ZPOOL_PROP_CACHEFILE);
root = read_append_zpool_property(pool, root, ZPOOL_PROP_FAILUREMODE);
root = read_append_zpool_property(pool, root, ZPOOL_PROP_LISTSNAPS);
root = read_append_zpool_property(pool, root, ZPOOL_PROP_AUTOEXPAND);
root = read_append_zpool_property(pool, root, ZPOOL_PROP_DEDUPDITTO);
root = read_append_zpool_property(pool, root, ZPOOL_PROP_DEDUPRATIO);
root = read_append_zpool_property(pool, root, ZPOOL_PROP_FREE);
root = read_append_zpool_property(pool, root, ZPOOL_PROP_ALLOCATED);
root = read_append_zpool_property(pool, root, ZPOOL_PROP_READONLY);
root = read_append_zpool_property(pool, root, ZPOOL_PROP_ASHIFT);
root = read_append_zpool_property(pool, root, ZPOOL_PROP_COMMENT);
root = read_append_zpool_property(pool, root, ZPOOL_PROP_EXPANDSZ);
root = read_append_zpool_property(pool, root, ZPOOL_PROP_FREEING);
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_SIZE);
if (r != 0) {
return 0;
}
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_CAPACITY);
if (r != 0) {
return 0;
}
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_ALTROOT);
if (r != 0) {
return 0;
}
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_HEALTH);
if (r != 0) {
return 0;
}
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_GUID);
if (r != 0) {
return 0;
}
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_VERSION);
if (r != 0) {
return 0;
}
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_BOOTFS);
if (r != 0) {
return 0;
}
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_DELEGATION);
if (r != 0) {
return 0;
}
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_AUTOREPLACE);
if (r != 0) {
return 0;
}
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_CACHEFILE);
if (r != 0) {
return 0;
}
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_FAILUREMODE);
if (r != 0) {
return 0;
}
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_LISTSNAPS);
if (r != 0) {
return 0;
}
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_AUTOEXPAND);
if (r != 0) {
return 0;
}
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_DEDUPDITTO);
if (r != 0) {
return 0;
}
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_DEDUPRATIO);
if (r != 0) {
return 0;
}
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_FREE);
if (r != 0) {
return 0;
}
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_ALLOCATED);
if (r != 0) {
return 0;
}
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_READONLY);
if (r != 0) {
return 0;
}
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_ASHIFT);
if (r != 0) {
return 0;
}
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_COMMENT);
if (r != 0) {
return 0;
}
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_EXPANDSZ);
if (r != 0) {
return 0;
}
r = read_append_zpool_property(zh, &root, ZPOOL_PROP_FREEING);
if (r != 0) {
return 0;
}
list = new_property_list(); list = new_property_list();
@ -370,85 +268,75 @@ const char *gettext(const char *txt) {
/* /*
* Add a property pair (name, string-value) into a property nvlist. * Add a property pair (name, string-value) into a property nvlist.
*/ */
int // int
add_prop_list(const char *propname, char *propval, nvlist_t **props, // add_prop_list(const char *propname, char *propval, nvlist_t **props,
boolean_t poolprop) { // boolean_t poolprop) {
zpool_prop_t prop = ZPROP_INVAL; // zpool_prop_t prop = ZPROP_INVAL;
zfs_prop_t fprop; // zfs_prop_t fprop;
nvlist_t *proplist; // nvlist_t *proplist;
const char *normnm; // const char *normnm;
char *strval; // char *strval;
if (*props == NULL && // if (*props == NULL &&
nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) { // nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) {
(void) snprintf(_lasterr_, 1024, "internal error: out of memory"); // (void) snprintf(_lasterr_, 1024, "internal error: out of memory");
return (1); // return (1);
} // }
proplist = *props; // proplist = *props;
if (poolprop) { // if (poolprop) {
const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION); // const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION);
if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL && // if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL &&
!zpool_prop_feature(propname)) { // !zpool_prop_feature(propname)) {
(void) snprintf(_lasterr_, 1024, "property '%s' is " // (void) snprintf(_lasterr_, 1024, "property '%s' is "
"not a valid pool property", propname); // "not a valid pool property", propname);
return (2); // return (2);
} // }
/* // /*
* feature@ properties and version should not be specified // * feature@ properties and version should not be specified
* at the same time. // * at the same time.
*/ // */
// if ((prop == ZPROP_INVAL && zpool_prop_feature(propname) && // // if ((prop == ZPROP_INVAL && zpool_prop_feature(propname) &&
// nvlist_exists(proplist, vname)) || // // nvlist_exists(proplist, vname)) ||
// (prop == ZPOOL_PROP_VERSION && // // (prop == ZPOOL_PROP_VERSION &&
// prop_list_contains_feature(proplist))) { // // prop_list_contains_feature(proplist))) {
// (void) fprintf(stderr, gettext("'feature@' and " // // (void) fprintf(stderr, gettext("'feature@' and "
// "'version' properties cannot be specified " // // "'version' properties cannot be specified "
// "together\n")); // // "together\n"));
// return (2); // // return (2);
// } // // }
if (zpool_prop_feature(propname)) // if (zpool_prop_feature(propname))
normnm = propname; // normnm = propname;
else // else
normnm = zpool_prop_to_name(prop); // normnm = zpool_prop_to_name(prop);
} else { // } else {
if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) { // if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) {
normnm = zfs_prop_to_name(fprop); // normnm = zfs_prop_to_name(fprop);
} else { // } else {
normnm = propname; // normnm = propname;
} // }
} // }
if (nvlist_lookup_string(proplist, normnm, &strval) == 0 && // if (nvlist_lookup_string(proplist, normnm, &strval) == 0 &&
prop != ZPOOL_PROP_CACHEFILE) { // prop != ZPOOL_PROP_CACHEFILE) {
(void) snprintf(_lasterr_, 1024, "property '%s' " // (void) snprintf(_lasterr_, 1024, "property '%s' "
"specified multiple times", propname); // "specified multiple times", propname);
return (2); // return (2);
} // }
if (nvlist_add_string(proplist, normnm, propval) != 0) { // if (nvlist_add_string(proplist, normnm, propval) != 0) {
(void) snprintf(_lasterr_, 1024, "internal " // (void) snprintf(_lasterr_, 1024, "internal "
"error: out of memory\n"); // "error: out of memory\n");
return (1); // return (1);
} // }
return (0); // return (0);
} // }
int nvlist_lookup_uint64_array_vds(nvlist_t *nv, const char *p,
vdev_stat_t **vds, uint_t *c) {
return nvlist_lookup_uint64_array(nv, p, (uint64_t**)vds, c);
}
int nvlist_lookup_uint64_array_ps(nvlist_t *nv, const char *p,
pool_scan_stat_t **vds, uint_t *c) {
return nvlist_lookup_uint64_array(nv, p, (uint64_t**)vds, c);
}
nvlist_t** nvlist_alloc_array(int count) { nvlist_t** nvlist_alloc_array(int count) {
return malloc(count*sizeof(nvlist_t*)); return malloc(count*sizeof(nvlist_t*));
@ -478,3 +366,100 @@ int refresh_stats(zpool_list_t *pool)
} }
return 0; return 0;
} }
const char *get_vdev_type(nvlist_ptr nv) {
char *value = NULL;
int r = nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &value);
if(r != 0) {
return NULL;
}
return value;
}
const vdev_stat_ptr get_vdev_stats(nvlist_ptr nv) {
vdev_stat_ptr vs = NULL;
uint_t count;
int r = nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, (uint64_t**)&vs, &count);
if(r != 0) {
return NULL;
}
return vs;
}
pool_scan_stat_ptr get_vdev_scan_stats(nvlist_t *nv) {
pool_scan_stat_ptr vds = NULL;
uint_t c;
int r = nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_SCAN_STATS, (uint64_t**)&vds, &c);
if(r != 0) {
return NULL;
}
return vds;
}
vdev_children_ptr get_vdev_children(nvlist_t *nv) {
int r;
vdev_children_ptr children = malloc(sizeof(vdev_children_t));
memset(children, 0, sizeof(vdev_children_t));
r = nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &(children->first), &(children->count));
if (r != 0) {
free(children);
return NULL;
}
return children;
}
const char *get_vdev_path(nvlist_ptr nv) {
char *path = NULL;
uint64_t notpresent = 0;
int r = nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, &notpresent);
if (r == 0 || notpresent != 0) {
if ( 0 != nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) ) {
return NULL;
}
}
return path;
}
uint64_t get_vdev_is_log(nvlist_ptr nv) {
uint64_t islog = B_FALSE;
nvlist_lookup_uint64(nv, ZPOOL_CONFIG_IS_LOG, &islog);
return islog;
}
// return
uint64_t get_zpool_state(nvlist_ptr nv) {
uint64_t state = 0;
nvlist_lookup_uint64(nv, ZPOOL_CONFIG_POOL_STATE, &state);
return state;
}
uint64_t get_zpool_guid(nvlist_ptr nv) {
uint64_t guid = 0;
nvlist_lookup_uint64(nv, ZPOOL_CONFIG_POOL_GUID, &guid);
return guid;
}
const char *get_zpool_name(nvlist_ptr nv) {
char *name = NULL;
if (0 != nvlist_lookup_string(nv, ZPOOL_CONFIG_POOL_NAME, &name)) {
return NULL;
}
return name;
}
const char *get_zpool_comment(nvlist_ptr nv) {
char *comment = NULL;
if (0 != nvlist_lookup_string(nv, ZPOOL_CONFIG_COMMENT, &comment)) {
return NULL;
}
return comment;
}
nvlist_ptr get_zpool_vdev_tree(nvlist_ptr nv) {
nvlist_ptr vdev_tree = NULL;
if ( 0 != nvlist_lookup_nvlist(nv, ZPOOL_CONFIG_VDEV_TREE, &vdev_tree) ) {
return NULL;
}
return vdev_tree;
}

152
zpool.go
View File

@ -2,6 +2,7 @@ package zfs
// #include <stdlib.h> // #include <stdlib.h>
// #include <libzfs.h> // #include <libzfs.h>
// #include "common.h"
// #include "zpool.h" // #include "zpool.h"
// #include "zfs.h" // #include "zfs.h"
import "C" import "C"
@ -138,7 +139,7 @@ type Pool struct {
func PoolOpen(name string) (pool Pool, err error) { func PoolOpen(name string) (pool Pool, err error) {
csName := C.CString(name) csName := C.CString(name)
defer C.free(unsafe.Pointer(csName)) defer C.free(unsafe.Pointer(csName))
pool.list = C.zpool_list_open(libzfsHandle, csName) pool.list = C.zpool_list_open(csName)
if pool.list != nil { if pool.list != nil {
err = pool.ReloadProperties() err = pool.ReloadProperties()
@ -150,12 +151,10 @@ func PoolOpen(name string) (pool Pool, err error) {
func poolGetConfig(name string, nv C.nvlist_ptr) (vdevs VDevTree, err error) { func poolGetConfig(name string, nv C.nvlist_ptr) (vdevs VDevTree, err error) {
var dtype C.char_ptr var dtype C.char_ptr
var c, children C.uint_t
var notpresent C.uint64_t
var vs C.vdev_stat_ptr var vs C.vdev_stat_ptr
var ps C.pool_scan_stat_ptr var ps C.pool_scan_stat_ptr
var child *C.nvlist_ptr var children C.vdev_children_ptr
if 0 != C.nvlist_lookup_string(nv, C.sZPOOL_CONFIG_TYPE, unsafe.Pointer(&dtype)) { if dtype = C.get_vdev_type(nv); dtype == nil {
err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_TYPE) err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_TYPE)
return return
} }
@ -166,8 +165,7 @@ func poolGetConfig(name string, nv C.nvlist_ptr) (vdevs VDevTree, err error) {
} }
// Fetch vdev state // Fetch vdev state
if 0 != C.nvlist_lookup_uint64_array_vds(nv, C.sZPOOL_CONFIG_VDEV_STATS, if vs = C.get_vdev_stats(nv); vs == nil {
unsafe.Pointer(&vs), &c) {
err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_VDEV_STATS) err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_VDEV_STATS)
return return
} }
@ -192,8 +190,7 @@ func poolGetConfig(name string, nv C.nvlist_ptr) (vdevs VDevTree, err error) {
vdevs.Stat.Fragmentation = uint64(vs.vs_fragmentation) vdevs.Stat.Fragmentation = uint64(vs.vs_fragmentation)
// Fetch vdev scan stats // Fetch vdev scan stats
if 0 == C.nvlist_lookup_uint64_array_ps(nv, C.sZPOOL_CONFIG_SCAN_STATS, if ps = C.get_vdev_scan_stats(nv); ps != nil {
unsafe.Pointer(&ps), &c) {
vdevs.ScanStat.Func = uint64(ps.pss_func) vdevs.ScanStat.Func = uint64(ps.pss_func)
vdevs.ScanStat.State = uint64(ps.pss_state) vdevs.ScanStat.State = uint64(ps.pss_state)
vdevs.ScanStat.StartTime = uint64(ps.pss_start_time) vdevs.ScanStat.StartTime = uint64(ps.pss_start_time)
@ -208,35 +205,28 @@ func poolGetConfig(name string, nv C.nvlist_ptr) (vdevs VDevTree, err error) {
} }
// Fetch the children // Fetch the children
if C.nvlist_lookup_nvlist_array(nv, C.sZPOOL_CONFIG_CHILDREN, children = C.get_vdev_children(nv)
unsafe.Pointer(&child), &children) != 0 { if children != nil {
children = 0 // this object that reference childrens and count should be deallocated from memory
defer C.free(unsafe.Pointer(children))
vdevs.Devices = make([]VDevTree, 0, children.count)
} }
if children > 0 { path := C.get_vdev_path(nv)
vdevs.Devices = make([]VDevTree, 0, children) if path != nil {
}
if C.nvlist_lookup_uint64(nv, C.sZPOOL_CONFIG_NOT_PRESENT,
&notpresent) == 0 || notpresent != 0 {
var path C.char_ptr
if 0 != C.nvlist_lookup_string(nv, C.sZPOOL_CONFIG_PATH, unsafe.Pointer(&path)) {
err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_PATH)
return
}
vdevs.Path = C.GoString(path) vdevs.Path = C.GoString(path)
} }
for c = 0; c < children; c++ { for c := C.uint_t(0); children != nil && c < children.count; c++ {
var islog = C.uint64_t(C.B_FALSE) var islog = C.uint64_t(C.B_FALSE)
C.nvlist_lookup_uint64(C.nvlist_array_at(child, c), islog = C.get_vdev_is_log(C.nvlist_array_at(children.first, c))
C.sZPOOL_CONFIG_IS_LOG, &islog)
if islog != C.B_FALSE { if islog != C.B_FALSE {
continue continue
} }
vname := C.zpool_vdev_name(libzfsHandle, nil, C.nvlist_array_at(child, c), vname := C.zpool_vdev_name(C.libzfsHandle, nil, C.nvlist_array_at(children.first, c),
C.B_TRUE) C.B_TRUE)
var vdev VDevTree var vdev VDevTree
vdev, err = poolGetConfig(C.GoString(vname), vdev, err = poolGetConfig(C.GoString(vname),
C.nvlist_array_at(child, c)) C.nvlist_array_at(children.first, c))
C.free(unsafe.Pointer(vname)) C.free(unsafe.Pointer(vname))
if err != nil { if err != nil {
return return
@ -251,7 +241,6 @@ func poolGetConfig(name string, nv C.nvlist_ptr) (vdevs VDevTree, err error) {
func PoolImportSearch(searchpaths []string) (epools []ExportedPool, err error) { func PoolImportSearch(searchpaths []string) (epools []ExportedPool, err error) {
var config, nvroot C.nvlist_ptr var config, nvroot C.nvlist_ptr
var cname, msgid, comment C.char_ptr var cname, msgid, comment C.char_ptr
var poolState, guid C.uint64_t
var reason C.zpool_status_t var reason C.zpool_status_t
var errata C.zpool_errata_t var errata C.zpool_errata_t
config = nil config = nil
@ -265,41 +254,35 @@ func PoolImportSearch(searchpaths []string) (epools []ExportedPool, err error) {
C.strings_setat(cpaths, C.int(i), csPath) C.strings_setat(cpaths, C.int(i), csPath)
} }
pools := C.zpool_find_import(libzfsHandle, C.int(numofp), cpaths) pools := C.zpool_find_import(C.libzfsHandle, C.int(numofp), cpaths)
defer C.nvlist_free(pools) defer C.nvlist_free(pools)
elem = C.nvlist_next_nvpair(pools, elem) elem = C.nvlist_next_nvpair(pools, elem)
epools = make([]ExportedPool, 0, 1) epools = make([]ExportedPool, 0, 1)
for ; elem != nil; elem = C.nvlist_next_nvpair(pools, elem) { for ; elem != nil; elem = C.nvlist_next_nvpair(pools, elem) {
ep := ExportedPool{} ep := ExportedPool{}
if C.nvpair_value_nvlist(elem, unsafe.Pointer(&config)) != 0 { if C.nvpair_value_nvlist(elem, (**C.struct_nvlist)(&config)) != 0 {
err = LastError() err = LastError()
return return
} }
if C.nvlist_lookup_uint64(config, C.sZPOOL_CONFIG_POOL_STATE,
&poolState) != 0 { ep.State = PoolState(C.get_zpool_state(config))
err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_POOL_STATE)
return if cname = C.get_zpool_name(config); cname == nil {
}
ep.State = PoolState(poolState)
if C.nvlist_lookup_string(config, C.sZPOOL_CONFIG_POOL_NAME, unsafe.Pointer(&cname)) != 0 {
err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_POOL_NAME) err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_POOL_NAME)
return return
} }
ep.Name = C.GoString(cname) ep.Name = C.GoString(cname)
if C.nvlist_lookup_uint64(config, C.sZPOOL_CONFIG_POOL_GUID, &guid) != 0 {
err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_POOL_GUID) ep.GUID = uint64(C.get_zpool_guid(config))
return
} reason = C.zpool_import_status(config, (**C.char)(&msgid), &errata)
ep.GUID = uint64(guid)
reason = C.zpool_import_status(config, &msgid, &errata)
ep.Status = PoolStatus(reason) ep.Status = PoolStatus(reason)
if C.nvlist_lookup_string(config, C.sZPOOL_CONFIG_COMMENT, unsafe.Pointer(&comment)) == 0 { if comment = C.get_zpool_comment(config); comment != nil {
ep.Comment = C.GoString(comment) ep.Comment = C.GoString(comment)
} }
if C.nvlist_lookup_nvlist(config, C.sZPOOL_CONFIG_VDEV_TREE, if nvroot = C.get_zpool_vdev_tree(config); nvroot == nil {
unsafe.Pointer(&nvroot)) != 0 {
err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_VDEV_TREE) err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_VDEV_TREE)
return return
} }
@ -325,33 +308,26 @@ func poolSearchImport(q string, searchpaths []string, guid bool) (name string,
C.strings_setat(cpaths, C.int(i), csPath) C.strings_setat(cpaths, C.int(i), csPath)
} }
pools := C.zpool_find_import(libzfsHandle, C.int(numofp), cpaths) pools := C.zpool_find_import(C.libzfsHandle, C.int(numofp), cpaths)
defer C.nvlist_free(pools) defer C.nvlist_free(pools)
elem = C.nvlist_next_nvpair(pools, elem) elem = C.nvlist_next_nvpair(pools, elem)
for ; elem != nil; elem = C.nvlist_next_nvpair(pools, elem) { for ; elem != nil; elem = C.nvlist_next_nvpair(pools, elem) {
var cq *C.char var cq *C.char
var tconfig *C.nvlist_t var tconfig *C.nvlist_t
retcode := C.nvpair_value_nvlist(elem, unsafe.Pointer(&tconfig)) retcode := C.nvpair_value_nvlist(elem, (**C.struct_nvlist)(&tconfig))
if retcode != 0 { if retcode != 0 {
err = errPoolList err = errPoolList
return return
} }
if guid { if guid {
var iguid C.uint64_t sguid := fmt.Sprint(C.get_zpool_guid(tconfig))
if retcode = C.nvlist_lookup_uint64(tconfig,
C.sZPOOL_CONFIG_POOL_GUID, &iguid); retcode != 0 {
err = errPoolList
return
}
sguid := fmt.Sprint(iguid)
if q == sguid { if q == sguid {
config = tconfig config = tconfig
break break
} }
} else { } else {
if retcode = C.nvlist_lookup_string(tconfig, if cq = C.get_zpool_name(tconfig); cq == nil {
C.sZPOOL_CONFIG_POOL_NAME, unsafe.Pointer(&cq)); retcode != 0 {
err = errPoolList err = errPoolList
return return
} }
@ -369,14 +345,13 @@ func poolSearchImport(q string, searchpaths []string, guid bool) (name string,
} }
if guid { if guid {
// We need to get name so we can open pool by name // We need to get name so we can open pool by name
if retcode := C.nvlist_lookup_string(config, if cname = C.get_zpool_name(config); cname == nil {
C.sZPOOL_CONFIG_POOL_NAME, unsafe.Pointer(&cname)); retcode != 0 {
err = errPoolList err = errPoolList
return return
} }
name = C.GoString(cname) name = C.GoString(cname)
} }
if retcode := C.zpool_import(libzfsHandle, config, cname, if retcode := C.zpool_import(C.libzfsHandle, config, cname,
nil); retcode != 0 { nil); retcode != 0 {
err = LastError() err = LastError()
return return
@ -416,17 +391,19 @@ func PoolImportByGUID(guid string, searchpaths []string) (pool Pool, err error)
// anymore. Call Pool.Close() method. // anymore. Call Pool.Close() method.
func PoolOpenAll() (pools []Pool, err error) { func PoolOpenAll() (pools []Pool, err error) {
var pool Pool var pool Pool
errcode := C.zpool_list(libzfsHandle, unsafe.Pointer(&pool.list)) if pool.list = C.zpool_list_openall(); pool.list == nil {
err = LastError()
return
}
for pool.list != nil { for pool.list != nil {
err = pool.ReloadProperties() err = pool.ReloadProperties()
if err != nil { if err != nil {
return return
} }
next := C.zpool_next(pool.list)
pool.list.pnext = nil
pools = append(pools, pool) pools = append(pools, pool)
pool.list = C.zpool_next(pool.list) pool.list = next
}
if errcode != 0 {
err = LastError()
} }
return return
} }
@ -469,7 +446,7 @@ func (pool *Pool) RefreshStats() (err error) {
// ReloadProperties re-read ZFS pool properties and features, refresh // ReloadProperties re-read ZFS pool properties and features, refresh
// Pool.Properties and Pool.Features map // Pool.Properties and Pool.Features map
func (pool *Pool) ReloadProperties() (err error) { func (pool *Pool) ReloadProperties() (err error) {
propList := C.read_zpool_properties(pool.list.zph) propList := C.read_zpool_properties(pool.list)
if propList == nil { if propList == nil {
err = LastError() err = LastError()
return return
@ -515,11 +492,12 @@ func (pool *Pool) GetProperty(p Prop) (prop Property, err error) {
PoolPropertyToName(p))) PoolPropertyToName(p)))
return return
} }
var list C.property_list_t list := C.read_zpool_property(pool.list, C.int(p))
r := C.read_zpool_property(pool.list.zph, unsafe.Pointer(&list), C.int(p)) if list == nil {
if r != 0 {
err = LastError() err = LastError()
return
} }
defer C.free_properties(list)
prop.Value = C.GoString(&(list.value[0])) prop.Value = C.GoString(&(list.value[0]))
prop.Source = C.GoString(&(list.source[0])) prop.Source = C.GoString(&(list.source[0]))
pool.Properties[p] = prop pool.Properties[p] = prop
@ -576,8 +554,10 @@ func (pool *Pool) SetProperty(p Prop, value string) (err error) {
// Close ZFS pool handler and release associated memory. // Close ZFS pool handler and release associated memory.
// Do not use Pool object after this. // Do not use Pool object after this.
func (pool *Pool) Close() { func (pool *Pool) Close() {
C.zpool_list_close(pool.list) if pool.list != nil {
pool.list = nil C.zpool_list_close(pool.list)
pool.list = nil
}
} }
// Name get (re-read) ZFS pool name property // Name get (re-read) ZFS pool name property
@ -633,11 +613,11 @@ func (vdev *VDevTree) isLog() (r C.uint64_t) {
} }
func toCPoolProperties(props PoolProperties) (cprops C.nvlist_ptr) { func toCPoolProperties(props PoolProperties) (cprops C.nvlist_ptr) {
cprops = nil cprops = C.new_property_nvlist()
for prop, value := range props { for prop, value := range props {
name := C.zpool_prop_to_name(C.zpool_prop_t(prop)) name := C.zpool_prop_to_name(C.zpool_prop_t(prop))
csPropValue := C.CString(value) csPropValue := C.CString(value)
r := C.add_prop_list(name, csPropValue, unsafe.Pointer(&cprops), C.boolean_t(1)) r := C.property_nvlist_add(cprops, name, csPropValue)
C.free(unsafe.Pointer(csPropValue)) C.free(unsafe.Pointer(csPropValue))
if r != 0 { if r != 0 {
if cprops != nil { if cprops != nil {
@ -651,11 +631,11 @@ func toCPoolProperties(props PoolProperties) (cprops C.nvlist_ptr) {
} }
func toCDatasetProperties(props DatasetProperties) (cprops C.nvlist_ptr) { func toCDatasetProperties(props DatasetProperties) (cprops C.nvlist_ptr) {
cprops = nil cprops = C.new_property_nvlist()
for prop, value := range props { for prop, value := range props {
name := C.zfs_prop_to_name(C.zfs_prop_t(prop)) name := C.zfs_prop_to_name(C.zfs_prop_t(prop))
csPropValue := C.CString(value) csPropValue := C.CString(value)
r := C.add_prop_list(name, csPropValue, unsafe.Pointer(&cprops), C.boolean_t(0)) r := C.property_nvlist_add(cprops, name, csPropValue)
C.free(unsafe.Pointer(csPropValue)) C.free(unsafe.Pointer(csPropValue))
if r != 0 { if r != 0 {
if cprops != nil { if cprops != nil {
@ -696,9 +676,9 @@ func buildVDevTree(root *C.nvlist_t, rtype VDevType, vdevs []VDevTree,
defer C.nvlist_free_array(l2cache) defer C.nvlist_free_array(l2cache)
for i, vdev := range vdevs { for i, vdev := range vdevs {
grouping, mindevs, maxdevs := vdev.isGrouping() grouping, mindevs, maxdevs := vdev.isGrouping()
var child C.nvlist_ptr var child *C.struct_nvlist
// fmt.Println(vdev.Type) // fmt.Println(vdev.Type)
if r := C.nvlist_alloc(unsafe.Pointer(&child), C.NV_UNIQUE_NAME, 0); r != 0 { if r := C.nvlist_alloc(&child, C.NV_UNIQUE_NAME, 0); r != 0 {
err = errors.New("Failed to allocate vdev") err = errors.New("Failed to allocate vdev")
return return
} }
@ -812,8 +792,8 @@ func buildVDevTree(root *C.nvlist_t, rtype VDevType, vdevs []VDevTree,
func PoolCreate(name string, vdevs []VDevTree, features map[string]string, func PoolCreate(name string, vdevs []VDevTree, features map[string]string,
props PoolProperties, fsprops DatasetProperties) (pool Pool, err error) { props PoolProperties, fsprops DatasetProperties) (pool Pool, err error) {
// create root vdev nvroot // create root vdev nvroot
var nvroot C.nvlist_ptr var nvroot *C.struct_nvlist
if r := C.nvlist_alloc(unsafe.Pointer(&nvroot), C.NV_UNIQUE_NAME, 0); r != 0 { if r := C.nvlist_alloc(&nvroot, C.NV_UNIQUE_NAME, 0); r != 0 {
err = errors.New("Failed to allocate root vdev") err = errors.New("Failed to allocate root vdev")
return return
} }
@ -860,8 +840,7 @@ func PoolCreate(name string, vdevs []VDevTree, features map[string]string,
for fname, fval := range features { for fname, fval := range features {
csName := C.CString(fmt.Sprintf("feature@%s", fname)) csName := C.CString(fmt.Sprintf("feature@%s", fname))
csVal := C.CString(fval) csVal := C.CString(fval)
r := C.add_prop_list(csName, csVal, unsafe.Pointer(&cprops), r := C.property_nvlist_add(cprops, csName, csVal)
C.boolean_t(1))
C.free(unsafe.Pointer(csName)) C.free(unsafe.Pointer(csName))
C.free(unsafe.Pointer(csVal)) C.free(unsafe.Pointer(csVal))
if r != 0 { if r != 0 {
@ -876,7 +855,7 @@ func PoolCreate(name string, vdevs []VDevTree, features map[string]string,
// Create actual pool then open // Create actual pool then open
csName := C.CString(name) csName := C.CString(name)
defer C.free(unsafe.Pointer(csName)) defer C.free(unsafe.Pointer(csName))
if r := C.zpool_create(libzfsHandle, csName, nvroot, if r := C.zpool_create(C.libzfsHandle, csName, nvroot,
cprops, cfsprops); r != 0 { cprops, cfsprops); r != 0 {
err = LastError() err = LastError()
err = errors.New(err.Error() + " (zpool_create)") err = errors.New(err.Error() + " (zpool_create)")
@ -890,14 +869,14 @@ func PoolCreate(name string, vdevs []VDevTree, features map[string]string,
// Status get pool status. Let you check if pool healthy. // Status get pool status. Let you check if pool healthy.
func (pool *Pool) Status() (status PoolStatus, err error) { func (pool *Pool) Status() (status PoolStatus, err error) {
var msgid C.char_ptr var msgid *C.char
var reason C.zpool_status_t var reason C.zpool_status_t
var errata C.zpool_errata_t var errata C.zpool_errata_t
if pool.list == nil { if pool.list == nil {
err = errors.New(msgPoolIsNil) err = errors.New(msgPoolIsNil)
return return
} }
reason = C.zpool_get_status(pool.list.zph, unsafe.Pointer(&msgid), &errata) reason = C.zpool_get_status(pool.list.zph, &msgid, &errata)
status = PoolStatus(reason) status = PoolStatus(reason)
return return
} }
@ -948,15 +927,14 @@ func (pool *Pool) ExportForce(log string) (err error) {
// VDevTree - Fetch pool's current vdev tree configuration, state and stats // VDevTree - Fetch pool's current vdev tree configuration, state and stats
func (pool *Pool) VDevTree() (vdevs VDevTree, err error) { func (pool *Pool) VDevTree() (vdevs VDevTree, err error) {
var nvroot C.nvlist_ptr var nvroot *C.struct_nvlist
var poolName string var poolName string
config := C.zpool_get_config(pool.list.zph, nil) config := C.zpool_get_config(pool.list.zph, nil)
if config == nil { if config == nil {
err = fmt.Errorf("Failed zpool_get_config") err = fmt.Errorf("Failed zpool_get_config")
return return
} }
if C.nvlist_lookup_nvlist(config, C.sZPOOL_CONFIG_VDEV_TREE, if C.nvlist_lookup_nvlist(config, C.sZPOOL_CONFIG_VDEV_TREE, &nvroot) != 0 {
unsafe.Pointer(&nvroot)) != 0 {
err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_VDEV_TREE) err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_VDEV_TREE)
return return
} }

64
zpool.h
View File

@ -5,72 +5,68 @@
#ifndef SERVERWARE_ZPOOL_H #ifndef SERVERWARE_ZPOOL_H
#define SERVERWARE_ZPOOL_H #define SERVERWARE_ZPOOL_H
#define INT_MAX_NAME 256
#define INT_MAX_VALUE 1024
#define ZAP_OLDMAXVALUELEN 1024
#define ZFS_MAX_DATASET_NAME_LEN 256
struct zpool_list { struct zpool_list {
zpool_handle_t *zph; zpool_handle_t *zph;
void *pnext; void *pnext;
}; };
typedef struct property_list { struct vdev_children {
char value[INT_MAX_VALUE]; nvlist_t **first;
char source[ZFS_MAX_DATASET_NAME_LEN]; uint_t count;
int property; };
void *pnext;
} property_list_t;
typedef struct zpool_list zpool_list_t; typedef struct zpool_list zpool_list_t;
typedef struct zpool_list* zpool_list_ptr; typedef struct zpool_list* zpool_list_ptr;
typedef struct libzfs_handle* libzfs_handle_ptr; typedef struct vdev_children vdev_children_t;
typedef struct nvlist* nvlist_ptr; typedef struct vdev_children* vdev_children_ptr;
typedef struct property_list *property_list_ptr;
typedef struct pool_scan_stat* pool_scan_stat_ptr; typedef struct pool_scan_stat* pool_scan_stat_ptr;
typedef struct nvpair* nvpair_ptr;
typedef struct vdev_stat* vdev_stat_ptr;
typedef char* char_ptr;
property_list_t *new_property_list();
zpool_list_t *create_zpool_list_item(); zpool_list_t *create_zpool_list_item();
void zprop_source_tostr(char *dst, zprop_source_t source); void zprop_source_tostr(char *dst, zprop_source_t source);
zpool_list_t* zpool_list_open(libzfs_handle_t *libzfs, const char *name); zpool_list_t* zpool_list_open(const char *name);
int zpool_list(libzfs_handle_t *libzfs, zpool_list_t **first); zpool_list_ptr zpool_list_openall();
zpool_list_t *zpool_next(zpool_list_t *pool); zpool_list_t *zpool_next(zpool_list_t *pool);
void zpool_list_free(zpool_list_t *list);
void zpool_list_close(zpool_list_t *pool); void zpool_list_close(zpool_list_t *pool);
int read_zpool_property(zpool_handle_t *zh, property_list_t *list, int prop); property_list_ptr read_zpool_property(zpool_list_ptr pool, int prop);
property_list_t *read_zpool_properties(zpool_handle_t *zh); property_list_t *read_zpool_properties(zpool_list_ptr pool);
property_list_t *next_property(property_list_t *list); property_list_t *next_property(property_list_t *list);
void free_properties(property_list_t *root);
pool_state_t zpool_read_state(zpool_handle_t *zh); pool_state_t zpool_read_state(zpool_handle_t *zh);
const char *lasterr(void); const char *lasterr(void);
int // int
add_prop_list(const char *propname, char *propval, nvlist_t **props, // add_prop_list(const char *propname, char *propval, nvlist_t **props,
boolean_t poolprop); // boolean_t poolprop);
nvlist_t** nvlist_alloc_array(int count); nvlist_t** nvlist_alloc_array(int count);
void nvlist_array_set(nvlist_t** a, int i, nvlist_t *item); void nvlist_array_set(nvlist_t** a, int i, nvlist_t *item);
void nvlist_free_array(nvlist_t **a); void nvlist_free_array(nvlist_t **a);
nvlist_t *nvlist_array_at(nvlist_t **a, uint_t i); nvlist_t *nvlist_array_at(nvlist_t **a, uint_t i);
int nvlist_lookup_uint64_array_vds(nvlist_t *nv, const char *p,
vdev_stat_t **vds, uint_t *c);
int nvlist_lookup_uint64_array_ps(nvlist_t *nv, const char *p,
pool_scan_stat_t **vds, uint_t *c);
int refresh_stats(zpool_list_t *pool); int refresh_stats(zpool_list_t *pool);
const char *get_vdev_type(nvlist_ptr nv);
const vdev_stat_ptr get_vdev_stats(nvlist_ptr nv);
pool_scan_stat_ptr get_vdev_scan_stats(nvlist_t *nv);
vdev_children_ptr get_vdev_children(nvlist_t *nv);
const char *get_vdev_path(nvlist_ptr nv);
uint64_t get_vdev_is_log(nvlist_ptr nv);
uint64_t get_zpool_state(nvlist_ptr nv);
uint64_t get_zpool_guid(nvlist_ptr nv);
const char *get_zpool_name(nvlist_ptr nv);
const char *get_zpool_comment(nvlist_ptr nv);
nvlist_ptr get_zpool_vdev_tree(nvlist_ptr nv);
char *sZPOOL_CONFIG_VERSION; char *sZPOOL_CONFIG_VERSION;
char *sZPOOL_CONFIG_POOL_NAME; char *sZPOOL_CONFIG_POOL_NAME;
char *sZPOOL_CONFIG_POOL_STATE; char *sZPOOL_CONFIG_POOL_STATE;

View File

@ -159,7 +159,7 @@ func zpoolTestPoolDestroy(t *testing.T) {
return return
} }
defer p.Close() defer p.Close()
if err = p.Destroy("Test of pool destroy (" + TSTPoolName + ")"); err != nil { if err = p.Destroy(TSTPoolName); err != nil {
t.Error(err.Error()) t.Error(err.Error())
return return
} }