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 3 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, see <http://www.gnu.org/licenses/>.
22 * This is one of the most system dependent parts of Samba, and its
23 * done a litle differently. Each system has its own way of doing
30 #define DBGC_CLASS DBGC_QUOTA
32 #ifndef HAVE_SYS_QUOTAS
34 /* just a quick hack because sysquotas.h is included before linux/quota.h */
35 #ifdef QUOTABLOCK_SIZE
36 #undef QUOTABLOCK_SIZE
41 #if defined(VXFS_QUOTA)
44 * In addition to their native filesystems, some systems have Veritas VxFS.
45 * Declare here, define at end: reduces likely "include" interaction problems.
46 * David Lee <T.D.Lee@durham.ac.uk>
48 BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize);
50 #endif /* VXFS_QUOTA */
54 #include <sys/types.h>
58 * This shouldn't be neccessary - it should be /usr/include/sys/quota.h
59 * So we include all the files has *should* be in the system into a large,
60 * grungy samba_linux_quoatas.h Sometimes I *hate* Linux :-). JRA.
63 #include "samba_linux_quota.h"
64 #include "samba_xfs_quota.h"
66 typedef struct _LINUX_SMB_DISK_QUOTA {
68 SMB_BIG_UINT hardlimit; /* In bsize units. */
69 SMB_BIG_UINT softlimit; /* In bsize units. */
70 SMB_BIG_UINT curblocks; /* In bsize units. */
71 SMB_BIG_UINT ihardlimit; /* inode hard limit. */
72 SMB_BIG_UINT isoftlimit; /* inode soft limit. */
73 SMB_BIG_UINT curinodes; /* Current used inodes. */
74 } LINUX_SMB_DISK_QUOTA;
76 /****************************************************************************
77 Abstract out the XFS Quota Manager quota get call.
78 ****************************************************************************/
80 static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
82 struct fs_disk_quota D;
87 ret = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
90 ret = quotactl(QCMD(Q_XGETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
95 dp->bsize = (SMB_BIG_UINT)512;
96 dp->softlimit = (SMB_BIG_UINT)D.d_blk_softlimit;
97 dp->hardlimit = (SMB_BIG_UINT)D.d_blk_hardlimit;
98 dp->ihardlimit = (SMB_BIG_UINT)D.d_ino_hardlimit;
99 dp->isoftlimit = (SMB_BIG_UINT)D.d_ino_softlimit;
100 dp->curinodes = (SMB_BIG_UINT)D.d_icount;
101 dp->curblocks = (SMB_BIG_UINT)D.d_bcount;
106 /****************************************************************************
107 Abstract out the old and new Linux quota get calls.
108 ****************************************************************************/
110 static int get_smb_linux_v1_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
112 struct v1_kern_dqblk D;
117 ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
119 if (ret && errno != EDQUOT)
120 ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
122 if (ret && errno != EDQUOT)
125 dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
126 dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
127 dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
128 dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
129 dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
130 dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
131 dp->curblocks = (SMB_BIG_UINT)D.dqb_curblocks;
136 static int get_smb_linux_v2_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
138 struct v2_kern_dqblk D;
143 ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
145 if (ret && errno != EDQUOT)
146 ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
148 if (ret && errno != EDQUOT)
151 dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
152 dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
153 dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
154 dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
155 dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
156 dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
157 dp->curblocks = ((SMB_BIG_UINT)D.dqb_curspace) / dp->bsize;
162 /****************************************************************************
163 Brand-new generic quota interface.
164 ****************************************************************************/
166 static int get_smb_linux_gen_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
173 ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
175 if (ret && errno != EDQUOT)
176 ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
178 if (ret && errno != EDQUOT)
181 dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
182 dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
183 dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
184 dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
185 dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
186 dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
187 dp->curblocks = ((SMB_BIG_UINT)D.dqb_curspace) / dp->bsize;
192 /****************************************************************************
193 Try to get the disk space from disk quotas (LINUX version).
194 ****************************************************************************/
196 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
201 LINUX_SMB_DISK_QUOTA D;
210 euser_id = geteuid();
213 /* find the block device file */
215 if ( sys_stat(path, &S) == -1 )
220 if ((fp = setmntent(MOUNTED,"r")) == NULL)
225 while ((mnt = getmntent(fp))) {
226 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
229 if (S.st_dev == devno) {
242 if (strcmp(mnt->mnt_type, "xfs")==0) {
243 r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
245 r=get_smb_linux_gen_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
246 if (r == -1 && errno != EDQUOT) {
247 r=get_smb_linux_v2_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
248 if (r == -1 && errno != EDQUOT)
249 r=get_smb_linux_v1_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
255 /* Use softlimit to determine disk space, except when it has been exceeded */
258 if (errno == EDQUOT) {
267 /* Use softlimit to determine disk space, except when it has been exceeded */
269 (D.softlimit && D.curblocks >= D.softlimit) ||
270 (D.hardlimit && D.curblocks >= D.hardlimit) ||
271 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
272 (D.ihardlimit && D.curinodes>=D.ihardlimit)
275 *dsize = D.curblocks;
276 } else if (D.softlimit==0 && D.hardlimit==0) {
279 if (D.softlimit == 0)
280 D.softlimit = D.hardlimit;
281 *dfree = D.softlimit - D.curblocks;
282 *dsize = D.softlimit;
290 #include <sys/quota.h>
293 /****************************************************************************
294 try to get the disk space from disk quotas (CRAY VERSION)
295 ****************************************************************************/
297 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
301 SMB_STRUCT_STAT sbuf;
303 static SMB_DEV_T devno_cached = 0 ;
305 struct q_request request ;
306 struct qf_header header ;
307 static int quota_default = 0 ;
310 if ( sys_stat(path,&sbuf) == -1 )
313 devno = sbuf.st_dev ;
315 if ( devno != devno_cached ) {
317 devno_cached = devno ;
319 if ((fd = setmntent(KMTAB)) == NULL)
324 while ((mnt = getmntent(fd)) != NULL) {
326 if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
329 if (sbuf.st_dev == devno) {
338 pstrcpy(name,mnt->mnt_dir) ;
345 request.qf_magic = QF_MAGIC ;
346 request.qf_entry.id = geteuid() ;
348 if (quotactl(name, Q_GETQUOTA, &request) == -1)
351 if ( ! request.user )
354 if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) {
356 if ( ! quota_default ) {
358 if ( quotactl(name, Q_GETHEADER, &header) == -1 )
361 quota_default = header.user_h.def_fq ;
364 *dfree = quota_default ;
366 }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) {
372 *dfree = request.qf_entry.user_q.f_quota ;
376 *dsize = request.qf_entry.user_q.f_use ;
378 if ( *dfree < *dsize )
383 *bsize = 4096 ; /* Cray blocksize */
390 #elif defined(SUNOS5) || defined(SUNOS4)
393 #include <sys/param.h>
395 #include <sys/fs/ufs_quota.h>
396 #include <sys/mnttab.h>
397 #include <sys/mntent.h>
398 #else /* defined(SUNOS4) */
399 #include <ufs/quota.h>
405 /****************************************************************************
406 Allows querying of remote hosts for quotas on NFS mounted shares.
407 Supports normal NFS and AMD mounts.
408 Alan Romeril <a.romeril@ic.ac.uk> July 2K.
409 ****************************************************************************/
412 #include <rpc/types.h>
413 #include <rpcsvc/rquota.h>
414 #include <rpc/nettype.h>
417 static int quotastat;
419 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
421 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
423 if (!xdr_int(xdrsp, &args->gqa_uid))
428 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
430 if (!xdr_int(xdrsp, "astat)) {
431 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
434 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
435 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
438 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
439 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
442 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
443 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
446 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
447 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
450 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
451 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
457 /* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
458 static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
460 uid_t uid = euser_id;
462 char *mnttype = nfspath;
464 struct getquota_rslt gqr;
465 struct getquota_args args;
466 char *cutstr, *pathname, *host, *testpath;
468 static struct timeval timeout = {2,0};
469 enum clnt_stat clnt_stat;
472 *bsize = *dfree = *dsize = (SMB_BIG_UINT)0;
474 len=strcspn(mnttype, ":");
475 pathname=strstr(mnttype, ":");
476 cutstr = (char *) SMB_MALLOC(len+1);
480 memset(cutstr, '\0', len+1);
481 host = strncat(cutstr,mnttype, sizeof(char) * len );
482 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
483 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
484 testpath=strchr_m(mnttype, ':');
485 args.gqa_pathp = testpath+1;
488 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
490 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
495 clnt->cl_auth = authunix_create_default();
496 DEBUG(9,("nfs_quotas: auth_success\n"));
498 clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, my_xdr_getquota_args, (caddr_t)&args, my_xdr_getquota_rslt, (caddr_t)&gqr, timeout);
500 if (clnt_stat != RPC_SUCCESS) {
501 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
507 * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
508 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
509 * something sensible.
512 switch ( quotastat ) {
514 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat ));
519 DEBUG(9,("nfs_quotas: Good quota data\n"));
520 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
521 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
522 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
527 D.dqb_bsoftlimit = 1;
529 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
533 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat ));
537 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",
539 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
540 gqr.getquota_rslt_u.gqr_rquota.rq_active,
541 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
542 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
543 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
545 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
546 *dsize = D.dqb_bsoftlimit;
548 if (D.dqb_curblocks == D.dqb_curblocks == 1)
551 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
553 *dsize = D.dqb_curblocks;
555 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
561 auth_destroy(clnt->cl_auth);
565 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
568 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
573 /****************************************************************************
574 try to get the disk space from disk quotas (SunOS & Solaris2 version)
575 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
576 ****************************************************************************/
578 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
584 struct quotctl command;
586 static struct mnttab mnt;
593 SMB_STRUCT_STAT sbuf;
595 static SMB_DEV_T devno_cached = 0 ;
598 euser_id = geteuid();
600 if ( sys_stat(path,&sbuf) == -1 )
603 devno = sbuf.st_dev ;
604 DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n",
605 path, (unsigned int)devno));
606 if ( devno != devno_cached ) {
607 devno_cached = devno ;
609 if ((fd = sys_fopen(MNTTAB, "r")) == NULL)
614 while (getmntent(fd, &mnt) == 0) {
615 if (sys_stat(mnt.mnt_mountp, &sbuf) == -1)
618 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
619 mnt.mnt_mountp, (unsigned int)devno));
621 /* quotas are only on vxfs, UFS or NFS */
622 if ( (sbuf.st_dev == devno) && (
623 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) ;
660 if ( strcmp( mnt.mnt_fstype, "nfs" ) == 0) {
662 DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n", mnt.mnt_special));
663 retval = nfs_quotas(mnt.mnt_special, euser_id, bsize, dfree, dsize);
668 DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
669 if((file=sys_open(name, O_RDONLY,0))<0) {
673 command.op = Q_GETQUOTA;
674 command.uid = euser_id;
675 command.addr = (caddr_t) &D;
676 ret = ioctl(file, Q_QUOTACTL, &command);
679 DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
680 ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
686 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n", strerror(errno) ));
688 #if defined(SUNOS5) && defined(VXFS_QUOTA)
689 /* If normal quotactl() fails, try vxfs private calls */
690 set_effective_uid(euser_id);
691 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype));
692 if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) {
694 retval = disk_quotas_vxfs(name, path, bsize, dfree, dsize);
702 /* If softlimit is zero, set it equal to hardlimit.
705 if (D.dqb_bsoftlimit==0)
706 D.dqb_bsoftlimit = D.dqb_bhardlimit;
708 /* Use softlimit to determine disk space. A user exceeding the quota is told
709 * that there's no space left. Writes might actually work for a bit if the
710 * hardlimit is set higher than softlimit. Effectively the disk becomes
711 * made of rubber latex and begins to expand to accommodate the user :-)
714 if (D.dqb_bsoftlimit==0)
717 *dsize = D.dqb_bsoftlimit;
719 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
721 *dsize = D.dqb_curblocks;
723 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
725 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
726 path,(double)*bsize,(double)*dfree,(double)*dsize));
733 #include <ufs/quota.h>
735 /****************************************************************************
736 try to get the disk space from disk quotas - OSF1 version
737 ****************************************************************************/
739 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
747 * This code presumes that OSF1 will only
748 * give out quota info when the real uid
749 * matches the effective uid. JRA.
751 euser_id = geteuid();
753 if (set_re_uid() != 0) return False;
755 r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
766 if (save_errno == EDQUOT) /* disk quota exceeded */
769 *dsize = D.dqb_curblocks;
776 /* If softlimit is zero, set it equal to hardlimit.
779 if (D.dqb_bsoftlimit==0)
780 D.dqb_bsoftlimit = D.dqb_bhardlimit;
782 /* Use softlimit to determine disk space, except when it has been exceeded */
784 if (D.dqb_bsoftlimit==0)
787 if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
789 *dsize = D.dqb_curblocks;
791 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
792 *dsize = D.dqb_bsoftlimit;
797 #elif defined (IRIX6)
798 /****************************************************************************
799 try to get the disk space from disk quotas (IRIX 6.2 version)
800 ****************************************************************************/
802 #include <sys/quota.h>
805 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
810 struct fs_disk_quota F;
817 /* find the block device file */
819 if ( sys_stat(path, &S) == -1 ) {
825 fp = setmntent(MOUNTED,"r");
828 while ((mnt = getmntent(fp))) {
829 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
831 if (S.st_dev == devno) {
845 /* Use softlimit to determine disk space, except when it has been exceeded */
849 if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
851 r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
858 /* Use softlimit to determine disk space, except when it has been exceeded */
860 (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
861 (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
862 (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
863 (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
867 *dsize = D.dqb_curblocks;
869 else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
875 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
876 *dsize = D.dqb_bsoftlimit;
880 else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
882 r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
888 DEBUG(5, ("quotactl for uid=%u: %s", euser_id, strerror(errno)));
892 /* No quota for this user. */
893 if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
898 /* Use softlimit to determine disk space, except when it has been exceeded */
900 (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
901 (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
902 (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
903 (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
911 *dfree = (F.d_blk_softlimit - F.d_bcount);
912 *dsize = F.d_blk_softlimit ? F.d_blk_softlimit : F.d_blk_hardlimit;
928 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
929 #include <ufs/ufs/quota.h>
930 #include <machine/param.h>
932 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
933 #include <jfs/quota.h>
934 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
935 #define dqb_curfiles dqb_curinodes
936 #define dqb_fhardlimit dqb_ihardlimit
937 #define dqb_fsoftlimit dqb_isoftlimit
938 #ifdef _AIXVERSION_530
939 #include <sys/statfs.h>
940 #include <sys/vmount.h>
942 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
943 #include <sys/quota.h>
947 #if defined(__FreeBSD__) || defined(__DragonFly__)
950 #include <rpc/types.h>
951 #include <rpcsvc/rquota.h>
952 #ifdef HAVE_RPC_NETTYPE_H
953 #include <rpc/nettype.h>
957 static int quotastat;
959 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
961 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
963 if (!xdr_int(xdrsp, &args->gqa_uid))
968 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
970 if (!xdr_int(xdrsp, "astat)) {
971 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
974 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
975 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
978 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
979 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
982 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
983 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
986 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
987 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
990 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
991 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
997 /* Works on FreeBSD, too. :-) */
998 static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
1000 uid_t uid = euser_id;
1002 char *mnttype = nfspath;
1004 struct getquota_rslt gqr;
1005 struct getquota_args args;
1006 char *cutstr, *pathname, *host, *testpath;
1008 static struct timeval timeout = {2,0};
1009 enum clnt_stat clnt_stat;
1012 *bsize = *dfree = *dsize = (SMB_BIG_UINT)0;
1014 len=strcspn(mnttype, ":");
1015 pathname=strstr(mnttype, ":");
1016 cutstr = (char *) SMB_MALLOC(len+1);
1020 memset(cutstr, '\0', len+1);
1021 host = strncat(cutstr,mnttype, sizeof(char) * len );
1022 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
1023 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
1024 testpath=strchr_m(mnttype, ':');
1025 args.gqa_pathp = testpath+1;
1028 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
1030 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
1035 clnt->cl_auth = authunix_create_default();
1036 DEBUG(9,("nfs_quotas: auth_success\n"));
1038 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);
1040 if (clnt_stat != RPC_SUCCESS) {
1041 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
1047 * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
1048 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
1049 * something sensible.
1052 switch ( quotastat ) {
1054 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat ));
1059 DEBUG(9,("nfs_quotas: Good quota data\n"));
1060 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
1061 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
1062 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
1067 D.dqb_bsoftlimit = 1;
1068 D.dqb_curblocks = 1;
1069 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
1073 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat ));
1077 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",
1079 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
1080 gqr.getquota_rslt_u.gqr_rquota.rq_active,
1081 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
1082 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
1083 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
1085 if (D.dqb_bsoftlimit == 0)
1086 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1087 if (D.dqb_bsoftlimit == 0)
1090 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
1091 *dsize = D.dqb_bsoftlimit;
1093 if (D.dqb_curblocks == D.dqb_curblocks == 1)
1096 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1098 *dsize = D.dqb_curblocks;
1100 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1106 auth_destroy(clnt->cl_auth);
1110 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
1113 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
1119 /****************************************************************************
1120 try to get the disk space from disk quotas - default version
1121 ****************************************************************************/
1123 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
1128 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1132 /* find the block device file */
1135 /* Need to set the cache flag to 1 for HPUX. Seems
1136 * to have a significant performance boost when
1137 * lstat calls on /dev access this function.
1139 if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 1)<0))
1141 if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0))
1143 #endif /* ifdef HPUX */
1145 #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__) */
1147 euser_id = geteuid();
1150 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
1152 if (set_re_uid() != 0) return False;
1154 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1158 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1160 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
1162 #if defined(__FreeBSD__) || defined(__DragonFly__)
1164 struct statfs *mnts;
1168 if (sys_stat(path,&st) < 0)
1172 mntsize = getmntinfo(&mnts,MNT_NOWAIT);
1176 for (i = 0; i < mntsize; i++) {
1177 if (sys_stat(mnts[i].f_mntonname,&st) < 0)
1179 if (st.st_dev == devno)
1188 #if defined(__FreeBSD__) || defined(__DragonFly__)
1189 if (strcmp(mnts[i].f_fstypename,"nfs") == 0) {
1191 retval = nfs_quotas(mnts[i].f_mntfromname,euser_id,bsize,dfree,dsize);
1197 egrp_id = getegid();
1198 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1200 /* As FreeBSD has group quotas, if getting the user
1201 quota fails, try getting the group instead. */
1203 r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
1209 /* AIX has both USER and GROUP quotas:
1210 Get the USER quota (ohnielse@fysik.dtu.dk) */
1211 #ifdef _AIXVERSION_530
1213 struct statfs statbuf;
1214 quota64_t user_quota;
1215 if (statfs(path,&statbuf) != 0)
1217 if(statbuf.f_vfstype == MNT_J2)
1219 /* For some reason we need to be root for jfs2 */
1221 r = quotactl(path,QCMD(Q_J2GETQUOTA,USRQUOTA),euser_id,(char *) &user_quota);
1223 /* Copy results to old struct to let the following code work as before */
1224 D.dqb_curblocks = user_quota.bused;
1225 D.dqb_bsoftlimit = user_quota.bsoft;
1226 D.dqb_bhardlimit = user_quota.bhard;
1228 else if(statbuf.f_vfstype == MNT_JFS)
1230 #endif /* AIX 5.3 */
1232 if (set_re_uid() != 0)
1234 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1236 #ifdef _AIXVERSION_530
1239 r = 1; /* Fail for other FS-types */
1241 #endif /* AIX 5.3 */
1242 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1243 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1244 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1247 /* Use softlimit to determine disk space, except when it has been exceeded */
1248 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1250 #else /* !__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1252 #endif /*!__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1256 if (errno == EDQUOT)
1259 *dsize =D.dqb_curblocks;
1265 /* If softlimit is zero, set it equal to hardlimit.
1268 if (D.dqb_bsoftlimit==0)
1269 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1271 if (D.dqb_bsoftlimit==0)
1273 /* Use softlimit to determine disk space, except when it has been exceeded */
1274 if ((D.dqb_curblocks>D.dqb_bsoftlimit)
1275 #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1276 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
1280 *dsize = D.dqb_curblocks;
1283 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1284 *dsize = D.dqb_bsoftlimit;
1291 #if defined(VXFS_QUOTA)
1293 /****************************************************************************
1294 Try to get the disk space from Veritas disk quotas.
1295 David Lee <T.D.Lee@durham.ac.uk> August 1999.
1297 Background assumptions:
1298 Potentially under many Operating Systems. Initially Solaris 2.
1300 My guess is that Veritas is largely, though not entirely,
1301 independent of OS. So I have separated it out.
1303 There may be some details. For example, OS-specific "include" files.
1305 It is understood that HPUX 10 somehow gets Veritas quotas without
1306 any special effort; if so, this routine need not be compiled in.
1307 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1310 It is understood that Veritas do not publicly support this ioctl interface.
1311 Rather their preference would be for the user (us) to call the native
1312 OS and then for the OS itself to call through to the VxFS filesystem.
1313 Presumably HPUX 10, see above, does this.
1316 Add your OS to "IFLIST" below.
1317 Get it to compile successfully:
1318 Almost certainly "include"s require attention: see SUNOS5.
1319 In the main code above, arrange for it to be called: see SUNOS5.
1322 ****************************************************************************/
1325 * This "if" is a list of ports:
1326 * if defined(OS1) || defined(OS2) || ...
1331 #include <sys/fs/vx_solaris.h>
1333 #include <sys/fs/vx_machdep.h>
1334 #include <sys/fs/vx_layout.h>
1335 #include <sys/fs/vx_quota.h>
1336 #include <sys/fs/vx_aioctl.h>
1337 #include <sys/fs/vx_ioctl.h>
1339 BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
1341 uid_t user_id, euser_id;
1344 struct vx_quotctl quotabuf;
1345 struct vx_genioctl genbuf;
1350 * "name" may or may not include a trailing "/quotas".
1351 * Arranging consistency of calling here in "quotas.c" may not be easy and
1352 * it might be easier to examine and adjust it here.
1353 * Fortunately, VxFS seems not to mind at present.
1355 pstrcpy(qfname, name) ;
1356 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
1358 euser_id = geteuid();
1359 set_effective_uid(0);
1361 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
1362 if((file=sys_open(qfname, O_RDONLY,0))<0) {
1363 set_effective_uid(euser_id);
1366 genbuf.ioc_cmd = VX_QUOTACTL;
1367 genbuf.ioc_up = (void *) "abuf;
1369 quotabuf.cmd = VX_GETQUOTA;
1370 quotabuf.uid = euser_id;
1371 quotabuf.addr = (caddr_t) &D;
1372 ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
1375 set_effective_uid(euser_id);
1378 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
1382 /* If softlimit is zero, set it equal to hardlimit.
1385 if (D.dqb_bsoftlimit==0)
1386 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1388 /* Use softlimit to determine disk space. A user exceeding the quota is told
1389 * that there's no space left. Writes might actually work for a bit if the
1390 * hardlimit is set higher than softlimit. Effectively the disk becomes
1391 * made of rubber latex and begins to expand to accommodate the user :-)
1393 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1394 path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
1395 D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
1397 if (D.dqb_bsoftlimit==0)
1400 *dsize = D.dqb_bsoftlimit;
1402 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1404 *dsize = D.dqb_curblocks;
1406 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1408 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
1409 path,(double)*bsize,(double)*dfree,(double)*dsize));
1414 #endif /* SUNOS5 || ... */
1416 #endif /* VXFS_QUOTA */
1418 #else /* WITH_QUOTAS */
1420 BOOL disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
1422 (*bsize) = 512; /* This value should be ignored */
1424 /* And just to be sure we set some values that hopefully */
1425 /* will be larger that any possible real-world value */
1426 (*dfree) = (SMB_BIG_UINT)-1;
1427 (*dsize) = (SMB_BIG_UINT)-1;
1429 /* As we have select not to use quotas, allways fail */
1432 #endif /* WITH_QUOTAS */
1434 #else /* HAVE_SYS_QUOTAS */
1435 /* wrapper to the new sys_quota interface
1436 this file should be removed later
1438 BOOL disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
1447 r=sys_get_quota(path, SMB_USER_QUOTA_TYPE, id, &D);
1449 /* Use softlimit to determine disk space, except when it has been exceeded */
1452 if (errno == EDQUOT) {
1454 *dsize =D.curblocks;
1457 goto try_group_quota;
1461 /* Use softlimit to determine disk space, except when it has been exceeded */
1463 (D.softlimit && D.curblocks >= D.softlimit) ||
1464 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1465 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1466 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1469 *dsize = D.curblocks;
1470 } else if (D.softlimit==0 && D.hardlimit==0) {
1471 goto try_group_quota;
1473 if (D.softlimit == 0)
1474 D.softlimit = D.hardlimit;
1475 *dfree = D.softlimit - D.curblocks;
1476 *dsize = D.softlimit;
1485 r=sys_get_quota(path, SMB_GROUP_QUOTA_TYPE, id, &D);
1487 /* Use softlimit to determine disk space, except when it has been exceeded */
1490 if (errno == EDQUOT) {
1492 *dsize =D.curblocks;
1499 /* Use softlimit to determine disk space, except when it has been exceeded */
1501 (D.softlimit && D.curblocks >= D.softlimit) ||
1502 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1503 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1504 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1507 *dsize = D.curblocks;
1508 } else if (D.softlimit==0 && D.hardlimit==0) {
1511 if (D.softlimit == 0)
1512 D.softlimit = D.hardlimit;
1513 *dfree = D.softlimit - D.curblocks;
1514 *dsize = D.softlimit;
1519 #endif /* HAVE_SYS_QUOTAS */