diff --git a/zfs.c b/zfs.c index 047ba48..f079ce6 100644 --- a/zfs.c +++ b/zfs.c @@ -82,6 +82,47 @@ int read_dataset_property(zfs_handle_t *zh, property_list_t *list, int prop) { return r; } +int read_user_property(zfs_handle_t *zh, property_list_t *list, const char *prop) { + nvlist_t *user_props = zfs_get_user_props(zh); + nvlist_t *propval; + zprop_source_t sourcetype; + char *strval; + char *sourceval; + // char source[ZFS_MAX_DATASET_NAME_LEN]; + + if (nvlist_lookup_nvlist(user_props, + prop, &propval) != 0) { + sourcetype = ZPROP_SRC_NONE; + (void) strncpy(list->source, + "none", sizeof (list->source)); + strval = "-"; + } else { + verify(nvlist_lookup_string(propval, + ZPROP_VALUE, &strval) == 0); + verify(nvlist_lookup_string(propval, + ZPROP_SOURCE, &sourceval) == 0); + + if (strcmp(sourceval, + zfs_get_name(zh)) == 0) { + sourcetype = ZPROP_SRC_LOCAL; + (void) strncpy(list->source, + "local", sizeof (list->source)); + } else if (strcmp(sourceval, + ZPROP_SOURCE_VAL_RECVD) == 0) { + sourcetype = ZPROP_SRC_RECEIVED; + (void) strncpy(list->source, + "received", sizeof (list->source)); + } else { + sourcetype = ZPROP_SRC_INHERITED; + (void) strncpy(list->source, + sourceval, sizeof (list->source)); + } + } + (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; diff --git a/zfs.go b/zfs.go index 82dc968..e5a94b4 100644 --- a/zfs.go +++ b/zfs.go @@ -278,6 +278,26 @@ func (d *Dataset) GetProperty(p Prop) (prop Property, err error) { return } +func (d *Dataset) GetUserProperty(p string) (prop Property, err error) { + if d.list == nil { + err = errors.New(msgDatasetIsNil) + return + } + var plist *C.property_list_t + 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 { + err = LastError() + return + } + prop = Property{Value: C.GoString(&(*plist).value[0]), + Source: C.GoString(&(*plist).source[0])} + return +} + // SetProperty set ZFS dataset property to value. Not all properties can be set, // some can be set only at creation time and some are read only. // Always check if returned error and its description. @@ -300,6 +320,22 @@ func (d *Dataset) SetProperty(p Prop, value string) (err error) { return } +func (d *Dataset) SetUserProperty(prop, value string) (err error) { + if d.list == nil { + err = errors.New(msgDatasetIsNil) + return + } + csValue := C.CString(value) + csProp := C.CString(prop) + errcode := C.zfs_prop_set(d.list.zh, csProp, csValue) + C.free(unsafe.Pointer(csValue)) + C.free(unsafe.Pointer(csProp)) + if errcode != 0 { + err = LastError() + } + return +} + // Clone - clones the dataset. The target must be of the same type as // the source. func (d *Dataset) Clone(target string, props map[Prop]Property) (rd Dataset, err error) { diff --git a/zfs.h b/zfs.h index 40a4cd5..6497961 100644 --- a/zfs.h +++ b/zfs.h @@ -21,6 +21,7 @@ int dataset_list_children(zfs_handle_t *zfs, dataset_list_t **first); dataset_list_t *dataset_next(dataset_list_t *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); int clear_last_error(libzfs_handle_t *libzfs); diff --git a/zfs_test.go b/zfs_test.go index a0d4412..7a64992 100644 --- a/zfs_test.go +++ b/zfs_test.go @@ -74,7 +74,22 @@ func zfsTestDatasetOpen(t *testing.T) { t.Error(err) return } - d.Close() + defer d.Close() + print("PASS\n\n") + + println("TEST Set/GetUserProperty(prop, value string) ... ") + var p zfs.Property + // Test set/get user property + if err = d.SetUserProperty("go-libzfs:test", "yes"); err != nil { + t.Error(err) + return + } + if p, err = d.GetUserProperty("go-libzfs:test"); err != nil { + t.Error(err) + return + } + println("go-libzfs:test", " = ", + p.Value) print("PASS\n\n") } diff --git a/zpool.h b/zpool.h index c45e5b7..7fbb190 100644 --- a/zpool.h +++ b/zpool.h @@ -7,6 +7,8 @@ #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; @@ -15,7 +17,7 @@ struct zpool_list { typedef struct property_list { char value[INT_MAX_VALUE]; - char source[INT_MAX_NAME]; + char source[ZFS_MAX_DATASET_NAME_LEN]; int property; void *pnext; } property_list_t;