r17915: Saturn fixes
[Samba/gbeck.git] / source / smbd / quotas.c
blobd6ba7bc2d55306c8a1899a0423f93e2ffe0977f7
1 /*
2 Unix SMB/CIFS implementation.
3 support for quotas
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.
22 /*
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
25 * things :-(
28 #include "includes.h"
30 #undef DBGC_CLASS
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
38 #endif
40 #ifdef WITH_QUOTAS
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 */
53 #ifdef LINUX
55 #include <sys/types.h>
56 #include <mntent.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 {
68 SMB_BIG_UINT bsize;
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;
84 int ret;
86 ZERO_STRUCT(D);
88 ret = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
90 if (ret)
91 ret = quotactl(QCMD(Q_XGETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
93 if (ret)
94 return ret;
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;
104 return ret;
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;
114 int ret;
116 ZERO_STRUCT(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)
124 return ret;
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;
134 return ret;
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;
140 int ret;
142 ZERO_STRUCT(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)
150 return ret;
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;
160 return ret;
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)
169 struct if_dqblk D;
170 int ret;
172 ZERO_STRUCT(D);
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)
180 return ret;
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;
190 return ret;
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)
199 int r;
200 SMB_STRUCT_STAT S;
201 FILE *fp;
202 LINUX_SMB_DISK_QUOTA D;
203 struct mntent *mnt;
204 SMB_DEV_T devno;
205 int found;
206 uid_t euser_id;
207 gid_t egrp_id;
209 ZERO_STRUCT(D);
211 euser_id = geteuid();
212 egrp_id = getegid();
214 /* find the block device file */
216 if ( sys_stat(path, &S) == -1 )
217 return(False) ;
219 devno = S.st_dev ;
221 if ((fp = setmntent(MOUNTED,"r")) == NULL)
222 return(False) ;
224 found = False ;
226 while ((mnt = getmntent(fp))) {
227 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
228 continue ;
230 if (S.st_dev == devno) {
231 found = True ;
232 break;
236 endmntent(fp) ;
238 if (!found)
239 return(False);
241 save_re_uid();
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);
246 } else {
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);
255 restore_re_uid();
257 /* Use softlimit to determine disk space, except when it has been exceeded */
258 *bsize = D.bsize;
259 if (r == -1) {
260 if (errno == EDQUOT) {
261 *dfree =0;
262 *dsize =D.curblocks;
263 return (True);
264 } else {
265 return(False);
269 /* Use softlimit to determine disk space, except when it has been exceeded */
270 if (
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)
276 *dfree = 0;
277 *dsize = D.curblocks;
278 } else if (D.softlimit==0 && D.hardlimit==0) {
279 return(False);
280 } else {
281 if (D.softlimit == 0)
282 D.softlimit = D.hardlimit;
283 *dfree = D.softlimit - D.curblocks;
284 *dsize = D.softlimit;
287 return (True);
290 #elif defined(CRAY)
292 #include <sys/quota.h>
293 #include <mntent.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)
301 struct mntent *mnt;
302 FILE *fd;
303 SMB_STRUCT_STAT sbuf;
304 SMB_DEV_T devno ;
305 static SMB_DEV_T devno_cached = 0 ;
306 static pstring name;
307 struct q_request request ;
308 struct qf_header header ;
309 static int quota_default = 0 ;
310 int found ;
312 if ( sys_stat(path,&sbuf) == -1 )
313 return(False) ;
315 devno = sbuf.st_dev ;
317 if ( devno != devno_cached ) {
319 devno_cached = devno ;
321 if ((fd = setmntent(KMTAB)) == NULL)
322 return(False) ;
324 found = False ;
326 while ((mnt = getmntent(fd)) != NULL) {
328 if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
329 continue ;
331 if (sbuf.st_dev == devno) {
333 found = True ;
334 break ;
340 pstrcpy(name,mnt->mnt_dir) ;
341 endmntent(fd) ;
343 if ( ! found )
344 return(False) ;
347 request.qf_magic = QF_MAGIC ;
348 request.qf_entry.id = geteuid() ;
350 if (quotactl(name, Q_GETQUOTA, &request) == -1)
351 return(False) ;
353 if ( ! request.user )
354 return(False) ;
356 if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) {
358 if ( ! quota_default ) {
360 if ( quotactl(name, Q_GETHEADER, &header) == -1 )
361 return(False) ;
362 else
363 quota_default = header.user_h.def_fq ;
366 *dfree = quota_default ;
368 }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) {
370 *dfree = 0 ;
372 }else{
374 *dfree = request.qf_entry.user_q.f_quota ;
378 *dsize = request.qf_entry.user_q.f_use ;
380 if ( *dfree < *dsize )
381 *dfree = 0 ;
382 else
383 *dfree -= *dsize ;
385 *bsize = 4096 ; /* Cray blocksize */
387 return(True) ;
392 #elif defined(SUNOS5) || defined(SUNOS4)
394 #include <fcntl.h>
395 #include <sys/param.h>
396 #if defined(SUNOS5)
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>
402 #include <mntent.h>
403 #endif
405 #if defined(SUNOS5)
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 ****************************************************************************/
413 #include <rpc/rpc.h>
414 #include <rpc/types.h>
415 #include <rpcsvc/rquota.h>
416 #include <rpc/nettype.h>
417 #include <rpc/xdr.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 ))
424 return(0);
425 if (!xdr_int(xdrsp, &args->gqa_uid))
426 return(0);
427 return (1);
430 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
432 if (!xdr_int(xdrsp, &quotastat)) {
433 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
434 return 0;
436 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
437 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
438 return 0;
440 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
441 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
442 return 0;
444 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
445 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
446 return 0;
448 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
449 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
450 return 0;
452 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
453 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
454 return 0;
456 return (1);
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;
463 struct dqblk D;
464 char *mnttype = nfspath;
465 CLIENT *clnt;
466 struct getquota_rslt gqr;
467 struct getquota_args args;
468 char *cutstr, *pathname, *host, *testpath;
469 int len;
470 static struct timeval timeout = {2,0};
471 enum clnt_stat clnt_stat;
472 BOOL ret = True;
474 *bsize = *dfree = *dsize = (SMB_BIG_UINT)0;
476 len=strcspn(mnttype, ":");
477 pathname=strstr(mnttype, ":");
478 cutstr = (char *) SMB_MALLOC(len+1);
479 if (!cutstr)
480 return False;
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;
488 args.gqa_uid = uid;
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) {
493 ret = False;
494 goto out;
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"));
504 ret = False;
505 goto out;
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 ) {
515 case 0:
516 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat ));
517 ret = False;
518 goto out;
520 case 1:
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;
525 break;
527 case 2:
528 case 3:
529 D.dqb_bsoftlimit = 1;
530 D.dqb_curblocks = 1;
531 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
532 break;
534 default:
535 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat ));
536 break;
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",
540 quotastat,
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)
551 *bsize = 512;
553 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
554 *dfree = 0;
555 *dsize = D.dqb_curblocks;
556 } else
557 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
559 out:
561 if (clnt) {
562 if (clnt->cl_auth)
563 auth_destroy(clnt->cl_auth);
564 clnt_destroy(clnt);
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));
569 SAFE_FREE(cutstr);
570 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
571 return ret;
573 #endif
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)
582 uid_t euser_id;
583 int ret;
584 struct dqblk D;
585 #if defined(SUNOS5)
586 struct quotctl command;
587 int file;
588 static struct mnttab mnt;
589 static pstring name;
590 pstring devopt;
591 #else /* SunOS4 */
592 struct mntent *mnt;
593 static pstring name;
594 #endif
595 FILE *fd;
596 SMB_STRUCT_STAT sbuf;
597 SMB_DEV_T devno ;
598 static SMB_DEV_T devno_cached = 0 ;
599 static int found ;
601 euser_id = geteuid();
603 if ( sys_stat(path,&sbuf) == -1 )
604 return(False) ;
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 ;
610 #if defined(SUNOS5)
611 if ((fd = sys_fopen(MNTTAB, "r")) == NULL)
612 return(False) ;
614 found = False ;
615 slprintf(devopt, sizeof(devopt) - 1, "dev=%x", (unsigned int)devno);
616 while (getmntent(fd, &mnt) == 0) {
617 if( !hasmntopt(&mnt, devopt) )
618 continue;
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 ) {
626 found = True ;
627 break;
631 pstrcpy(name,mnt.mnt_mountp) ;
632 pstrcat(name,"/quotas") ;
633 fclose(fd) ;
634 #else /* SunOS4 */
635 if ((fd = setmntent(MOUNTED, "r")) == NULL)
636 return(False) ;
638 found = False ;
639 while ((mnt = getmntent(fd)) != NULL) {
640 if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
641 continue ;
642 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n", mnt->mnt_dir,(unsigned int)sbuf.st_dev));
643 if (sbuf.st_dev == devno) {
644 found = True ;
645 break;
649 pstrcpy(name,mnt->mnt_fsname) ;
650 endmntent(fd) ;
651 #endif
654 if ( ! found )
655 return(False) ;
657 save_re_uid();
658 set_effective_uid(0);
660 #if defined(SUNOS5)
661 if ( strcmp( mnt.mnt_fstype, "nfs" ) == 0) {
662 BOOL retval;
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);
665 restore_re_uid();
666 return retval;
669 DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
670 if((file=sys_open(name, O_RDONLY,0))<0) {
671 restore_re_uid();
672 return(False);
674 command.op = Q_GETQUOTA;
675 command.uid = euser_id;
676 command.addr = (caddr_t) &D;
677 ret = ioctl(file, Q_QUOTACTL, &command);
678 close(file);
679 #else
680 DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
681 ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
682 #endif
684 restore_re_uid();
686 if (ret < 0) {
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" )) {
694 BOOL retval;
695 retval = disk_quotas_vxfs(name, path, bsize, dfree, dsize);
696 return(retval);
698 #else
699 return(False);
700 #endif
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)
716 return(False);
717 *bsize = DEV_BSIZE;
718 *dsize = D.dqb_bsoftlimit;
720 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
721 *dfree = 0;
722 *dsize = D.dqb_curblocks;
723 } else
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));
729 return(True);
733 #elif defined(OSF1)
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)
742 int r, save_errno;
743 struct dqblk D;
744 SMB_STRUCT_STAT S;
745 uid_t euser_id;
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();
753 save_re_uid();
754 if (set_re_uid() != 0) return False;
756 r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
757 if (r) {
758 save_errno = errno;
761 restore_re_uid();
763 *bsize = DEV_BSIZE;
765 if (r)
767 if (save_errno == EDQUOT) /* disk quota exceeded */
769 *dfree = 0;
770 *dsize = D.dqb_curblocks;
771 return (True);
773 else
774 return (False);
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)
786 return(False);
788 if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
789 *dfree = 0;
790 *dsize = D.dqb_curblocks;
791 } else {
792 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
793 *dsize = D.dqb_bsoftlimit;
795 return (True);
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>
804 #include <mntent.h>
806 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
808 uid_t euser_id;
809 int r;
810 struct dqblk D;
811 struct fs_disk_quota F;
812 SMB_STRUCT_STAT S;
813 FILE *fp;
814 struct mntent *mnt;
815 SMB_DEV_T devno;
816 int found;
818 /* find the block device file */
820 if ( sys_stat(path, &S) == -1 ) {
821 return(False) ;
824 devno = S.st_dev ;
826 fp = setmntent(MOUNTED,"r");
827 found = False ;
829 while ((mnt = getmntent(fp))) {
830 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
831 continue ;
832 if (S.st_dev == devno) {
833 found = True ;
834 break ;
837 endmntent(fp) ;
839 if (!found) {
840 return(False);
843 euser_id=geteuid();
844 save_re_uid();
845 set_effective_uid(0);
847 /* Use softlimit to determine disk space, except when it has been exceeded */
849 *bsize = 512;
851 if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
853 r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
855 restore_re_uid();
857 if (r==-1)
858 return(False);
860 /* Use softlimit to determine disk space, except when it has been exceeded */
861 if (
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)
868 *dfree = 0;
869 *dsize = D.dqb_curblocks;
871 else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
873 return(False);
875 else
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);
886 restore_re_uid();
888 if (r==-1)
890 DEBUG(5, ("quotactl for uid=%u: %s", euser_id, strerror(errno)));
891 return(False);
894 /* No quota for this user. */
895 if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
897 return(False);
900 /* Use softlimit to determine disk space, except when it has been exceeded */
901 if (
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)
908 *dfree = 0;
909 *dsize = F.d_bcount;
911 else
913 *dfree = (F.d_blk_softlimit - F.d_bcount);
914 *dsize = F.d_blk_softlimit ? F.d_blk_softlimit : F.d_blk_hardlimit;
918 else
920 restore_re_uid();
921 return(False);
924 return (True);
928 #else
930 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
931 #include <ufs/ufs/quota.h>
932 #include <machine/param.h>
933 #elif AIX
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>
942 #include <devnm.h>
943 #endif
945 #if defined(__FreeBSD__) || defined(__DragonFly__)
947 #include <rpc/rpc.h>
948 #include <rpc/types.h>
949 #include <rpcsvc/rquota.h>
950 #ifdef HAVE_RPC_NETTYPE_H
951 #include <rpc/nettype.h>
952 #endif
953 #include <rpc/xdr.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 ))
960 return(0);
961 if (!xdr_int(xdrsp, &args->gqa_uid))
962 return(0);
963 return (1);
966 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
968 if (!xdr_int(xdrsp, &quotastat)) {
969 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
970 return 0;
972 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
973 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
974 return 0;
976 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
977 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
978 return 0;
980 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
981 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
982 return 0;
984 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
985 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
986 return 0;
988 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
989 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
990 return 0;
992 return (1);
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;
999 struct dqblk D;
1000 char *mnttype = nfspath;
1001 CLIENT *clnt;
1002 struct getquota_rslt gqr;
1003 struct getquota_args args;
1004 char *cutstr, *pathname, *host, *testpath;
1005 int len;
1006 static struct timeval timeout = {2,0};
1007 enum clnt_stat clnt_stat;
1008 BOOL ret = True;
1010 *bsize = *dfree = *dsize = (SMB_BIG_UINT)0;
1012 len=strcspn(mnttype, ":");
1013 pathname=strstr(mnttype, ":");
1014 cutstr = (char *) SMB_MALLOC(len+1);
1015 if (!cutstr)
1016 return False;
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;
1024 args.gqa_uid = uid;
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) {
1029 ret = False;
1030 goto out;
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"));
1040 ret = False;
1041 goto out;
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 ) {
1051 case 0:
1052 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat ));
1053 ret = False;
1054 goto out;
1056 case 1:
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;
1061 break;
1063 case 2:
1064 case 3:
1065 D.dqb_bsoftlimit = 1;
1066 D.dqb_curblocks = 1;
1067 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
1068 break;
1070 default:
1071 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat ));
1072 break;
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",
1076 quotastat,
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)
1086 return False;
1088 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
1089 *dsize = D.dqb_bsoftlimit;
1091 if (D.dqb_curblocks == D.dqb_curblocks == 1)
1092 *bsize = DEV_BSIZE;
1094 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1095 *dfree = 0;
1096 *dsize = D.dqb_curblocks;
1097 } else
1098 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1100 out:
1102 if (clnt) {
1103 if (clnt->cl_auth)
1104 auth_destroy(clnt->cl_auth);
1105 clnt_destroy(clnt);
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));
1110 SAFE_FREE(cutstr);
1111 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
1112 return ret;
1115 #endif
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)
1123 int r;
1124 struct dqblk D;
1125 uid_t euser_id;
1126 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1127 char dev_disk[256];
1128 SMB_STRUCT_STAT S;
1130 /* find the block device file */
1132 #ifdef HPUX
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))
1138 #else
1139 if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0))
1140 return (False);
1141 #endif /* ifdef HPUX */
1143 #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__) */
1145 euser_id = geteuid();
1147 #ifdef HPUX
1148 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
1149 save_re_uid();
1150 if (set_re_uid() != 0) return False;
1152 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1154 restore_re_uid();
1155 #else
1156 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1158 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
1159 gid_t egrp_id;
1160 #if defined(__FreeBSD__) || defined(__DragonFly__)
1161 SMB_DEV_T devno;
1162 struct statfs *mnts;
1163 SMB_STRUCT_STAT st;
1164 int mntsize, i;
1166 if (sys_stat(path,&st) < 0)
1167 return False;
1168 devno = st.st_dev;
1170 mntsize = getmntinfo(&mnts,MNT_NOWAIT);
1171 if (mntsize <= 0)
1172 return False;
1174 for (i = 0; i < mntsize; i++) {
1175 if (sys_stat(mnts[i].f_mntonname,&st) < 0)
1176 return False;
1177 if (st.st_dev == devno)
1178 break;
1180 if (i == mntsize)
1181 return False;
1182 #endif
1184 save_re_uid();
1185 set_effective_uid(0);
1187 #if defined(__FreeBSD__) || defined(__DragonFly__)
1188 if (strcmp(mnts[i].f_fstypename,"nfs") == 0) {
1189 BOOL retval;
1190 retval = nfs_quotas(mnts[i].f_mntfromname,euser_id,bsize,dfree,dsize);
1191 restore_re_uid();
1192 return retval;
1194 #endif
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. */
1201 if (r) {
1202 r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
1205 restore_re_uid();
1207 #elif defined(AIX)
1208 /* AIX has both USER and GROUP quotas:
1209 Get the USER quota (ohnielse@fysik.dtu.dk) */
1210 save_re_uid();
1211 if (set_re_uid() != 0)
1212 return False;
1213 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1214 restore_re_uid();
1215 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1216 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1217 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1218 #endif /* HPUX */
1220 /* Use softlimit to determine disk space, except when it has been exceeded */
1221 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1222 *bsize = DEV_BSIZE;
1223 #else /* !__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1224 *bsize = 1024;
1225 #endif /*!__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1227 if (r)
1229 if (errno == EDQUOT)
1231 *dfree =0;
1232 *dsize =D.dqb_curblocks;
1233 return (True);
1235 else return(False);
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)
1245 return(False);
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))
1250 #endif
1252 *dfree = 0;
1253 *dsize = D.dqb_curblocks;
1255 else {
1256 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1257 *dsize = D.dqb_bsoftlimit;
1259 return (True);
1262 #endif
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>
1282 Warning:
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.
1288 Hints for porting:
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.
1293 Test!
1295 ****************************************************************************/
1297 /* "IFLIST"
1298 * This "if" is a list of ports:
1299 * if defined(OS1) || defined(OS2) || ...
1301 #if defined(SUNOS5)
1303 #if defined(SUNOS5)
1304 #include <sys/fs/vx_solaris.h>
1305 #endif
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;
1315 int ret;
1316 struct vx_dqblk D;
1317 struct vx_quotctl quotabuf;
1318 struct vx_genioctl genbuf;
1319 pstring qfname;
1320 int file;
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);
1337 return(False);
1339 genbuf.ioc_cmd = VX_QUOTACTL;
1340 genbuf.ioc_up = (void *) &quotabuf;
1342 quotabuf.cmd = VX_GETQUOTA;
1343 quotabuf.uid = euser_id;
1344 quotabuf.addr = (caddr_t) &D;
1345 ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
1346 close(file);
1348 set_effective_uid(euser_id);
1350 if (ret < 0) {
1351 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
1352 return(False);
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)
1371 return(False);
1372 *bsize = DEV_BSIZE;
1373 *dsize = D.dqb_bsoftlimit;
1375 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1376 *dfree = 0;
1377 *dsize = D.dqb_curblocks;
1378 } else
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));
1384 return(True);
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 */
1403 return False;
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)
1413 int r;
1414 SMB_DISK_QUOTA D;
1415 unid_t id;
1417 id.uid = geteuid();
1419 ZERO_STRUCT(D);
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 */
1423 *bsize = D.bsize;
1424 if (r == -1) {
1425 if (errno == EDQUOT) {
1426 *dfree =0;
1427 *dsize =D.curblocks;
1428 return (True);
1429 } else {
1430 goto try_group_quota;
1434 /* Use softlimit to determine disk space, except when it has been exceeded */
1435 if (
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)
1441 *dfree = 0;
1442 *dsize = D.curblocks;
1443 } else if (D.softlimit==0 && D.hardlimit==0) {
1444 goto try_group_quota;
1445 } else {
1446 if (D.softlimit == 0)
1447 D.softlimit = D.hardlimit;
1448 *dfree = D.softlimit - D.curblocks;
1449 *dsize = D.softlimit;
1452 return True;
1454 try_group_quota:
1455 id.gid = getegid();
1457 ZERO_STRUCT(D);
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 */
1461 *bsize = D.bsize;
1462 if (r == -1) {
1463 if (errno == EDQUOT) {
1464 *dfree =0;
1465 *dsize =D.curblocks;
1466 return (True);
1467 } else {
1468 return False;
1472 /* Use softlimit to determine disk space, except when it has been exceeded */
1473 if (
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)
1479 *dfree = 0;
1480 *dsize = D.curblocks;
1481 } else if (D.softlimit==0 && D.hardlimit==0) {
1482 return False;
1483 } else {
1484 if (D.softlimit == 0)
1485 D.softlimit = D.hardlimit;
1486 *dfree = D.softlimit - D.curblocks;
1487 *dsize = D.softlimit;
1490 return (True);
1492 #endif /* HAVE_SYS_QUOTAS */