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
;
209 euser_id
= geteuid();
212 /* find the block device file */
214 if ( sys_stat(path
, &S
) == -1 )
219 fp
= setmntent(MOUNTED
,"r");
222 while ((mnt
= getmntent(fp
))) {
223 if ( sys_stat(mnt
->mnt_dir
,&S
) == -1 )
226 if (S
.st_dev
== devno
) {
238 set_effective_uid(0);
240 if (strcmp(mnt
->mnt_type
, "xfs")==0) {
241 r
=get_smb_linux_xfs_quota(mnt
->mnt_fsname
, euser_id
, egrp_id
, &D
);
243 r
=get_smb_linux_gen_quota(mnt
->mnt_fsname
, euser_id
, egrp_id
, &D
);
244 if (r
== -1 && errno
!= EDQUOT
) {
245 r
=get_smb_linux_v2_quota(mnt
->mnt_fsname
, euser_id
, egrp_id
, &D
);
246 if (r
== -1 && errno
!= EDQUOT
)
247 r
=get_smb_linux_v1_quota(mnt
->mnt_fsname
, euser_id
, egrp_id
, &D
);
253 /* Use softlimit to determine disk space, except when it has been exceeded */
256 if (errno
== EDQUOT
) {
265 /* Use softlimit to determine disk space, except when it has been exceeded */
267 (D
.softlimit
&& D
.curblocks
>= D
.softlimit
) ||
268 (D
.hardlimit
&& D
.curblocks
>= D
.hardlimit
) ||
269 (D
.isoftlimit
&& D
.curinodes
>= D
.isoftlimit
) ||
270 (D
.ihardlimit
&& D
.curinodes
>=D
.ihardlimit
)
273 *dsize
= D
.curblocks
;
274 } else if (D
.softlimit
==0 && D
.hardlimit
==0) {
277 if (D
.softlimit
== 0)
278 D
.softlimit
= D
.hardlimit
;
279 *dfree
= D
.softlimit
- D
.curblocks
;
280 *dsize
= D
.softlimit
;
288 #include <sys/quota.h>
291 /****************************************************************************
292 try to get the disk space from disk quotas (CRAY VERSION)
293 ****************************************************************************/
295 BOOL
disk_quotas(const char *path
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
299 SMB_STRUCT_STAT sbuf
;
301 static SMB_DEV_T devno_cached
= 0 ;
303 struct q_request request
;
304 struct qf_header header
;
305 static int quota_default
= 0 ;
308 if ( sys_stat(path
,&sbuf
) == -1 )
311 devno
= sbuf
.st_dev
;
313 if ( devno
!= devno_cached
) {
315 devno_cached
= devno
;
317 if ((fd
= setmntent(KMTAB
)) == NULL
)
322 while ((mnt
= getmntent(fd
)) != NULL
) {
324 if ( sys_stat(mnt
->mnt_dir
,&sbuf
) == -1 )
327 if (sbuf
.st_dev
== devno
) {
336 pstrcpy(name
,mnt
->mnt_dir
) ;
343 request
.qf_magic
= QF_MAGIC
;
344 request
.qf_entry
.id
= geteuid() ;
346 if (quotactl(name
, Q_GETQUOTA
, &request
) == -1)
349 if ( ! request
.user
)
352 if ( request
.qf_entry
.user_q
.f_quota
== QFV_DEFAULT
) {
354 if ( ! quota_default
) {
356 if ( quotactl(name
, Q_GETHEADER
, &header
) == -1 )
359 quota_default
= header
.user_h
.def_fq
;
362 *dfree
= quota_default
;
364 }else if ( request
.qf_entry
.user_q
.f_quota
== QFV_PREVENT
) {
370 *dfree
= request
.qf_entry
.user_q
.f_quota
;
374 *dsize
= request
.qf_entry
.user_q
.f_use
;
376 if ( *dfree
< *dsize
)
381 *bsize
= 4096 ; /* Cray blocksize */
388 #elif defined(SUNOS5) || defined(SUNOS4)
391 #include <sys/param.h>
393 #include <sys/fs/ufs_quota.h>
394 #include <sys/mnttab.h>
395 #include <sys/mntent.h>
396 #else /* defined(SUNOS4) */
397 #include <ufs/quota.h>
403 /****************************************************************************
404 Allows querying of remote hosts for quotas on NFS mounted shares.
405 Supports normal NFS and AMD mounts.
406 Alan Romeril <a.romeril@ic.ac.uk> July 2K.
407 ****************************************************************************/
410 #include <rpc/types.h>
411 #include <rpcsvc/rquota.h>
412 #include <rpc/nettype.h>
415 static int quotastat
;
417 static int my_xdr_getquota_args(XDR
*xdrsp
, struct getquota_args
*args
)
419 if (!xdr_string(xdrsp
, &args
->gqa_pathp
, RQ_PATHLEN
))
421 if (!xdr_int(xdrsp
, &args
->gqa_uid
))
426 static int my_xdr_getquota_rslt(XDR
*xdrsp
, struct getquota_rslt
*gqr
)
428 if (!xdr_int(xdrsp
, "astat
)) {
429 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
432 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bsize
)) {
433 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
436 if (!xdr_bool(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_active
)) {
437 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
440 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
)) {
441 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
444 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
)) {
445 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
448 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_curblocks
)) {
449 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
455 /* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
456 static BOOL
nfs_quotas(char *nfspath
, uid_t euser_id
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
458 uid_t uid
= euser_id
;
460 char *mnttype
= nfspath
;
462 struct getquota_rslt gqr
;
463 struct getquota_args args
;
464 char *cutstr
, *pathname
, *host
, *testpath
;
466 static struct timeval timeout
= {2,0};
467 enum clnt_stat clnt_stat
;
470 *bsize
= *dfree
= *dsize
= (SMB_BIG_UINT
)0;
472 len
=strcspn(mnttype
, ":");
473 pathname
=strstr(mnttype
, ":");
474 cutstr
= (char *) SMB_MALLOC(len
+1);
478 memset(cutstr
, '\0', len
+1);
479 host
= strncat(cutstr
,mnttype
, sizeof(char) * len
);
480 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr
));
481 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype
));
482 testpath
=strchr_m(mnttype
, ':');
483 args
.gqa_pathp
= testpath
+1;
486 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host
, RQUOTAPROG
, RQUOTAVERS
, "udp"));
488 if ((clnt
= clnt_create(host
, RQUOTAPROG
, RQUOTAVERS
, "udp")) == NULL
) {
493 clnt
->cl_auth
= authunix_create_default();
494 DEBUG(9,("nfs_quotas: auth_success\n"));
496 clnt_stat
=clnt_call(clnt
, RQUOTAPROC_GETQUOTA
, my_xdr_getquota_args
, (caddr_t
)&args
, my_xdr_getquota_rslt
, (caddr_t
)&gqr
, timeout
);
498 if (clnt_stat
!= RPC_SUCCESS
) {
499 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
505 * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
506 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
507 * something sensible.
510 switch ( quotastat
) {
512 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat
));
517 DEBUG(9,("nfs_quotas: Good quota data\n"));
518 D
.dqb_bsoftlimit
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
;
519 D
.dqb_bhardlimit
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
;
520 D
.dqb_curblocks
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_curblocks
;
525 D
.dqb_bsoftlimit
= 1;
527 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat
));
531 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat
));
535 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",
537 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsize
,
538 gqr
.getquota_rslt_u
.gqr_rquota
.rq_active
,
539 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
,
540 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
,
541 gqr
.getquota_rslt_u
.gqr_rquota
.rq_curblocks
));
543 *bsize
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsize
;
544 *dsize
= D
.dqb_bsoftlimit
;
546 if (D
.dqb_curblocks
== D
.dqb_curblocks
== 1)
549 if (D
.dqb_curblocks
> D
.dqb_bsoftlimit
) {
551 *dsize
= D
.dqb_curblocks
;
553 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
559 auth_destroy(clnt
->cl_auth
);
563 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args
.gqa_pathp
,(double)*bsize
,(double)*dfree
,(double)*dsize
));
566 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
571 /****************************************************************************
572 try to get the disk space from disk quotas (SunOS & Solaris2 version)
573 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
574 ****************************************************************************/
576 BOOL
disk_quotas(const char *path
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
582 struct quotctl command
;
584 static struct mnttab mnt
;
592 SMB_STRUCT_STAT sbuf
;
594 static SMB_DEV_T devno_cached
= 0 ;
597 euser_id
= geteuid();
599 if ( sys_stat(path
,&sbuf
) == -1 )
602 devno
= sbuf
.st_dev
;
603 DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n", path
,(unsigned int)devno
));
604 if ( devno
!= devno_cached
) {
605 devno_cached
= devno
;
607 if ((fd
= sys_fopen(MNTTAB
, "r")) == NULL
)
611 slprintf(devopt
, sizeof(devopt
) - 1, "dev=%x", (unsigned int)devno
);
612 while (getmntent(fd
, &mnt
) == 0) {
613 if( !hasmntopt(&mnt
, devopt
) )
616 DEBUG(5,("disk_quotas: testing \"%s\" %s\n", mnt
.mnt_mountp
,devopt
));
618 /* quotas are only on vxfs, UFS or NFS */
619 if ( strcmp( mnt
.mnt_fstype
, MNTTYPE_UFS
) == 0 ||
620 strcmp( mnt
.mnt_fstype
, "nfs" ) == 0 ||
621 strcmp( mnt
.mnt_fstype
, "vxfs" ) == 0 ) {
627 pstrcpy(name
,mnt
.mnt_mountp
) ;
628 pstrcat(name
,"/quotas") ;
631 if ((fd
= setmntent(MOUNTED
, "r")) == NULL
)
635 while ((mnt
= getmntent(fd
)) != NULL
) {
636 if ( sys_stat(mnt
->mnt_dir
,&sbuf
) == -1 )
638 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n", mnt
->mnt_dir
,(unsigned int)sbuf
.st_dev
));
639 if (sbuf
.st_dev
== devno
) {
645 pstrcpy(name
,mnt
->mnt_fsname
) ;
654 set_effective_uid(0);
657 if ( strcmp( mnt
.mnt_fstype
, "nfs" ) == 0) {
659 DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n", mnt
.mnt_special
));
660 retval
= nfs_quotas(mnt
.mnt_special
, euser_id
, bsize
, dfree
, dsize
);
665 DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name
));
666 if((file
=sys_open(name
, O_RDONLY
,0))<0) {
670 command
.op
= Q_GETQUOTA
;
671 command
.uid
= euser_id
;
672 command
.addr
= (caddr_t
) &D
;
673 ret
= ioctl(file
, Q_QUOTACTL
, &command
);
676 DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name
));
677 ret
= quotactl(Q_GETQUOTA
, name
, euser_id
, &D
);
683 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n", strerror(errno
) ));
685 #if defined(SUNOS5) && defined(VXFS_QUOTA)
686 /* If normal quotactl() fails, try vxfs private calls */
687 set_effective_uid(euser_id
);
688 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt
.mnt_fstype
));
689 if ( 0 == strcmp ( mnt
.mnt_fstype
, "vxfs" )) {
691 retval
= disk_quotas_vxfs(name
, path
, bsize
, dfree
, dsize
);
699 /* If softlimit is zero, set it equal to hardlimit.
702 if (D
.dqb_bsoftlimit
==0)
703 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
705 /* Use softlimit to determine disk space. A user exceeding the quota is told
706 * that there's no space left. Writes might actually work for a bit if the
707 * hardlimit is set higher than softlimit. Effectively the disk becomes
708 * made of rubber latex and begins to expand to accommodate the user :-)
711 if (D
.dqb_bsoftlimit
==0)
714 *dsize
= D
.dqb_bsoftlimit
;
716 if (D
.dqb_curblocks
> D
.dqb_bsoftlimit
) {
718 *dsize
= D
.dqb_curblocks
;
720 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
722 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
723 path
,(double)*bsize
,(double)*dfree
,(double)*dsize
));
730 #include <ufs/quota.h>
732 /****************************************************************************
733 try to get the disk space from disk quotas - OSF1 version
734 ****************************************************************************/
736 BOOL
disk_quotas(const char *path
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
744 * This code presumes that OSF1 will only
745 * give out quota info when the real uid
746 * matches the effective uid. JRA.
748 euser_id
= geteuid();
750 if (set_re_uid() != 0) return False
;
752 r
= quotactl(path
,QCMD(Q_GETQUOTA
, USRQUOTA
),euser_id
,(char *) &D
);
763 if (save_errno
== EDQUOT
) /* disk quota exceeded */
766 *dsize
= D
.dqb_curblocks
;
773 /* If softlimit is zero, set it equal to hardlimit.
776 if (D
.dqb_bsoftlimit
==0)
777 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
779 /* Use softlimit to determine disk space, except when it has been exceeded */
781 if (D
.dqb_bsoftlimit
==0)
784 if ((D
.dqb_curblocks
>D
.dqb_bsoftlimit
)) {
786 *dsize
= D
.dqb_curblocks
;
788 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
789 *dsize
= D
.dqb_bsoftlimit
;
794 #elif defined (IRIX6)
795 /****************************************************************************
796 try to get the disk space from disk quotas (IRIX 6.2 version)
797 ****************************************************************************/
799 #include <sys/quota.h>
802 BOOL
disk_quotas(const char *path
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
807 struct fs_disk_quota F
;
814 /* find the block device file */
816 if ( sys_stat(path
, &S
) == -1 ) {
822 fp
= setmntent(MOUNTED
,"r");
825 while ((mnt
= getmntent(fp
))) {
826 if ( sys_stat(mnt
->mnt_dir
,&S
) == -1 )
828 if (S
.st_dev
== devno
) {
841 set_effective_uid(0);
843 /* Use softlimit to determine disk space, except when it has been exceeded */
847 if ( 0 == strcmp ( mnt
->mnt_type
, "efs" ))
849 r
=quotactl (Q_GETQUOTA
, mnt
->mnt_fsname
, euser_id
, (caddr_t
) &D
);
856 /* Use softlimit to determine disk space, except when it has been exceeded */
858 (D
.dqb_bsoftlimit
&& D
.dqb_curblocks
>=D
.dqb_bsoftlimit
) ||
859 (D
.dqb_bhardlimit
&& D
.dqb_curblocks
>=D
.dqb_bhardlimit
) ||
860 (D
.dqb_fsoftlimit
&& D
.dqb_curfiles
>=D
.dqb_fsoftlimit
) ||
861 (D
.dqb_fhardlimit
&& D
.dqb_curfiles
>=D
.dqb_fhardlimit
)
865 *dsize
= D
.dqb_curblocks
;
867 else if (D
.dqb_bsoftlimit
==0 && D
.dqb_bhardlimit
==0)
873 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
874 *dsize
= D
.dqb_bsoftlimit
;
878 else if ( 0 == strcmp ( mnt
->mnt_type
, "xfs" ))
880 r
=quotactl (Q_XGETQUOTA
, mnt
->mnt_fsname
, euser_id
, (caddr_t
) &F
);
886 DEBUG(5, ("quotactl for uid=%u: %s", euser_id
, strerror(errno
)));
890 /* No quota for this user. */
891 if (F
.d_blk_softlimit
==0 && F
.d_blk_hardlimit
==0)
896 /* Use softlimit to determine disk space, except when it has been exceeded */
898 (F
.d_blk_softlimit
&& F
.d_bcount
>=F
.d_blk_softlimit
) ||
899 (F
.d_blk_hardlimit
&& F
.d_bcount
>=F
.d_blk_hardlimit
) ||
900 (F
.d_ino_softlimit
&& F
.d_icount
>=F
.d_ino_softlimit
) ||
901 (F
.d_ino_hardlimit
&& F
.d_icount
>=F
.d_ino_hardlimit
)
909 *dfree
= (F
.d_blk_softlimit
- F
.d_bcount
);
910 *dsize
= F
.d_blk_softlimit
? F
.d_blk_softlimit
: F
.d_blk_hardlimit
;
926 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
927 #include <ufs/ufs/quota.h>
928 #include <machine/param.h>
930 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
931 #include <jfs/quota.h>
932 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
933 #define dqb_curfiles dqb_curinodes
934 #define dqb_fhardlimit dqb_ihardlimit
935 #define dqb_fsoftlimit dqb_isoftlimit
936 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
937 #include <sys/quota.h>
941 #if defined(__FreeBSD__) || defined(__DragonFly__)
944 #include <rpc/types.h>
945 #include <rpcsvc/rquota.h>
946 #ifdef HAVE_RPC_NETTYPE_H
947 #include <rpc/nettype.h>
951 static int quotastat
;
953 static int my_xdr_getquota_args(XDR
*xdrsp
, struct getquota_args
*args
)
955 if (!xdr_string(xdrsp
, &args
->gqa_pathp
, RQ_PATHLEN
))
957 if (!xdr_int(xdrsp
, &args
->gqa_uid
))
962 static int my_xdr_getquota_rslt(XDR
*xdrsp
, struct getquota_rslt
*gqr
)
964 if (!xdr_int(xdrsp
, "astat
)) {
965 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
968 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bsize
)) {
969 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
972 if (!xdr_bool(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_active
)) {
973 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
976 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
)) {
977 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
980 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
)) {
981 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
984 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_curblocks
)) {
985 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
991 /* Works on FreeBSD, too. :-) */
992 static BOOL
nfs_quotas(char *nfspath
, uid_t euser_id
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
994 uid_t uid
= euser_id
;
996 char *mnttype
= nfspath
;
998 struct getquota_rslt gqr
;
999 struct getquota_args args
;
1000 char *cutstr
, *pathname
, *host
, *testpath
;
1002 static struct timeval timeout
= {2,0};
1003 enum clnt_stat clnt_stat
;
1006 *bsize
= *dfree
= *dsize
= (SMB_BIG_UINT
)0;
1008 len
=strcspn(mnttype
, ":");
1009 pathname
=strstr(mnttype
, ":");
1010 cutstr
= (char *) SMB_MALLOC(len
+1);
1014 memset(cutstr
, '\0', len
+1);
1015 host
= strncat(cutstr
,mnttype
, sizeof(char) * len
);
1016 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr
));
1017 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype
));
1018 testpath
=strchr_m(mnttype
, ':');
1019 args
.gqa_pathp
= testpath
+1;
1022 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host
, RQUOTAPROG
, RQUOTAVERS
, "udp"));
1024 if ((clnt
= clnt_create(host
, RQUOTAPROG
, RQUOTAVERS
, "udp")) == NULL
) {
1029 clnt
->cl_auth
= authunix_create_default();
1030 DEBUG(9,("nfs_quotas: auth_success\n"));
1032 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
);
1034 if (clnt_stat
!= RPC_SUCCESS
) {
1035 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
1041 * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
1042 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
1043 * something sensible.
1046 switch ( quotastat
) {
1048 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat
));
1053 DEBUG(9,("nfs_quotas: Good quota data\n"));
1054 D
.dqb_bsoftlimit
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
;
1055 D
.dqb_bhardlimit
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
;
1056 D
.dqb_curblocks
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_curblocks
;
1061 D
.dqb_bsoftlimit
= 1;
1062 D
.dqb_curblocks
= 1;
1063 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat
));
1067 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat
));
1071 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",
1073 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsize
,
1074 gqr
.getquota_rslt_u
.gqr_rquota
.rq_active
,
1075 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
,
1076 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
,
1077 gqr
.getquota_rslt_u
.gqr_rquota
.rq_curblocks
));
1079 if (D
.dqb_bsoftlimit
== 0)
1080 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
1081 if (D
.dqb_bsoftlimit
== 0)
1084 *bsize
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsize
;
1085 *dsize
= D
.dqb_bsoftlimit
;
1087 if (D
.dqb_curblocks
== D
.dqb_curblocks
== 1)
1090 if (D
.dqb_curblocks
> D
.dqb_bsoftlimit
) {
1092 *dsize
= D
.dqb_curblocks
;
1094 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
1100 auth_destroy(clnt
->cl_auth
);
1104 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args
.gqa_pathp
,(double)*bsize
,(double)*dfree
,(double)*dsize
));
1107 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
1113 /****************************************************************************
1114 try to get the disk space from disk quotas - default version
1115 ****************************************************************************/
1117 BOOL
disk_quotas(const char *path
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
1122 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1126 /* find the block device file */
1129 /* Need to set the cache flag to 1 for HPUX. Seems
1130 * to have a significant performance boost when
1131 * lstat calls on /dev access this function.
1133 if ((sys_stat(path
, &S
)<0) || (devnm(S_IFBLK
, S
.st_dev
, dev_disk
, 256, 1)<0))
1135 if ((sys_stat(path
, &S
)<0) || (devnm(S_IFBLK
, S
.st_dev
, dev_disk
, 256, 0)<0))
1137 #endif /* ifdef HPUX */
1139 #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__) */
1141 euser_id
= geteuid();
1144 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
1146 if (set_re_uid() != 0) return False
;
1148 r
=quotactl(Q_GETQUOTA
, dev_disk
, euser_id
, &D
);
1152 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1154 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
1156 #if defined(__FreeBSD__) || defined(__DragonFly__)
1158 struct statfs
*mnts
;
1162 if (sys_stat(path
,&st
) < 0)
1166 mntsize
= getmntinfo(&mnts
,MNT_NOWAIT
);
1170 for (i
= 0; i
< mntsize
; i
++) {
1171 if (sys_stat(mnts
[i
].f_mntonname
,&st
) < 0)
1173 if (st
.st_dev
== devno
)
1181 set_effective_uid(0);
1183 #if defined(__FreeBSD__) || defined(__DragonFly__)
1184 if (strcmp(mnts
[i
].f_fstypename
,"nfs") == 0) {
1186 retval
= nfs_quotas(mnts
[i
].f_mntfromname
,euser_id
,bsize
,dfree
,dsize
);
1192 egrp_id
= getegid();
1193 r
= quotactl(path
,QCMD(Q_GETQUOTA
,USRQUOTA
),euser_id
,(char *) &D
);
1195 /* As FreeBSD has group quotas, if getting the user
1196 quota fails, try getting the group instead. */
1198 r
= quotactl(path
,QCMD(Q_GETQUOTA
,GRPQUOTA
),egrp_id
,(char *) &D
);
1204 /* AIX has both USER and GROUP quotas:
1205 Get the USER quota (ohnielse@fysik.dtu.dk) */
1207 if (set_re_uid() != 0)
1209 r
= quotactl(path
,QCMD(Q_GETQUOTA
,USRQUOTA
),euser_id
,(char *) &D
);
1211 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1212 r
=quotactl(Q_GETQUOTA
, dev_disk
, euser_id
, &D
);
1213 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1216 /* Use softlimit to determine disk space, except when it has been exceeded */
1217 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1219 #else /* !__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1221 #endif /*!__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1225 if (errno
== EDQUOT
)
1228 *dsize
=D
.dqb_curblocks
;
1234 /* If softlimit is zero, set it equal to hardlimit.
1237 if (D
.dqb_bsoftlimit
==0)
1238 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
1240 if (D
.dqb_bsoftlimit
==0)
1242 /* Use softlimit to determine disk space, except when it has been exceeded */
1243 if ((D
.dqb_curblocks
>D
.dqb_bsoftlimit
)
1244 #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1245 ||((D
.dqb_curfiles
>D
.dqb_fsoftlimit
) && (D
.dqb_fsoftlimit
!= 0))
1249 *dsize
= D
.dqb_curblocks
;
1252 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
1253 *dsize
= D
.dqb_bsoftlimit
;
1260 #if defined(VXFS_QUOTA)
1262 /****************************************************************************
1263 Try to get the disk space from Veritas disk quotas.
1264 David Lee <T.D.Lee@durham.ac.uk> August 1999.
1266 Background assumptions:
1267 Potentially under many Operating Systems. Initially Solaris 2.
1269 My guess is that Veritas is largely, though not entirely,
1270 independent of OS. So I have separated it out.
1272 There may be some details. For example, OS-specific "include" files.
1274 It is understood that HPUX 10 somehow gets Veritas quotas without
1275 any special effort; if so, this routine need not be compiled in.
1276 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1279 It is understood that Veritas do not publicly support this ioctl interface.
1280 Rather their preference would be for the user (us) to call the native
1281 OS and then for the OS itself to call through to the VxFS filesystem.
1282 Presumably HPUX 10, see above, does this.
1285 Add your OS to "IFLIST" below.
1286 Get it to compile successfully:
1287 Almost certainly "include"s require attention: see SUNOS5.
1288 In the main code above, arrange for it to be called: see SUNOS5.
1291 ****************************************************************************/
1294 * This "if" is a list of ports:
1295 * if defined(OS1) || defined(OS2) || ...
1300 #include <sys/fs/vx_solaris.h>
1302 #include <sys/fs/vx_machdep.h>
1303 #include <sys/fs/vx_layout.h>
1304 #include <sys/fs/vx_quota.h>
1305 #include <sys/fs/vx_aioctl.h>
1306 #include <sys/fs/vx_ioctl.h>
1308 BOOL
disk_quotas_vxfs(const pstring name
, char *path
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
1310 uid_t user_id
, euser_id
;
1313 struct vx_quotctl quotabuf
;
1314 struct vx_genioctl genbuf
;
1319 * "name" may or may not include a trailing "/quotas".
1320 * Arranging consistency of calling here in "quotas.c" may not be easy and
1321 * it might be easier to examine and adjust it here.
1322 * Fortunately, VxFS seems not to mind at present.
1324 pstrcpy(qfname
, name
) ;
1325 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
1327 euser_id
= geteuid();
1328 set_effective_uid(0);
1330 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname
));
1331 if((file
=sys_open(qfname
, O_RDONLY
,0))<0) {
1332 set_effective_uid(euser_id
);
1335 genbuf
.ioc_cmd
= VX_QUOTACTL
;
1336 genbuf
.ioc_up
= (void *) "abuf
;
1338 quotabuf
.cmd
= VX_GETQUOTA
;
1339 quotabuf
.uid
= euser_id
;
1340 quotabuf
.addr
= (caddr_t
) &D
;
1341 ret
= ioctl(file
, VX_ADMIN_IOCTL
, &genbuf
);
1344 set_effective_uid(euser_id
);
1347 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno
) ));
1351 /* If softlimit is zero, set it equal to hardlimit.
1354 if (D
.dqb_bsoftlimit
==0)
1355 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
1357 /* Use softlimit to determine disk space. A user exceeding the quota is told
1358 * that there's no space left. Writes might actually work for a bit if the
1359 * hardlimit is set higher than softlimit. Effectively the disk becomes
1360 * made of rubber latex and begins to expand to accommodate the user :-)
1362 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1363 path
, D
.dqb_curblocks
, D
.dqb_bsoftlimit
, D
.dqb_bhardlimit
,
1364 D
.dqb_curfiles
, D
.dqb_fsoftlimit
, D
.dqb_fhardlimit
));
1366 if (D
.dqb_bsoftlimit
==0)
1369 *dsize
= D
.dqb_bsoftlimit
;
1371 if (D
.dqb_curblocks
> D
.dqb_bsoftlimit
) {
1373 *dsize
= D
.dqb_curblocks
;
1375 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
1377 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
1378 path
,(double)*bsize
,(double)*dfree
,(double)*dsize
));
1383 #endif /* SUNOS5 || ... */
1385 #endif /* VXFS_QUOTA */
1387 #else /* WITH_QUOTAS */
1389 BOOL
disk_quotas(const char *path
,SMB_BIG_UINT
*bsize
,SMB_BIG_UINT
*dfree
,SMB_BIG_UINT
*dsize
)
1391 (*bsize
) = 512; /* This value should be ignored */
1393 /* And just to be sure we set some values that hopefully */
1394 /* will be larger that any possible real-world value */
1395 (*dfree
) = (SMB_BIG_UINT
)-1;
1396 (*dsize
) = (SMB_BIG_UINT
)-1;
1398 /* As we have select not to use quotas, allways fail */
1401 #endif /* WITH_QUOTAS */
1403 #else /* HAVE_SYS_QUOTAS */
1404 /* wrapper to the new sys_quota interface
1405 this file should be removed later
1407 BOOL
disk_quotas(const char *path
,SMB_BIG_UINT
*bsize
,SMB_BIG_UINT
*dfree
,SMB_BIG_UINT
*dsize
)
1416 r
=sys_get_quota(path
, SMB_USER_QUOTA_TYPE
, id
, &D
);
1418 /* Use softlimit to determine disk space, except when it has been exceeded */
1421 if (errno
== EDQUOT
) {
1423 *dsize
=D
.curblocks
;
1426 goto try_group_quota
;
1430 /* Use softlimit to determine disk space, except when it has been exceeded */
1432 (D
.softlimit
&& D
.curblocks
>= D
.softlimit
) ||
1433 (D
.hardlimit
&& D
.curblocks
>= D
.hardlimit
) ||
1434 (D
.isoftlimit
&& D
.curinodes
>= D
.isoftlimit
) ||
1435 (D
.ihardlimit
&& D
.curinodes
>=D
.ihardlimit
)
1438 *dsize
= D
.curblocks
;
1439 } else if (D
.softlimit
==0 && D
.hardlimit
==0) {
1440 goto try_group_quota
;
1442 if (D
.softlimit
== 0)
1443 D
.softlimit
= D
.hardlimit
;
1444 *dfree
= D
.softlimit
- D
.curblocks
;
1445 *dsize
= D
.softlimit
;
1454 r
=sys_get_quota(path
, SMB_GROUP_QUOTA_TYPE
, id
, &D
);
1456 /* Use softlimit to determine disk space, except when it has been exceeded */
1459 if (errno
== EDQUOT
) {
1461 *dsize
=D
.curblocks
;
1468 /* Use softlimit to determine disk space, except when it has been exceeded */
1470 (D
.softlimit
&& D
.curblocks
>= D
.softlimit
) ||
1471 (D
.hardlimit
&& D
.curblocks
>= D
.hardlimit
) ||
1472 (D
.isoftlimit
&& D
.curinodes
>= D
.isoftlimit
) ||
1473 (D
.ihardlimit
&& D
.curinodes
>=D
.ihardlimit
)
1476 *dsize
= D
.curblocks
;
1477 } else if (D
.softlimit
==0 && D
.hardlimit
==0) {
1480 if (D
.softlimit
== 0)
1481 D
.softlimit
= D
.hardlimit
;
1482 *dfree
= D
.softlimit
- D
.curblocks
;
1483 *dsize
= D
.softlimit
;
1488 #endif /* HAVE_SYS_QUOTAS */