diff --git a/common.c b/common.c new file mode 100644 index 0000000..cec48de --- /dev/null +++ b/common.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include + +#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); +} diff --git a/common.go b/common.go index 2cffd35..0b0ab88 100644 --- a/common.go +++ b/common.go @@ -14,6 +14,7 @@ package zfs #include #include +#include "common.h" #include "zpool.h" #include "zfs.h" */ @@ -26,10 +27,8 @@ import ( // VDevType type of device in the pool type VDevType string -var libzfsHandle C.libzfs_handle_ptr - func init() { - libzfsHandle = C.libzfs_init() + C.go_libzfs_init() return } @@ -256,17 +255,13 @@ const ( // LastError get last underlying libzfs error description if any func LastError() (err error) { - errno := C.libzfs_errno(libzfsHandle) - if errno == 0 { - return nil - } - return errors.New(C.GoString(C.libzfs_error_description(libzfsHandle))) + return errors.New(C.GoString(C.libzfs_last_error_str())) } // ClearLastError force clear of any last error set by undeliying libzfs func ClearLastError() (err error) { err = LastError() - C.clear_last_error(libzfsHandle) + C.libzfs_clear_last_error() return } diff --git a/common.h b/common.h new file mode 100644 index 0000000..105554f --- /dev/null +++ b/common.h @@ -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); + diff --git a/zfs.c b/zfs.c index 9089392..a54affc 100644 --- a/zfs.c +++ b/zfs.c @@ -7,6 +7,7 @@ #include #include +#include "common.h" #include "zpool.h" #include "zfs.h" @@ -46,59 +47,144 @@ int dataset_list_callb(zfs_handle_t *dataset, void *data) { return 0; } -int dataset_list_root(libzfs_handle_t *libzfs, dataset_list_t **first) { +dataset_list_ptr dataset_list_root() { int err = 0; dataset_list_t *zlist = create_dataset_list_item(); - err = zfs_iter_root(libzfs, dataset_list_callb, &zlist); - if ( zlist->zh ) { - *first = zlist; - } else { - *first = 0; + err = zfs_iter_root(libzfsHandle, dataset_list_callb, &zlist); + if ( err != 0 || zlist->zh == NULL) { 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; } - -int dataset_list_children(zfs_handle_t *zfs, dataset_list_t **first) { - 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 dataset_type(dataset_list_ptr dataset) { + return zfs_get_type(dataset->zh); } -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; zprop_source_t source; 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); if (r == 0) { // strcpy(list->name, zpool_prop_to_name(prop)); zprop_source_tostr(list->source, source); + list->property = (int)prop; + } else { + free_properties(list); + list = NULL; } - list->property = (int)prop; - return r; + return list; } -int read_user_property(zfs_handle_t *zh, property_list_t *list, const char *prop) { - nvlist_t *user_props = zfs_get_user_props(zh); +// int read_user_property(zfs_handle_t *zh, property_list_t *list, const char *prop) { +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; zprop_source_t sourcetype; char *strval; char *sourceval; // char source[ZFS_MAX_DATASET_NAME_LEN]; + property_list_ptr list = new_property_list(); if (nvlist_lookup_nvlist(user_props, 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); if (strcmp(sourceval, - zfs_get_name(zh)) == 0) { + zfs_get_name(dataset->zh)) == 0) { sourcetype = ZPROP_SRC_LOCAL; (void) strncpy(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, strval, sizeof (list->value)); - return 0; -} - -int clear_last_error(libzfs_handle_t *hdl) { - zfs_standard_error(hdl, EZFS_SUCCESS, "success"); - return 0; + return list; } char** alloc_cstrings(int size) { diff --git a/zfs.go b/zfs.go index 2be0be1..e4ec4f3 100644 --- a/zfs.go +++ b/zfs.go @@ -2,6 +2,7 @@ package zfs // #include // #include +// #include "common.h" // #include "zpool.h" // #include "zfs.h" import "C" @@ -44,12 +45,11 @@ type Dataset struct { } func (d *Dataset) openChildren() (err error) { - var list C.dataset_list_ptr 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 { 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) err = dataset.ReloadProperties() if err != nil { @@ -58,10 +58,6 @@ func (d *Dataset) openChildren() (err error) { d.Children = append(d.Children, dataset) list = C.dataset_next(list) } - if errcode != 0 { - err = LastError() - return - } for ci := range d.Children { if err = d.Children[ci].openChildren(); err != nil { return @@ -74,9 +70,9 @@ func (d *Dataset) openChildren() (err error) { // (file-systems, volumes or snapshots). func DatasetOpenAll() (datasets []Dataset, err error) { var dataset Dataset - errcode := C.dataset_list_root(libzfsHandle, unsafe.Pointer(&dataset.list)) + dataset.list = C.dataset_list_root() 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() if err != nil { return @@ -84,10 +80,6 @@ func DatasetOpenAll() (datasets []Dataset, err error) { datasets = append(datasets, dataset) dataset.list = C.dataset_next(dataset.list) } - if errcode != 0 { - err = LastError() - return - } for ci := range datasets { if err = datasets[ci].openChildren(); err != nil { return @@ -106,22 +98,23 @@ func DatasetCloseAll(datasets []Dataset) { // DatasetOpen open dataset and all of its recursive children datasets func DatasetOpen(path string) (d Dataset, err error) { - d.list = C.create_dataset_list_item() csPath := C.CString(path) - d.list.zh = C.zfs_open(libzfsHandle, csPath, 0xF) + d.list = C.dataset_open(csPath) C.free(unsafe.Pointer(csPath)) - if d.list.zh == nil { + if d.list == nil || d.list.zh == nil { err = LastError() if err == nil { err = fmt.Errorf("dataset not found.") } + println("open failed") 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) err = d.ReloadProperties() if err != nil { + println("reload properties failed") return } err = d.openChildren() @@ -131,16 +124,15 @@ func DatasetOpen(path string) (d Dataset, err error) { func datasetPropertiesTonvlist(props map[Prop]Property) ( cprops C.nvlist_ptr, err error) { // convert properties to nvlist C type - r := C.nvlist_alloc(unsafe.Pointer(&cprops), C.NV_UNIQUE_NAME, 0) - if r != 0 { + cprops = C.new_property_nvlist() + if cprops == nil { err = errors.New("Failed to allocate properties") return } for prop, value := range props { csValue := C.CString(value.Value) - r := C.nvlist_add_string( - cprops, C.zfs_prop_to_name( - C.zfs_prop_t(prop)), csValue) + r := C.property_nvlist_add( + cprops, C.zfs_prop_to_name(C.zfs_prop_t(prop)), csValue) C.free(unsafe.Pointer(csValue)) if r != 0 { err = errors.New("Failed to convert property") @@ -161,13 +153,13 @@ func DatasetCreate(path string, dtype DatasetType, defer C.nvlist_free(cprops) csPath := C.CString(path) - errcode := C.zfs_create(libzfsHandle, csPath, - C.zfs_type_t(dtype), cprops) + errcode := C.dataset_create(csPath, C.zfs_type_t(dtype), cprops) C.free(unsafe.Pointer(csPath)) if errcode != 0 { err = LastError() + return } - return + return DatasetOpen(path) } // 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 // 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) { if len(d.Children) > 0 { path, e := d.Path() @@ -200,7 +193,7 @@ func (d *Dataset) Destroy(Defer bool) (err error) { return } 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() } } else { @@ -232,9 +225,8 @@ func (d *Dataset) Pool() (p Pool, err error) { err = errors.New(msgDatasetIsNil) return } - p.list = C.create_zpool_list_item() - p.list.zph = C.zfs_get_pool_handle(d.list.zh) - if p.list != nil { + p.list = C.dataset_get_pool(d.list) + if p.list != nil && p.list.zph != nil { err = p.ReloadProperties() return } @@ -248,14 +240,10 @@ func (d *Dataset) ReloadProperties() (err error) { err = errors.New(msgDatasetIsNil) return } - var plist C.property_list_ptr - d.Properties = make(map[Prop]Property) for prop := DatasetPropType; prop < DatasetNumProps; prop++ { - plist = C.new_property_list() - errcode := C.read_dataset_property(d.list.zh, plist, C.int(prop)) - if errcode != 0 { - C.free_properties(plist) + plist := C.read_dataset_property(d.list, C.int(prop)) + if plist == nil { continue } 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) return } - var plist C.property_list_ptr - plist = C.new_property_list() - defer C.free_properties(plist) - errcode := C.read_dataset_property(d.list.zh, plist, C.int(p)) - if errcode != 0 { + plist := C.read_dataset_property(d.list, C.int(p)) + if plist == nil { err = LastError() return } + defer C.free_properties(plist) prop = Property{Value: C.GoString(&(*plist).value[0]), Source: C.GoString(&(*plist).source[0])} d.Properties[p] = prop @@ -291,16 +277,14 @@ func (d *Dataset) GetUserProperty(p string) (prop Property, err error) { err = errors.New(msgDatasetIsNil) return } - var plist C.property_list_ptr - plist = C.new_property_list() - defer C.free_properties(plist) csp := C.CString(p) defer C.free(unsafe.Pointer(csp)) - errcode := C.read_user_property(d.list.zh, plist, csp) - if errcode != 0 { + plist := C.read_user_property(d.list, csp) + if plist == nil { err = LastError() return } + defer C.free_properties(plist) prop = Property{Value: C.GoString(&(*plist).value[0]), Source: C.GoString(&(*plist).source[0])} return @@ -315,8 +299,7 @@ func (d *Dataset) SetProperty(p Prop, value string) (err error) { return } csValue := C.CString(value) - errcode := C.zfs_prop_set(d.list.zh, C.zfs_prop_to_name( - C.zfs_prop_t(p)), csValue) + errcode := C.dataset_prop_set(d.list, C.zfs_prop_t(p), csValue) C.free(unsafe.Pointer(csValue)) if errcode != 0 { err = LastError() @@ -335,7 +318,7 @@ func (d *Dataset) SetUserProperty(prop, value string) (err error) { } csValue := C.CString(value) 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(csProp)) 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) csTarget := C.CString(target) 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() return } @@ -375,7 +358,7 @@ func DatasetSnapshot(path string, recur bool, props map[Prop]Property) (rd Datas defer C.nvlist_free(cprops) csPath := C.CString(path) 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() return } @@ -389,7 +372,7 @@ func (d *Dataset) Path() (path string, err error) { err = errors.New(msgDatasetIsNil) return } - name := C.zfs_get_name(d.list.zh) + name := C.dataset_get_name(d.list) path = C.GoString(name) return } @@ -400,10 +383,11 @@ func (d *Dataset) Rollback(snap *Dataset, force bool) (err error) { err = errors.New(msgDatasetIsNil) return } - if errc := C.zfs_rollback(d.list.zh, - snap.list.zh, booleanT(force)); errc != 0 { + if errc := C.dataset_rollback(d.list, snap.list, booleanT(force)); errc != 0 { err = LastError() + return } + d.ReloadProperties() return } @@ -413,9 +397,11 @@ func (d *Dataset) Promote() (err error) { err = errors.New(msgDatasetIsNil) return } - if errc := C.zfs_promote(d.list.zh); errc != 0 { + if errc := C.dataset_promote(d.list); errc != 0 { err = LastError() + return } + d.ReloadProperties() return } @@ -428,10 +414,12 @@ func (d *Dataset) Rename(newName string, recur, } csNewName := C.CString(newName) 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 { err = LastError() + return } + d.ReloadProperties() return } @@ -439,16 +427,15 @@ func (d *Dataset) Rename(newName string, recur, // sets in 'where' argument the current mountpoint, and returns true. Otherwise, // returns false. func (d *Dataset) IsMounted() (mounted bool, where string) { - var cw C.char_ptr if d.list == nil { - return false, "" + return } - m := C.zfs_is_mounted(d.list.zh, unsafe.Pointer(&cw)) - // defer C.free(cw) - if m != 0 { - return true, C.GoString(cw) + mp := C.dataset_is_mounted(d.list) + // defer C.free(mp) + if mounted = (mp != nil); mounted { + where = C.GoString(mp) } - return false, "" + return } // Mount the given filesystem. @@ -459,7 +446,7 @@ func (d *Dataset) Mount(options string, flags int) (err error) { } csOptions := C.CString(options) 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() } return @@ -471,7 +458,7 @@ func (d *Dataset) Unmount(flags int) (err error) { err = errors.New(msgDatasetIsNil) 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() } return @@ -484,7 +471,7 @@ func (d *Dataset) UnmountAll(flags int) (err error) { err = errors.New(msgDatasetIsNil) 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() } return diff --git a/zfs.h b/zfs.h index 0885e25..d70566e 100644 --- a/zfs.h +++ b/zfs.h @@ -18,14 +18,30 @@ dataset_list_t *create_dataset_list_item(); void dataset_list_close(dataset_list_t *list); void dataset_list_free(dataset_list_t *list); -int dataset_list_root(libzfs_handle_t *libzfs, dataset_list_t **first); -int dataset_list_children(zfs_handle_t *zfs, dataset_list_t **first); +dataset_list_t* dataset_list_root(); +dataset_list_t* dataset_list_children(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); -int read_user_property(zfs_handle_t *zh, property_list_t *list, const char* prop); +dataset_list_ptr dataset_open(const char *path); +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); void strings_setat(char **a, int at, char *v); diff --git a/zpool.c b/zpool.c index 5755312..c63665a 100644 --- a/zpool.c +++ b/zpool.c @@ -7,6 +7,7 @@ #include #include +#include "common.h" #include "zpool.h" char *sZPOOL_CONFIG_VERSION = ZPOOL_CONFIG_VERSION; @@ -109,26 +110,24 @@ int zpool_list_callb(zpool_handle_t *pool, void *data) { return 0; } -int zpool_list(libzfs_handle_t *libzfs, zpool_list_t **first) { +zpool_list_ptr zpool_list_openall() { int err = 0; zpool_list_t *zlist = create_zpool_list_item(); - err = zpool_iter(libzfs, zpool_list_callb, &zlist); - if ( zlist->zph ) { - *first = zlist; - } else { - *first = 0; - free(zlist); + err = zpool_iter(libzfsHandle, zpool_list_callb, &zlist); + if ( err != 0 || zlist->zph == NULL ) { + zpool_list_free(zlist); + zlist = NULL; } - 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(); - zlist->zph = zpool_open(libzfs, name); + zlist->zph = zpool_open(libzfsHandle, name); if ( zlist->zph ) { return zlist; } else { - free(zlist); + zpool_list_free(zlist); } return 0; } @@ -137,26 +136,18 @@ zpool_list_t *zpool_next(zpool_list_t *pool) { 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) { zpool_close(pool->zph); - 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); - } + zpool_list_free(pool); } 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; 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); if (r == 0) { // strcpy(list->name, zpool_prop_to_name(prop)); zprop_source_tostr(list->source, source); + } else { + free_properties(list); + return NULL; } list->property = (int)prop; - return r; + return list; } -int read_append_zpool_property(zpool_handle_t *zh, property_list_t **proot, - zpool_prop_t prop) { +property_list_ptr read_append_zpool_property(zpool_list_ptr pool, property_list_ptr proot, zpool_prop_t prop) { int r = 0; - property_list_t *newitem = NULL, *root = *proot; - newitem = new_property_list(); + property_list_t *newitem = NULL; - r = read_zpool_property(zh, newitem, prop); - // printf("p: %s %s %s\n", newitem->name, newitem->value, newitem->source); - newitem->pnext = root; - *proot = root = newitem; - if (r != 0) { - free_properties(root); - *proot = NULL; + newitem = read_zpool_property(pool, prop); + if (newitem == NULL) { + return proot; } - 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 property_list_t *root = NULL, *list = NULL; - int r = read_append_zpool_property(zh, &root, ZPOOL_PROP_NAME); - if (r != 0) { - return 0; - } - - 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; - } + root = read_append_zpool_property(pool, root, ZPOOL_PROP_NAME); + root = read_append_zpool_property(pool, root, ZPOOL_PROP_SIZE); + 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); + 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. */ -int -add_prop_list(const char *propname, char *propval, nvlist_t **props, - boolean_t poolprop) { - zpool_prop_t prop = ZPROP_INVAL; - zfs_prop_t fprop; - nvlist_t *proplist; - const char *normnm; - char *strval; +// int +// add_prop_list(const char *propname, char *propval, nvlist_t **props, +// boolean_t poolprop) { +// zpool_prop_t prop = ZPROP_INVAL; +// zfs_prop_t fprop; +// nvlist_t *proplist; +// const char *normnm; +// char *strval; - if (*props == NULL && - nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) { - (void) snprintf(_lasterr_, 1024, "internal error: out of memory"); - return (1); - } +// if (*props == NULL && +// nvlist_alloc(props, NV_UNIQUE_NAME, 0) != 0) { +// (void) snprintf(_lasterr_, 1024, "internal error: out of memory"); +// return (1); +// } - proplist = *props; +// proplist = *props; - if (poolprop) { - const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION); +// if (poolprop) { +// const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION); - if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL && - !zpool_prop_feature(propname)) { - (void) snprintf(_lasterr_, 1024, "property '%s' is " - "not a valid pool property", propname); - return (2); - } +// if ((prop = zpool_name_to_prop(propname)) == ZPROP_INVAL && +// !zpool_prop_feature(propname)) { +// (void) snprintf(_lasterr_, 1024, "property '%s' is " +// "not a valid pool property", propname); +// return (2); +// } - /* - * feature@ properties and version should not be specified - * at the same time. - */ - // if ((prop == ZPROP_INVAL && zpool_prop_feature(propname) && - // nvlist_exists(proplist, vname)) || - // (prop == ZPOOL_PROP_VERSION && - // prop_list_contains_feature(proplist))) { - // (void) fprintf(stderr, gettext("'feature@' and " - // "'version' properties cannot be specified " - // "together\n")); - // return (2); - // } +// /* +// * feature@ properties and version should not be specified +// * at the same time. +// */ +// // if ((prop == ZPROP_INVAL && zpool_prop_feature(propname) && +// // nvlist_exists(proplist, vname)) || +// // (prop == ZPOOL_PROP_VERSION && +// // prop_list_contains_feature(proplist))) { +// // (void) fprintf(stderr, gettext("'feature@' and " +// // "'version' properties cannot be specified " +// // "together\n")); +// // return (2); +// // } - if (zpool_prop_feature(propname)) - normnm = propname; - else - normnm = zpool_prop_to_name(prop); - } else { - if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) { - normnm = zfs_prop_to_name(fprop); - } else { - normnm = propname; - } - } +// if (zpool_prop_feature(propname)) +// normnm = propname; +// else +// normnm = zpool_prop_to_name(prop); +// } else { +// if ((fprop = zfs_name_to_prop(propname)) != ZPROP_INVAL) { +// normnm = zfs_prop_to_name(fprop); +// } else { +// normnm = propname; +// } +// } - if (nvlist_lookup_string(proplist, normnm, &strval) == 0 && - prop != ZPOOL_PROP_CACHEFILE) { - (void) snprintf(_lasterr_, 1024, "property '%s' " - "specified multiple times", propname); - return (2); - } +// if (nvlist_lookup_string(proplist, normnm, &strval) == 0 && +// prop != ZPOOL_PROP_CACHEFILE) { +// (void) snprintf(_lasterr_, 1024, "property '%s' " +// "specified multiple times", propname); +// return (2); +// } - if (nvlist_add_string(proplist, normnm, propval) != 0) { - (void) snprintf(_lasterr_, 1024, "internal " - "error: out of memory\n"); - return (1); - } +// if (nvlist_add_string(proplist, normnm, propval) != 0) { +// (void) snprintf(_lasterr_, 1024, "internal " +// "error: out of memory\n"); +// return (1); +// } - 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); -} +// return (0); +// } nvlist_t** nvlist_alloc_array(int count) { return malloc(count*sizeof(nvlist_t*)); @@ -478,3 +366,100 @@ int refresh_stats(zpool_list_t *pool) } 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, ¬present); + 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; +} \ No newline at end of file diff --git a/zpool.go b/zpool.go index 940f8b0..d6aefda 100644 --- a/zpool.go +++ b/zpool.go @@ -2,6 +2,7 @@ package zfs // #include // #include +// #include "common.h" // #include "zpool.h" // #include "zfs.h" import "C" @@ -138,7 +139,7 @@ type Pool struct { func PoolOpen(name string) (pool Pool, err error) { csName := C.CString(name) 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 { 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) { var dtype C.char_ptr - var c, children C.uint_t - var notpresent C.uint64_t var vs C.vdev_stat_ptr var ps C.pool_scan_stat_ptr - var child *C.nvlist_ptr - if 0 != C.nvlist_lookup_string(nv, C.sZPOOL_CONFIG_TYPE, unsafe.Pointer(&dtype)) { + 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 } @@ -166,8 +165,7 @@ func poolGetConfig(name string, nv C.nvlist_ptr) (vdevs VDevTree, err error) { } // Fetch vdev state - if 0 != C.nvlist_lookup_uint64_array_vds(nv, C.sZPOOL_CONFIG_VDEV_STATS, - unsafe.Pointer(&vs), &c) { + if vs = C.get_vdev_stats(nv); vs == nil { err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_VDEV_STATS) return } @@ -192,8 +190,7 @@ func poolGetConfig(name string, nv C.nvlist_ptr) (vdevs VDevTree, err error) { vdevs.Stat.Fragmentation = uint64(vs.vs_fragmentation) // Fetch vdev scan stats - if 0 == C.nvlist_lookup_uint64_array_ps(nv, C.sZPOOL_CONFIG_SCAN_STATS, - unsafe.Pointer(&ps), &c) { + 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) @@ -208,35 +205,28 @@ func poolGetConfig(name string, nv C.nvlist_ptr) (vdevs VDevTree, err error) { } // Fetch the children - if C.nvlist_lookup_nvlist_array(nv, C.sZPOOL_CONFIG_CHILDREN, - unsafe.Pointer(&child), &children) != 0 { - children = 0 + children = C.get_vdev_children(nv) + if children != nil { + // 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 { - vdevs.Devices = make([]VDevTree, 0, children) - } - if C.nvlist_lookup_uint64(nv, C.sZPOOL_CONFIG_NOT_PRESENT, - ¬present) == 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 - } + path := C.get_vdev_path(nv) + if path != nil { 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) - C.nvlist_lookup_uint64(C.nvlist_array_at(child, c), - C.sZPOOL_CONFIG_IS_LOG, &islog) + islog = C.get_vdev_is_log(C.nvlist_array_at(children.first, c)) if islog != C.B_FALSE { 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) var vdev VDevTree vdev, err = poolGetConfig(C.GoString(vname), - C.nvlist_array_at(child, c)) + C.nvlist_array_at(children.first, c)) C.free(unsafe.Pointer(vname)) if err != nil { 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) { var config, nvroot C.nvlist_ptr var cname, msgid, comment C.char_ptr - var poolState, guid C.uint64_t var reason C.zpool_status_t var errata C.zpool_errata_t config = nil @@ -265,41 +254,35 @@ func PoolImportSearch(searchpaths []string) (epools []ExportedPool, err error) { 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) 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, unsafe.Pointer(&config)) != 0 { + if C.nvpair_value_nvlist(elem, (**C.struct_nvlist)(&config)) != 0 { err = LastError() return } - if C.nvlist_lookup_uint64(config, C.sZPOOL_CONFIG_POOL_STATE, - &poolState) != 0 { - err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_POOL_STATE) - return - } - ep.State = PoolState(poolState) - if C.nvlist_lookup_string(config, C.sZPOOL_CONFIG_POOL_NAME, unsafe.Pointer(&cname)) != 0 { + + ep.State = PoolState(C.get_zpool_state(config)) + + 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) - 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) - return - } - ep.GUID = uint64(guid) - reason = C.zpool_import_status(config, &msgid, &errata) + + ep.GUID = uint64(C.get_zpool_guid(config)) + + reason = C.zpool_import_status(config, (**C.char)(&msgid), &errata) 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) } - if C.nvlist_lookup_nvlist(config, C.sZPOOL_CONFIG_VDEV_TREE, - unsafe.Pointer(&nvroot)) != 0 { + if nvroot = C.get_zpool_vdev_tree(config); nvroot == nil { err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_VDEV_TREE) return } @@ -325,33 +308,26 @@ func poolSearchImport(q string, searchpaths []string, guid bool) (name string, 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) 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, unsafe.Pointer(&tconfig)) + retcode := C.nvpair_value_nvlist(elem, (**C.struct_nvlist)(&tconfig)) if retcode != 0 { err = errPoolList return } if guid { - var iguid C.uint64_t - if retcode = C.nvlist_lookup_uint64(tconfig, - C.sZPOOL_CONFIG_POOL_GUID, &iguid); retcode != 0 { - err = errPoolList - return - } - sguid := fmt.Sprint(iguid) + sguid := fmt.Sprint(C.get_zpool_guid(tconfig)) if q == sguid { config = tconfig break } } else { - if retcode = C.nvlist_lookup_string(tconfig, - C.sZPOOL_CONFIG_POOL_NAME, unsafe.Pointer(&cq)); retcode != 0 { + if cq = C.get_zpool_name(tconfig); cq == nil { err = errPoolList return } @@ -369,14 +345,13 @@ func poolSearchImport(q string, searchpaths []string, guid bool) (name string, } if guid { // We need to get name so we can open pool by name - if retcode := C.nvlist_lookup_string(config, - C.sZPOOL_CONFIG_POOL_NAME, unsafe.Pointer(&cname)); retcode != 0 { + if cname = C.get_zpool_name(config); cname == nil { err = errPoolList return } name = C.GoString(cname) } - if retcode := C.zpool_import(libzfsHandle, config, cname, + if retcode := C.zpool_import(C.libzfsHandle, config, cname, nil); retcode != 0 { err = LastError() return @@ -416,17 +391,19 @@ func PoolImportByGUID(guid string, searchpaths []string) (pool Pool, err error) // anymore. Call Pool.Close() method. func PoolOpenAll() (pools []Pool, err error) { 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 { err = pool.ReloadProperties() if err != nil { return } + next := C.zpool_next(pool.list) + pool.list.pnext = nil pools = append(pools, pool) - pool.list = C.zpool_next(pool.list) - } - if errcode != 0 { - err = LastError() + pool.list = next } return } @@ -469,7 +446,7 @@ func (pool *Pool) RefreshStats() (err error) { // ReloadProperties re-read ZFS pool properties and features, refresh // Pool.Properties and Pool.Features map func (pool *Pool) ReloadProperties() (err error) { - propList := C.read_zpool_properties(pool.list.zph) + propList := C.read_zpool_properties(pool.list) if propList == nil { err = LastError() return @@ -515,11 +492,12 @@ func (pool *Pool) GetProperty(p Prop) (prop Property, err error) { PoolPropertyToName(p))) return } - var list C.property_list_t - r := C.read_zpool_property(pool.list.zph, unsafe.Pointer(&list), C.int(p)) - if r != 0 { + 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 @@ -576,8 +554,10 @@ func (pool *Pool) SetProperty(p Prop, value string) (err error) { // Close ZFS pool handler and release associated memory. // Do not use Pool object after this. func (pool *Pool) Close() { - C.zpool_list_close(pool.list) - pool.list = nil + if pool.list != nil { + C.zpool_list_close(pool.list) + pool.list = nil + } } // 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) { - cprops = nil + cprops = C.new_property_nvlist() for prop, value := range props { name := C.zpool_prop_to_name(C.zpool_prop_t(prop)) 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)) if r != 0 { if cprops != nil { @@ -651,11 +631,11 @@ func toCPoolProperties(props PoolProperties) (cprops C.nvlist_ptr) { } func toCDatasetProperties(props DatasetProperties) (cprops C.nvlist_ptr) { - cprops = nil + cprops = C.new_property_nvlist() for prop, value := range props { name := C.zfs_prop_to_name(C.zfs_prop_t(prop)) 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)) if r != 0 { if cprops != nil { @@ -696,9 +676,9 @@ func buildVDevTree(root *C.nvlist_t, rtype VDevType, vdevs []VDevTree, defer C.nvlist_free_array(l2cache) for i, vdev := range vdevs { grouping, mindevs, maxdevs := vdev.isGrouping() - var child C.nvlist_ptr + var child *C.struct_nvlist // 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") 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, props PoolProperties, fsprops DatasetProperties) (pool Pool, err error) { // create root vdev nvroot - var nvroot C.nvlist_ptr - if r := C.nvlist_alloc(unsafe.Pointer(&nvroot), C.NV_UNIQUE_NAME, 0); r != 0 { + var nvroot *C.struct_nvlist + if r := C.nvlist_alloc(&nvroot, C.NV_UNIQUE_NAME, 0); r != 0 { err = errors.New("Failed to allocate root vdev") return } @@ -860,8 +840,7 @@ func PoolCreate(name string, vdevs []VDevTree, features map[string]string, for fname, fval := range features { csName := C.CString(fmt.Sprintf("feature@%s", fname)) csVal := C.CString(fval) - r := C.add_prop_list(csName, csVal, unsafe.Pointer(&cprops), - C.boolean_t(1)) + r := C.property_nvlist_add(cprops, csName, csVal) C.free(unsafe.Pointer(csName)) C.free(unsafe.Pointer(csVal)) if r != 0 { @@ -876,7 +855,7 @@ func PoolCreate(name string, vdevs []VDevTree, features map[string]string, // Create actual pool then open csName := C.CString(name) 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 { err = LastError() 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. func (pool *Pool) Status() (status PoolStatus, err error) { - var msgid C.char_ptr + var msgid *C.char var reason C.zpool_status_t var errata C.zpool_errata_t if pool.list == nil { err = errors.New(msgPoolIsNil) 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) return } @@ -948,15 +927,14 @@ func (pool *Pool) ExportForce(log string) (err error) { // VDevTree - Fetch pool's current vdev tree configuration, state and stats func (pool *Pool) VDevTree() (vdevs VDevTree, err error) { - var nvroot C.nvlist_ptr + var nvroot *C.struct_nvlist var poolName string config := C.zpool_get_config(pool.list.zph, nil) if config == nil { err = fmt.Errorf("Failed zpool_get_config") return } - if C.nvlist_lookup_nvlist(config, C.sZPOOL_CONFIG_VDEV_TREE, - unsafe.Pointer(&nvroot)) != 0 { + if C.nvlist_lookup_nvlist(config, C.sZPOOL_CONFIG_VDEV_TREE, &nvroot) != 0 { err = fmt.Errorf("Failed to fetch %s", C.ZPOOL_CONFIG_VDEV_TREE) return } diff --git a/zpool.h b/zpool.h index 3aaf3c8..b86b9bd 100644 --- a/zpool.h +++ b/zpool.h @@ -5,72 +5,68 @@ #ifndef 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 { zpool_handle_t *zph; void *pnext; }; -typedef struct property_list { - char value[INT_MAX_VALUE]; - char source[ZFS_MAX_DATASET_NAME_LEN]; - int property; - void *pnext; -} property_list_t; +struct vdev_children { + nvlist_t **first; + uint_t count; +}; typedef struct zpool_list zpool_list_t; typedef struct zpool_list* zpool_list_ptr; -typedef struct libzfs_handle* libzfs_handle_ptr; -typedef struct nvlist* nvlist_ptr; -typedef struct property_list *property_list_ptr; +typedef struct vdev_children vdev_children_t; +typedef struct vdev_children* vdev_children_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(); void zprop_source_tostr(char *dst, zprop_source_t source); -zpool_list_t* zpool_list_open(libzfs_handle_t *libzfs, const char *name); -int zpool_list(libzfs_handle_t *libzfs, zpool_list_t **first); +zpool_list_t* zpool_list_open(const char *name); +zpool_list_ptr zpool_list_openall(); 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); -int read_zpool_property(zpool_handle_t *zh, property_list_t *list, int prop); -property_list_t *read_zpool_properties(zpool_handle_t *zh); +property_list_ptr read_zpool_property(zpool_list_ptr pool, int prop); +property_list_t *read_zpool_properties(zpool_list_ptr pool); 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); const char *lasterr(void); -int -add_prop_list(const char *propname, char *propval, nvlist_t **props, - boolean_t poolprop); +// int +// add_prop_list(const char *propname, char *propval, nvlist_t **props, +// boolean_t poolprop); nvlist_t** nvlist_alloc_array(int count); void nvlist_array_set(nvlist_t** a, int i, nvlist_t *item); void nvlist_free_array(nvlist_t **a); 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); +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_POOL_NAME; char *sZPOOL_CONFIG_POOL_STATE; diff --git a/zpool_test.go b/zpool_test.go index c55382c..e257d30 100644 --- a/zpool_test.go +++ b/zpool_test.go @@ -159,7 +159,7 @@ func zpoolTestPoolDestroy(t *testing.T) { return } 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()) return }