2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 1992-1998
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * This is one of the most system dependent parts of Samba, and its
24 * done a litle differently. Each system has its own way of doing
31 #define DBGC_CLASS DBGC_QUOTA
33 #ifndef HAVE_SYS_QUOTAS
35 /* just a quick hack because sysquotas.h is included before linux/quota.h */
36 #ifdef QUOTABLOCK_SIZE
37 #undef QUOTABLOCK_SIZE
42 #if defined(VXFS_QUOTA)
45 * In addition to their native filesystems, some systems have Veritas VxFS.
46 * Declare here, define at end: reduces likely "include" interaction problems.
47 * David Lee <T.D.Lee@durham.ac.uk>
49 BOOL
disk_quotas_vxfs(const pstring name
, char *path
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
);
51 #endif /* VXFS_QUOTA */
55 #include <sys/types.h>
59 * This shouldn't be neccessary - it should be /usr/include/sys/quota.h
60 * So we include all the files has *should* be in the system into a large,
61 * grungy samba_linux_quoatas.h Sometimes I *hate* Linux :-). JRA.
64 #include "samba_linux_quota.h"
65 #include "samba_xfs_quota.h"
67 typedef struct _LINUX_SMB_DISK_QUOTA
{
69 SMB_BIG_UINT hardlimit
; /* In bsize units. */
70 SMB_BIG_UINT softlimit
; /* In bsize units. */
71 SMB_BIG_UINT curblocks
; /* In bsize units. */
72 SMB_BIG_UINT ihardlimit
; /* inode hard limit. */
73 SMB_BIG_UINT isoftlimit
; /* inode soft limit. */
74 SMB_BIG_UINT curinodes
; /* Current used inodes. */
75 } LINUX_SMB_DISK_QUOTA
;
77 /****************************************************************************
78 Abstract out the XFS Quota Manager quota get call.
79 ****************************************************************************/
81 static int get_smb_linux_xfs_quota(char *path
, uid_t euser_id
, gid_t egrp_id
, LINUX_SMB_DISK_QUOTA
*dp
)
83 struct fs_disk_quota D
;
88 ret
= quotactl(QCMD(Q_XGETQUOTA
,USRQUOTA
), path
, euser_id
, (caddr_t
)&D
);
91 ret
= quotactl(QCMD(Q_XGETQUOTA
,GRPQUOTA
), path
, egrp_id
, (caddr_t
)&D
);
96 dp
->bsize
= (SMB_BIG_UINT
)512;
97 dp
->softlimit
= (SMB_BIG_UINT
)D
.d_blk_softlimit
;
98 dp
->hardlimit
= (SMB_BIG_UINT
)D
.d_blk_hardlimit
;
99 dp
->ihardlimit
= (SMB_BIG_UINT
)D
.d_ino_hardlimit
;
100 dp
->isoftlimit
= (SMB_BIG_UINT
)D
.d_ino_softlimit
;
101 dp
->curinodes
= (SMB_BIG_UINT
)D
.d_icount
;
102 dp
->curblocks
= (SMB_BIG_UINT
)D
.d_bcount
;
107 /****************************************************************************
108 Abstract out the old and new Linux quota get calls.
109 ****************************************************************************/
111 static int get_smb_linux_v1_quota(char *path
, uid_t euser_id
, gid_t egrp_id
, LINUX_SMB_DISK_QUOTA
*dp
)
113 struct v1_kern_dqblk D
;
118 ret
= quotactl(QCMD(Q_V1_GETQUOTA
,USRQUOTA
), path
, euser_id
, (caddr_t
)&D
);
120 if (ret
&& errno
!= EDQUOT
)
121 ret
= quotactl(QCMD(Q_V1_GETQUOTA
,GRPQUOTA
), path
, egrp_id
, (caddr_t
)&D
);
123 if (ret
&& errno
!= EDQUOT
)
126 dp
->bsize
= (SMB_BIG_UINT
)QUOTABLOCK_SIZE
;
127 dp
->softlimit
= (SMB_BIG_UINT
)D
.dqb_bsoftlimit
;
128 dp
->hardlimit
= (SMB_BIG_UINT
)D
.dqb_bhardlimit
;
129 dp
->ihardlimit
= (SMB_BIG_UINT
)D
.dqb_ihardlimit
;
130 dp
->isoftlimit
= (SMB_BIG_UINT
)D
.dqb_isoftlimit
;
131 dp
->curinodes
= (SMB_BIG_UINT
)D
.dqb_curinodes
;
132 dp
->curblocks
= (SMB_BIG_UINT
)D
.dqb_curblocks
;
137 static int get_smb_linux_v2_quota(char *path
, uid_t euser_id
, gid_t egrp_id
, LINUX_SMB_DISK_QUOTA
*dp
)
139 struct v2_kern_dqblk D
;
144 ret
= quotactl(QCMD(Q_V2_GETQUOTA
,USRQUOTA
), path
, euser_id
, (caddr_t
)&D
);
146 if (ret
&& errno
!= EDQUOT
)
147 ret
= quotactl(QCMD(Q_V2_GETQUOTA
,GRPQUOTA
), path
, egrp_id
, (caddr_t
)&D
);
149 if (ret
&& errno
!= EDQUOT
)
152 dp
->bsize
= (SMB_BIG_UINT
)QUOTABLOCK_SIZE
;
153 dp
->softlimit
= (SMB_BIG_UINT
)D
.dqb_bsoftlimit
;
154 dp
->hardlimit
= (SMB_BIG_UINT
)D
.dqb_bhardlimit
;
155 dp
->ihardlimit
= (SMB_BIG_UINT
)D
.dqb_ihardlimit
;
156 dp
->isoftlimit
= (SMB_BIG_UINT
)D
.dqb_isoftlimit
;
157 dp
->curinodes
= (SMB_BIG_UINT
)D
.dqb_curinodes
;
158 dp
->curblocks
= ((SMB_BIG_UINT
)D
.dqb_curspace
) / dp
->bsize
;
163 /****************************************************************************
164 Brand-new generic quota interface.
165 ****************************************************************************/
167 static int get_smb_linux_gen_quota(char *path
, uid_t euser_id
, gid_t egrp_id
, LINUX_SMB_DISK_QUOTA
*dp
)
174 ret
= quotactl(QCMD(Q_GETQUOTA
,USRQUOTA
), path
, euser_id
, (caddr_t
)&D
);
176 if (ret
&& errno
!= EDQUOT
)
177 ret
= quotactl(QCMD(Q_GETQUOTA
,GRPQUOTA
), path
, egrp_id
, (caddr_t
)&D
);
179 if (ret
&& errno
!= EDQUOT
)
182 dp
->bsize
= (SMB_BIG_UINT
)QUOTABLOCK_SIZE
;
183 dp
->softlimit
= (SMB_BIG_UINT
)D
.dqb_bsoftlimit
;
184 dp
->hardlimit
= (SMB_BIG_UINT
)D
.dqb_bhardlimit
;
185 dp
->ihardlimit
= (SMB_BIG_UINT
)D
.dqb_ihardlimit
;
186 dp
->isoftlimit
= (SMB_BIG_UINT
)D
.dqb_isoftlimit
;
187 dp
->curinodes
= (SMB_BIG_UINT
)D
.dqb_curinodes
;
188 dp
->curblocks
= ((SMB_BIG_UINT
)D
.dqb_curspace
) / dp
->bsize
;
193 /****************************************************************************
194 Try to get the disk space from disk quotas (LINUX version).
195 ****************************************************************************/
197 BOOL
disk_quotas(const char *path
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
202 LINUX_SMB_DISK_QUOTA D
;
211 euser_id
= geteuid();
214 /* find the block device file */
216 if ( sys_stat(path
, &S
) == -1 )
221 if ((fp
= setmntent(MOUNTED
,"r")) == NULL
)
226 while ((mnt
= getmntent(fp
))) {
227 if ( sys_stat(mnt
->mnt_dir
,&S
) == -1 )
230 if (S
.st_dev
== devno
) {
243 if (strcmp(mnt
->mnt_type
, "xfs")==0) {
244 r
=get_smb_linux_xfs_quota(mnt
->mnt_fsname
, euser_id
, egrp_id
, &D
);
246 r
=get_smb_linux_gen_quota(mnt
->mnt_fsname
, euser_id
, egrp_id
, &D
);
247 if (r
== -1 && errno
!= EDQUOT
) {
248 r
=get_smb_linux_v2_quota(mnt
->mnt_fsname
, euser_id
, egrp_id
, &D
);
249 if (r
== -1 && errno
!= EDQUOT
)
250 r
=get_smb_linux_v1_quota(mnt
->mnt_fsname
, euser_id
, egrp_id
, &D
);
256 /* Use softlimit to determine disk space, except when it has been exceeded */
259 if (errno
== EDQUOT
) {
268 /* Use softlimit to determine disk space, except when it has been exceeded */
270 (D
.softlimit
&& D
.curblocks
>= D
.softlimit
) ||
271 (D
.hardlimit
&& D
.curblocks
>= D
.hardlimit
) ||
272 (D
.isoftlimit
&& D
.curinodes
>= D
.isoftlimit
) ||
273 (D
.ihardlimit
&& D
.curinodes
>=D
.ihardlimit
)
276 *dsize
= D
.curblocks
;
277 } else if (D
.softlimit
==0 && D
.hardlimit
==0) {
280 if (D
.softlimit
== 0)
281 D
.softlimit
= D
.hardlimit
;
282 *dfree
= D
.softlimit
- D
.curblocks
;
283 *dsize
= D
.softlimit
;
291 #include <sys/quota.h>
294 /****************************************************************************
295 try to get the disk space from disk quotas (CRAY VERSION)
296 ****************************************************************************/
298 BOOL
disk_quotas(const char *path
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
302 SMB_STRUCT_STAT sbuf
;
304 static SMB_DEV_T devno_cached
= 0 ;
306 struct q_request request
;
307 struct qf_header header
;
308 static int quota_default
= 0 ;
311 if ( sys_stat(path
,&sbuf
) == -1 )
314 devno
= sbuf
.st_dev
;
316 if ( devno
!= devno_cached
) {
318 devno_cached
= devno
;
320 if ((fd
= setmntent(KMTAB
)) == NULL
)
325 while ((mnt
= getmntent(fd
)) != NULL
) {
327 if ( sys_stat(mnt
->mnt_dir
,&sbuf
) == -1 )
330 if (sbuf
.st_dev
== devno
) {
339 pstrcpy(name
,mnt
->mnt_dir
) ;
346 request
.qf_magic
= QF_MAGIC
;
347 request
.qf_entry
.id
= geteuid() ;
349 if (quotactl(name
, Q_GETQUOTA
, &request
) == -1)
352 if ( ! request
.user
)
355 if ( request
.qf_entry
.user_q
.f_quota
== QFV_DEFAULT
) {
357 if ( ! quota_default
) {
359 if ( quotactl(name
, Q_GETHEADER
, &header
) == -1 )
362 quota_default
= header
.user_h
.def_fq
;
365 *dfree
= quota_default
;
367 }else if ( request
.qf_entry
.user_q
.f_quota
== QFV_PREVENT
) {
373 *dfree
= request
.qf_entry
.user_q
.f_quota
;
377 *dsize
= request
.qf_entry
.user_q
.f_use
;
379 if ( *dfree
< *dsize
)
384 *bsize
= 4096 ; /* Cray blocksize */
391 #elif defined(SUNOS5) || defined(SUNOS4)
394 #include <sys/param.h>
396 #include <sys/fs/ufs_quota.h>
397 #include <sys/mnttab.h>
398 #include <sys/mntent.h>
399 #else /* defined(SUNOS4) */
400 #include <ufs/quota.h>
406 /****************************************************************************
407 Allows querying of remote hosts for quotas on NFS mounted shares.
408 Supports normal NFS and AMD mounts.
409 Alan Romeril <a.romeril@ic.ac.uk> July 2K.
410 ****************************************************************************/
413 #include <rpc/types.h>
414 #include <rpcsvc/rquota.h>
415 #include <rpc/nettype.h>
418 static int quotastat
;
420 static int my_xdr_getquota_args(XDR
*xdrsp
, struct getquota_args
*args
)
422 if (!xdr_string(xdrsp
, &args
->gqa_pathp
, RQ_PATHLEN
))
424 if (!xdr_int(xdrsp
, &args
->gqa_uid
))
429 static int my_xdr_getquota_rslt(XDR
*xdrsp
, struct getquota_rslt
*gqr
)
431 if (!xdr_int(xdrsp
, "astat
)) {
432 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
435 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bsize
)) {
436 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
439 if (!xdr_bool(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_active
)) {
440 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
443 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
)) {
444 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
447 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
)) {
448 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
451 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_curblocks
)) {
452 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
458 /* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
459 static BOOL
nfs_quotas(char *nfspath
, uid_t euser_id
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
461 uid_t uid
= euser_id
;
463 char *mnttype
= nfspath
;
465 struct getquota_rslt gqr
;
466 struct getquota_args args
;
467 char *cutstr
, *pathname
, *host
, *testpath
;
469 static struct timeval timeout
= {2,0};
470 enum clnt_stat clnt_stat
;
473 *bsize
= *dfree
= *dsize
= (SMB_BIG_UINT
)0;
475 len
=strcspn(mnttype
, ":");
476 pathname
=strstr(mnttype
, ":");
477 cutstr
= (char *) SMB_MALLOC(len
+1);
481 memset(cutstr
, '\0', len
+1);
482 host
= strncat(cutstr
,mnttype
, sizeof(char) * len
);
483 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr
));
484 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype
));
485 testpath
=strchr_m(mnttype
, ':');
486 args
.gqa_pathp
= testpath
+1;
489 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host
, RQUOTAPROG
, RQUOTAVERS
, "udp"));
491 if ((clnt
= clnt_create(host
, RQUOTAPROG
, RQUOTAVERS
, "udp")) == NULL
) {
496 clnt
->cl_auth
= authunix_create_default();
497 DEBUG(9,("nfs_quotas: auth_success\n"));
499 clnt_stat
=clnt_call(clnt
, RQUOTAPROC_GETQUOTA
, my_xdr_getquota_args
, (caddr_t
)&args
, my_xdr_getquota_rslt
, (caddr_t
)&gqr
, timeout
);
501 if (clnt_stat
!= RPC_SUCCESS
) {
502 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
508 * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
509 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
510 * something sensible.
513 switch ( quotastat
) {
515 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat
));
520 DEBUG(9,("nfs_quotas: Good quota data\n"));
521 D
.dqb_bsoftlimit
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
;
522 D
.dqb_bhardlimit
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
;
523 D
.dqb_curblocks
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_curblocks
;
528 D
.dqb_bsoftlimit
= 1;
530 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat
));
534 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat
));
538 DEBUG(10,("nfs_quotas: Let`s look at D a bit closer... status \"%i\" bsize \"%i\" active? \"%i\" bhard \"%i\" bsoft \"%i\" curb \"%i\" \n",
540 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsize
,
541 gqr
.getquota_rslt_u
.gqr_rquota
.rq_active
,
542 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
,
543 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
,
544 gqr
.getquota_rslt_u
.gqr_rquota
.rq_curblocks
));
546 *bsize
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsize
;
547 *dsize
= D
.dqb_bsoftlimit
;
549 if (D
.dqb_curblocks
== D
.dqb_curblocks
== 1)
552 if (D
.dqb_curblocks
> D
.dqb_bsoftlimit
) {
554 *dsize
= D
.dqb_curblocks
;
556 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
562 auth_destroy(clnt
->cl_auth
);
566 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args
.gqa_pathp
,(double)*bsize
,(double)*dfree
,(double)*dsize
));
569 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
574 /****************************************************************************
575 try to get the disk space from disk quotas (SunOS & Solaris2 version)
576 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
577 ****************************************************************************/
579 BOOL
disk_quotas(const char *path
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
585 struct quotctl command
;
587 static struct mnttab mnt
;
594 SMB_STRUCT_STAT sbuf
;
596 static SMB_DEV_T devno_cached
= 0 ;
599 euser_id
= geteuid();
601 if ( sys_stat(path
,&sbuf
) == -1 )
604 devno
= sbuf
.st_dev
;
605 DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n",
606 path
, (unsigned int)devno
));
607 if ( devno
!= devno_cached
) {
608 devno_cached
= devno
;
610 if ((fd
= sys_fopen(MNTTAB
, "r")) == NULL
)
615 while (getmntent(fd
, &mnt
) == 0) {
616 if (sys_stat(mnt
.mnt_mountp
, &sbuf
) == -1)
619 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
620 mnt
.mnt_mountp
, (unsigned int)devno
));
622 /* quotas are only on vxfs, UFS or NFS */
623 if ( (sbuf
.st_dev
== devno
) && (
624 strcmp( mnt
.mnt_fstype
, MNTTYPE_UFS
) == 0 ||
625 strcmp( mnt
.mnt_fstype
, "nfs" ) == 0 ||
626 strcmp( mnt
.mnt_fstype
, "vxfs" ) == 0 )) {
632 pstrcpy(name
,mnt
.mnt_mountp
) ;
633 pstrcat(name
,"/quotas") ;
636 if ((fd
= setmntent(MOUNTED
, "r")) == NULL
)
640 while ((mnt
= getmntent(fd
)) != NULL
) {
641 if ( sys_stat(mnt
->mnt_dir
,&sbuf
) == -1 )
643 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n", mnt
->mnt_dir
,(unsigned int)sbuf
.st_dev
));
644 if (sbuf
.st_dev
== devno
) {
650 pstrcpy(name
,mnt
->mnt_fsname
) ;
661 if ( strcmp( mnt
.mnt_fstype
, "nfs" ) == 0) {
663 DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n", mnt
.mnt_special
));
664 retval
= nfs_quotas(mnt
.mnt_special
, euser_id
, bsize
, dfree
, dsize
);
669 DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name
));
670 if((file
=sys_open(name
, O_RDONLY
,0))<0) {
674 command
.op
= Q_GETQUOTA
;
675 command
.uid
= euser_id
;
676 command
.addr
= (caddr_t
) &D
;
677 ret
= ioctl(file
, Q_QUOTACTL
, &command
);
680 DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name
));
681 ret
= quotactl(Q_GETQUOTA
, name
, euser_id
, &D
);
687 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n", strerror(errno
) ));
689 #if defined(SUNOS5) && defined(VXFS_QUOTA)
690 /* If normal quotactl() fails, try vxfs private calls */
691 set_effective_uid(euser_id
);
692 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt
.mnt_fstype
));
693 if ( 0 == strcmp ( mnt
.mnt_fstype
, "vxfs" )) {
695 retval
= disk_quotas_vxfs(name
, path
, bsize
, dfree
, dsize
);
703 /* If softlimit is zero, set it equal to hardlimit.
706 if (D
.dqb_bsoftlimit
==0)
707 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
709 /* Use softlimit to determine disk space. A user exceeding the quota is told
710 * that there's no space left. Writes might actually work for a bit if the
711 * hardlimit is set higher than softlimit. Effectively the disk becomes
712 * made of rubber latex and begins to expand to accommodate the user :-)
715 if (D
.dqb_bsoftlimit
==0)
718 *dsize
= D
.dqb_bsoftlimit
;
720 if (D
.dqb_curblocks
> D
.dqb_bsoftlimit
) {
722 *dsize
= D
.dqb_curblocks
;
724 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
726 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
727 path
,(double)*bsize
,(double)*dfree
,(double)*dsize
));
734 #include <ufs/quota.h>
736 /****************************************************************************
737 try to get the disk space from disk quotas - OSF1 version
738 ****************************************************************************/
740 BOOL
disk_quotas(const char *path
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
748 * This code presumes that OSF1 will only
749 * give out quota info when the real uid
750 * matches the effective uid. JRA.
752 euser_id
= geteuid();
754 if (set_re_uid() != 0) return False
;
756 r
= quotactl(path
,QCMD(Q_GETQUOTA
, USRQUOTA
),euser_id
,(char *) &D
);
767 if (save_errno
== EDQUOT
) /* disk quota exceeded */
770 *dsize
= D
.dqb_curblocks
;
777 /* If softlimit is zero, set it equal to hardlimit.
780 if (D
.dqb_bsoftlimit
==0)
781 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
783 /* Use softlimit to determine disk space, except when it has been exceeded */
785 if (D
.dqb_bsoftlimit
==0)
788 if ((D
.dqb_curblocks
>D
.dqb_bsoftlimit
)) {
790 *dsize
= D
.dqb_curblocks
;
792 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
793 *dsize
= D
.dqb_bsoftlimit
;
798 #elif defined (IRIX6)
799 /****************************************************************************
800 try to get the disk space from disk quotas (IRIX 6.2 version)
801 ****************************************************************************/
803 #include <sys/quota.h>
806 BOOL
disk_quotas(const char *path
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
811 struct fs_disk_quota F
;
818 /* find the block device file */
820 if ( sys_stat(path
, &S
) == -1 ) {
826 fp
= setmntent(MOUNTED
,"r");
829 while ((mnt
= getmntent(fp
))) {
830 if ( sys_stat(mnt
->mnt_dir
,&S
) == -1 )
832 if (S
.st_dev
== devno
) {
846 /* Use softlimit to determine disk space, except when it has been exceeded */
850 if ( 0 == strcmp ( mnt
->mnt_type
, "efs" ))
852 r
=quotactl (Q_GETQUOTA
, mnt
->mnt_fsname
, euser_id
, (caddr_t
) &D
);
859 /* Use softlimit to determine disk space, except when it has been exceeded */
861 (D
.dqb_bsoftlimit
&& D
.dqb_curblocks
>=D
.dqb_bsoftlimit
) ||
862 (D
.dqb_bhardlimit
&& D
.dqb_curblocks
>=D
.dqb_bhardlimit
) ||
863 (D
.dqb_fsoftlimit
&& D
.dqb_curfiles
>=D
.dqb_fsoftlimit
) ||
864 (D
.dqb_fhardlimit
&& D
.dqb_curfiles
>=D
.dqb_fhardlimit
)
868 *dsize
= D
.dqb_curblocks
;
870 else if (D
.dqb_bsoftlimit
==0 && D
.dqb_bhardlimit
==0)
876 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
877 *dsize
= D
.dqb_bsoftlimit
;
881 else if ( 0 == strcmp ( mnt
->mnt_type
, "xfs" ))
883 r
=quotactl (Q_XGETQUOTA
, mnt
->mnt_fsname
, euser_id
, (caddr_t
) &F
);
889 DEBUG(5, ("quotactl for uid=%u: %s", euser_id
, strerror(errno
)));
893 /* No quota for this user. */
894 if (F
.d_blk_softlimit
==0 && F
.d_blk_hardlimit
==0)
899 /* Use softlimit to determine disk space, except when it has been exceeded */
901 (F
.d_blk_softlimit
&& F
.d_bcount
>=F
.d_blk_softlimit
) ||
902 (F
.d_blk_hardlimit
&& F
.d_bcount
>=F
.d_blk_hardlimit
) ||
903 (F
.d_ino_softlimit
&& F
.d_icount
>=F
.d_ino_softlimit
) ||
904 (F
.d_ino_hardlimit
&& F
.d_icount
>=F
.d_ino_hardlimit
)
912 *dfree
= (F
.d_blk_softlimit
- F
.d_bcount
);
913 *dsize
= F
.d_blk_softlimit
? F
.d_blk_softlimit
: F
.d_blk_hardlimit
;
929 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
930 #include <ufs/ufs/quota.h>
931 #include <machine/param.h>
933 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
934 #include <jfs/quota.h>
935 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
936 #define dqb_curfiles dqb_curinodes
937 #define dqb_fhardlimit dqb_ihardlimit
938 #define dqb_fsoftlimit dqb_isoftlimit
939 #ifdef _AIXVERSION_530
940 #include <sys/statfs.h>
941 #include <sys/vmount.h>
943 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
944 #include <sys/quota.h>
948 #if defined(__FreeBSD__) || defined(__DragonFly__)
951 #include <rpc/types.h>
952 #include <rpcsvc/rquota.h>
953 #ifdef HAVE_RPC_NETTYPE_H
954 #include <rpc/nettype.h>
958 static int quotastat
;
960 static int my_xdr_getquota_args(XDR
*xdrsp
, struct getquota_args
*args
)
962 if (!xdr_string(xdrsp
, &args
->gqa_pathp
, RQ_PATHLEN
))
964 if (!xdr_int(xdrsp
, &args
->gqa_uid
))
969 static int my_xdr_getquota_rslt(XDR
*xdrsp
, struct getquota_rslt
*gqr
)
971 if (!xdr_int(xdrsp
, "astat
)) {
972 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
975 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bsize
)) {
976 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
979 if (!xdr_bool(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_active
)) {
980 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
983 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
)) {
984 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
987 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
)) {
988 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
991 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_curblocks
)) {
992 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
998 /* Works on FreeBSD, too. :-) */
999 static BOOL
nfs_quotas(char *nfspath
, uid_t euser_id
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
1001 uid_t uid
= euser_id
;
1003 char *mnttype
= nfspath
;
1005 struct getquota_rslt gqr
;
1006 struct getquota_args args
;
1007 char *cutstr
, *pathname
, *host
, *testpath
;
1009 static struct timeval timeout
= {2,0};
1010 enum clnt_stat clnt_stat
;
1013 *bsize
= *dfree
= *dsize
= (SMB_BIG_UINT
)0;
1015 len
=strcspn(mnttype
, ":");
1016 pathname
=strstr(mnttype
, ":");
1017 cutstr
= (char *) SMB_MALLOC(len
+1);
1021 memset(cutstr
, '\0', len
+1);
1022 host
= strncat(cutstr
,mnttype
, sizeof(char) * len
);
1023 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr
));
1024 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype
));
1025 testpath
=strchr_m(mnttype
, ':');
1026 args
.gqa_pathp
= testpath
+1;
1029 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host
, RQUOTAPROG
, RQUOTAVERS
, "udp"));
1031 if ((clnt
= clnt_create(host
, RQUOTAPROG
, RQUOTAVERS
, "udp")) == NULL
) {
1036 clnt
->cl_auth
= authunix_create_default();
1037 DEBUG(9,("nfs_quotas: auth_success\n"));
1039 clnt_stat
=clnt_call(clnt
, RQUOTAPROC_GETQUOTA
, (const xdrproc_t
) my_xdr_getquota_args
, (caddr_t
)&args
, (const xdrproc_t
) my_xdr_getquota_rslt
, (caddr_t
)&gqr
, timeout
);
1041 if (clnt_stat
!= RPC_SUCCESS
) {
1042 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
1048 * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
1049 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
1050 * something sensible.
1053 switch ( quotastat
) {
1055 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat
));
1060 DEBUG(9,("nfs_quotas: Good quota data\n"));
1061 D
.dqb_bsoftlimit
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
;
1062 D
.dqb_bhardlimit
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
;
1063 D
.dqb_curblocks
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_curblocks
;
1068 D
.dqb_bsoftlimit
= 1;
1069 D
.dqb_curblocks
= 1;
1070 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat
));
1074 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat
));
1078 DEBUG(10,("nfs_quotas: Let`s look at D a bit closer... status \"%i\" bsize \"%i\" active? \"%i\" bhard \"%i\" bsoft \"%i\" curb \"%i\" \n",
1080 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsize
,
1081 gqr
.getquota_rslt_u
.gqr_rquota
.rq_active
,
1082 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
,
1083 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
,
1084 gqr
.getquota_rslt_u
.gqr_rquota
.rq_curblocks
));
1086 if (D
.dqb_bsoftlimit
== 0)
1087 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
1088 if (D
.dqb_bsoftlimit
== 0)
1091 *bsize
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsize
;
1092 *dsize
= D
.dqb_bsoftlimit
;
1094 if (D
.dqb_curblocks
== D
.dqb_curblocks
== 1)
1097 if (D
.dqb_curblocks
> D
.dqb_bsoftlimit
) {
1099 *dsize
= D
.dqb_curblocks
;
1101 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
1107 auth_destroy(clnt
->cl_auth
);
1111 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args
.gqa_pathp
,(double)*bsize
,(double)*dfree
,(double)*dsize
));
1114 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
1120 /****************************************************************************
1121 try to get the disk space from disk quotas - default version
1122 ****************************************************************************/
1124 BOOL
disk_quotas(const char *path
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
1129 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1133 /* find the block device file */
1136 /* Need to set the cache flag to 1 for HPUX. Seems
1137 * to have a significant performance boost when
1138 * lstat calls on /dev access this function.
1140 if ((sys_stat(path
, &S
)<0) || (devnm(S_IFBLK
, S
.st_dev
, dev_disk
, 256, 1)<0))
1142 if ((sys_stat(path
, &S
)<0) || (devnm(S_IFBLK
, S
.st_dev
, dev_disk
, 256, 0)<0))
1144 #endif /* ifdef HPUX */
1146 #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__) */
1148 euser_id
= geteuid();
1151 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
1153 if (set_re_uid() != 0) return False
;
1155 r
=quotactl(Q_GETQUOTA
, dev_disk
, euser_id
, &D
);
1159 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1161 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
1163 #if defined(__FreeBSD__) || defined(__DragonFly__)
1165 struct statfs
*mnts
;
1169 if (sys_stat(path
,&st
) < 0)
1173 mntsize
= getmntinfo(&mnts
,MNT_NOWAIT
);
1177 for (i
= 0; i
< mntsize
; i
++) {
1178 if (sys_stat(mnts
[i
].f_mntonname
,&st
) < 0)
1180 if (st
.st_dev
== devno
)
1189 #if defined(__FreeBSD__) || defined(__DragonFly__)
1190 if (strcmp(mnts
[i
].f_fstypename
,"nfs") == 0) {
1192 retval
= nfs_quotas(mnts
[i
].f_mntfromname
,euser_id
,bsize
,dfree
,dsize
);
1198 egrp_id
= getegid();
1199 r
= quotactl(path
,QCMD(Q_GETQUOTA
,USRQUOTA
),euser_id
,(char *) &D
);
1201 /* As FreeBSD has group quotas, if getting the user
1202 quota fails, try getting the group instead. */
1204 r
= quotactl(path
,QCMD(Q_GETQUOTA
,GRPQUOTA
),egrp_id
,(char *) &D
);
1210 /* AIX has both USER and GROUP quotas:
1211 Get the USER quota (ohnielse@fysik.dtu.dk) */
1212 #ifdef _AIXVERSION_530
1214 struct statfs statbuf
;
1215 quota64_t user_quota
;
1216 if (statfs(path
,&statbuf
) != 0)
1218 if(statbuf
.f_vfstype
== MNT_J2
)
1220 /* For some reason we need to be root for jfs2 */
1222 r
= quotactl(path
,QCMD(Q_J2GETQUOTA
,USRQUOTA
),euser_id
,(char *) &user_quota
);
1224 /* Copy results to old struct to let the following code work as before */
1225 D
.dqb_curblocks
= user_quota
.bused
;
1226 D
.dqb_bsoftlimit
= user_quota
.bsoft
;
1227 D
.dqb_bhardlimit
= user_quota
.bhard
;
1229 else if(statbuf
.f_vfstype
== MNT_JFS
)
1231 #endif /* AIX 5.3 */
1233 if (set_re_uid() != 0)
1235 r
= quotactl(path
,QCMD(Q_GETQUOTA
,USRQUOTA
),euser_id
,(char *) &D
);
1237 #ifdef _AIXVERSION_530
1240 r
= 1; /* Fail for other FS-types */
1242 #endif /* AIX 5.3 */
1243 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1244 r
=quotactl(Q_GETQUOTA
, dev_disk
, euser_id
, &D
);
1245 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1248 /* Use softlimit to determine disk space, except when it has been exceeded */
1249 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1251 #else /* !__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1253 #endif /*!__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1257 if (errno
== EDQUOT
)
1260 *dsize
=D
.dqb_curblocks
;
1266 /* If softlimit is zero, set it equal to hardlimit.
1269 if (D
.dqb_bsoftlimit
==0)
1270 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
1272 if (D
.dqb_bsoftlimit
==0)
1274 /* Use softlimit to determine disk space, except when it has been exceeded */
1275 if ((D
.dqb_curblocks
>D
.dqb_bsoftlimit
)
1276 #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1277 ||((D
.dqb_curfiles
>D
.dqb_fsoftlimit
) && (D
.dqb_fsoftlimit
!= 0))
1281 *dsize
= D
.dqb_curblocks
;
1284 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
1285 *dsize
= D
.dqb_bsoftlimit
;
1292 #if defined(VXFS_QUOTA)
1294 /****************************************************************************
1295 Try to get the disk space from Veritas disk quotas.
1296 David Lee <T.D.Lee@durham.ac.uk> August 1999.
1298 Background assumptions:
1299 Potentially under many Operating Systems. Initially Solaris 2.
1301 My guess is that Veritas is largely, though not entirely,
1302 independent of OS. So I have separated it out.
1304 There may be some details. For example, OS-specific "include" files.
1306 It is understood that HPUX 10 somehow gets Veritas quotas without
1307 any special effort; if so, this routine need not be compiled in.
1308 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1311 It is understood that Veritas do not publicly support this ioctl interface.
1312 Rather their preference would be for the user (us) to call the native
1313 OS and then for the OS itself to call through to the VxFS filesystem.
1314 Presumably HPUX 10, see above, does this.
1317 Add your OS to "IFLIST" below.
1318 Get it to compile successfully:
1319 Almost certainly "include"s require attention: see SUNOS5.
1320 In the main code above, arrange for it to be called: see SUNOS5.
1323 ****************************************************************************/
1326 * This "if" is a list of ports:
1327 * if defined(OS1) || defined(OS2) || ...
1332 #include <sys/fs/vx_solaris.h>
1334 #include <sys/fs/vx_machdep.h>
1335 #include <sys/fs/vx_layout.h>
1336 #include <sys/fs/vx_quota.h>
1337 #include <sys/fs/vx_aioctl.h>
1338 #include <sys/fs/vx_ioctl.h>
1340 BOOL
disk_quotas_vxfs(const pstring name
, char *path
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
1342 uid_t user_id
, euser_id
;
1345 struct vx_quotctl quotabuf
;
1346 struct vx_genioctl genbuf
;
1351 * "name" may or may not include a trailing "/quotas".
1352 * Arranging consistency of calling here in "quotas.c" may not be easy and
1353 * it might be easier to examine and adjust it here.
1354 * Fortunately, VxFS seems not to mind at present.
1356 pstrcpy(qfname
, name
) ;
1357 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
1359 euser_id
= geteuid();
1360 set_effective_uid(0);
1362 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname
));
1363 if((file
=sys_open(qfname
, O_RDONLY
,0))<0) {
1364 set_effective_uid(euser_id
);
1367 genbuf
.ioc_cmd
= VX_QUOTACTL
;
1368 genbuf
.ioc_up
= (void *) "abuf
;
1370 quotabuf
.cmd
= VX_GETQUOTA
;
1371 quotabuf
.uid
= euser_id
;
1372 quotabuf
.addr
= (caddr_t
) &D
;
1373 ret
= ioctl(file
, VX_ADMIN_IOCTL
, &genbuf
);
1376 set_effective_uid(euser_id
);
1379 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno
) ));
1383 /* If softlimit is zero, set it equal to hardlimit.
1386 if (D
.dqb_bsoftlimit
==0)
1387 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
1389 /* Use softlimit to determine disk space. A user exceeding the quota is told
1390 * that there's no space left. Writes might actually work for a bit if the
1391 * hardlimit is set higher than softlimit. Effectively the disk becomes
1392 * made of rubber latex and begins to expand to accommodate the user :-)
1394 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1395 path
, D
.dqb_curblocks
, D
.dqb_bsoftlimit
, D
.dqb_bhardlimit
,
1396 D
.dqb_curfiles
, D
.dqb_fsoftlimit
, D
.dqb_fhardlimit
));
1398 if (D
.dqb_bsoftlimit
==0)
1401 *dsize
= D
.dqb_bsoftlimit
;
1403 if (D
.dqb_curblocks
> D
.dqb_bsoftlimit
) {
1405 *dsize
= D
.dqb_curblocks
;
1407 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
1409 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
1410 path
,(double)*bsize
,(double)*dfree
,(double)*dsize
));
1415 #endif /* SUNOS5 || ... */
1417 #endif /* VXFS_QUOTA */
1419 #else /* WITH_QUOTAS */
1421 BOOL
disk_quotas(const char *path
,SMB_BIG_UINT
*bsize
,SMB_BIG_UINT
*dfree
,SMB_BIG_UINT
*dsize
)
1423 (*bsize
) = 512; /* This value should be ignored */
1425 /* And just to be sure we set some values that hopefully */
1426 /* will be larger that any possible real-world value */
1427 (*dfree
) = (SMB_BIG_UINT
)-1;
1428 (*dsize
) = (SMB_BIG_UINT
)-1;
1430 /* As we have select not to use quotas, allways fail */
1433 #endif /* WITH_QUOTAS */
1435 #else /* HAVE_SYS_QUOTAS */
1436 /* wrapper to the new sys_quota interface
1437 this file should be removed later
1439 BOOL
disk_quotas(const char *path
,SMB_BIG_UINT
*bsize
,SMB_BIG_UINT
*dfree
,SMB_BIG_UINT
*dsize
)
1448 r
=sys_get_quota(path
, SMB_USER_QUOTA_TYPE
, id
, &D
);
1450 /* Use softlimit to determine disk space, except when it has been exceeded */
1453 if (errno
== EDQUOT
) {
1455 *dsize
=D
.curblocks
;
1458 goto try_group_quota
;
1462 /* Use softlimit to determine disk space, except when it has been exceeded */
1464 (D
.softlimit
&& D
.curblocks
>= D
.softlimit
) ||
1465 (D
.hardlimit
&& D
.curblocks
>= D
.hardlimit
) ||
1466 (D
.isoftlimit
&& D
.curinodes
>= D
.isoftlimit
) ||
1467 (D
.ihardlimit
&& D
.curinodes
>=D
.ihardlimit
)
1470 *dsize
= D
.curblocks
;
1471 } else if (D
.softlimit
==0 && D
.hardlimit
==0) {
1472 goto try_group_quota
;
1474 if (D
.softlimit
== 0)
1475 D
.softlimit
= D
.hardlimit
;
1476 *dfree
= D
.softlimit
- D
.curblocks
;
1477 *dsize
= D
.softlimit
;
1486 r
=sys_get_quota(path
, SMB_GROUP_QUOTA_TYPE
, id
, &D
);
1488 /* Use softlimit to determine disk space, except when it has been exceeded */
1491 if (errno
== EDQUOT
) {
1493 *dsize
=D
.curblocks
;
1500 /* Use softlimit to determine disk space, except when it has been exceeded */
1502 (D
.softlimit
&& D
.curblocks
>= D
.softlimit
) ||
1503 (D
.hardlimit
&& D
.curblocks
>= D
.hardlimit
) ||
1504 (D
.isoftlimit
&& D
.curinodes
>= D
.isoftlimit
) ||
1505 (D
.ihardlimit
&& D
.curinodes
>=D
.ihardlimit
)
1508 *dsize
= D
.curblocks
;
1509 } else if (D
.softlimit
==0 && D
.hardlimit
==0) {
1512 if (D
.softlimit
== 0)
1513 D
.softlimit
= D
.hardlimit
;
1514 *dfree
= D
.softlimit
- D
.curblocks
;
1515 *dsize
= D
.softlimit
;
1520 #endif /* HAVE_SYS_QUOTAS */