]> git.proxmox.com Git - mirror_zfs.git/blobdiff - lib/libzfs/libzfs_dataset.c
Make createtxg and guid properties public
[mirror_zfs.git] / lib / libzfs / libzfs_dataset.c
index 469bdee20f8508fbf442673862eee201d357f61e..f1346b69c6f43316a46ac07328d733982643c900 100644 (file)
@@ -27,7 +27,8 @@
  * Copyright (c) 2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
  * Copyright (c) 2013 Martin Matuska. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2016 Nexenta Systems, Inc.
+ * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
  */
 
 #include <ctype.h>
@@ -80,8 +81,12 @@ zfs_type_to_name(zfs_type_t type)
                return (dgettext(TEXT_DOMAIN, "snapshot"));
        case ZFS_TYPE_VOLUME:
                return (dgettext(TEXT_DOMAIN, "volume"));
+       case ZFS_TYPE_POOL:
+               return (dgettext(TEXT_DOMAIN, "pool"));
+       case ZFS_TYPE_BOOKMARK:
+               return (dgettext(TEXT_DOMAIN, "bookmark"));
        default:
-               break;
+               assert(!"unhandled zfs_type_t");
        }
 
        return (NULL);
@@ -100,7 +105,7 @@ zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type,
        char what;
 
        (void) zfs_prop_get_table();
-       if (dataset_namecheck(path, &why, &what) != 0) {
+       if (entity_namecheck(path, &why, &what) != 0) {
                if (hdl != NULL) {
                        switch (why) {
                        case NAME_ERR_TOOLONG:
@@ -129,9 +134,10 @@ zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type,
                                    "'%c' in name"), what);
                                break;
 
-                       case NAME_ERR_MULTIPLE_AT:
+                       case NAME_ERR_MULTIPLE_DELIMITERS:
                                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
-                                   "multiple '@' delimiters in name"));
+                                   "multiple '@' and/or '#' delimiters in "
+                                   "name"));
                                break;
 
                        case NAME_ERR_NOLETTER:
@@ -148,7 +154,10 @@ zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type,
                                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
                                    "reserved disk name"));
                                break;
+
                        default:
+                               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                                   "(%d) not defined"), why);
                                break;
                        }
                }
@@ -159,7 +168,7 @@ zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type,
        if (!(type & ZFS_TYPE_SNAPSHOT) && strchr(path, '@') != NULL) {
                if (hdl != NULL)
                        zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
-                           "snapshot delimiter '@' in filesystem name"));
+                           "snapshot delimiter '@' is not expected here"));
                return (0);
        }
 
@@ -170,6 +179,20 @@ zfs_validate_name(libzfs_handle_t *hdl, const char *path, int type,
                return (0);
        }
 
+       if (!(type & ZFS_TYPE_BOOKMARK) && strchr(path, '#') != NULL) {
+               if (hdl != NULL)
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "bookmark delimiter '#' is not expected here"));
+               return (0);
+       }
+
+       if (type == ZFS_TYPE_BOOKMARK && strchr(path, '#') == NULL) {
+               if (hdl != NULL)
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                           "missing '#' delimiter in bookmark name"));
+               return (0);
+       }
+
        if (modifying && strchr(path, '%') != NULL) {
                if (hdl != NULL)
                        zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
@@ -610,8 +633,36 @@ make_bookmark_handle(zfs_handle_t *parent, const char *path,
        return (zhp);
 }
 
+struct zfs_open_bookmarks_cb_data {
+       const char *path;
+       zfs_handle_t *zhp;
+};
+
+static int
+zfs_open_bookmarks_cb(zfs_handle_t *zhp, void *data)
+{
+       struct zfs_open_bookmarks_cb_data *dp = data;
+
+       /*
+        * Is it the one we are looking for?
+        */
+       if (strcmp(dp->path, zfs_get_name(zhp)) == 0) {
+               /*
+                * We found it.  Save it and let the caller know we are done.
+                */
+               dp->zhp = zhp;
+               return (EEXIST);
+       }
+
+       /*
+        * Not found.  Close the handle and ask for another one.
+        */
+       zfs_close(zhp);
+       return (0);
+}
+
 /*
- * Opens the given snapshot, filesystem, or volume.   The 'types'
+ * Opens the given snapshot, bookmark, filesystem, or volume.   The 'types'
  * argument is a mask of acceptable types.  The function will print an
  * appropriate error message and return NULL if it can't be opened.
  */
@@ -620,6 +671,7 @@ zfs_open(libzfs_handle_t *hdl, const char *path, int types)
 {
        zfs_handle_t *zhp;
        char errbuf[1024];
+       char *bookp;
 
        (void) snprintf(errbuf, sizeof (errbuf),
            dgettext(TEXT_DOMAIN, "cannot open '%s'"), path);
@@ -627,20 +679,68 @@ zfs_open(libzfs_handle_t *hdl, const char *path, int types)
        /*
         * Validate the name before we even try to open it.
         */
-       if (!zfs_validate_name(hdl, path, ZFS_TYPE_DATASET, B_FALSE)) {
-               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
-                   "invalid dataset name"));
+       if (!zfs_validate_name(hdl, path, types, B_FALSE)) {
                (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf);
                return (NULL);
        }
 
        /*
-        * Try to get stats for the dataset, which will tell us if it exists.
+        * Bookmarks needs to be handled separately.
         */
-       errno = 0;
-       if ((zhp = make_dataset_handle(hdl, path)) == NULL) {
-               (void) zfs_standard_error(hdl, errno, errbuf);
-               return (NULL);
+       bookp = strchr(path, '#');
+       if (bookp == NULL) {
+               /*
+                * Try to get stats for the dataset, which will tell us if it
+                * exists.
+                */
+               errno = 0;
+               if ((zhp = make_dataset_handle(hdl, path)) == NULL) {
+                       (void) zfs_standard_error(hdl, errno, errbuf);
+                       return (NULL);
+               }
+       } else {
+               char dsname[ZFS_MAX_DATASET_NAME_LEN];
+               zfs_handle_t *pzhp;
+               struct zfs_open_bookmarks_cb_data cb_data = {path, NULL};
+
+               /*
+                * We need to cut out '#' and everything after '#'
+                * to get the parent dataset name only.
+                */
+               assert(bookp - path < sizeof (dsname));
+               (void) strncpy(dsname, path, bookp - path);
+               dsname[bookp - path] = '\0';
+
+               /*
+                * Create handle for the parent dataset.
+                */
+               errno = 0;
+               if ((pzhp = make_dataset_handle(hdl, dsname)) == NULL) {
+                       (void) zfs_standard_error(hdl, errno, errbuf);
+                       return (NULL);
+               }
+
+               /*
+                * Iterate bookmarks to find the right one.
+                */
+               errno = 0;
+               if ((zfs_iter_bookmarks(pzhp, zfs_open_bookmarks_cb,
+                   &cb_data) == 0) && (cb_data.zhp == NULL)) {
+                       (void) zfs_error(hdl, EZFS_NOENT, errbuf);
+                       zfs_close(pzhp);
+                       return (NULL);
+               }
+               if (cb_data.zhp == NULL) {
+                       (void) zfs_standard_error(hdl, errno, errbuf);
+                       zfs_close(pzhp);
+                       return (NULL);
+               }
+               zhp = cb_data.zhp;
+
+               /*
+                * Cleanup.
+                */
+               zfs_close(pzhp);
        }
 
        if (!(types & zhp->zfs_type)) {
@@ -735,7 +835,8 @@ libzfs_mnttab_fini(libzfs_handle_t *hdl)
        void *cookie = NULL;
        mnttab_node_t *mtn;
 
-       while ((mtn = avl_destroy_nodes(&hdl->libzfs_mnttab_cache, &cookie))) {
+       while ((mtn = avl_destroy_nodes(&hdl->libzfs_mnttab_cache, &cookie))
+           != NULL) {
                free(mtn->mtn_mt.mnt_special);
                free(mtn->mtn_mt.mnt_mountp);
                free(mtn->mtn_mt.mnt_fstype);
@@ -813,7 +914,8 @@ libzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname)
        mnttab_node_t *ret;
 
        find.mtn_mt.mnt_special = (char *)fsname;
-       if ((ret = avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL))) {
+       if ((ret = avl_find(&hdl->libzfs_mnttab_cache, (void *)&find, NULL))
+           != NULL) {
                avl_remove(&hdl->libzfs_mnttab_cache, ret);
                free(ret->mtn_mt.mnt_special);
                free(ret->mtn_mt.mnt_mountp);
@@ -1071,7 +1173,7 @@ zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
                         */
                        if (intval < SPA_MINBLOCKSIZE ||
                            intval > maxbs || !ISP2(intval)) {
-                               zfs_nicenum(maxbs, buf, sizeof (buf));
+                               zfs_nicebytes(maxbs, buf, sizeof (buf));
                                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
                                    "'%s' must be power of 2 from 512B "
                                    "to %s"), propname, buf);
@@ -1162,7 +1264,12 @@ badlabel:
                                            "component of '%s' is too long"),
                                            propname);
                                        break;
+
                                default:
+                                       zfs_error_aux(hdl,
+                                           dgettext(TEXT_DOMAIN,
+                                           "(%d) not defined"),
+                                           why);
                                        break;
                                }
                                (void) zfs_error(hdl, EZFS_BADPROP, errbuf);
@@ -1282,12 +1389,15 @@ badlabel:
                        }
 
                        break;
+
                case ZFS_PROP_UTF8ONLY:
                        chosen_utf = (int)intval;
                        break;
+
                case ZFS_PROP_NORMALIZE:
                        chosen_normal = (int)intval;
                        break;
+
                default:
                        break;
                }
@@ -1318,7 +1428,7 @@ badlabel:
 
                        case ZFS_PROP_VOLSIZE:
                                if (intval % blocksize != 0) {
-                                       zfs_nicenum(blocksize, buf,
+                                       zfs_nicebytes(blocksize, buf,
                                            sizeof (buf));
                                        zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
                                            "'%s' must be a multiple of "
@@ -1338,6 +1448,7 @@ badlabel:
                                        goto error;
                                }
                                break;
+
                        default:
                                break;
                        }
@@ -1984,6 +2095,7 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src,
                mntopt_on = MNTOPT_NBMAND;
                mntopt_off = MNTOPT_NONBMAND;
                break;
+
        default:
                break;
        }
@@ -2457,7 +2569,7 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
                                (void) snprintf(propbuf, proplen, "%llu",
                                    (u_longlong_t)val);
                        else
-                               zfs_nicenum(val, propbuf, proplen);
+                               zfs_nicebytes(val, propbuf, proplen);
                }
                break;
 
@@ -2583,6 +2695,7 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
                break;
 
        case ZFS_PROP_GUID:
+       case ZFS_PROP_CREATETXG:
                /*
                 * GUIDs are stored as numbers, but they are identifiers.
                 * We don't want them to be pretty printed, because pretty
@@ -2593,6 +2706,22 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
                (void) snprintf(propbuf, proplen, "%llu", (u_longlong_t)val);
                break;
 
+       case ZFS_PROP_REFERENCED:
+       case ZFS_PROP_AVAILABLE:
+       case ZFS_PROP_USED:
+       case ZFS_PROP_USEDSNAP:
+       case ZFS_PROP_USEDDS:
+       case ZFS_PROP_USEDREFRESERV:
+       case ZFS_PROP_USEDCHILD:
+               if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
+                       return (-1);
+               if (literal)
+                       (void) snprintf(propbuf, proplen, "%llu",
+                           (u_longlong_t)val);
+               else
+                       zfs_nicebytes(val, propbuf, proplen);
+               break;
+
        default:
                switch (zfs_prop_get_type(prop)) {
                case PROP_TYPE_NUMBER:
@@ -2889,6 +3018,9 @@ zfs_prop_get_userquota(zfs_handle_t *zhp, const char *propname,
            (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA ||
            type == ZFS_PROP_USEROBJQUOTA || type == ZFS_PROP_GROUPOBJQUOTA)) {
                (void) strlcpy(propbuf, "none", proplen);
+       } else if (type == ZFS_PROP_USERQUOTA || type == ZFS_PROP_GROUPQUOTA ||
+           type == ZFS_PROP_USERUSED || type == ZFS_PROP_GROUPUSED) {
+               zfs_nicebytes(propvalue, propbuf, proplen);
        } else {
                zfs_nicenum(propvalue, propbuf, proplen);
        }
@@ -2945,7 +3077,7 @@ zfs_prop_get_written(zfs_handle_t *zhp, const char *propname,
                (void) snprintf(propbuf, proplen, "%llu",
                    (u_longlong_t)propvalue);
        } else {
-               zfs_nicenum(propvalue, propbuf, proplen);
+               zfs_nicebytes(propvalue, propbuf, proplen);
        }
 
        return (0);
@@ -2960,6 +3092,15 @@ zfs_get_name(const zfs_handle_t *zhp)
        return (zhp->zfs_name);
 }
 
+/*
+ * Returns the name of the parent pool for the given zfs handle.
+ */
+const char *
+zfs_get_pool_name(const zfs_handle_t *zhp)
+{
+       return (zhp->zpool_hdl->zpool_name);
+}
+
 /*
  * Returns the type of the given zfs handle.
  */
@@ -3150,7 +3291,7 @@ create_parents(libzfs_handle_t *hdl, char *target, int prefixlen)
         * up to the prefixlen-long one.
         */
        for (cp = target + prefixlen + 1;
-           (cp = strchr(cp, '/')); *cp = '/', cp++) {
+           (cp = strchr(cp, '/')) != NULL; *cp = '/', cp++) {
 
                *cp = '\0';
 
@@ -3230,6 +3371,7 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
        char errbuf[1024];
        uint64_t zoned;
        enum lzc_dataset_type ost;
+       zpool_handle_t *zpool_handle;
 
        (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
            "cannot create '%s'"), path);
@@ -3269,7 +3411,8 @@ zfs_create(libzfs_handle_t *hdl, const char *path, zfs_type_t type,
        if (p != NULL)
                *p = '\0';
 
-       zpool_handle_t *zpool_handle = zpool_open(hdl, pool_path);
+       if ((zpool_handle = zpool_open(hdl, pool_path)) == NULL)
+               return (-1);
 
        if (props && (props = zfs_valid_proplist(hdl, type, props,
            zoned, NULL, zpool_handle, errbuf)) == 0) {
@@ -3920,7 +4063,7 @@ int
 zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive,
     boolean_t force_unmount)
 {
-       int ret;
+       int ret = 0;
        zfs_cmd_t zc = {"\0"};
        char *delim;
        prop_changelist_t *cl = NULL;