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,30 ****
--- 21,32 ----
  /*
   * 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,74 ****
--- 67,92 ----
  #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,134 ****
  #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 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 heading(uid_t, char *);
! static void prquota(struct mnttab *, struct dqblk *);
  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;
--- 99,124 ----
  #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 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 *, 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 *, 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 *g_zfs = NULL;
  
  int
  main(int argc, char *argv[])
  {
          int     opt;
          int     i;
*** 151,161 ****
                      "file_dac_read privileges\n"));
  
                  exit(1);
          }
  
-         load_libzfs();
  
          while ((opt = getopt(argc, argv, "vV")) != EOF) {
                  switch (opt) {
  
                  case 'v':
--- 141,150 ----
*** 240,249 ****
--- 229,239 ----
  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,275 ****
  
          if (vflag)
                  heading(uid, name);
          mtab = fopen(MNTTAB, "r");
          while (getmntent(mtab, &mnt) == NULL) {
                  if (strcmp(mnt.mnt_fstype, MNTTYPE_ZFS) == 0) {
!                         bzero(&dqblk, sizeof (dqblk));
!                         if (getzfsquota(name, mnt.mnt_special, &dqblk))
                                  continue;
                  } else if (strcmp(mnt.mnt_fstype, MNTTYPE_UFS) == 0) {
                          if (nolocalquota ||
                              (quotactl(Q_GETQUOTA,
                              mnt.mnt_mountp, uid, &dqblk) != 0 &&
--- 253,268 ----
  
          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) {
!                         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,425 ****
  
                          free_replica(rl, count);
                  } else {
                          continue;
                  }
!                 if (dqblk.dqb_bsoftlimit == 0 && dqblk.dqb_bhardlimit == 0 &&
!                     dqblk.dqb_fsoftlimit == 0 && dqblk.dqb_fhardlimit == 0)
                          continue;
                  if (vflag)
!                         prquota(&mnt, &dqblk);
                  else
!                         warn(&mnt, &dqblk);
          }
  
          /*
           * Free list of failed servers
           */
--- 402,420 ----
  
                          free_replica(rl, count);
                  } else {
                          continue;
                  }
! 
!                 if (blklimits_is_zero(&dqblk, is_zfs ? &dqblkz : NULL))
                          continue;
+ 
                  if (vflag)
!                         prquota(&mnt, &dqblk, is_zfs ? &dqblkz : NULL);
                  else
!                         warn(&mnt, &dqblk, is_zfs ? &dqblkz : NULL);
! 
          }
  
          /*
           * Free list of failed servers
           */
*** 433,502 ****
  
          fclose(mtab);
  }
  
  static void
! warn(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
  heading(uid_t uid, char *name)
  {
--- 428,443 ----
  
          fclose(mtab);
  }
  
  static void
! warn(struct mnttab *mntp, struct dqblk *dqp, struct dqblk_zfs *dqzp)
  {
!         if (dqzp != NULL)
!                 warn_dqblk_zfs_impl(mntp, dqzp);
!         else
!                 warn_dqblk_impl(mntp, dqp);
  }
  
  static void
  heading(uid_t uid, char *name)
  {
*** 512,582 ****
              "limit",
              "timeleft");
  }
  
  static void
! prquota(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
  fmttime(char *buf, long time)
  {
--- 453,468 ----
              "limit",
              "timeleft");
  }
  
  static void
! prquota(struct mnttab *mntp, struct dqblk *dqp, struct dqblk_zfs *dqzp)
  {
!         if (dqzp != NULL)
!                 prquota_dqblk_zfs_impl(mntp, dqzp);
!         else
!                 prquota_dqblk_impl(mntp, dqp);
  }
  
  static void
  fmttime(char *buf, long time)
  {
*** 866,908 ****
  
          return ((int)clnt_stat);
  }
  
  static int
! getzfsquota(char *user, char *dataset, struct dqblk *zq)
  {
          zfs_handle_t *zhp = NULL;
          char propname[ZFS_MAXPROPLEN];
          uint64_t userquota, userused;
  
!         if (g_zfs == NULL)
!                 return (1);
  
!         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);
                  return (1);
          }
  
          (void) snprintf(propname, sizeof (propname), "userused@%s", user);
!         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);
          return (0);
  }
  
  static void
  zexit(int n)
  {
          if (g_zfs != NULL)
!                 _libzfs_fini(g_zfs);
          exit(n);
  }
--- 752,1071 ----
  
          return ((int)clnt_stat);
  }
  
  static int
! 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) {
!                 g_zfs = libzfs_init();
!         }
  
!         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);
                  return (1);
          }
  
          (void) snprintf(propname, sizeof (propname), "userused@%s", user);
!         if (zfs_prop_get_userquota_int(zhp, propname, &userused) != 0) {
!                 zfs_close(zhp);
                  return (1);
          }
  
!         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);
          exit(n);
  }