4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
40 * Disk quota reporting program.
43 #include <sys/mnttab.h>
50 #include <sys/param.h>
51 #include <sys/types.h>
52 #include <sys/sysmacros.h>
53 #include <sys/mntent.h>
56 #include <sys/fs/ufs_quota.h>
57 #include <priv_utils.h>
61 #include <rpcsvc/rquota.h>
63 #include "../../nfs/lib/replica.h"
73 #define QFNAME "quotas"
76 #define kb(x) ((x) / (1024 / DEV_BSIZE))
78 #define kb(x) ((x) * (DEV_BSIZE / 1024))
81 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
82 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
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);
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 *,
101 static libzfs_handle_t
*g_zfs
= NULL
;
104 * Dynamically check for libzfs, in case the user hasn't installed the SUNWzfs
105 * packages. 'quota' utility supports zfs as an option.
115 if ((hdl
= dlopen("libzfs.so", RTLD_LAZY
)) != NULL
) {
116 _libzfs_init
= (libzfs_handle_t
*(*)(void))dlsym(hdl
,
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");
124 if (_libzfs_init
&& _libzfs_fini
&& _zfs_open
&&
125 _zfs_close
&& _zfs_prop_get_userquota_int
)
126 g_zfs
= _libzfs_init();
131 main(int argc
, char *argv
[])
137 (void) setlocale(LC_ALL
, "");
138 (void) textdomain(TEXT_DOMAIN
);
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.
146 if (__init_suid_priv(PU_CLEARLIMITSET
, PRIV_FILE_DAC_READ
,
148 (void) fprintf(stderr
,
149 gettext("Insufficient privileges, "
150 "quota must be set-uid root or have "
151 "file_dac_read privileges\n"));
158 while ((opt
= getopt(argc
, argv
, "vV")) != EOF
) {
165 case 'V': /* Print command line */
170 (void) fprintf(stdout
, "quota -F UFS ");
171 for (opt_count
= 1; opt_count
< argc
; opt_count
++) {
172 opt_text
= argv
[opt_count
];
174 (void) fprintf(stdout
, " %s ",
177 (void) fprintf(stdout
, "\n");
182 fprintf(stderr
, "usage: quota [-v] [username]\n");
186 if (quotactl(Q_ALLSYNC
, NULL
, (uid_t
)0, NULL
) < 0 && errno
== EINVAL
) {
188 fprintf(stderr
, "There are no quotas on this system\n");
191 if (argc
== optind
) {
195 for (i
= optind
; i
< argc
; i
++) {
196 if (alldigits(argv
[i
])) {
197 showuid((uid_t
)atoi(argv
[i
]));
199 status
|= showname(argv
[i
]);
208 struct passwd
*pwd
= getpwuid(uid
);
212 printf("no disk quota for uid 0\n");
216 showquotas(uid
, "(no account)");
218 showquotas(uid
, pwd
->pw_name
);
224 struct passwd
*pwd
= getpwnam(name
);
227 fprintf(stderr
, "quota: %s: unknown user\n", name
);
230 if (pwd
->pw_uid
== 0) {
232 printf("no disk quota for %s (uid 0)\n", name
);
235 showquotas(pwd
->pw_uid
, name
);
240 showquotas(uid_t uid
, char *name
)
248 struct failed_srv
*next
;
250 struct failed_srv
*failed_srv_list
= NULL
;
252 char my_zonename
[ZONENAME_MAX
];
253 zoneid_t my_zoneid
= getzoneid();
256 if (uid
!= myuid
&& myuid
!= 0) {
257 printf("quota: %s (uid %d): permission denied\n", name
, uid
);
261 memset(my_zonename
, '\0', ZONENAME_MAX
);
262 getzonenamebyid(my_zoneid
, my_zonename
, ZONENAME_MAX
);
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
))
272 } else if (strcmp(mnt
.mnt_fstype
, MNTTYPE_UFS
) == 0) {
274 (quotactl(Q_GETQUOTA
,
275 mnt
.mnt_mountp
, uid
, &dqblk
) != 0 &&
276 !(vflag
&& getdiskquota(&mnt
, uid
, &dqblk
))))
278 } else if (strcmp(mnt
.mnt_fstype
, MNTTYPE_NFS
) == 0) {
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...>"
290 if ((mntopt
= hasmntopt(&mnt
, MNTOPT_ZONE
)) &&
291 (my_zonename
[0] != '\0')) {
292 mntopt
+= strcspn(mntopt
, "=") + 1;
293 if (strncmp(mntopt
, my_zonename
,
294 strcspn(mntopt
, ",")) != 0)
298 if (hasopt(MNTOPT_NOQUOTA
, mnt
.mnt_mntopts
))
302 * Skip quota processing if mounted with public
303 * option. We are not likely to be able to pierce
304 * a fire wall to contact the quota server.
306 if (hasopt(MNTOPT_PUBLIC
, mnt
.mnt_mntopts
))
309 rl
= parse_replica(mnt
.mnt_special
, &count
);
314 fprintf(stderr
, "cannot find hostname "
315 "and/or pathname for %s\n",
318 fprintf(stderr
, "no memory to parse "
319 "mnttab entry for %s\n",
325 * We skip quota reporting on mounts with replicas
326 * for the following reasons:
328 * (1) Very little point in reporting quotas on
329 * a set of read-only replicas ... how will the
330 * user correct the problem?
332 * (2) Which replica would we report the quota
333 * for? If we pick the current replica, what
334 * happens when a fail over event occurs? The
335 * next time quota is run, the quota will look
336 * all different, or there won't even be one.
337 * This has the potential to break scripts.
339 * If we prnt quouta for all replicas, how do
340 * we present the output without breaking scripts?
344 free_replica(rl
, count
);
349 * Skip file systems mounted using public fh.
350 * We are not likely to be able to pierce
351 * a fire wall to contact the quota server.
353 if (strcmp(rl
[0].host
, "nfs") == 0 &&
354 strncmp(rl
[0].path
, "//", 2) == 0) {
355 free_replica(rl
, count
);
360 * Skip getting quotas from failing servers
362 if (failed_srv_list
!= NULL
) {
363 struct failed_srv
*tmp_list
;
364 int found_failed
= 0;
365 size_t len
= strlen(rl
[0].host
);
367 tmp_list
= failed_srv_list
;
369 if (strncasecmp(rl
[0].host
,
370 tmp_list
->serv_name
, len
) == 0) {
374 } while ((tmp_list
= tmp_list
->next
) != NULL
);
376 free_replica(rl
, count
);
381 rc
= getnfsquota(rl
[0].host
, rl
[0].path
, uid
, &dqblk
);
382 if (rc
!= RPC_SUCCESS
) {
384 struct failed_srv
*tmp_srv
;
387 * Failed to get quota from this server. Add
388 * this server to failed_srv_list and skip
389 * getting quotas for other mounted filesystems
392 if (rc
== RPC_TIMEDOUT
|| rc
== RPC_CANTSEND
) {
393 len
= strlen(rl
[0].host
);
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
,
400 tmp_srv
->serv_name
[len
] = '\0';
402 tmp_srv
->next
= failed_srv_list
;
403 failed_srv_list
= tmp_srv
;
406 free_replica(rl
, count
);
410 free_replica(rl
, count
);
414 if (dqblk
.dqb_bsoftlimit
== 0 && dqblk
.dqb_bhardlimit
== 0 &&
415 dqblk
.dqb_fsoftlimit
== 0 && dqblk
.dqb_fhardlimit
== 0)
418 prquota(&mnt
, &dqblk
);
424 * Free list of failed servers
426 while (failed_srv_list
!= NULL
) {
427 struct failed_srv
*tmp_srv
= failed_srv_list
;
429 failed_srv_list
= failed_srv_list
->next
;
430 free(tmp_srv
->serv_name
);
438 warn(struct mnttab
*mntp
, struct dqblk
*dqp
)
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",
452 kb(dqp
->dqb_curblocks
- dqp
->dqb_bsoftlimit
+ 1));
453 } else if (dqp
->dqb_btimelimit
> tv
.tv_sec
) {
456 fmttime(btimeleft
, dqp
->dqb_btimelimit
- tv
.tv_sec
);
457 printf("Over disk quota on %s, remove %luK within %s\n",
459 kb(dqp
->dqb_curblocks
- dqp
->dqb_bsoftlimit
+ 1),
463 "Over disk quota on %s, time limit has expired, remove %luK\n",
465 kb(dqp
->dqb_curblocks
- dqp
->dqb_bsoftlimit
+ 1));
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",
476 dqp
->dqb_curfiles
- dqp
->dqb_fsoftlimit
+ 1,
477 ((dqp
->dqb_curfiles
- dqp
->dqb_fsoftlimit
+ 1) > 1 ?
479 } else if (dqp
->dqb_ftimelimit
> tv
.tv_sec
) {
482 fmttime(ftimeleft
, dqp
->dqb_ftimelimit
- tv
.tv_sec
);
484 "Over file quota on %s, remove %lu file%s within %s\n",
486 dqp
->dqb_curfiles
- dqp
->dqb_fsoftlimit
+ 1,
487 ((dqp
->dqb_curfiles
- dqp
->dqb_fsoftlimit
+ 1) > 1 ?
488 "s" : ""), ftimeleft
);
491 "Over file quota on %s, time limit has expired, remove %lu file%s\n",
493 dqp
->dqb_curfiles
- dqp
->dqb_fsoftlimit
+ 1,
494 ((dqp
->dqb_curfiles
- dqp
->dqb_fsoftlimit
+ 1) > 1 ?
501 heading(uid_t uid
, char *name
)
503 printf("Disk quotas for %s (uid %ld):\n", name
, (long)uid
);
504 printf("%-12s %7s%7s%7s%12s%7s%7s%7s%12s\n",
517 prquota(struct mnttab
*mntp
, struct dqblk
*dqp
)
520 char ftimeleft
[80], btimeleft
[80];
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
);
531 strlcpy(btimeleft
, "EXPIRED", sizeof (btimeleft
));
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
);
542 strlcpy(ftimeleft
, "EXPIRED", sizeof (ftimeleft
));
547 if (strlen(mntp
->mnt_mountp
) > 12) {
548 printf("%s\n", mntp
->mnt_mountp
);
551 cp
= mntp
->mnt_mountp
;
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",
558 kb(dqp
->dqb_curblocks
),
559 kb(dqp
->dqb_bsoftlimit
),
560 kb(dqp
->dqb_bhardlimit
),
567 printf("%-12.12s %7d %6d %6d %11s %6d %6d %6d %11s\n",
569 kb(dqp
->dqb_curblocks
),
570 kb(dqp
->dqb_bsoftlimit
),
571 kb(dqp
->dqb_bhardlimit
),
581 fmttime(char *buf
, long time
)
585 int c_secs
; /* conversion units in secs */
586 char *c_str
; /* unit string */
588 {60*60*24*28, "months"},
589 {60*60*24*7, "weeks"},
597 strlcpy(buf
, "EXPIRED", sizeof (*buf
));
600 for (i
= 0; i
< sizeof (cunits
)/sizeof (cunits
[0]); i
++) {
601 if (time
>= cunits
[i
].c_secs
)
604 snprintf(buf
, sizeof (*buf
), "%.1f %s",
605 (double)time
/cunits
[i
].c_secs
, cunits
[i
].c_str
);
622 getdiskquota(struct mnttab
*mntp
, uid_t uid
, struct dqblk
*dqp
)
627 char qfilename
[MAXPATHLEN
];
629 if (stat64(mntp
->mnt_special
, &statb
) < 0 ||
630 (statb
.st_mode
& S_IFMT
) != S_IFBLK
)
632 fsdev
= statb
.st_rdev
;
633 (void) snprintf(qfilename
, sizeof (qfilename
), "%s/%s",
634 mntp
->mnt_mountp
, QFNAME
);
635 if (stat64(qfilename
, &statb
) < 0 || statb
.st_dev
!= fsdev
)
637 (void) __priv_bracket(PRIV_ON
);
638 fd
= open64(qfilename
, O_RDONLY
);
639 (void) __priv_bracket(PRIV_OFF
);
642 (void) llseek(fd
, (offset_t
)dqoff(uid
), L_SET
);
643 switch (read(fd
, dqp
, sizeof (struct dqblk
))) {
646 * Convert implicit 0 quota (EOF)
647 * into an explicit one (zero'ed dqblk).
649 memset((caddr_t
)dqp
, 0, sizeof (struct dqblk
));
652 case sizeof (struct dqblk
): /* OK */
664 quotactl(int cmd
, char *mountp
, uid_t uid
, caddr_t addr
)
668 struct quotctl quota
;
669 char qfile
[MAXPATHLEN
];
675 if ((mountp
== NULL
) && (cmd
== Q_ALLSYNC
)) {
677 * Find the mount point of any mounted file system. This is
678 * because the ioctl that implements the quotactl call has
679 * to go to a real file, and not to the block device.
681 if ((fstab
= fopen(MNTTAB
, "r")) == NULL
) {
682 fprintf(stderr
, "%s: ", MNTTAB
);
687 while ((status
= getmntent(fstab
, &mnt
)) == NULL
) {
688 if (strcmp(mnt
.mnt_fstype
, MNTTYPE_UFS
) != 0 ||
689 hasopt(MNTOPT_RO
, mnt
.mnt_mntopts
))
691 if ((strlcpy(qfile
, mnt
.mnt_mountp
,
692 sizeof (qfile
)) >= sizeof (qfile
)) ||
693 (strlcat(qfile
, "/" QFNAME
, sizeof (qfile
)) >=
697 (void) __priv_bracket(PRIV_ON
);
698 fd
= open64(qfile
, O_RDONLY
);
699 (void) __priv_bracket(PRIV_OFF
);
709 if (mountp
== NULL
|| mountp
[0] == '\0') {
713 if ((strlcpy(qfile
, mountp
, sizeof (qfile
)) >= sizeof
715 (strlcat(qfile
, "/" QFNAME
, sizeof (qfile
)) >= sizeof
720 (void) __priv_bracket(PRIV_ON
);
721 fd
= open64(qfile
, O_RDONLY
);
722 (void) __priv_bracket(PRIV_OFF
);
729 status
= ioctl(fd
, Q_QUOTACTL
, "a
);
737 * Return 1 if opt appears in optlist
740 hasopt(char *opt
, char *optlist
)
750 while (*optlist
!= '\0') {
751 if (getsubopt(&optlist
, opts
, &value
) == 0)
758 * If there are no quotas available, then getnfsquota() returns
759 * RPC_SYSTEMERROR to caller.
762 getnfsquota(char *hostp
, char *path
, uid_t uid
, struct dqblk
*dqp
)
764 struct getquota_args gq_args
;
765 struct getquota_rslt gq_rslt
;
766 struct rquota
*rquota
;
767 extern char *strchr();
770 gq_args
.gqa_pathp
= path
;
771 gq_args
.gqa_uid
= uid
;
772 rpc_err
= callaurpc(hostp
, RQUOTAPROG
, RQUOTAVERS
,
773 (vflag
? RQUOTAPROC_GETQUOTA
: RQUOTAPROC_GETACTIVEQUOTA
),
774 xdr_getquota_args
, &gq_args
, xdr_getquota_rslt
, &gq_rslt
);
775 if (rpc_err
!= RPC_SUCCESS
) {
778 switch (gq_rslt
.status
) {
784 rquota
= &gq_rslt
.getquota_rslt_u
.gqr_rquota
;
786 if (!vflag
&& rquota
->rq_active
== FALSE
) {
787 return (RPC_SYSTEMERROR
);
789 gettimeofday(&tv
, NULL
);
790 limit
= (u_longlong_t
)(rquota
->rq_bhardlimit
) *
791 rquota
->rq_bsize
/ DEV_BSIZE
;
792 dqp
->dqb_bhardlimit
= limit
;
793 limit
= (u_longlong_t
)(rquota
->rq_bsoftlimit
) *
794 rquota
->rq_bsize
/ DEV_BSIZE
;
795 dqp
->dqb_bsoftlimit
= limit
;
796 limit
= (u_longlong_t
)(rquota
->rq_curblocks
) *
797 rquota
->rq_bsize
/ DEV_BSIZE
;
798 dqp
->dqb_curblocks
= limit
;
799 dqp
->dqb_fhardlimit
= rquota
->rq_fhardlimit
;
800 dqp
->dqb_fsoftlimit
= rquota
->rq_fsoftlimit
;
801 dqp
->dqb_curfiles
= rquota
->rq_curfiles
;
802 dqp
->dqb_btimelimit
=
803 tv
.tv_sec
+ rquota
->rq_btimeleft
;
804 dqp
->dqb_ftimelimit
=
805 tv
.tv_sec
+ rquota
->rq_ftimeleft
;
806 return (RPC_SUCCESS
);
810 return (RPC_SYSTEMERROR
);
813 fprintf(stderr
, "quota permission error, host: %s\n", hostp
);
814 return (RPC_AUTHERROR
);
817 fprintf(stderr
, "bad rpc result, host: %s\n", hostp
);
818 return (RPC_CANTDECODEARGS
);
825 callaurpc(char *host
, int prognum
, int versnum
, int procnum
,
826 xdrproc_t inproc
, char *in
, xdrproc_t outproc
, char *out
)
828 static enum clnt_stat clnt_stat
;
829 struct timeval tottimeout
= {20, 0};
831 static CLIENT
*cl
= NULL
;
832 static int oldprognum
, oldversnum
;
833 static char oldhost
[MAXHOSTNAMELEN
+1];
836 * Cache the client handle in case there are lots
837 * of entries in the /etc/mnttab for the same
838 * server. If the server returns an error, don't
839 * make further calls.
841 if (cl
== NULL
|| oldprognum
!= prognum
|| oldversnum
!= versnum
||
842 strcmp(oldhost
, host
) != 0) {
847 cl
= clnt_create_timed(host
, prognum
, versnum
, "udp",
850 return ((int)RPC_TIMEDOUT
);
851 if ((cl
->cl_auth
= authunix_create_default()) == NULL
) {
853 return (RPC_CANTSEND
);
855 oldprognum
= prognum
;
856 oldversnum
= versnum
;
857 (void) strlcpy(oldhost
, host
, sizeof (oldhost
));
858 clnt_stat
= RPC_SUCCESS
;
861 if (clnt_stat
!= RPC_SUCCESS
)
862 return ((int)clnt_stat
); /* don't bother retrying */
864 clnt_stat
= clnt_call(cl
, procnum
, inproc
, in
,
865 outproc
, out
, tottimeout
);
867 return ((int)clnt_stat
);
871 getzfsquota(char *user
, char *dataset
, struct dqblk
*zq
)
873 zfs_handle_t
*zhp
= NULL
;
874 char propname
[ZFS_MAXPROPLEN
];
875 uint64_t userquota
, userused
;
880 if ((zhp
= _zfs_open(g_zfs
, dataset
, ZFS_TYPE_DATASET
)) == NULL
)
883 (void) snprintf(propname
, sizeof (propname
), "userquota@%s", user
);
884 if (_zfs_prop_get_userquota_int(zhp
, propname
, &userquota
) != 0) {
889 (void) snprintf(propname
, sizeof (propname
), "userused@%s", user
);
890 if (_zfs_prop_get_userquota_int(zhp
, propname
, &userused
) != 0) {
895 zq
->dqb_bhardlimit
= userquota
/ DEV_BSIZE
;
896 zq
->dqb_bsoftlimit
= userquota
/ DEV_BSIZE
;
897 zq
->dqb_curblocks
= userused
/ DEV_BSIZE
;