- Fix issue not building on go 1.8 , and some more improvements
This commit is contained in:
		
							parent
							
								
									fa91900915
								
							
						
					
					
						commit
						8fd0833477
					
				| 
						 | 
				
			
			@ -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);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								common.go
								
								
								
								
							
							
						
						
									
										13
									
								
								common.go
								
								
								
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										137
									
								
								zfs.c
								
								
								
								
							
							
						
						
									
										137
									
								
								zfs.c
								
								
								
								
							| 
						 | 
				
			
			@ -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_type(dataset_list_ptr dataset) {
 | 
			
		||||
	return zfs_get_type(dataset->zh);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dataset_list_children(zfs_handle_t *zfs, dataset_list_t **first) {
 | 
			
		||||
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(zfs, dataset_list_callb, &zlist);
 | 
			
		||||
	if ( zlist->zh ) {
 | 
			
		||||
		*first = zlist;
 | 
			
		||||
	} else {
 | 
			
		||||
		*first = 0;
 | 
			
		||||
	err = zfs_iter_children(dataset->zh, dataset_list_callb, &zlist);
 | 
			
		||||
	if ( err != 0  || zlist->zh == NULL) {
 | 
			
		||||
		dataset_list_free(zlist);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	return err;
 | 
			
		||||
	return zlist;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int read_dataset_property(zfs_handle_t *zh, property_list_t *list, int prop) {
 | 
			
		||||
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;
 | 
			
		||||
	return r;
 | 
			
		||||
	} else {
 | 
			
		||||
		free_properties(list);
 | 
			
		||||
		list = NULL;
 | 
			
		||||
	}
 | 
			
		||||
	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
								
								
								
								
							
							
						
						
									
										119
									
								
								zfs.go
								
								
								
								
							| 
						 | 
				
			
			@ -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,14 +153,14 @@ 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 DatasetOpen(path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close close dataset and all its recursive children datasets (close handle
 | 
			
		||||
// and cleanup dataset object/s from memory)
 | 
			
		||||
| 
						 | 
				
			
			@ -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
								
								
								
								
							
							
						
						
									
										26
									
								
								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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										445
									
								
								zpool.c
								
								
								
								
							
							
						
						
									
										445
									
								
								zpool.c
								
								
								
								
							| 
						 | 
				
			
			@ -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);
 | 
			
		||||
	newitem = read_zpool_property(pool, prop);
 | 
			
		||||
	if (newitem == NULL) {
 | 
			
		||||
		return proot;
 | 
			
		||||
	}
 | 
			
		||||
	// 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;
 | 
			
		||||
	}
 | 
			
		||||
	return r;
 | 
			
		||||
	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;
 | 
			
		||||
	}
 | 
			
		||||
	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);
 | 
			
		||||
	
 | 
			
		||||
	r = read_append_zpool_property(zh, &root, ZPOOL_PROP_SIZE);
 | 
			
		||||
	if (r != 0) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = read_append_zpool_property(zh, &root, ZPOOL_PROP_CAPACITY);
 | 
			
		||||
	if (r != 0) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = read_append_zpool_property(zh, &root, ZPOOL_PROP_ALTROOT);
 | 
			
		||||
	if (r != 0) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = read_append_zpool_property(zh, &root, ZPOOL_PROP_HEALTH);
 | 
			
		||||
	if (r != 0) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = read_append_zpool_property(zh, &root, ZPOOL_PROP_GUID);
 | 
			
		||||
	if (r != 0) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = read_append_zpool_property(zh, &root, ZPOOL_PROP_VERSION);
 | 
			
		||||
	if (r != 0) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = read_append_zpool_property(zh, &root, ZPOOL_PROP_BOOTFS);
 | 
			
		||||
	if (r != 0) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = read_append_zpool_property(zh, &root, ZPOOL_PROP_DELEGATION);
 | 
			
		||||
	if (r != 0) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = read_append_zpool_property(zh, &root, ZPOOL_PROP_AUTOREPLACE);
 | 
			
		||||
	if (r != 0) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	r = read_append_zpool_property(zh, &root, ZPOOL_PROP_CACHEFILE);
 | 
			
		||||
	if (r != 0) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	r = read_append_zpool_property(zh, &root, ZPOOL_PROP_FAILUREMODE);
 | 
			
		||||
	if (r != 0) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	r = read_append_zpool_property(zh, &root, ZPOOL_PROP_LISTSNAPS);
 | 
			
		||||
	if (r != 0) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	r = read_append_zpool_property(zh, &root, ZPOOL_PROP_AUTOEXPAND);
 | 
			
		||||
	if (r != 0) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	r = read_append_zpool_property(zh, &root, ZPOOL_PROP_DEDUPDITTO);
 | 
			
		||||
	if (r != 0) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = read_append_zpool_property(zh, &root, ZPOOL_PROP_DEDUPRATIO);
 | 
			
		||||
	if (r != 0) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = read_append_zpool_property(zh, &root, ZPOOL_PROP_FREE);
 | 
			
		||||
	if (r != 0) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = read_append_zpool_property(zh, &root, ZPOOL_PROP_ALLOCATED);
 | 
			
		||||
	if (r != 0) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = read_append_zpool_property(zh, &root, ZPOOL_PROP_READONLY);
 | 
			
		||||
	if (r != 0) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = read_append_zpool_property(zh, &root, ZPOOL_PROP_ASHIFT);
 | 
			
		||||
	if (r != 0) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = read_append_zpool_property(zh, &root, ZPOOL_PROP_COMMENT);
 | 
			
		||||
	if (r != 0) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = read_append_zpool_property(zh, &root, ZPOOL_PROP_EXPANDSZ);
 | 
			
		||||
	if (r != 0) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = read_append_zpool_property(zh, &root, ZPOOL_PROP_FREEING);
 | 
			
		||||
	if (r != 0) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	list = new_property_list();
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * 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"));
 | 
			
		||||
// 		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);
 | 
			
		||||
// 		// }
 | 
			
		||||
 | 
			
		||||
		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 (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_add_string(proplist, normnm, propval) != 0) {
 | 
			
		||||
		(void) snprintf(_lasterr_, 1024, "internal "
 | 
			
		||||
		    "error: out of memory\n");
 | 
			
		||||
		return (1);
 | 
			
		||||
	}
 | 
			
		||||
// 	if (nvlist_lookup_string(proplist, normnm, &strval) == 0 &&
 | 
			
		||||
// 	    prop != ZPOOL_PROP_CACHEFILE) {
 | 
			
		||||
// 		(void) snprintf(_lasterr_, 1024, "property '%s' "
 | 
			
		||||
// 		    "specified multiple times", propname);
 | 
			
		||||
// 		return (2);
 | 
			
		||||
// 	}
 | 
			
		||||
 | 
			
		||||
	return (0);
 | 
			
		||||
}
 | 
			
		||||
// 	if (nvlist_add_string(proplist, normnm, propval) != 0) {
 | 
			
		||||
// 		(void) snprintf(_lasterr_, 1024, "internal "
 | 
			
		||||
// 		    "error: out of memory\n");
 | 
			
		||||
// 		return (1);
 | 
			
		||||
// 	}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										148
									
								
								zpool.go
								
								
								
								
							
							
						
						
									
										148
									
								
								zpool.go
								
								
								
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
	}
 | 
			
		||||
	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
 | 
			
		||||
	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)
 | 
			
		||||
	}
 | 
			
		||||
	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,9 +554,11 @@ 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() {
 | 
			
		||||
	if pool.list != nil {
 | 
			
		||||
		C.zpool_list_close(pool.list)
 | 
			
		||||
		pool.list = nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Name get (re-read) ZFS pool name property
 | 
			
		||||
func (pool *Pool) Name() (name string, err error) {
 | 
			
		||||
| 
						 | 
				
			
			@ -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
								
								
								
								
							
							
						
						
									
										64
									
								
								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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue