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 }
|