Print this page
NEX-7498 Cannot display userquota of 2TB or larger using quota
Reviewed by:  Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>

@@ -21,10 +21,12 @@
 /*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
+/* Copyright 2016 Nexenta Systems, Inc.  All rights reserved. */
+
 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
 /*        All Rights Reserved   */
 
 /*
  * University Copyright- Copyright (c) 1982, 1986, 1988

@@ -65,10 +67,26 @@
 #include <libzfs.h>
 
 int     vflag;
 int     nolocalquota;
 
+/*
+ * struct dqblk is a 32 bit quantity and is common across NFS and UFS.
+ * UFS has a 2TB limit and an uint32_t can hold this value.
+ * NFS translates this to rquota where all members are unit32_t in size.
+ * A private dqblk, dqblk_zfs is defined here.
+ */
+struct dqblk_zfs {
+        uint64_t  dqbz_bhardlimit; /* absolute limit on disk blks alloc */
+        uint64_t  dqbz_bsoftlimit; /* preferred limit on disk blks */
+        uint64_t  dqbz_curblocks;  /* current block count */
+        uint64_t  dqbz_fhardlimit; /* maximum # allocated files + 1 */
+        uint64_t  dqbz_fsoftlimit; /* preferred file limit */
+        uint64_t  dqbz_curfiles;   /* current # allocated files */
+        uint64_t  dqbz_btimelimit; /* time limit for excessive disk use */
+        uint64_t  dqbz_ftimelimit; /* time limit for excessive files */
+};
 extern int      optind;
 extern char     *optarg;
 
 #define QFNAME  "quotas"
 

@@ -81,54 +99,26 @@
 #if     !defined(TEXT_DOMAIN)   /* Should be defined by cc -D */
 #define TEXT_DOMAIN "SYS_TEST"  /* Use this only if it weren't */
 #endif
 
 static void zexit(int);
-static int getzfsquota(char *, char *, struct dqblk *);
+static boolean_t blklimits_is_zero(struct dqblk *, struct dqblk_zfs *);
+static int getzfsquota(char *, char *, struct dqblk_zfs *);
 static int getnfsquota(char *, char *, uid_t, struct dqblk *);
 static void showuid(uid_t);
 static void showquotas(uid_t, char *);
-static void warn(struct mnttab *, struct dqblk *);
+static void warn(struct mnttab *, struct dqblk *, struct dqblk_zfs *);
+static void warn_dqblk_impl(struct mnttab *, struct dqblk *);
+static void warn_dqblk_zfs_impl(struct mnttab *, struct dqblk_zfs *);
 static void heading(uid_t, char *);
-static void prquota(struct mnttab *, struct dqblk *);
+static void prquota(struct mnttab *, struct dqblk *, struct dqblk_zfs *);
+static void prquota_dqblk_impl(struct mnttab *, struct dqblk *);
+static void prquota_dqblk_zfs_impl(struct mnttab *, struct dqblk_zfs *);
 static void fmttime(char *, long);
 
-static libzfs_handle_t *(*_libzfs_init)(void);
-static void (*_libzfs_fini)(libzfs_handle_t *);
-static zfs_handle_t *(*_zfs_open)(libzfs_handle_t *, const char *, int);
-static void (*_zfs_close)(zfs_handle_t *);
-static int (*_zfs_prop_get_userquota_int)(zfs_handle_t *, const char *,
-    uint64_t *);
 static libzfs_handle_t *g_zfs = NULL;
 
-/*
- * Dynamically check for libzfs, in case the user hasn't installed the SUNWzfs
- * packages.  'quota' utility supports zfs as an option.
- */
-static void
-load_libzfs(void)
-{
-        void *hdl;
-
-        if (g_zfs != NULL)
-                return;
-
-        if ((hdl = dlopen("libzfs.so", RTLD_LAZY)) != NULL) {
-                _libzfs_init = (libzfs_handle_t *(*)(void))dlsym(hdl,
-                    "libzfs_init");
-                _libzfs_fini = (void (*)())dlsym(hdl, "libzfs_fini");
-                _zfs_open = (zfs_handle_t *(*)())dlsym(hdl, "zfs_open");
-                _zfs_close = (void (*)())dlsym(hdl, "zfs_close");
-                _zfs_prop_get_userquota_int = (int (*)())
-                    dlsym(hdl, "zfs_prop_get_userquota_int");
-
-                if (_libzfs_init && _libzfs_fini && _zfs_open &&
-                    _zfs_close && _zfs_prop_get_userquota_int)
-                        g_zfs = _libzfs_init();
-        }
-}
-
 int
 main(int argc, char *argv[])
 {
         int     opt;
         int     i;

@@ -151,11 +141,10 @@
                     "file_dac_read privileges\n"));
 
                 exit(1);
         }
 
-        load_libzfs();
 
         while ((opt = getopt(argc, argv, "vV")) != EOF) {
                 switch (opt) {
 
                 case 'v':

@@ -240,10 +229,11 @@
 showquotas(uid_t uid, char *name)
 {
         struct mnttab mnt;
         FILE *mtab;
         struct dqblk dqblk;
+        struct dqblk_zfs dqblkz;
         uid_t myuid;
         struct failed_srv {
                 char *serv_name;
                 struct failed_srv *next;
         };

@@ -263,13 +253,16 @@
 
         if (vflag)
                 heading(uid, name);
         mtab = fopen(MNTTAB, "r");
         while (getmntent(mtab, &mnt) == NULL) {
+                boolean_t is_zfs = B_FALSE;
+
                 if (strcmp(mnt.mnt_fstype, MNTTYPE_ZFS) == 0) {
-                        bzero(&dqblk, sizeof (dqblk));
-                        if (getzfsquota(name, mnt.mnt_special, &dqblk))
+                        is_zfs = B_TRUE;
+                        bzero(&dqblkz, sizeof (dqblkz));
+                        if (getzfsquota(name, mnt.mnt_special, &dqblkz))
                                 continue;
                 } else if (strcmp(mnt.mnt_fstype, MNTTYPE_UFS) == 0) {
                         if (nolocalquota ||
                             (quotactl(Q_GETQUOTA,
                             mnt.mnt_mountp, uid, &dqblk) != 0 &&

@@ -409,17 +402,19 @@
 
                         free_replica(rl, count);
                 } else {
                         continue;
                 }
-                if (dqblk.dqb_bsoftlimit == 0 && dqblk.dqb_bhardlimit == 0 &&
-                    dqblk.dqb_fsoftlimit == 0 && dqblk.dqb_fhardlimit == 0)
+
+                if (blklimits_is_zero(&dqblk, is_zfs ? &dqblkz : NULL))
                         continue;
+
                 if (vflag)
-                        prquota(&mnt, &dqblk);
+                        prquota(&mnt, &dqblk, is_zfs ? &dqblkz : NULL);
                 else
-                        warn(&mnt, &dqblk);
+                        warn(&mnt, &dqblk, is_zfs ? &dqblkz : NULL);
+
         }
 
         /*
          * Free list of failed servers
          */

@@ -433,70 +428,16 @@
 
         fclose(mtab);
 }
 
 static void
-warn(struct mnttab *mntp, struct dqblk *dqp)
+warn(struct mnttab *mntp, struct dqblk *dqp, struct dqblk_zfs *dqzp)
 {
-        struct timeval tv;
-
-        time(&(tv.tv_sec));
-        tv.tv_usec = 0;
-        if (dqp->dqb_bhardlimit &&
-            dqp->dqb_curblocks >= dqp->dqb_bhardlimit) {
-                printf("Block limit reached on %s\n", mntp->mnt_mountp);
-        } else if (dqp->dqb_bsoftlimit &&
-            dqp->dqb_curblocks >= dqp->dqb_bsoftlimit) {
-                if (dqp->dqb_btimelimit == 0) {
-                        printf("Over disk quota on %s, remove %luK\n",
-                            mntp->mnt_mountp,
-                            kb(dqp->dqb_curblocks - dqp->dqb_bsoftlimit + 1));
-                } else if (dqp->dqb_btimelimit > tv.tv_sec) {
-                        char btimeleft[80];
-
-                        fmttime(btimeleft, dqp->dqb_btimelimit - tv.tv_sec);
-                        printf("Over disk quota on %s, remove %luK within %s\n",
-                            mntp->mnt_mountp,
-                            kb(dqp->dqb_curblocks - dqp->dqb_bsoftlimit + 1),
-                            btimeleft);
-                } else {
-                        printf(
-                "Over disk quota on %s, time limit has expired, remove %luK\n",
-                            mntp->mnt_mountp,
-                            kb(dqp->dqb_curblocks - dqp->dqb_bsoftlimit + 1));
-                }
-        }
-        if (dqp->dqb_fhardlimit &&
-            dqp->dqb_curfiles >= dqp->dqb_fhardlimit) {
-                printf("File count limit reached on %s\n", mntp->mnt_mountp);
-        } else if (dqp->dqb_fsoftlimit &&
-            dqp->dqb_curfiles >= dqp->dqb_fsoftlimit) {
-                if (dqp->dqb_ftimelimit == 0) {
-                        printf("Over file quota on %s, remove %lu file%s\n",
-                            mntp->mnt_mountp,
-                            dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1,
-                            ((dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1) > 1 ?
-                            "s" : ""));
-                } else if (dqp->dqb_ftimelimit > tv.tv_sec) {
-                        char ftimeleft[80];
-
-                        fmttime(ftimeleft, dqp->dqb_ftimelimit - tv.tv_sec);
-                        printf(
-"Over file quota on %s, remove %lu file%s within %s\n",
-                            mntp->mnt_mountp,
-                            dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1,
-                            ((dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1) > 1 ?
-                            "s" : ""), ftimeleft);
-                } else {
-                        printf(
-"Over file quota on %s, time limit has expired, remove %lu file%s\n",
-                            mntp->mnt_mountp,
-                            dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1,
-                            ((dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1) > 1 ?
-                            "s" : ""));
-                }
-        }
+        if (dqzp != NULL)
+                warn_dqblk_zfs_impl(mntp, dqzp);
+        else
+                warn_dqblk_impl(mntp, dqp);
 }
 
 static void
 heading(uid_t uid, char *name)
 {

@@ -512,71 +453,16 @@
             "limit",
             "timeleft");
 }
 
 static void
-prquota(struct mnttab *mntp, struct dqblk *dqp)
+prquota(struct mnttab *mntp, struct dqblk *dqp, struct dqblk_zfs *dqzp)
 {
-        struct timeval tv;
-        char ftimeleft[80], btimeleft[80];
-        char *cp;
-
-        time(&(tv.tv_sec));
-        tv.tv_usec = 0;
-        if (dqp->dqb_bsoftlimit && dqp->dqb_curblocks >= dqp->dqb_bsoftlimit) {
-                if (dqp->dqb_btimelimit == 0) {
-                        strlcpy(btimeleft, "NOT STARTED", sizeof (btimeleft));
-                } else if (dqp->dqb_btimelimit > tv.tv_sec) {
-                        fmttime(btimeleft, dqp->dqb_btimelimit - tv.tv_sec);
-                } else {
-                        strlcpy(btimeleft, "EXPIRED", sizeof (btimeleft));
-                }
-        } else {
-                btimeleft[0] = '\0';
-        }
-        if (dqp->dqb_fsoftlimit && dqp->dqb_curfiles >= dqp->dqb_fsoftlimit) {
-                if (dqp->dqb_ftimelimit == 0) {
-                        strlcpy(ftimeleft, "NOT STARTED", sizeof (ftimeleft));
-                } else if (dqp->dqb_ftimelimit > tv.tv_sec) {
-                        fmttime(ftimeleft, dqp->dqb_ftimelimit - tv.tv_sec);
-                } else {
-                        strlcpy(ftimeleft, "EXPIRED", sizeof (ftimeleft));
-                }
-        } else {
-                ftimeleft[0] = '\0';
-        }
-        if (strlen(mntp->mnt_mountp) > 12) {
-                printf("%s\n", mntp->mnt_mountp);
-                cp = "";
-        } else {
-                cp = mntp->mnt_mountp;
-        }
-
-        if (dqp->dqb_curfiles == 0 &&
-            dqp->dqb_fsoftlimit == 0 && dqp->dqb_fhardlimit == 0) {
-                printf("%-12.12s %7d %6d %6d %11s %6s %6s %6s %11s\n",
-                    cp,
-                    kb(dqp->dqb_curblocks),
-                    kb(dqp->dqb_bsoftlimit),
-                    kb(dqp->dqb_bhardlimit),
-                    "-",
-                    "-",
-                    "-",
-                    "-",
-                    "-");
-        } else {
-                printf("%-12.12s %7d %6d %6d %11s %6d %6d %6d %11s\n",
-                    cp,
-                    kb(dqp->dqb_curblocks),
-                    kb(dqp->dqb_bsoftlimit),
-                    kb(dqp->dqb_bhardlimit),
-                    btimeleft,
-                    dqp->dqb_curfiles,
-                    dqp->dqb_fsoftlimit,
-                    dqp->dqb_fhardlimit,
-                    ftimeleft);
-        }
+        if (dqzp != NULL)
+                prquota_dqblk_zfs_impl(mntp, dqzp);
+        else
+                prquota_dqblk_impl(mntp, dqp);
 }
 
 static void
 fmttime(char *buf, long time)
 {

@@ -866,43 +752,320 @@
 
         return ((int)clnt_stat);
 }
 
 static int
-getzfsquota(char *user, char *dataset, struct dqblk *zq)
+getzfsquota(char *user, char *dataset, struct dqblk_zfs *zq)
 {
         zfs_handle_t *zhp = NULL;
         char propname[ZFS_MAXPROPLEN];
         uint64_t userquota, userused;
 
-        if (g_zfs == NULL)
-                return (1);
+        if (g_zfs == NULL) {
+                g_zfs = libzfs_init();
+        }
 
-        if ((zhp = _zfs_open(g_zfs, dataset, ZFS_TYPE_DATASET)) == NULL)
+        if ((zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_DATASET)) == NULL)
                 return (1);
 
         (void) snprintf(propname, sizeof (propname), "userquota@%s", user);
-        if (_zfs_prop_get_userquota_int(zhp, propname, &userquota) != 0) {
-                _zfs_close(zhp);
+        if (zfs_prop_get_userquota_int(zhp, propname, &userquota) != 0) {
+                zfs_close(zhp);
                 return (1);
         }
 
         (void) snprintf(propname, sizeof (propname), "userused@%s", user);
-        if (_zfs_prop_get_userquota_int(zhp, propname, &userused) != 0) {
-                _zfs_close(zhp);
+        if (zfs_prop_get_userquota_int(zhp, propname, &userused) != 0) {
+                zfs_close(zhp);
                 return (1);
         }
 
-        zq->dqb_bhardlimit = userquota / DEV_BSIZE;
-        zq->dqb_bsoftlimit = userquota / DEV_BSIZE;
-        zq->dqb_curblocks = userused / DEV_BSIZE;
-        _zfs_close(zhp);
+        zq->dqbz_bhardlimit = userquota / DEV_BSIZE;
+        zq->dqbz_bsoftlimit = userquota / DEV_BSIZE;
+        zq->dqbz_curblocks = userused / DEV_BSIZE;
+        zfs_close(zhp);
         return (0);
 }
 
+static boolean_t
+blklimits_is_zero(struct dqblk *dqp, struct dqblk_zfs *dqzp)
+{
+        if (dqzp == NULL) {
+                if (dqp->dqb_bsoftlimit == 0 && dqp->dqb_bhardlimit == 0 &&
+                    dqp->dqb_fsoftlimit == 0 && dqp->dqb_fhardlimit == 0) {
+                        return (B_TRUE);
+                } else {
+                        return (B_FALSE);
+                }
+        } else {
+                if (dqzp->dqbz_bsoftlimit == 0 && dqzp->dqbz_bhardlimit == 0 &&
+                    dqzp->dqbz_fsoftlimit == 0 && dqzp->dqbz_fhardlimit == 0) {
+                        return (B_TRUE);
+                } else {
+                        return (B_FALSE);
+                }
+        }
+}
+
 static void
+warn_dqblk_impl(struct mnttab *mntp, struct dqblk *dqp)
+{
+        struct timeval tv;
+
+        time(&(tv.tv_sec));
+        tv.tv_usec = 0;
+        if (dqp->dqb_bhardlimit &&
+            dqp->dqb_curblocks >= dqp->dqb_bhardlimit) {
+                printf("Block limit reached on %s\n", mntp->mnt_mountp);
+        } else if (dqp->dqb_bsoftlimit &&
+            dqp->dqb_curblocks >= dqp->dqb_bsoftlimit) {
+                if (dqp->dqb_btimelimit == 0) {
+                        printf("Over disk quota on %s, remove %luK\n",
+                            mntp->mnt_mountp,
+                            kb(dqp->dqb_curblocks - dqp->dqb_bsoftlimit + 1));
+                } else if (dqp->dqb_btimelimit > tv.tv_sec) {
+                        char btimeleft[80];
+
+                        fmttime(btimeleft, dqp->dqb_btimelimit - tv.tv_sec);
+                        printf("Over disk quota on %s, remove %luK within %s\n",
+                            mntp->mnt_mountp,
+                            kb(dqp->dqb_curblocks - dqp->dqb_bsoftlimit + 1),
+                            btimeleft);
+                } else {
+                        printf("Over disk quota on %s, time limit has expired,"
+                            " remove %luK\n", mntp->mnt_mountp,
+                            kb(dqp->dqb_curblocks - dqp->dqb_bsoftlimit + 1));
+                }
+        }
+        if (dqp->dqb_fhardlimit &&
+            dqp->dqb_curfiles >= dqp->dqb_fhardlimit) {
+                printf("File count limit reached on %s\n", mntp->mnt_mountp);
+        } else if (dqp->dqb_fsoftlimit &&
+            dqp->dqb_curfiles >= dqp->dqb_fsoftlimit) {
+                if (dqp->dqb_ftimelimit == 0) {
+                        printf("Over file quota on %s, remove %lu file%s\n",
+                            mntp->mnt_mountp,
+                            dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1,
+                            ((dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1) > 1 ?
+                            "s" : ""));
+                } else if (dqp->dqb_ftimelimit > tv.tv_sec) {
+                        char ftimeleft[80];
+
+                        fmttime(ftimeleft, dqp->dqb_ftimelimit - tv.tv_sec);
+                        printf("Over file quota on %s, remove %lu file%s"
+                            " within %s\n", mntp->mnt_mountp,
+                            dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1,
+                            ((dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1) > 1 ?
+                            "s" : ""), ftimeleft);
+                } else {
+                        printf("Over file quota on %s, time limit has expired,"
+                            " remove %lu file%s\n", mntp->mnt_mountp,
+                            dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1,
+                            ((dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1) > 1 ?
+                            "s" : ""));
+                }
+        }
+}
+
+static void
+warn_dqblk_zfs_impl(struct mnttab *mntp, struct dqblk_zfs *dqzp)
+{
+        struct timeval tv;
+
+        time(&(tv.tv_sec));
+        tv.tv_usec = 0;
+        if (dqzp->dqbz_bhardlimit &&
+            dqzp->dqbz_curblocks >= dqzp->dqbz_bhardlimit) {
+                printf("Block limit reached on %s\n", mntp->mnt_mountp);
+        } else if (dqzp->dqbz_bsoftlimit &&
+            dqzp->dqbz_curblocks >= dqzp->dqbz_bsoftlimit) {
+                if (dqzp->dqbz_btimelimit == 0) {
+                        printf("Over disk quota on %s, remove %luK\n",
+                            mntp->mnt_mountp,
+                            kb(dqzp->dqbz_curblocks -
+                            dqzp->dqbz_bsoftlimit + 1));
+                } else if (dqzp->dqbz_btimelimit > tv.tv_sec) {
+                        char btimeleft[80];
+
+                        fmttime(btimeleft, dqzp->dqbz_btimelimit - tv.tv_sec);
+                        printf("Over disk quota on %s, remove %luK within %s\n",
+                            mntp->mnt_mountp,
+                            kb(dqzp->dqbz_curblocks -
+                            dqzp->dqbz_bsoftlimit + 1),
+                            btimeleft);
+                } else {
+                        printf("Over disk quota on %s, time limit has expired,"
+                            " remove %luK\n", mntp->mnt_mountp,
+                            kb(dqzp->dqbz_curblocks -
+                            dqzp->dqbz_bsoftlimit + 1));
+                }
+        }
+        if (dqzp->dqbz_fhardlimit &&
+            dqzp->dqbz_curfiles >= dqzp->dqbz_fhardlimit) {
+                printf("File count limit reached on %s\n", mntp->mnt_mountp);
+        } else if (dqzp->dqbz_fsoftlimit &&
+            dqzp->dqbz_curfiles >= dqzp->dqbz_fsoftlimit) {
+                if (dqzp->dqbz_ftimelimit == 0) {
+                        printf("Over file quota on %s, remove %lu file%s\n",
+                            mntp->mnt_mountp,
+                            dqzp->dqbz_curfiles - dqzp->dqbz_fsoftlimit + 1,
+                            ((dqzp->dqbz_curfiles -
+                            dqzp->dqbz_fsoftlimit + 1) > 1 ?
+                            "s" : ""));
+                } else if (dqzp->dqbz_ftimelimit > tv.tv_sec) {
+                        char ftimeleft[80];
+
+                        fmttime(ftimeleft, dqzp->dqbz_ftimelimit - tv.tv_sec);
+                        printf("Over file quota on %s, remove %lu file%s "
+                            " within %s\n", mntp->mnt_mountp,
+                            dqzp->dqbz_curfiles - dqzp->dqbz_fsoftlimit + 1,
+                            ((dqzp->dqbz_curfiles -
+                            dqzp->dqbz_fsoftlimit + 1) > 1 ?
+                            "s" : ""), ftimeleft);
+                } else {
+                        printf("Over file quota on %s, time limit has expired,"
+                            " remove %lu file%s\n", mntp->mnt_mountp,
+                            dqzp->dqbz_curfiles - dqzp->dqbz_fsoftlimit + 1,
+                            ((dqzp->dqbz_curfiles -
+                            dqzp->dqbz_fsoftlimit + 1) > 1 ?
+                            "s" : ""));
+                }
+        }
+}
+
+static void
+prquota_dqblk_impl(struct mnttab *mntp, struct dqblk *dqp)
+{
+        struct timeval tv;
+        char ftimeleft[80], btimeleft[80];
+        char *cp;
+
+        time(&(tv.tv_sec));
+        tv.tv_usec = 0;
+        if (dqp->dqb_bsoftlimit && dqp->dqb_curblocks >= dqp->dqb_bsoftlimit) {
+                if (dqp->dqb_btimelimit == 0) {
+                        strlcpy(btimeleft, "NOT STARTED", sizeof (btimeleft));
+                } else if (dqp->dqb_btimelimit > tv.tv_sec) {
+                        fmttime(btimeleft, dqp->dqb_btimelimit - tv.tv_sec);
+                } else {
+                        strlcpy(btimeleft, "EXPIRED", sizeof (btimeleft));
+                }
+        } else {
+                btimeleft[0] = '\0';
+        }
+        if (dqp->dqb_fsoftlimit && dqp->dqb_curfiles >= dqp->dqb_fsoftlimit) {
+                if (dqp->dqb_ftimelimit == 0) {
+                        strlcpy(ftimeleft, "NOT STARTED", sizeof (ftimeleft));
+                } else if (dqp->dqb_ftimelimit > tv.tv_sec) {
+                        fmttime(ftimeleft, dqp->dqb_ftimelimit - tv.tv_sec);
+                } else {
+                        strlcpy(ftimeleft, "EXPIRED", sizeof (ftimeleft));
+                }
+        } else {
+                ftimeleft[0] = '\0';
+        }
+        if (strlen(mntp->mnt_mountp) > 12) {
+                printf("%s\n", mntp->mnt_mountp);
+                cp = "";
+        } else {
+                cp = mntp->mnt_mountp;
+        }
+
+        if (dqp->dqb_curfiles == 0 &&
+            dqp->dqb_fsoftlimit == 0 && dqp->dqb_fhardlimit == 0) {
+                printf("%-12.12s %7d %6d %6d %11s %6s %6s %6s %11s\n",
+                    cp,
+                    kb(dqp->dqb_curblocks),
+                    kb(dqp->dqb_bsoftlimit),
+                    kb(dqp->dqb_bhardlimit),
+                    "-",
+                    "-",
+                    "-",
+                    "-",
+                    "-");
+        } else {
+                printf("%-12.12s %7d %6d %6d %11s %6d %6d %6d %11s\n",
+                    cp,
+                    kb(dqp->dqb_curblocks),
+                    kb(dqp->dqb_bsoftlimit),
+                    kb(dqp->dqb_bhardlimit),
+                    btimeleft,
+                    dqp->dqb_curfiles,
+                    dqp->dqb_fsoftlimit,
+                    dqp->dqb_fhardlimit,
+                    ftimeleft);
+        }
+}
+
+static void
+prquota_dqblk_zfs_impl(struct mnttab *mntp, struct dqblk_zfs *dqzp)
+{
+        struct timeval tv;
+        char ftimeleft[80], btimeleft[80];
+        char *cp;
+
+        time(&(tv.tv_sec));
+        tv.tv_usec = 0;
+        if (dqzp->dqbz_bsoftlimit &&
+            dqzp->dqbz_curblocks >= dqzp->dqbz_bsoftlimit) {
+                if (dqzp->dqbz_btimelimit == 0) {
+                        strlcpy(btimeleft, "NOT STARTED", sizeof (btimeleft));
+                } else if (dqzp->dqbz_btimelimit > tv.tv_sec) {
+                        fmttime(btimeleft, dqzp->dqbz_btimelimit - tv.tv_sec);
+                } else {
+                        strlcpy(btimeleft, "EXPIRED", sizeof (btimeleft));
+                }
+        } else {
+                btimeleft[0] = '\0';
+        }
+        if (dqzp->dqbz_fsoftlimit &&
+            dqzp->dqbz_curfiles >= dqzp->dqbz_fsoftlimit) {
+                if (dqzp->dqbz_ftimelimit == 0) {
+                        strlcpy(ftimeleft, "NOT STARTED", sizeof (ftimeleft));
+                } else if (dqzp->dqbz_ftimelimit > tv.tv_sec) {
+                        fmttime(ftimeleft, dqzp->dqbz_ftimelimit - tv.tv_sec);
+                } else {
+                        strlcpy(ftimeleft, "EXPIRED", sizeof (ftimeleft));
+                }
+        } else {
+                ftimeleft[0] = '\0';
+        }
+        if (strlen(mntp->mnt_mountp) > 12) {
+                printf("%s\n", mntp->mnt_mountp);
+                cp = "";
+        } else {
+                cp = mntp->mnt_mountp;
+        }
+
+        if (dqzp->dqbz_curfiles == 0 &&
+            dqzp->dqbz_fsoftlimit == 0 && dqzp->dqbz_fhardlimit == 0) {
+                printf("%-12.12s %7llu %6llu %6llu %11s %6s %6s %6s %11s\n",
+                    cp,
+                    kb(dqzp->dqbz_curblocks),
+                    kb(dqzp->dqbz_bsoftlimit),
+                    kb(dqzp->dqbz_bhardlimit),
+                    "-",
+                    "-",
+                    "-",
+                    "-",
+                    "-");
+        } else {
+                printf("%-12.12s %7llu %6llu %6llu %11s %6d %6d %6d %11s\n",
+                    cp,
+                    kb(dqzp->dqbz_curblocks),
+                    kb(dqzp->dqbz_bsoftlimit),
+                    kb(dqzp->dqbz_bhardlimit),
+                    btimeleft,
+                    dqzp->dqbz_curfiles,
+                    dqzp->dqbz_fsoftlimit,
+                    dqzp->dqbz_fhardlimit,
+                    ftimeleft);
+        }
+}
+
+static void
 zexit(int n)
 {
         if (g_zfs != NULL)
-                _libzfs_fini(g_zfs);
+                libzfs_fini(g_zfs);
         exit(n);
 }