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
) {
242 set_effective_uid(0);
244 if (strcmp(mnt
->mnt_type
, "xfs")==0) {
245 r
=get_smb_linux_xfs_quota(mnt
->mnt_fsname
, euser_id
, egrp_id
, &D
);
247 r
=get_smb_linux_gen_quota(mnt
->mnt_fsname
, euser_id
, egrp_id
, &D
);
248 if (r
== -1 && errno
!= EDQUOT
) {
249 r
=get_smb_linux_v2_quota(mnt
->mnt_fsname
, euser_id
, egrp_id
, &D
);
250 if (r
== -1 && errno
!= EDQUOT
)
251 r
=get_smb_linux_v1_quota(mnt
->mnt_fsname
, euser_id
, egrp_id
, &D
);
257 /* Use softlimit to determine disk space, except when it has been exceeded */
260 if (errno
== EDQUOT
) {
269 /* Use softlimit to determine disk space, except when it has been exceeded */
271 (D
.softlimit
&& D
.curblocks
>= D
.softlimit
) ||
272 (D
.hardlimit
&& D
.curblocks
>= D
.hardlimit
) ||
273 (D
.isoftlimit
&& D
.curinodes
>= D
.isoftlimit
) ||
274 (D
.ihardlimit
&& D
.curinodes
>=D
.ihardlimit
)
277 *dsize
= D
.curblocks
;
278 } else if (D
.softlimit
==0 && D
.hardlimit
==0) {
281 if (D
.softlimit
== 0)
282 D
.softlimit
= D
.hardlimit
;
283 *dfree
= D
.softlimit
- D
.curblocks
;
284 *dsize
= D
.softlimit
;
292 #include <sys/quota.h>
295 /****************************************************************************
296 try to get the disk space from disk quotas (CRAY VERSION)
297 ****************************************************************************/
299 BOOL
disk_quotas(const char *path
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
303 SMB_STRUCT_STAT sbuf
;
305 static SMB_DEV_T devno_cached
= 0 ;
307 struct q_request request
;
308 struct qf_header header
;
309 static int quota_default
= 0 ;
312 if ( sys_stat(path
,&sbuf
) == -1 )
315 devno
= sbuf
.st_dev
;
317 if ( devno
!= devno_cached
) {
319 devno_cached
= devno
;
321 if ((fd
= setmntent(KMTAB
)) == NULL
)
326 while ((mnt
= getmntent(fd
)) != NULL
) {
328 if ( sys_stat(mnt
->mnt_dir
,&sbuf
) == -1 )
331 if (sbuf
.st_dev
== devno
) {
340 pstrcpy(name
,mnt
->mnt_dir
) ;
347 request
.qf_magic
= QF_MAGIC
;
348 request
.qf_entry
.id
= geteuid() ;
350 if (quotactl(name
, Q_GETQUOTA
, &request
) == -1)
353 if ( ! request
.user
)
356 if ( request
.qf_entry
.user_q
.f_quota
== QFV_DEFAULT
) {
358 if ( ! quota_default
) {
360 if ( quotactl(name
, Q_GETHEADER
, &header
) == -1 )
363 quota_default
= header
.user_h
.def_fq
;
366 *dfree
= quota_default
;
368 }else if ( request
.qf_entry
.user_q
.f_quota
== QFV_PREVENT
) {
374 *dfree
= request
.qf_entry
.user_q
.f_quota
;
378 *dsize
= request
.qf_entry
.user_q
.f_use
;
380 if ( *dfree
< *dsize
)
385 *bsize
= 4096 ; /* Cray blocksize */
392 #elif defined(SUNOS5) || defined(SUNOS4)
395 #include <sys/param.h>
397 #include <sys/fs/ufs_quota.h>
398 #include <sys/mnttab.h>
399 #include <sys/mntent.h>
400 #else /* defined(SUNOS4) */
401 #include <ufs/quota.h>
407 /****************************************************************************
408 Allows querying of remote hosts for quotas on NFS mounted shares.
409 Supports normal NFS and AMD mounts.
410 Alan Romeril <a.romeril@ic.ac.uk> July 2K.
411 ****************************************************************************/
414 #include <rpc/types.h>
415 #include <rpcsvc/rquota.h>
416 #include <rpc/nettype.h>
419 static int quotastat
;
421 static int my_xdr_getquota_args(XDR
*xdrsp
, struct getquota_args
*args
)
423 if (!xdr_string(xdrsp
, &args
->gqa_pathp
, RQ_PATHLEN
))
425 if (!xdr_int(xdrsp
, &args
->gqa_uid
))
430 static int my_xdr_getquota_rslt(XDR
*xdrsp
, struct getquota_rslt
*gqr
)
432 if (!xdr_int(xdrsp
, "astat
)) {
433 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
436 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bsize
)) {
437 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
440 if (!xdr_bool(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_active
)) {
441 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
444 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
)) {
445 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
448 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
)) {
449 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
452 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_curblocks
)) {
453 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
459 /* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
460 static BOOL
nfs_quotas(char *nfspath
, uid_t euser_id
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
462 uid_t uid
= euser_id
;
464 char *mnttype
= nfspath
;
466 struct getquota_rslt gqr
;
467 struct getquota_args args
;
468 char *cutstr
, *pathname
, *host
, *testpath
;
470 static struct timeval timeout
= {2,0};
471 enum clnt_stat clnt_stat
;
474 *bsize
= *dfree
= *dsize
= (SMB_BIG_UINT
)0;
476 len
=strcspn(mnttype
, ":");
477 pathname
=strstr(mnttype
, ":");
478 cutstr
= (char *) SMB_MALLOC(len
+1);
482 memset(cutstr
, '\0', len
+1);
483 host
= strncat(cutstr
,mnttype
, sizeof(char) * len
);
484 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr
));
485 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype
));
486 testpath
=strchr_m(mnttype
, ':');
487 args
.gqa_pathp
= testpath
+1;
490 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host
, RQUOTAPROG
, RQUOTAVERS
, "udp"));
492 if ((clnt
= clnt_create(host
, RQUOTAPROG
, RQUOTAVERS
, "udp")) == NULL
) {
497 clnt
->cl_auth
= authunix_create_default();
498 DEBUG(9,("nfs_quotas: auth_success\n"));
500 clnt_stat
=clnt_call(clnt
, RQUOTAPROC_GETQUOTA
, my_xdr_getquota_args
, (caddr_t
)&args
, my_xdr_getquota_rslt
, (caddr_t
)&gqr
, timeout
);
502 if (clnt_stat
!= RPC_SUCCESS
) {
503 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
509 * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
510 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
511 * something sensible.
514 switch ( quotastat
) {
516 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat
));
521 DEBUG(9,("nfs_quotas: Good quota data\n"));
522 D
.dqb_bsoftlimit
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
;
523 D
.dqb_bhardlimit
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
;
524 D
.dqb_curblocks
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_curblocks
;
529 D
.dqb_bsoftlimit
= 1;
531 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat
));
535 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat
));
539 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",
541 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsize
,
542 gqr
.getquota_rslt_u
.gqr_rquota
.rq_active
,
543 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
,
544 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
,
545 gqr
.getquota_rslt_u
.gqr_rquota
.rq_curblocks
));
547 *bsize
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsize
;
548 *dsize
= D
.dqb_bsoftlimit
;
550 if (D
.dqb_curblocks
== D
.dqb_curblocks
== 1)
553 if (D
.dqb_curblocks
> D
.dqb_bsoftlimit
) {
555 *dsize
= D
.dqb_curblocks
;
557 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
563 auth_destroy(clnt
->cl_auth
);
567 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args
.gqa_pathp
,(double)*bsize
,(double)*dfree
,(double)*dsize
));
570 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
575 /****************************************************************************
576 try to get the disk space from disk quotas (SunOS & Solaris2 version)
577 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
578 ****************************************************************************/
580 BOOL
disk_quotas(const char *path
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
586 struct quotctl command
;
588 static struct mnttab mnt
;
596 SMB_STRUCT_STAT sbuf
;
598 static SMB_DEV_T devno_cached
= 0 ;
601 euser_id
= geteuid();
603 if ( sys_stat(path
,&sbuf
) == -1 )
606 devno
= sbuf
.st_dev
;
607 DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n", path
,(unsigned int)devno
));
608 if ( devno
!= devno_cached
) {
609 devno_cached
= devno
;
611 if ((fd
= sys_fopen(MNTTAB
, "r")) == NULL
)
615 slprintf(devopt
, sizeof(devopt
) - 1, "dev=%x", (unsigned int)devno
);
616 while (getmntent(fd
, &mnt
) == 0) {
617 if( !hasmntopt(&mnt
, devopt
) )
620 DEBUG(5,("disk_quotas: testing \"%s\" %s\n", mnt
.mnt_mountp
,devopt
));
622 /* quotas are only on vxfs, UFS or NFS */
623 if ( strcmp( mnt
.mnt_fstype
, MNTTYPE_UFS
) == 0 ||
624 strcmp( mnt
.mnt_fstype
, "nfs" ) == 0 ||
625 strcmp( mnt
.mnt_fstype
, "vxfs" ) == 0 ) {
631 pstrcpy(name
,mnt
.mnt_mountp
) ;
632 pstrcat(name
,"/quotas") ;
635 if ((fd
= setmntent(MOUNTED
, "r")) == NULL
)
639 while ((mnt
= getmntent(fd
)) != NULL
) {
640 if ( sys_stat(mnt
->mnt_dir
,&sbuf
) == -1 )
642 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n", mnt
->mnt_dir
,(unsigned int)sbuf
.st_dev
));
643 if (sbuf
.st_dev
== devno
) {
649 pstrcpy(name
,mnt
->mnt_fsname
) ;
658 set_effective_uid(0);
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
) {
845 set_effective_uid(0);
847 /* Use softlimit to determine disk space, except when it has been exceeded */
851 if ( 0 == strcmp ( mnt
->mnt_type
, "efs" ))
853 r
=quotactl (Q_GETQUOTA
, mnt
->mnt_fsname
, euser_id
, (caddr_t
) &D
);
860 /* Use softlimit to determine disk space, except when it has been exceeded */
862 (D
.dqb_bsoftlimit
&& D
.dqb_curblocks
>=D
.dqb_bsoftlimit
) ||
863 (D
.dqb_bhardlimit
&& D
.dqb_curblocks
>=D
.dqb_bhardlimit
) ||
864 (D
.dqb_fsoftlimit
&& D
.dqb_curfiles
>=D
.dqb_fsoftlimit
) ||
865 (D
.dqb_fhardlimit
&& D
.dqb_curfiles
>=D
.dqb_fhardlimit
)
869 *dsize
= D
.dqb_curblocks
;
871 else if (D
.dqb_bsoftlimit
==0 && D
.dqb_bhardlimit
==0)
877 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
878 *dsize
= D
.dqb_bsoftlimit
;
882 else if ( 0 == strcmp ( mnt
->mnt_type
, "xfs" ))
884 r
=quotactl (Q_XGETQUOTA
, mnt
->mnt_fsname
, euser_id
, (caddr_t
) &F
);
890 DEBUG(5, ("quotactl for uid=%u: %s", euser_id
, strerror(errno
)));
894 /* No quota for this user. */
895 if (F
.d_blk_softlimit
==0 && F
.d_blk_hardlimit
==0)
900 /* Use softlimit to determine disk space, except when it has been exceeded */
902 (F
.d_blk_softlimit
&& F
.d_bcount
>=F
.d_blk_softlimit
) ||
903 (F
.d_blk_hardlimit
&& F
.d_bcount
>=F
.d_blk_hardlimit
) ||
904 (F
.d_ino_softlimit
&& F
.d_icount
>=F
.d_ino_softlimit
) ||
905 (F
.d_ino_hardlimit
&& F
.d_icount
>=F
.d_ino_hardlimit
)
913 *dfree
= (F
.d_blk_softlimit
- F
.d_bcount
);
914 *dsize
= F
.d_blk_softlimit
? F
.d_blk_softlimit
: F
.d_blk_hardlimit
;
930 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
931 #include <ufs/ufs/quota.h>
932 #include <machine/param.h>
934 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
935 #include <jfs/quota.h>
936 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
937 #define dqb_curfiles dqb_curinodes
938 #define dqb_fhardlimit dqb_ihardlimit
939 #define dqb_fsoftlimit dqb_isoftlimit
940 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
941 #include <sys/quota.h>
945 #if defined(__FreeBSD__) || defined(__DragonFly__)
948 #include <rpc/types.h>
949 #include <rpcsvc/rquota.h>
950 #ifdef HAVE_RPC_NETTYPE_H
951 #include <rpc/nettype.h>
955 static int quotastat
;
957 static int my_xdr_getquota_args(XDR
*xdrsp
, struct getquota_args
*args
)
959 if (!xdr_string(xdrsp
, &args
->gqa_pathp
, RQ_PATHLEN
))
961 if (!xdr_int(xdrsp
, &args
->gqa_uid
))
966 static int my_xdr_getquota_rslt(XDR
*xdrsp
, struct getquota_rslt
*gqr
)
968 if (!xdr_int(xdrsp
, "astat
)) {
969 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
972 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bsize
)) {
973 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
976 if (!xdr_bool(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_active
)) {
977 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
980 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
)) {
981 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
984 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
)) {
985 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
988 if (!xdr_int(xdrsp
, &gqr
->getquota_rslt_u
.gqr_rquota
.rq_curblocks
)) {
989 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
995 /* Works on FreeBSD, too. :-) */
996 static BOOL
nfs_quotas(char *nfspath
, uid_t euser_id
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
998 uid_t uid
= euser_id
;
1000 char *mnttype
= nfspath
;
1002 struct getquota_rslt gqr
;
1003 struct getquota_args args
;
1004 char *cutstr
, *pathname
, *host
, *testpath
;
1006 static struct timeval timeout
= {2,0};
1007 enum clnt_stat clnt_stat
;
1010 *bsize
= *dfree
= *dsize
= (SMB_BIG_UINT
)0;
1012 len
=strcspn(mnttype
, ":");
1013 pathname
=strstr(mnttype
, ":");
1014 cutstr
= (char *) SMB_MALLOC(len
+1);
1018 memset(cutstr
, '\0', len
+1);
1019 host
= strncat(cutstr
,mnttype
, sizeof(char) * len
);
1020 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr
));
1021 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype
));
1022 testpath
=strchr_m(mnttype
, ':');
1023 args
.gqa_pathp
= testpath
+1;
1026 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host
, RQUOTAPROG
, RQUOTAVERS
, "udp"));
1028 if ((clnt
= clnt_create(host
, RQUOTAPROG
, RQUOTAVERS
, "udp")) == NULL
) {
1033 clnt
->cl_auth
= authunix_create_default();
1034 DEBUG(9,("nfs_quotas: auth_success\n"));
1036 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
);
1038 if (clnt_stat
!= RPC_SUCCESS
) {
1039 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
1045 * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
1046 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
1047 * something sensible.
1050 switch ( quotastat
) {
1052 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat
));
1057 DEBUG(9,("nfs_quotas: Good quota data\n"));
1058 D
.dqb_bsoftlimit
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
;
1059 D
.dqb_bhardlimit
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
;
1060 D
.dqb_curblocks
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_curblocks
;
1065 D
.dqb_bsoftlimit
= 1;
1066 D
.dqb_curblocks
= 1;
1067 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat
));
1071 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat
));
1075 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",
1077 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsize
,
1078 gqr
.getquota_rslt_u
.gqr_rquota
.rq_active
,
1079 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bhardlimit
,
1080 gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsoftlimit
,
1081 gqr
.getquota_rslt_u
.gqr_rquota
.rq_curblocks
));
1083 if (D
.dqb_bsoftlimit
== 0)
1084 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
1085 if (D
.dqb_bsoftlimit
== 0)
1088 *bsize
= gqr
.getquota_rslt_u
.gqr_rquota
.rq_bsize
;
1089 *dsize
= D
.dqb_bsoftlimit
;
1091 if (D
.dqb_curblocks
== D
.dqb_curblocks
== 1)
1094 if (D
.dqb_curblocks
> D
.dqb_bsoftlimit
) {
1096 *dsize
= D
.dqb_curblocks
;
1098 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
1104 auth_destroy(clnt
->cl_auth
);
1108 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args
.gqa_pathp
,(double)*bsize
,(double)*dfree
,(double)*dsize
));
1111 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
1117 /****************************************************************************
1118 try to get the disk space from disk quotas - default version
1119 ****************************************************************************/
1121 BOOL
disk_quotas(const char *path
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
1126 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1130 /* find the block device file */
1133 /* Need to set the cache flag to 1 for HPUX. Seems
1134 * to have a significant performance boost when
1135 * lstat calls on /dev access this function.
1137 if ((sys_stat(path
, &S
)<0) || (devnm(S_IFBLK
, S
.st_dev
, dev_disk
, 256, 1)<0))
1139 if ((sys_stat(path
, &S
)<0) || (devnm(S_IFBLK
, S
.st_dev
, dev_disk
, 256, 0)<0))
1141 #endif /* ifdef HPUX */
1143 #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__) */
1145 euser_id
= geteuid();
1148 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
1150 if (set_re_uid() != 0) return False
;
1152 r
=quotactl(Q_GETQUOTA
, dev_disk
, euser_id
, &D
);
1156 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1158 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
1160 #if defined(__FreeBSD__) || defined(__DragonFly__)
1162 struct statfs
*mnts
;
1166 if (sys_stat(path
,&st
) < 0)
1170 mntsize
= getmntinfo(&mnts
,MNT_NOWAIT
);
1174 for (i
= 0; i
< mntsize
; i
++) {
1175 if (sys_stat(mnts
[i
].f_mntonname
,&st
) < 0)
1177 if (st
.st_dev
== devno
)
1185 set_effective_uid(0);
1187 #if defined(__FreeBSD__) || defined(__DragonFly__)
1188 if (strcmp(mnts
[i
].f_fstypename
,"nfs") == 0) {
1190 retval
= nfs_quotas(mnts
[i
].f_mntfromname
,euser_id
,bsize
,dfree
,dsize
);
1196 egrp_id
= getegid();
1197 r
= quotactl(path
,QCMD(Q_GETQUOTA
,USRQUOTA
),euser_id
,(char *) &D
);
1199 /* As FreeBSD has group quotas, if getting the user
1200 quota fails, try getting the group instead. */
1202 r
= quotactl(path
,QCMD(Q_GETQUOTA
,GRPQUOTA
),egrp_id
,(char *) &D
);
1208 /* AIX has both USER and GROUP quotas:
1209 Get the USER quota (ohnielse@fysik.dtu.dk) */
1211 if (set_re_uid() != 0)
1213 r
= quotactl(path
,QCMD(Q_GETQUOTA
,USRQUOTA
),euser_id
,(char *) &D
);
1215 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1216 r
=quotactl(Q_GETQUOTA
, dev_disk
, euser_id
, &D
);
1217 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1220 /* Use softlimit to determine disk space, except when it has been exceeded */
1221 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1223 #else /* !__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1225 #endif /*!__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1229 if (errno
== EDQUOT
)
1232 *dsize
=D
.dqb_curblocks
;
1238 /* If softlimit is zero, set it equal to hardlimit.
1241 if (D
.dqb_bsoftlimit
==0)
1242 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
1244 if (D
.dqb_bsoftlimit
==0)
1246 /* Use softlimit to determine disk space, except when it has been exceeded */
1247 if ((D
.dqb_curblocks
>D
.dqb_bsoftlimit
)
1248 #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1249 ||((D
.dqb_curfiles
>D
.dqb_fsoftlimit
) && (D
.dqb_fsoftlimit
!= 0))
1253 *dsize
= D
.dqb_curblocks
;
1256 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
1257 *dsize
= D
.dqb_bsoftlimit
;
1264 #if defined(VXFS_QUOTA)
1266 /****************************************************************************
1267 Try to get the disk space from Veritas disk quotas.
1268 David Lee <T.D.Lee@durham.ac.uk> August 1999.
1270 Background assumptions:
1271 Potentially under many Operating Systems. Initially Solaris 2.
1273 My guess is that Veritas is largely, though not entirely,
1274 independent of OS. So I have separated it out.
1276 There may be some details. For example, OS-specific "include" files.
1278 It is understood that HPUX 10 somehow gets Veritas quotas without
1279 any special effort; if so, this routine need not be compiled in.
1280 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1283 It is understood that Veritas do not publicly support this ioctl interface.
1284 Rather their preference would be for the user (us) to call the native
1285 OS and then for the OS itself to call through to the VxFS filesystem.
1286 Presumably HPUX 10, see above, does this.
1289 Add your OS to "IFLIST" below.
1290 Get it to compile successfully:
1291 Almost certainly "include"s require attention: see SUNOS5.
1292 In the main code above, arrange for it to be called: see SUNOS5.
1295 ****************************************************************************/
1298 * This "if" is a list of ports:
1299 * if defined(OS1) || defined(OS2) || ...
1304 #include <sys/fs/vx_solaris.h>
1306 #include <sys/fs/vx_machdep.h>
1307 #include <sys/fs/vx_layout.h>
1308 #include <sys/fs/vx_quota.h>
1309 #include <sys/fs/vx_aioctl.h>
1310 #include <sys/fs/vx_ioctl.h>
1312 BOOL
disk_quotas_vxfs(const pstring name
, char *path
, SMB_BIG_UINT
*bsize
, SMB_BIG_UINT
*dfree
, SMB_BIG_UINT
*dsize
)
1314 uid_t user_id
, euser_id
;
1317 struct vx_quotctl quotabuf
;
1318 struct vx_genioctl genbuf
;
1323 * "name" may or may not include a trailing "/quotas".
1324 * Arranging consistency of calling here in "quotas.c" may not be easy and
1325 * it might be easier to examine and adjust it here.
1326 * Fortunately, VxFS seems not to mind at present.
1328 pstrcpy(qfname
, name
) ;
1329 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
1331 euser_id
= geteuid();
1332 set_effective_uid(0);
1334 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname
));
1335 if((file
=sys_open(qfname
, O_RDONLY
,0))<0) {
1336 set_effective_uid(euser_id
);
1339 genbuf
.ioc_cmd
= VX_QUOTACTL
;
1340 genbuf
.ioc_up
= (void *) "abuf
;
1342 quotabuf
.cmd
= VX_GETQUOTA
;
1343 quotabuf
.uid
= euser_id
;
1344 quotabuf
.addr
= (caddr_t
) &D
;
1345 ret
= ioctl(file
, VX_ADMIN_IOCTL
, &genbuf
);
1348 set_effective_uid(euser_id
);
1351 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno
) ));
1355 /* If softlimit is zero, set it equal to hardlimit.
1358 if (D
.dqb_bsoftlimit
==0)
1359 D
.dqb_bsoftlimit
= D
.dqb_bhardlimit
;
1361 /* Use softlimit to determine disk space. A user exceeding the quota is told
1362 * that there's no space left. Writes might actually work for a bit if the
1363 * hardlimit is set higher than softlimit. Effectively the disk becomes
1364 * made of rubber latex and begins to expand to accommodate the user :-)
1366 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1367 path
, D
.dqb_curblocks
, D
.dqb_bsoftlimit
, D
.dqb_bhardlimit
,
1368 D
.dqb_curfiles
, D
.dqb_fsoftlimit
, D
.dqb_fhardlimit
));
1370 if (D
.dqb_bsoftlimit
==0)
1373 *dsize
= D
.dqb_bsoftlimit
;
1375 if (D
.dqb_curblocks
> D
.dqb_bsoftlimit
) {
1377 *dsize
= D
.dqb_curblocks
;
1379 *dfree
= D
.dqb_bsoftlimit
- D
.dqb_curblocks
;
1381 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
1382 path
,(double)*bsize
,(double)*dfree
,(double)*dsize
));
1387 #endif /* SUNOS5 || ... */
1389 #endif /* VXFS_QUOTA */
1391 #else /* WITH_QUOTAS */
1393 BOOL
disk_quotas(const char *path
,SMB_BIG_UINT
*bsize
,SMB_BIG_UINT
*dfree
,SMB_BIG_UINT
*dsize
)
1395 (*bsize
) = 512; /* This value should be ignored */
1397 /* And just to be sure we set some values that hopefully */
1398 /* will be larger that any possible real-world value */
1399 (*dfree
) = (SMB_BIG_UINT
)-1;
1400 (*dsize
) = (SMB_BIG_UINT
)-1;
1402 /* As we have select not to use quotas, allways fail */
1405 #endif /* WITH_QUOTAS */
1407 #else /* HAVE_SYS_QUOTAS */
1408 /* wrapper to the new sys_quota interface
1409 this file should be removed later
1411 BOOL
disk_quotas(const char *path
,SMB_BIG_UINT
*bsize
,SMB_BIG_UINT
*dfree
,SMB_BIG_UINT
*dsize
)
1420 r
=sys_get_quota(path
, SMB_USER_QUOTA_TYPE
, id
, &D
);
1422 /* Use softlimit to determine disk space, except when it has been exceeded */
1425 if (errno
== EDQUOT
) {
1427 *dsize
=D
.curblocks
;
1430 goto try_group_quota
;
1434 /* Use softlimit to determine disk space, except when it has been exceeded */
1436 (D
.softlimit
&& D
.curblocks
>= D
.softlimit
) ||
1437 (D
.hardlimit
&& D
.curblocks
>= D
.hardlimit
) ||
1438 (D
.isoftlimit
&& D
.curinodes
>= D
.isoftlimit
) ||
1439 (D
.ihardlimit
&& D
.curinodes
>=D
.ihardlimit
)
1442 *dsize
= D
.curblocks
;
1443 } else if (D
.softlimit
==0 && D
.hardlimit
==0) {
1444 goto try_group_quota
;
1446 if (D
.softlimit
== 0)
1447 D
.softlimit
= D
.hardlimit
;
1448 *dfree
= D
.softlimit
- D
.curblocks
;
1449 *dsize
= D
.softlimit
;
1458 r
=sys_get_quota(path
, SMB_GROUP_QUOTA_TYPE
, id
, &D
);
1460 /* Use softlimit to determine disk space, except when it has been exceeded */
1463 if (errno
== EDQUOT
) {
1465 *dsize
=D
.curblocks
;
1472 /* Use softlimit to determine disk space, except when it has been exceeded */
1474 (D
.softlimit
&& D
.curblocks
>= D
.softlimit
) ||
1475 (D
.hardlimit
&& D
.curblocks
>= D
.hardlimit
) ||
1476 (D
.isoftlimit
&& D
.curinodes
>= D
.isoftlimit
) ||
1477 (D
.ihardlimit
&& D
.curinodes
>=D
.ihardlimit
)
1480 *dsize
= D
.curblocks
;
1481 } else if (D
.softlimit
==0 && D
.hardlimit
==0) {
1484 if (D
.softlimit
== 0)
1485 D
.softlimit
= D
.hardlimit
;
1486 *dfree
= D
.softlimit
- D
.curblocks
;
1487 *dsize
= D
.softlimit
;
1492 #endif /* HAVE_SYS_QUOTAS */