- 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 <libzfs.h>
#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
}

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 <stdio.h>
#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) {

119
zfs.go
View File

@ -2,6 +2,7 @@ package zfs
// #include <stdlib.h>
// #include <libzfs.h>
// #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

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_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);

451
zpool.c
View File

@ -7,6 +7,7 @@
#include <string.h>
#include <stdio.h>
#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, &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 <libzfs.h>
// #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,
&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
}
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
}

64
zpool.h
View File

@ -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;

View File

@ -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
}