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>


   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 


  26 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  27 /*        All Rights Reserved   */
  28 
  29 /*
  30  * University Copyright- Copyright (c) 1982, 1986, 1988
  31  * The Regents of the University of California
  32  * All Rights Reserved
  33  *
  34  * University Acknowledgment- Portions of this document are derived from
  35  * software developed by the University of California, Berkeley, and its
  36  * contributors.
  37  */
  38 
  39 /*
  40  * Disk quota reporting program.
  41  */
  42 #include <stdio.h>
  43 #include <sys/mnttab.h>
  44 #include <ctype.h>
  45 #include <pwd.h>


  50 #include <sys/param.h>
  51 #include <sys/types.h>
  52 #include <sys/sysmacros.h>
  53 #include <sys/mntent.h>
  54 #include <sys/file.h>
  55 #include <sys/stat.h>
  56 #include <sys/fs/ufs_quota.h>
  57 #include <priv_utils.h>
  58 #include <locale.h>
  59 #include <rpc/rpc.h>
  60 #include <netdb.h>
  61 #include <rpcsvc/rquota.h>
  62 #include <zone.h>
  63 #include "../../nfs/lib/replica.h"
  64 #include <dlfcn.h>
  65 #include <libzfs.h>
  66 
  67 int     vflag;
  68 int     nolocalquota;
  69 
















  70 extern int      optind;
  71 extern char     *optarg;
  72 
  73 #define QFNAME  "quotas"
  74 
  75 #if DEV_BSIZE < 1024
  76 #define kb(x)   ((x) / (1024 / DEV_BSIZE))
  77 #else
  78 #define kb(x)   ((x) * (DEV_BSIZE / 1024))
  79 #endif
  80 
  81 #if     !defined(TEXT_DOMAIN)   /* Should be defined by cc -D */
  82 #define TEXT_DOMAIN "SYS_TEST"  /* Use this only if it weren't */
  83 #endif
  84 
  85 static void zexit(int);
  86 static int getzfsquota(char *, char *, struct dqblk *);

  87 static int getnfsquota(char *, char *, uid_t, struct dqblk *);
  88 static void showuid(uid_t);
  89 static void showquotas(uid_t, char *);
  90 static void warn(struct mnttab *, struct dqblk *);


  91 static void heading(uid_t, char *);
  92 static void prquota(struct mnttab *, struct dqblk *);


  93 static void fmttime(char *, long);
  94 
  95 static libzfs_handle_t *(*_libzfs_init)(void);
  96 static void (*_libzfs_fini)(libzfs_handle_t *);
  97 static zfs_handle_t *(*_zfs_open)(libzfs_handle_t *, const char *, int);
  98 static void (*_zfs_close)(zfs_handle_t *);
  99 static int (*_zfs_prop_get_userquota_int)(zfs_handle_t *, const char *,
 100     uint64_t *);
 101 static libzfs_handle_t *g_zfs = NULL;
 102 
 103 /*
 104  * Dynamically check for libzfs, in case the user hasn't installed the SUNWzfs
 105  * packages.  'quota' utility supports zfs as an option.
 106  */
 107 static void
 108 load_libzfs(void)
 109 {
 110         void *hdl;
 111 
 112         if (g_zfs != NULL)
 113                 return;
 114 
 115         if ((hdl = dlopen("libzfs.so", RTLD_LAZY)) != NULL) {
 116                 _libzfs_init = (libzfs_handle_t *(*)(void))dlsym(hdl,
 117                     "libzfs_init");
 118                 _libzfs_fini = (void (*)())dlsym(hdl, "libzfs_fini");
 119                 _zfs_open = (zfs_handle_t *(*)())dlsym(hdl, "zfs_open");
 120                 _zfs_close = (void (*)())dlsym(hdl, "zfs_close");
 121                 _zfs_prop_get_userquota_int = (int (*)())
 122                     dlsym(hdl, "zfs_prop_get_userquota_int");
 123 
 124                 if (_libzfs_init && _libzfs_fini && _zfs_open &&
 125                     _zfs_close && _zfs_prop_get_userquota_int)
 126                         g_zfs = _libzfs_init();
 127         }
 128 }
 129 
 130 int
 131 main(int argc, char *argv[])
 132 {
 133         int     opt;
 134         int     i;
 135         int     status = 0;
 136 
 137         (void) setlocale(LC_ALL, "");
 138         (void) textdomain(TEXT_DOMAIN);
 139 
 140         /*
 141          * PRIV_FILE_DAC_READ is needed to read the QFNAME file
 142          * Clear all other privleges from the limit set, and add
 143          * the required privilege to the bracketed set.
 144          */
 145 
 146         if (__init_suid_priv(PU_CLEARLIMITSET, PRIV_FILE_DAC_READ,
 147             NULL) == -1) {
 148                 (void) fprintf(stderr,
 149                     gettext("Insufficient privileges, "
 150                     "quota must be set-uid root or have "
 151                     "file_dac_read privileges\n"));
 152 
 153                 exit(1);
 154         }
 155 
 156         load_libzfs();
 157 
 158         while ((opt = getopt(argc, argv, "vV")) != EOF) {
 159                 switch (opt) {
 160 
 161                 case 'v':
 162                         vflag++;
 163                         break;
 164 
 165                 case 'V':               /* Print command line */
 166                         {
 167                         char    *opt_text;
 168                         int     opt_count;
 169 
 170                         (void) fprintf(stdout, "quota -F UFS ");
 171                         for (opt_count = 1; opt_count < argc; opt_count++) {
 172                                 opt_text = argv[opt_count];
 173                                 if (opt_text)
 174                                         (void) fprintf(stdout, " %s ",
 175                                             opt_text);
 176                         }


 225 
 226         if (pwd == NULL) {
 227                 fprintf(stderr, "quota: %s: unknown user\n", name);
 228                 return (32);
 229         }
 230         if (pwd->pw_uid == 0) {
 231                 if (vflag)
 232                         printf("no disk quota for %s (uid 0)\n", name);
 233                 return (0);
 234         }
 235         showquotas(pwd->pw_uid, name);
 236         return (0);
 237 }
 238 
 239 static void
 240 showquotas(uid_t uid, char *name)
 241 {
 242         struct mnttab mnt;
 243         FILE *mtab;
 244         struct dqblk dqblk;

 245         uid_t myuid;
 246         struct failed_srv {
 247                 char *serv_name;
 248                 struct failed_srv *next;
 249         };
 250         struct failed_srv *failed_srv_list = NULL;
 251         int     rc;
 252         char    my_zonename[ZONENAME_MAX];
 253         zoneid_t my_zoneid = getzoneid();
 254 
 255         myuid = getuid();
 256         if (uid != myuid && myuid != 0) {
 257                 printf("quota: %s (uid %d): permission denied\n", name, uid);
 258                 zexit(32);
 259         }
 260 
 261         memset(my_zonename, '\0', ZONENAME_MAX);
 262         getzonenamebyid(my_zoneid, my_zonename, ZONENAME_MAX);
 263 
 264         if (vflag)
 265                 heading(uid, name);
 266         mtab = fopen(MNTTAB, "r");
 267         while (getmntent(mtab, &mnt) == NULL) {


 268                 if (strcmp(mnt.mnt_fstype, MNTTYPE_ZFS) == 0) {
 269                         bzero(&dqblk, sizeof (dqblk));
 270                         if (getzfsquota(name, mnt.mnt_special, &dqblk))

 271                                 continue;
 272                 } else if (strcmp(mnt.mnt_fstype, MNTTYPE_UFS) == 0) {
 273                         if (nolocalquota ||
 274                             (quotactl(Q_GETQUOTA,
 275                             mnt.mnt_mountp, uid, &dqblk) != 0 &&
 276                             !(vflag && getdiskquota(&mnt, uid, &dqblk))))
 277                                 continue;
 278                 } else if (strcmp(mnt.mnt_fstype, MNTTYPE_NFS) == 0) {
 279 
 280                         struct replica *rl;
 281                         int count;
 282                         char *mntopt = NULL;
 283 
 284                         /*
 285                          * Skip checking quotas for file systems mounted
 286                          * in other zones. Zone names will be passed in
 287                          * following format from hasmntopt():
 288                          * "zone=<zone-name>,<mnt options...>"
 289                          */
 290                         if ((mntopt = hasmntopt(&mnt, MNTOPT_ZONE)) &&


 394                                         tmp_srv = (struct failed_srv *)malloc(
 395                                             sizeof (struct failed_srv));
 396                                         tmp_srv->serv_name = (char *)malloc(
 397                                             len * sizeof (char) + 1);
 398                                         strncpy(tmp_srv->serv_name, rl[0].host,
 399                                             len);
 400                                         tmp_srv->serv_name[len] = '\0';
 401 
 402                                         tmp_srv->next = failed_srv_list;
 403                                         failed_srv_list = tmp_srv;
 404                                 }
 405 
 406                                 free_replica(rl, count);
 407                                 continue;
 408                         }
 409 
 410                         free_replica(rl, count);
 411                 } else {
 412                         continue;
 413                 }
 414                 if (dqblk.dqb_bsoftlimit == 0 && dqblk.dqb_bhardlimit == 0 &&
 415                     dqblk.dqb_fsoftlimit == 0 && dqblk.dqb_fhardlimit == 0)
 416                         continue;

 417                 if (vflag)
 418                         prquota(&mnt, &dqblk);
 419                 else
 420                         warn(&mnt, &dqblk);

 421         }
 422 
 423         /*
 424          * Free list of failed servers
 425          */
 426         while (failed_srv_list != NULL) {
 427                 struct failed_srv *tmp_srv = failed_srv_list;
 428 
 429                 failed_srv_list = failed_srv_list->next;
 430                 free(tmp_srv->serv_name);
 431                 free(tmp_srv);
 432         }
 433 
 434         fclose(mtab);
 435 }
 436 
 437 static void
 438 warn(struct mnttab *mntp, struct dqblk *dqp)
 439 {
 440         struct timeval tv;
 441 
 442         time(&(tv.tv_sec));
 443         tv.tv_usec = 0;
 444         if (dqp->dqb_bhardlimit &&
 445             dqp->dqb_curblocks >= dqp->dqb_bhardlimit) {
 446                 printf("Block limit reached on %s\n", mntp->mnt_mountp);
 447         } else if (dqp->dqb_bsoftlimit &&
 448             dqp->dqb_curblocks >= dqp->dqb_bsoftlimit) {
 449                 if (dqp->dqb_btimelimit == 0) {
 450                         printf("Over disk quota on %s, remove %luK\n",
 451                             mntp->mnt_mountp,
 452                             kb(dqp->dqb_curblocks - dqp->dqb_bsoftlimit + 1));
 453                 } else if (dqp->dqb_btimelimit > tv.tv_sec) {
 454                         char btimeleft[80];
 455 
 456                         fmttime(btimeleft, dqp->dqb_btimelimit - tv.tv_sec);
 457                         printf("Over disk quota on %s, remove %luK within %s\n",
 458                             mntp->mnt_mountp,
 459                             kb(dqp->dqb_curblocks - dqp->dqb_bsoftlimit + 1),
 460                             btimeleft);
 461                 } else {
 462                         printf(
 463                 "Over disk quota on %s, time limit has expired, remove %luK\n",
 464                             mntp->mnt_mountp,
 465                             kb(dqp->dqb_curblocks - dqp->dqb_bsoftlimit + 1));
 466                 }
 467         }
 468         if (dqp->dqb_fhardlimit &&
 469             dqp->dqb_curfiles >= dqp->dqb_fhardlimit) {
 470                 printf("File count limit reached on %s\n", mntp->mnt_mountp);
 471         } else if (dqp->dqb_fsoftlimit &&
 472             dqp->dqb_curfiles >= dqp->dqb_fsoftlimit) {
 473                 if (dqp->dqb_ftimelimit == 0) {
 474                         printf("Over file quota on %s, remove %lu file%s\n",
 475                             mntp->mnt_mountp,
 476                             dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1,
 477                             ((dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1) > 1 ?
 478                             "s" : ""));
 479                 } else if (dqp->dqb_ftimelimit > tv.tv_sec) {
 480                         char ftimeleft[80];
 481 
 482                         fmttime(ftimeleft, dqp->dqb_ftimelimit - tv.tv_sec);
 483                         printf(
 484 "Over file quota on %s, remove %lu file%s within %s\n",
 485                             mntp->mnt_mountp,
 486                             dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1,
 487                             ((dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1) > 1 ?
 488                             "s" : ""), ftimeleft);
 489                 } else {
 490                         printf(
 491 "Over file quota on %s, time limit has expired, remove %lu file%s\n",
 492                             mntp->mnt_mountp,
 493                             dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1,
 494                             ((dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1) > 1 ?
 495                             "s" : ""));
 496                 }
 497         }
 498 }
 499 
 500 static void
 501 heading(uid_t uid, char *name)
 502 {
 503         printf("Disk quotas for %s (uid %ld):\n", name, (long)uid);
 504         printf("%-12s %7s%7s%7s%12s%7s%7s%7s%12s\n",
 505             "Filesystem",
 506             "usage",
 507             "quota",
 508             "limit",
 509             "timeleft",
 510             "files",
 511             "quota",
 512             "limit",
 513             "timeleft");
 514 }
 515 
 516 static void
 517 prquota(struct mnttab *mntp, struct dqblk *dqp)
 518 {
 519         struct timeval tv;
 520         char ftimeleft[80], btimeleft[80];
 521         char *cp;
 522 
 523         time(&(tv.tv_sec));
 524         tv.tv_usec = 0;
 525         if (dqp->dqb_bsoftlimit && dqp->dqb_curblocks >= dqp->dqb_bsoftlimit) {
 526                 if (dqp->dqb_btimelimit == 0) {
 527                         strlcpy(btimeleft, "NOT STARTED", sizeof (btimeleft));
 528                 } else if (dqp->dqb_btimelimit > tv.tv_sec) {
 529                         fmttime(btimeleft, dqp->dqb_btimelimit - tv.tv_sec);
 530                 } else {
 531                         strlcpy(btimeleft, "EXPIRED", sizeof (btimeleft));
 532                 }
 533         } else {
 534                 btimeleft[0] = '\0';
 535         }
 536         if (dqp->dqb_fsoftlimit && dqp->dqb_curfiles >= dqp->dqb_fsoftlimit) {
 537                 if (dqp->dqb_ftimelimit == 0) {
 538                         strlcpy(ftimeleft, "NOT STARTED", sizeof (ftimeleft));
 539                 } else if (dqp->dqb_ftimelimit > tv.tv_sec) {
 540                         fmttime(ftimeleft, dqp->dqb_ftimelimit - tv.tv_sec);
 541                 } else {
 542                         strlcpy(ftimeleft, "EXPIRED", sizeof (ftimeleft));
 543                 }
 544         } else {
 545                 ftimeleft[0] = '\0';
 546         }
 547         if (strlen(mntp->mnt_mountp) > 12) {
 548                 printf("%s\n", mntp->mnt_mountp);
 549                 cp = "";
 550         } else {
 551                 cp = mntp->mnt_mountp;
 552         }
 553 
 554         if (dqp->dqb_curfiles == 0 &&
 555             dqp->dqb_fsoftlimit == 0 && dqp->dqb_fhardlimit == 0) {
 556                 printf("%-12.12s %7d %6d %6d %11s %6s %6s %6s %11s\n",
 557                     cp,
 558                     kb(dqp->dqb_curblocks),
 559                     kb(dqp->dqb_bsoftlimit),
 560                     kb(dqp->dqb_bhardlimit),
 561                     "-",
 562                     "-",
 563                     "-",
 564                     "-",
 565                     "-");
 566         } else {
 567                 printf("%-12.12s %7d %6d %6d %11s %6d %6d %6d %11s\n",
 568                     cp,
 569                     kb(dqp->dqb_curblocks),
 570                     kb(dqp->dqb_bsoftlimit),
 571                     kb(dqp->dqb_bhardlimit),
 572                     btimeleft,
 573                     dqp->dqb_curfiles,
 574                     dqp->dqb_fsoftlimit,
 575                     dqp->dqb_fhardlimit,
 576                     ftimeleft);
 577         }
 578 }
 579 
 580 static void
 581 fmttime(char *buf, long time)
 582 {
 583         int i;
 584         static struct {
 585                 int c_secs;             /* conversion units in secs */
 586                 char *c_str;            /* unit string */
 587         } cunits [] = {
 588                 {60*60*24*28, "months"},
 589                 {60*60*24*7, "weeks"},
 590                 {60*60*24, "days"},
 591                 {60*60, "hours"},
 592                 {60, "mins"},
 593                 {1, "secs"}
 594         };
 595 
 596         if (time <= 0) {
 597                 strlcpy(buf, "EXPIRED", sizeof (*buf));


 851                 if ((cl->cl_auth = authunix_create_default()) == NULL) {
 852                         clnt_destroy(cl);
 853                         return (RPC_CANTSEND);
 854                 }
 855                 oldprognum = prognum;
 856                 oldversnum = versnum;
 857                 (void) strlcpy(oldhost, host, sizeof (oldhost));
 858                 clnt_stat = RPC_SUCCESS;
 859         }
 860 
 861         if (clnt_stat != RPC_SUCCESS)
 862                 return ((int)clnt_stat);        /* don't bother retrying */
 863 
 864         clnt_stat = clnt_call(cl, procnum, inproc, in,
 865             outproc, out, tottimeout);
 866 
 867         return ((int)clnt_stat);
 868 }
 869 
 870 static int
 871 getzfsquota(char *user, char *dataset, struct dqblk *zq)
 872 {
 873         zfs_handle_t *zhp = NULL;
 874         char propname[ZFS_MAXPROPLEN];
 875         uint64_t userquota, userused;
 876 
 877         if (g_zfs == NULL)
 878                 return (1);

 879 
 880         if ((zhp = _zfs_open(g_zfs, dataset, ZFS_TYPE_DATASET)) == NULL)
 881                 return (1);
 882 
 883         (void) snprintf(propname, sizeof (propname), "userquota@%s", user);
 884         if (_zfs_prop_get_userquota_int(zhp, propname, &userquota) != 0) {
 885                 _zfs_close(zhp);
 886                 return (1);
 887         }
 888 
 889         (void) snprintf(propname, sizeof (propname), "userused@%s", user);
 890         if (_zfs_prop_get_userquota_int(zhp, propname, &userused) != 0) {
 891                 _zfs_close(zhp);
 892                 return (1);
 893         }
 894 
 895         zq->dqb_bhardlimit = userquota / DEV_BSIZE;
 896         zq->dqb_bsoftlimit = userquota / DEV_BSIZE;
 897         zq->dqb_curblocks = userused / DEV_BSIZE;
 898         _zfs_close(zhp);
 899         return (0);
 900 }
 901 




















 902 static void
































































































































































































































































 903 zexit(int n)
 904 {
 905         if (g_zfs != NULL)
 906                 _libzfs_fini(g_zfs);
 907         exit(n);
 908 }


   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /* Copyright 2016 Nexenta Systems, Inc.  All rights reserved. */
  27 
  28 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  29 /*        All Rights Reserved   */
  30 
  31 /*
  32  * University Copyright- Copyright (c) 1982, 1986, 1988
  33  * The Regents of the University of California
  34  * All Rights Reserved
  35  *
  36  * University Acknowledgment- Portions of this document are derived from
  37  * software developed by the University of California, Berkeley, and its
  38  * contributors.
  39  */
  40 
  41 /*
  42  * Disk quota reporting program.
  43  */
  44 #include <stdio.h>
  45 #include <sys/mnttab.h>
  46 #include <ctype.h>
  47 #include <pwd.h>


  52 #include <sys/param.h>
  53 #include <sys/types.h>
  54 #include <sys/sysmacros.h>
  55 #include <sys/mntent.h>
  56 #include <sys/file.h>
  57 #include <sys/stat.h>
  58 #include <sys/fs/ufs_quota.h>
  59 #include <priv_utils.h>
  60 #include <locale.h>
  61 #include <rpc/rpc.h>
  62 #include <netdb.h>
  63 #include <rpcsvc/rquota.h>
  64 #include <zone.h>
  65 #include "../../nfs/lib/replica.h"
  66 #include <dlfcn.h>
  67 #include <libzfs.h>
  68 
  69 int     vflag;
  70 int     nolocalquota;
  71 
  72 /*
  73  * struct dqblk is a 32 bit quantity and is common across NFS and UFS.
  74  * UFS has a 2TB limit and an uint32_t can hold this value.
  75  * NFS translates this to rquota where all members are unit32_t in size.
  76  * A private dqblk, dqblk_zfs is defined here.
  77  */
  78 struct dqblk_zfs {
  79         uint64_t  dqbz_bhardlimit; /* absolute limit on disk blks alloc */
  80         uint64_t  dqbz_bsoftlimit; /* preferred limit on disk blks */
  81         uint64_t  dqbz_curblocks;  /* current block count */
  82         uint64_t  dqbz_fhardlimit; /* maximum # allocated files + 1 */
  83         uint64_t  dqbz_fsoftlimit; /* preferred file limit */
  84         uint64_t  dqbz_curfiles;   /* current # allocated files */
  85         uint64_t  dqbz_btimelimit; /* time limit for excessive disk use */
  86         uint64_t  dqbz_ftimelimit; /* time limit for excessive files */
  87 };
  88 extern int      optind;
  89 extern char     *optarg;
  90 
  91 #define QFNAME  "quotas"
  92 
  93 #if DEV_BSIZE < 1024
  94 #define kb(x)   ((x) / (1024 / DEV_BSIZE))
  95 #else
  96 #define kb(x)   ((x) * (DEV_BSIZE / 1024))
  97 #endif
  98 
  99 #if     !defined(TEXT_DOMAIN)   /* Should be defined by cc -D */
 100 #define TEXT_DOMAIN "SYS_TEST"  /* Use this only if it weren't */
 101 #endif
 102 
 103 static void zexit(int);
 104 static boolean_t blklimits_is_zero(struct dqblk *, struct dqblk_zfs *);
 105 static int getzfsquota(char *, char *, struct dqblk_zfs *);
 106 static int getnfsquota(char *, char *, uid_t, struct dqblk *);
 107 static void showuid(uid_t);
 108 static void showquotas(uid_t, char *);
 109 static void warn(struct mnttab *, struct dqblk *, struct dqblk_zfs *);
 110 static void warn_dqblk_impl(struct mnttab *, struct dqblk *);
 111 static void warn_dqblk_zfs_impl(struct mnttab *, struct dqblk_zfs *);
 112 static void heading(uid_t, char *);
 113 static void prquota(struct mnttab *, struct dqblk *, struct dqblk_zfs *);
 114 static void prquota_dqblk_impl(struct mnttab *, struct dqblk *);
 115 static void prquota_dqblk_zfs_impl(struct mnttab *, struct dqblk_zfs *);
 116 static void fmttime(char *, long);
 117 






 118 static libzfs_handle_t *g_zfs = NULL;
 119 



























 120 int
 121 main(int argc, char *argv[])
 122 {
 123         int     opt;
 124         int     i;
 125         int     status = 0;
 126 
 127         (void) setlocale(LC_ALL, "");
 128         (void) textdomain(TEXT_DOMAIN);
 129 
 130         /*
 131          * PRIV_FILE_DAC_READ is needed to read the QFNAME file
 132          * Clear all other privleges from the limit set, and add
 133          * the required privilege to the bracketed set.
 134          */
 135 
 136         if (__init_suid_priv(PU_CLEARLIMITSET, PRIV_FILE_DAC_READ,
 137             NULL) == -1) {
 138                 (void) fprintf(stderr,
 139                     gettext("Insufficient privileges, "
 140                     "quota must be set-uid root or have "
 141                     "file_dac_read privileges\n"));
 142 
 143                 exit(1);
 144         }
 145 

 146 
 147         while ((opt = getopt(argc, argv, "vV")) != EOF) {
 148                 switch (opt) {
 149 
 150                 case 'v':
 151                         vflag++;
 152                         break;
 153 
 154                 case 'V':               /* Print command line */
 155                         {
 156                         char    *opt_text;
 157                         int     opt_count;
 158 
 159                         (void) fprintf(stdout, "quota -F UFS ");
 160                         for (opt_count = 1; opt_count < argc; opt_count++) {
 161                                 opt_text = argv[opt_count];
 162                                 if (opt_text)
 163                                         (void) fprintf(stdout, " %s ",
 164                                             opt_text);
 165                         }


 214 
 215         if (pwd == NULL) {
 216                 fprintf(stderr, "quota: %s: unknown user\n", name);
 217                 return (32);
 218         }
 219         if (pwd->pw_uid == 0) {
 220                 if (vflag)
 221                         printf("no disk quota for %s (uid 0)\n", name);
 222                 return (0);
 223         }
 224         showquotas(pwd->pw_uid, name);
 225         return (0);
 226 }
 227 
 228 static void
 229 showquotas(uid_t uid, char *name)
 230 {
 231         struct mnttab mnt;
 232         FILE *mtab;
 233         struct dqblk dqblk;
 234         struct dqblk_zfs dqblkz;
 235         uid_t myuid;
 236         struct failed_srv {
 237                 char *serv_name;
 238                 struct failed_srv *next;
 239         };
 240         struct failed_srv *failed_srv_list = NULL;
 241         int     rc;
 242         char    my_zonename[ZONENAME_MAX];
 243         zoneid_t my_zoneid = getzoneid();
 244 
 245         myuid = getuid();
 246         if (uid != myuid && myuid != 0) {
 247                 printf("quota: %s (uid %d): permission denied\n", name, uid);
 248                 zexit(32);
 249         }
 250 
 251         memset(my_zonename, '\0', ZONENAME_MAX);
 252         getzonenamebyid(my_zoneid, my_zonename, ZONENAME_MAX);
 253 
 254         if (vflag)
 255                 heading(uid, name);
 256         mtab = fopen(MNTTAB, "r");
 257         while (getmntent(mtab, &mnt) == NULL) {
 258                 boolean_t is_zfs = B_FALSE;
 259 
 260                 if (strcmp(mnt.mnt_fstype, MNTTYPE_ZFS) == 0) {
 261                         is_zfs = B_TRUE;
 262                         bzero(&dqblkz, sizeof (dqblkz));
 263                         if (getzfsquota(name, mnt.mnt_special, &dqblkz))
 264                                 continue;
 265                 } else if (strcmp(mnt.mnt_fstype, MNTTYPE_UFS) == 0) {
 266                         if (nolocalquota ||
 267                             (quotactl(Q_GETQUOTA,
 268                             mnt.mnt_mountp, uid, &dqblk) != 0 &&
 269                             !(vflag && getdiskquota(&mnt, uid, &dqblk))))
 270                                 continue;
 271                 } else if (strcmp(mnt.mnt_fstype, MNTTYPE_NFS) == 0) {
 272 
 273                         struct replica *rl;
 274                         int count;
 275                         char *mntopt = NULL;
 276 
 277                         /*
 278                          * Skip checking quotas for file systems mounted
 279                          * in other zones. Zone names will be passed in
 280                          * following format from hasmntopt():
 281                          * "zone=<zone-name>,<mnt options...>"
 282                          */
 283                         if ((mntopt = hasmntopt(&mnt, MNTOPT_ZONE)) &&


 387                                         tmp_srv = (struct failed_srv *)malloc(
 388                                             sizeof (struct failed_srv));
 389                                         tmp_srv->serv_name = (char *)malloc(
 390                                             len * sizeof (char) + 1);
 391                                         strncpy(tmp_srv->serv_name, rl[0].host,
 392                                             len);
 393                                         tmp_srv->serv_name[len] = '\0';
 394 
 395                                         tmp_srv->next = failed_srv_list;
 396                                         failed_srv_list = tmp_srv;
 397                                 }
 398 
 399                                 free_replica(rl, count);
 400                                 continue;
 401                         }
 402 
 403                         free_replica(rl, count);
 404                 } else {
 405                         continue;
 406                 }
 407 
 408                 if (blklimits_is_zero(&dqblk, is_zfs ? &dqblkz : NULL))
 409                         continue;
 410 
 411                 if (vflag)
 412                         prquota(&mnt, &dqblk, is_zfs ? &dqblkz : NULL);
 413                 else
 414                         warn(&mnt, &dqblk, is_zfs ? &dqblkz : NULL);
 415 
 416         }
 417 
 418         /*
 419          * Free list of failed servers
 420          */
 421         while (failed_srv_list != NULL) {
 422                 struct failed_srv *tmp_srv = failed_srv_list;
 423 
 424                 failed_srv_list = failed_srv_list->next;
 425                 free(tmp_srv->serv_name);
 426                 free(tmp_srv);
 427         }
 428 
 429         fclose(mtab);
 430 }
 431 
 432 static void
 433 warn(struct mnttab *mntp, struct dqblk *dqp, struct dqblk_zfs *dqzp)
 434 {
 435         if (dqzp != NULL)
 436                 warn_dqblk_zfs_impl(mntp, dqzp);
 437         else
 438                 warn_dqblk_impl(mntp, dqp);






















































 439 }
 440 
 441 static void
 442 heading(uid_t uid, char *name)
 443 {
 444         printf("Disk quotas for %s (uid %ld):\n", name, (long)uid);
 445         printf("%-12s %7s%7s%7s%12s%7s%7s%7s%12s\n",
 446             "Filesystem",
 447             "usage",
 448             "quota",
 449             "limit",
 450             "timeleft",
 451             "files",
 452             "quota",
 453             "limit",
 454             "timeleft");
 455 }
 456 
 457 static void
 458 prquota(struct mnttab *mntp, struct dqblk *dqp, struct dqblk_zfs *dqzp)
 459 {
 460         if (dqzp != NULL)
 461                 prquota_dqblk_zfs_impl(mntp, dqzp);
 462         else
 463                 prquota_dqblk_impl(mntp, dqp);























































 464 }
 465 
 466 static void
 467 fmttime(char *buf, long time)
 468 {
 469         int i;
 470         static struct {
 471                 int c_secs;             /* conversion units in secs */
 472                 char *c_str;            /* unit string */
 473         } cunits [] = {
 474                 {60*60*24*28, "months"},
 475                 {60*60*24*7, "weeks"},
 476                 {60*60*24, "days"},
 477                 {60*60, "hours"},
 478                 {60, "mins"},
 479                 {1, "secs"}
 480         };
 481 
 482         if (time <= 0) {
 483                 strlcpy(buf, "EXPIRED", sizeof (*buf));


 737                 if ((cl->cl_auth = authunix_create_default()) == NULL) {
 738                         clnt_destroy(cl);
 739                         return (RPC_CANTSEND);
 740                 }
 741                 oldprognum = prognum;
 742                 oldversnum = versnum;
 743                 (void) strlcpy(oldhost, host, sizeof (oldhost));
 744                 clnt_stat = RPC_SUCCESS;
 745         }
 746 
 747         if (clnt_stat != RPC_SUCCESS)
 748                 return ((int)clnt_stat);        /* don't bother retrying */
 749 
 750         clnt_stat = clnt_call(cl, procnum, inproc, in,
 751             outproc, out, tottimeout);
 752 
 753         return ((int)clnt_stat);
 754 }
 755 
 756 static int
 757 getzfsquota(char *user, char *dataset, struct dqblk_zfs *zq)
 758 {
 759         zfs_handle_t *zhp = NULL;
 760         char propname[ZFS_MAXPROPLEN];
 761         uint64_t userquota, userused;
 762 
 763         if (g_zfs == NULL) {
 764                 g_zfs = libzfs_init();
 765         }
 766 
 767         if ((zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_DATASET)) == NULL)
 768                 return (1);
 769 
 770         (void) snprintf(propname, sizeof (propname), "userquota@%s", user);
 771         if (zfs_prop_get_userquota_int(zhp, propname, &userquota) != 0) {
 772                 zfs_close(zhp);
 773                 return (1);
 774         }
 775 
 776         (void) snprintf(propname, sizeof (propname), "userused@%s", user);
 777         if (zfs_prop_get_userquota_int(zhp, propname, &userused) != 0) {
 778                 zfs_close(zhp);
 779                 return (1);
 780         }
 781 
 782         zq->dqbz_bhardlimit = userquota / DEV_BSIZE;
 783         zq->dqbz_bsoftlimit = userquota / DEV_BSIZE;
 784         zq->dqbz_curblocks = userused / DEV_BSIZE;
 785         zfs_close(zhp);
 786         return (0);
 787 }
 788 
 789 static boolean_t
 790 blklimits_is_zero(struct dqblk *dqp, struct dqblk_zfs *dqzp)
 791 {
 792         if (dqzp == NULL) {
 793                 if (dqp->dqb_bsoftlimit == 0 && dqp->dqb_bhardlimit == 0 &&
 794                     dqp->dqb_fsoftlimit == 0 && dqp->dqb_fhardlimit == 0) {
 795                         return (B_TRUE);
 796                 } else {
 797                         return (B_FALSE);
 798                 }
 799         } else {
 800                 if (dqzp->dqbz_bsoftlimit == 0 && dqzp->dqbz_bhardlimit == 0 &&
 801                     dqzp->dqbz_fsoftlimit == 0 && dqzp->dqbz_fhardlimit == 0) {
 802                         return (B_TRUE);
 803                 } else {
 804                         return (B_FALSE);
 805                 }
 806         }
 807 }
 808 
 809 static void
 810 warn_dqblk_impl(struct mnttab *mntp, struct dqblk *dqp)
 811 {
 812         struct timeval tv;
 813 
 814         time(&(tv.tv_sec));
 815         tv.tv_usec = 0;
 816         if (dqp->dqb_bhardlimit &&
 817             dqp->dqb_curblocks >= dqp->dqb_bhardlimit) {
 818                 printf("Block limit reached on %s\n", mntp->mnt_mountp);
 819         } else if (dqp->dqb_bsoftlimit &&
 820             dqp->dqb_curblocks >= dqp->dqb_bsoftlimit) {
 821                 if (dqp->dqb_btimelimit == 0) {
 822                         printf("Over disk quota on %s, remove %luK\n",
 823                             mntp->mnt_mountp,
 824                             kb(dqp->dqb_curblocks - dqp->dqb_bsoftlimit + 1));
 825                 } else if (dqp->dqb_btimelimit > tv.tv_sec) {
 826                         char btimeleft[80];
 827 
 828                         fmttime(btimeleft, dqp->dqb_btimelimit - tv.tv_sec);
 829                         printf("Over disk quota on %s, remove %luK within %s\n",
 830                             mntp->mnt_mountp,
 831                             kb(dqp->dqb_curblocks - dqp->dqb_bsoftlimit + 1),
 832                             btimeleft);
 833                 } else {
 834                         printf("Over disk quota on %s, time limit has expired,"
 835                             " remove %luK\n", mntp->mnt_mountp,
 836                             kb(dqp->dqb_curblocks - dqp->dqb_bsoftlimit + 1));
 837                 }
 838         }
 839         if (dqp->dqb_fhardlimit &&
 840             dqp->dqb_curfiles >= dqp->dqb_fhardlimit) {
 841                 printf("File count limit reached on %s\n", mntp->mnt_mountp);
 842         } else if (dqp->dqb_fsoftlimit &&
 843             dqp->dqb_curfiles >= dqp->dqb_fsoftlimit) {
 844                 if (dqp->dqb_ftimelimit == 0) {
 845                         printf("Over file quota on %s, remove %lu file%s\n",
 846                             mntp->mnt_mountp,
 847                             dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1,
 848                             ((dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1) > 1 ?
 849                             "s" : ""));
 850                 } else if (dqp->dqb_ftimelimit > tv.tv_sec) {
 851                         char ftimeleft[80];
 852 
 853                         fmttime(ftimeleft, dqp->dqb_ftimelimit - tv.tv_sec);
 854                         printf("Over file quota on %s, remove %lu file%s"
 855                             " within %s\n", mntp->mnt_mountp,
 856                             dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1,
 857                             ((dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1) > 1 ?
 858                             "s" : ""), ftimeleft);
 859                 } else {
 860                         printf("Over file quota on %s, time limit has expired,"
 861                             " remove %lu file%s\n", mntp->mnt_mountp,
 862                             dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1,
 863                             ((dqp->dqb_curfiles - dqp->dqb_fsoftlimit + 1) > 1 ?
 864                             "s" : ""));
 865                 }
 866         }
 867 }
 868 
 869 static void
 870 warn_dqblk_zfs_impl(struct mnttab *mntp, struct dqblk_zfs *dqzp)
 871 {
 872         struct timeval tv;
 873 
 874         time(&(tv.tv_sec));
 875         tv.tv_usec = 0;
 876         if (dqzp->dqbz_bhardlimit &&
 877             dqzp->dqbz_curblocks >= dqzp->dqbz_bhardlimit) {
 878                 printf("Block limit reached on %s\n", mntp->mnt_mountp);
 879         } else if (dqzp->dqbz_bsoftlimit &&
 880             dqzp->dqbz_curblocks >= dqzp->dqbz_bsoftlimit) {
 881                 if (dqzp->dqbz_btimelimit == 0) {
 882                         printf("Over disk quota on %s, remove %luK\n",
 883                             mntp->mnt_mountp,
 884                             kb(dqzp->dqbz_curblocks -
 885                             dqzp->dqbz_bsoftlimit + 1));
 886                 } else if (dqzp->dqbz_btimelimit > tv.tv_sec) {
 887                         char btimeleft[80];
 888 
 889                         fmttime(btimeleft, dqzp->dqbz_btimelimit - tv.tv_sec);
 890                         printf("Over disk quota on %s, remove %luK within %s\n",
 891                             mntp->mnt_mountp,
 892                             kb(dqzp->dqbz_curblocks -
 893                             dqzp->dqbz_bsoftlimit + 1),
 894                             btimeleft);
 895                 } else {
 896                         printf("Over disk quota on %s, time limit has expired,"
 897                             " remove %luK\n", mntp->mnt_mountp,
 898                             kb(dqzp->dqbz_curblocks -
 899                             dqzp->dqbz_bsoftlimit + 1));
 900                 }
 901         }
 902         if (dqzp->dqbz_fhardlimit &&
 903             dqzp->dqbz_curfiles >= dqzp->dqbz_fhardlimit) {
 904                 printf("File count limit reached on %s\n", mntp->mnt_mountp);
 905         } else if (dqzp->dqbz_fsoftlimit &&
 906             dqzp->dqbz_curfiles >= dqzp->dqbz_fsoftlimit) {
 907                 if (dqzp->dqbz_ftimelimit == 0) {
 908                         printf("Over file quota on %s, remove %lu file%s\n",
 909                             mntp->mnt_mountp,
 910                             dqzp->dqbz_curfiles - dqzp->dqbz_fsoftlimit + 1,
 911                             ((dqzp->dqbz_curfiles -
 912                             dqzp->dqbz_fsoftlimit + 1) > 1 ?
 913                             "s" : ""));
 914                 } else if (dqzp->dqbz_ftimelimit > tv.tv_sec) {
 915                         char ftimeleft[80];
 916 
 917                         fmttime(ftimeleft, dqzp->dqbz_ftimelimit - tv.tv_sec);
 918                         printf("Over file quota on %s, remove %lu file%s "
 919                             " within %s\n", mntp->mnt_mountp,
 920                             dqzp->dqbz_curfiles - dqzp->dqbz_fsoftlimit + 1,
 921                             ((dqzp->dqbz_curfiles -
 922                             dqzp->dqbz_fsoftlimit + 1) > 1 ?
 923                             "s" : ""), ftimeleft);
 924                 } else {
 925                         printf("Over file quota on %s, time limit has expired,"
 926                             " remove %lu file%s\n", mntp->mnt_mountp,
 927                             dqzp->dqbz_curfiles - dqzp->dqbz_fsoftlimit + 1,
 928                             ((dqzp->dqbz_curfiles -
 929                             dqzp->dqbz_fsoftlimit + 1) > 1 ?
 930                             "s" : ""));
 931                 }
 932         }
 933 }
 934 
 935 static void
 936 prquota_dqblk_impl(struct mnttab *mntp, struct dqblk *dqp)
 937 {
 938         struct timeval tv;
 939         char ftimeleft[80], btimeleft[80];
 940         char *cp;
 941 
 942         time(&(tv.tv_sec));
 943         tv.tv_usec = 0;
 944         if (dqp->dqb_bsoftlimit && dqp->dqb_curblocks >= dqp->dqb_bsoftlimit) {
 945                 if (dqp->dqb_btimelimit == 0) {
 946                         strlcpy(btimeleft, "NOT STARTED", sizeof (btimeleft));
 947                 } else if (dqp->dqb_btimelimit > tv.tv_sec) {
 948                         fmttime(btimeleft, dqp->dqb_btimelimit - tv.tv_sec);
 949                 } else {
 950                         strlcpy(btimeleft, "EXPIRED", sizeof (btimeleft));
 951                 }
 952         } else {
 953                 btimeleft[0] = '\0';
 954         }
 955         if (dqp->dqb_fsoftlimit && dqp->dqb_curfiles >= dqp->dqb_fsoftlimit) {
 956                 if (dqp->dqb_ftimelimit == 0) {
 957                         strlcpy(ftimeleft, "NOT STARTED", sizeof (ftimeleft));
 958                 } else if (dqp->dqb_ftimelimit > tv.tv_sec) {
 959                         fmttime(ftimeleft, dqp->dqb_ftimelimit - tv.tv_sec);
 960                 } else {
 961                         strlcpy(ftimeleft, "EXPIRED", sizeof (ftimeleft));
 962                 }
 963         } else {
 964                 ftimeleft[0] = '\0';
 965         }
 966         if (strlen(mntp->mnt_mountp) > 12) {
 967                 printf("%s\n", mntp->mnt_mountp);
 968                 cp = "";
 969         } else {
 970                 cp = mntp->mnt_mountp;
 971         }
 972 
 973         if (dqp->dqb_curfiles == 0 &&
 974             dqp->dqb_fsoftlimit == 0 && dqp->dqb_fhardlimit == 0) {
 975                 printf("%-12.12s %7d %6d %6d %11s %6s %6s %6s %11s\n",
 976                     cp,
 977                     kb(dqp->dqb_curblocks),
 978                     kb(dqp->dqb_bsoftlimit),
 979                     kb(dqp->dqb_bhardlimit),
 980                     "-",
 981                     "-",
 982                     "-",
 983                     "-",
 984                     "-");
 985         } else {
 986                 printf("%-12.12s %7d %6d %6d %11s %6d %6d %6d %11s\n",
 987                     cp,
 988                     kb(dqp->dqb_curblocks),
 989                     kb(dqp->dqb_bsoftlimit),
 990                     kb(dqp->dqb_bhardlimit),
 991                     btimeleft,
 992                     dqp->dqb_curfiles,
 993                     dqp->dqb_fsoftlimit,
 994                     dqp->dqb_fhardlimit,
 995                     ftimeleft);
 996         }
 997 }
 998 
 999 static void
1000 prquota_dqblk_zfs_impl(struct mnttab *mntp, struct dqblk_zfs *dqzp)
1001 {
1002         struct timeval tv;
1003         char ftimeleft[80], btimeleft[80];
1004         char *cp;
1005 
1006         time(&(tv.tv_sec));
1007         tv.tv_usec = 0;
1008         if (dqzp->dqbz_bsoftlimit &&
1009             dqzp->dqbz_curblocks >= dqzp->dqbz_bsoftlimit) {
1010                 if (dqzp->dqbz_btimelimit == 0) {
1011                         strlcpy(btimeleft, "NOT STARTED", sizeof (btimeleft));
1012                 } else if (dqzp->dqbz_btimelimit > tv.tv_sec) {
1013                         fmttime(btimeleft, dqzp->dqbz_btimelimit - tv.tv_sec);
1014                 } else {
1015                         strlcpy(btimeleft, "EXPIRED", sizeof (btimeleft));
1016                 }
1017         } else {
1018                 btimeleft[0] = '\0';
1019         }
1020         if (dqzp->dqbz_fsoftlimit &&
1021             dqzp->dqbz_curfiles >= dqzp->dqbz_fsoftlimit) {
1022                 if (dqzp->dqbz_ftimelimit == 0) {
1023                         strlcpy(ftimeleft, "NOT STARTED", sizeof (ftimeleft));
1024                 } else if (dqzp->dqbz_ftimelimit > tv.tv_sec) {
1025                         fmttime(ftimeleft, dqzp->dqbz_ftimelimit - tv.tv_sec);
1026                 } else {
1027                         strlcpy(ftimeleft, "EXPIRED", sizeof (ftimeleft));
1028                 }
1029         } else {
1030                 ftimeleft[0] = '\0';
1031         }
1032         if (strlen(mntp->mnt_mountp) > 12) {
1033                 printf("%s\n", mntp->mnt_mountp);
1034                 cp = "";
1035         } else {
1036                 cp = mntp->mnt_mountp;
1037         }
1038 
1039         if (dqzp->dqbz_curfiles == 0 &&
1040             dqzp->dqbz_fsoftlimit == 0 && dqzp->dqbz_fhardlimit == 0) {
1041                 printf("%-12.12s %7llu %6llu %6llu %11s %6s %6s %6s %11s\n",
1042                     cp,
1043                     kb(dqzp->dqbz_curblocks),
1044                     kb(dqzp->dqbz_bsoftlimit),
1045                     kb(dqzp->dqbz_bhardlimit),
1046                     "-",
1047                     "-",
1048                     "-",
1049                     "-",
1050                     "-");
1051         } else {
1052                 printf("%-12.12s %7llu %6llu %6llu %11s %6d %6d %6d %11s\n",
1053                     cp,
1054                     kb(dqzp->dqbz_curblocks),
1055                     kb(dqzp->dqbz_bsoftlimit),
1056                     kb(dqzp->dqbz_bhardlimit),
1057                     btimeleft,
1058                     dqzp->dqbz_curfiles,
1059                     dqzp->dqbz_fsoftlimit,
1060                     dqzp->dqbz_fhardlimit,
1061                     ftimeleft);
1062         }
1063 }
1064 
1065 static void
1066 zexit(int n)
1067 {
1068         if (g_zfs != NULL)
1069                 libzfs_fini(g_zfs);
1070         exit(n);
1071 }