Updated with sepcifics of how we determine sendfile.
[Samba.git] / source / smbd / quotas.c
blobb6d3257c0fff5e6c4d9666775a95a22e87253524
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 become_root();
243 if (strcmp(mnt->mnt_type, "xfs")==0) {
244 r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
245 } else {
246 r=get_smb_linux_gen_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
247 if (r == -1 && errno != EDQUOT) {
248 r=get_smb_linux_v2_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
249 if (r == -1 && errno != EDQUOT)
250 r=get_smb_linux_v1_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
254 unbecome_root();
256 /* Use softlimit to determine disk space, except when it has been exceeded */
257 *bsize = D.bsize;
258 if (r == -1) {
259 if (errno == EDQUOT) {
260 *dfree =0;
261 *dsize =D.curblocks;
262 return (True);
263 } else {
264 return(False);
268 /* Use softlimit to determine disk space, except when it has been exceeded */
269 if (
270 (D.softlimit && D.curblocks >= D.softlimit) ||
271 (D.hardlimit && D.curblocks >= D.hardlimit) ||
272 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
273 (D.ihardlimit && D.curinodes>=D.ihardlimit)
275 *dfree = 0;
276 *dsize = D.curblocks;
277 } else if (D.softlimit==0 && D.hardlimit==0) {
278 return(False);
279 } else {
280 if (D.softlimit == 0)
281 D.softlimit = D.hardlimit;
282 *dfree = D.softlimit - D.curblocks;
283 *dsize = D.softlimit;
286 return (True);
289 #elif defined(CRAY)
291 #include <sys/quota.h>
292 #include <mntent.h>
294 /****************************************************************************
295 try to get the disk space from disk quotas (CRAY VERSION)
296 ****************************************************************************/
298 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
300 struct mntent *mnt;
301 FILE *fd;
302 SMB_STRUCT_STAT sbuf;
303 SMB_DEV_T devno ;
304 static SMB_DEV_T devno_cached = 0 ;
305 static pstring name;
306 struct q_request request ;
307 struct qf_header header ;
308 static int quota_default = 0 ;
309 int found ;
311 if ( sys_stat(path,&sbuf) == -1 )
312 return(False) ;
314 devno = sbuf.st_dev ;
316 if ( devno != devno_cached ) {
318 devno_cached = devno ;
320 if ((fd = setmntent(KMTAB)) == NULL)
321 return(False) ;
323 found = False ;
325 while ((mnt = getmntent(fd)) != NULL) {
327 if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
328 continue ;
330 if (sbuf.st_dev == devno) {
332 found = True ;
333 break ;
339 pstrcpy(name,mnt->mnt_dir) ;
340 endmntent(fd) ;
342 if ( ! found )
343 return(False) ;
346 request.qf_magic = QF_MAGIC ;
347 request.qf_entry.id = geteuid() ;
349 if (quotactl(name, Q_GETQUOTA, &request) == -1)
350 return(False) ;
352 if ( ! request.user )
353 return(False) ;
355 if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) {
357 if ( ! quota_default ) {
359 if ( quotactl(name, Q_GETHEADER, &header) == -1 )
360 return(False) ;
361 else
362 quota_default = header.user_h.def_fq ;
365 *dfree = quota_default ;
367 }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) {
369 *dfree = 0 ;
371 }else{
373 *dfree = request.qf_entry.user_q.f_quota ;
377 *dsize = request.qf_entry.user_q.f_use ;
379 if ( *dfree < *dsize )
380 *dfree = 0 ;
381 else
382 *dfree -= *dsize ;
384 *bsize = 4096 ; /* Cray blocksize */
386 return(True) ;
391 #elif defined(SUNOS5) || defined(SUNOS4)
393 #include <fcntl.h>
394 #include <sys/param.h>
395 #if defined(SUNOS5)
396 #include <sys/fs/ufs_quota.h>
397 #include <sys/mnttab.h>
398 #include <sys/mntent.h>
399 #else /* defined(SUNOS4) */
400 #include <ufs/quota.h>
401 #include <mntent.h>
402 #endif
404 #if defined(SUNOS5)
406 /****************************************************************************
407 Allows querying of remote hosts for quotas on NFS mounted shares.
408 Supports normal NFS and AMD mounts.
409 Alan Romeril <a.romeril@ic.ac.uk> July 2K.
410 ****************************************************************************/
412 #include <rpc/rpc.h>
413 #include <rpc/types.h>
414 #include <rpcsvc/rquota.h>
415 #include <rpc/nettype.h>
416 #include <rpc/xdr.h>
418 static int quotastat;
420 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
422 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
423 return(0);
424 if (!xdr_int(xdrsp, &args->gqa_uid))
425 return(0);
426 return (1);
429 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
431 if (!xdr_int(xdrsp, &quotastat)) {
432 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
433 return 0;
435 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
436 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
437 return 0;
439 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
440 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
441 return 0;
443 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
444 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
445 return 0;
447 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
448 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
449 return 0;
451 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
452 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
453 return 0;
455 return (1);
458 /* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
459 static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
461 uid_t uid = euser_id;
462 struct dqblk D;
463 char *mnttype = nfspath;
464 CLIENT *clnt;
465 struct getquota_rslt gqr;
466 struct getquota_args args;
467 char *cutstr, *pathname, *host, *testpath;
468 int len;
469 static struct timeval timeout = {2,0};
470 enum clnt_stat clnt_stat;
471 BOOL ret = True;
473 *bsize = *dfree = *dsize = (SMB_BIG_UINT)0;
475 len=strcspn(mnttype, ":");
476 pathname=strstr(mnttype, ":");
477 cutstr = (char *) SMB_MALLOC(len+1);
478 if (!cutstr)
479 return False;
481 memset(cutstr, '\0', len+1);
482 host = strncat(cutstr,mnttype, sizeof(char) * len );
483 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
484 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
485 testpath=strchr_m(mnttype, ':');
486 args.gqa_pathp = testpath+1;
487 args.gqa_uid = uid;
489 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
491 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
492 ret = False;
493 goto out;
496 clnt->cl_auth = authunix_create_default();
497 DEBUG(9,("nfs_quotas: auth_success\n"));
499 clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, my_xdr_getquota_args, (caddr_t)&args, my_xdr_getquota_rslt, (caddr_t)&gqr, timeout);
501 if (clnt_stat != RPC_SUCCESS) {
502 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
503 ret = False;
504 goto out;
508 * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
509 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
510 * something sensible.
513 switch ( quotastat ) {
514 case 0:
515 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat ));
516 ret = False;
517 goto out;
519 case 1:
520 DEBUG(9,("nfs_quotas: Good quota data\n"));
521 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
522 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
523 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
524 break;
526 case 2:
527 case 3:
528 D.dqb_bsoftlimit = 1;
529 D.dqb_curblocks = 1;
530 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
531 break;
533 default:
534 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat ));
535 break;
538 DEBUG(10,("nfs_quotas: Let`s look at D a bit closer... status \"%i\" bsize \"%i\" active? \"%i\" bhard \"%i\" bsoft \"%i\" curb \"%i\" \n",
539 quotastat,
540 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
541 gqr.getquota_rslt_u.gqr_rquota.rq_active,
542 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
543 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
544 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
546 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
547 *dsize = D.dqb_bsoftlimit;
549 if (D.dqb_curblocks == D.dqb_curblocks == 1)
550 *bsize = 512;
552 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
553 *dfree = 0;
554 *dsize = D.dqb_curblocks;
555 } else
556 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
558 out:
560 if (clnt) {
561 if (clnt->cl_auth)
562 auth_destroy(clnt->cl_auth);
563 clnt_destroy(clnt);
566 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
568 SAFE_FREE(cutstr);
569 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
570 return ret;
572 #endif
574 /****************************************************************************
575 try to get the disk space from disk quotas (SunOS & Solaris2 version)
576 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
577 ****************************************************************************/
579 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
581 uid_t euser_id;
582 int ret;
583 struct dqblk D;
584 #if defined(SUNOS5)
585 struct quotctl command;
586 int file;
587 static struct mnttab mnt;
588 static pstring name;
589 #else /* SunOS4 */
590 struct mntent *mnt;
591 static pstring name;
592 #endif
593 FILE *fd;
594 SMB_STRUCT_STAT sbuf;
595 SMB_DEV_T devno ;
596 static SMB_DEV_T devno_cached = 0 ;
597 static int found ;
599 euser_id = geteuid();
601 if ( sys_stat(path,&sbuf) == -1 )
602 return(False) ;
604 devno = sbuf.st_dev ;
605 DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n",
606 path, (unsigned int)devno));
607 if ( devno != devno_cached ) {
608 devno_cached = devno ;
609 #if defined(SUNOS5)
610 if ((fd = sys_fopen(MNTTAB, "r")) == NULL)
611 return(False) ;
613 found = False ;
615 while (getmntent(fd, &mnt) == 0) {
616 if (sys_stat(mnt.mnt_mountp, &sbuf) == -1)
617 continue;
619 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
620 mnt.mnt_mountp, (unsigned int)devno));
622 /* quotas are only on vxfs, UFS or NFS */
623 if ( (sbuf.st_dev == devno) && (
624 strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
625 strcmp( mnt.mnt_fstype, "nfs" ) == 0 ||
626 strcmp( mnt.mnt_fstype, "vxfs" ) == 0 )) {
627 found = True ;
628 break;
632 pstrcpy(name,mnt.mnt_mountp) ;
633 pstrcat(name,"/quotas") ;
634 fclose(fd) ;
635 #else /* SunOS4 */
636 if ((fd = setmntent(MOUNTED, "r")) == NULL)
637 return(False) ;
639 found = False ;
640 while ((mnt = getmntent(fd)) != NULL) {
641 if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
642 continue ;
643 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n", mnt->mnt_dir,(unsigned int)sbuf.st_dev));
644 if (sbuf.st_dev == devno) {
645 found = True ;
646 break;
650 pstrcpy(name,mnt->mnt_fsname) ;
651 endmntent(fd) ;
652 #endif
655 if ( ! found )
656 return(False) ;
658 become_root();
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 unbecome_root();
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 unbecome_root();
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 unbecome_root();
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 become_root();
846 /* Use softlimit to determine disk space, except when it has been exceeded */
848 *bsize = 512;
850 if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
852 r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
854 unbecome_root();
856 if (r==-1)
857 return(False);
859 /* Use softlimit to determine disk space, except when it has been exceeded */
860 if (
861 (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
862 (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
863 (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
864 (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
867 *dfree = 0;
868 *dsize = D.dqb_curblocks;
870 else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
872 return(False);
874 else
876 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
877 *dsize = D.dqb_bsoftlimit;
881 else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
883 r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
885 unbecome_root();
887 if (r==-1)
889 DEBUG(5, ("quotactl for uid=%u: %s", euser_id, strerror(errno)));
890 return(False);
893 /* No quota for this user. */
894 if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
896 return(False);
899 /* Use softlimit to determine disk space, except when it has been exceeded */
900 if (
901 (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
902 (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
903 (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
904 (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
907 *dfree = 0;
908 *dsize = F.d_bcount;
910 else
912 *dfree = (F.d_blk_softlimit - F.d_bcount);
913 *dsize = F.d_blk_softlimit ? F.d_blk_softlimit : F.d_blk_hardlimit;
917 else
919 unbecome_root();
920 return(False);
923 return (True);
927 #else
929 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
930 #include <ufs/ufs/quota.h>
931 #include <machine/param.h>
932 #elif AIX
933 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
934 #include <jfs/quota.h>
935 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
936 #define dqb_curfiles dqb_curinodes
937 #define dqb_fhardlimit dqb_ihardlimit
938 #define dqb_fsoftlimit dqb_isoftlimit
939 #ifdef _AIXVERSION_530
940 #include <sys/statfs.h>
941 #include <sys/vmount.h>
942 #endif /* AIX 5.3 */
943 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
944 #include <sys/quota.h>
945 #include <devnm.h>
946 #endif
948 #if defined(__FreeBSD__) || defined(__DragonFly__)
950 #include <rpc/rpc.h>
951 #include <rpc/types.h>
952 #include <rpcsvc/rquota.h>
953 #ifdef HAVE_RPC_NETTYPE_H
954 #include <rpc/nettype.h>
955 #endif
956 #include <rpc/xdr.h>
958 static int quotastat;
960 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
962 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
963 return(0);
964 if (!xdr_int(xdrsp, &args->gqa_uid))
965 return(0);
966 return (1);
969 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
971 if (!xdr_int(xdrsp, &quotastat)) {
972 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
973 return 0;
975 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
976 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
977 return 0;
979 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
980 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
981 return 0;
983 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
984 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
985 return 0;
987 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
988 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
989 return 0;
991 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
992 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
993 return 0;
995 return (1);
998 /* Works on FreeBSD, too. :-) */
999 static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
1001 uid_t uid = euser_id;
1002 struct dqblk D;
1003 char *mnttype = nfspath;
1004 CLIENT *clnt;
1005 struct getquota_rslt gqr;
1006 struct getquota_args args;
1007 char *cutstr, *pathname, *host, *testpath;
1008 int len;
1009 static struct timeval timeout = {2,0};
1010 enum clnt_stat clnt_stat;
1011 BOOL ret = True;
1013 *bsize = *dfree = *dsize = (SMB_BIG_UINT)0;
1015 len=strcspn(mnttype, ":");
1016 pathname=strstr(mnttype, ":");
1017 cutstr = (char *) SMB_MALLOC(len+1);
1018 if (!cutstr)
1019 return False;
1021 memset(cutstr, '\0', len+1);
1022 host = strncat(cutstr,mnttype, sizeof(char) * len );
1023 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
1024 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
1025 testpath=strchr_m(mnttype, ':');
1026 args.gqa_pathp = testpath+1;
1027 args.gqa_uid = uid;
1029 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
1031 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
1032 ret = False;
1033 goto out;
1036 clnt->cl_auth = authunix_create_default();
1037 DEBUG(9,("nfs_quotas: auth_success\n"));
1039 clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, (const xdrproc_t) my_xdr_getquota_args, (caddr_t)&args, (const xdrproc_t) my_xdr_getquota_rslt, (caddr_t)&gqr, timeout);
1041 if (clnt_stat != RPC_SUCCESS) {
1042 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
1043 ret = False;
1044 goto out;
1048 * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
1049 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
1050 * something sensible.
1053 switch ( quotastat ) {
1054 case 0:
1055 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat ));
1056 ret = False;
1057 goto out;
1059 case 1:
1060 DEBUG(9,("nfs_quotas: Good quota data\n"));
1061 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
1062 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
1063 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
1064 break;
1066 case 2:
1067 case 3:
1068 D.dqb_bsoftlimit = 1;
1069 D.dqb_curblocks = 1;
1070 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
1071 break;
1073 default:
1074 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat ));
1075 break;
1078 DEBUG(10,("nfs_quotas: Let`s look at D a bit closer... status \"%i\" bsize \"%i\" active? \"%i\" bhard \"%i\" bsoft \"%i\" curb \"%i\" \n",
1079 quotastat,
1080 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
1081 gqr.getquota_rslt_u.gqr_rquota.rq_active,
1082 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
1083 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
1084 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
1086 if (D.dqb_bsoftlimit == 0)
1087 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1088 if (D.dqb_bsoftlimit == 0)
1089 return False;
1091 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
1092 *dsize = D.dqb_bsoftlimit;
1094 if (D.dqb_curblocks == D.dqb_curblocks == 1)
1095 *bsize = DEV_BSIZE;
1097 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1098 *dfree = 0;
1099 *dsize = D.dqb_curblocks;
1100 } else
1101 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1103 out:
1105 if (clnt) {
1106 if (clnt->cl_auth)
1107 auth_destroy(clnt->cl_auth);
1108 clnt_destroy(clnt);
1111 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
1113 SAFE_FREE(cutstr);
1114 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
1115 return ret;
1118 #endif
1120 /****************************************************************************
1121 try to get the disk space from disk quotas - default version
1122 ****************************************************************************/
1124 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
1126 int r;
1127 struct dqblk D;
1128 uid_t euser_id;
1129 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1130 char dev_disk[256];
1131 SMB_STRUCT_STAT S;
1133 /* find the block device file */
1135 #ifdef HPUX
1136 /* Need to set the cache flag to 1 for HPUX. Seems
1137 * to have a significant performance boost when
1138 * lstat calls on /dev access this function.
1140 if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 1)<0))
1141 #else
1142 if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0))
1143 return (False);
1144 #endif /* ifdef HPUX */
1146 #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__) */
1148 euser_id = geteuid();
1150 #ifdef HPUX
1151 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
1152 save_re_uid();
1153 if (set_re_uid() != 0) return False;
1155 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1157 restore_re_uid();
1158 #else
1159 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1161 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
1162 gid_t egrp_id;
1163 #if defined(__FreeBSD__) || defined(__DragonFly__)
1164 SMB_DEV_T devno;
1165 struct statfs *mnts;
1166 SMB_STRUCT_STAT st;
1167 int mntsize, i;
1169 if (sys_stat(path,&st) < 0)
1170 return False;
1171 devno = st.st_dev;
1173 mntsize = getmntinfo(&mnts,MNT_NOWAIT);
1174 if (mntsize <= 0)
1175 return False;
1177 for (i = 0; i < mntsize; i++) {
1178 if (sys_stat(mnts[i].f_mntonname,&st) < 0)
1179 return False;
1180 if (st.st_dev == devno)
1181 break;
1183 if (i == mntsize)
1184 return False;
1185 #endif
1187 become_root();
1189 #if defined(__FreeBSD__) || defined(__DragonFly__)
1190 if (strcmp(mnts[i].f_fstypename,"nfs") == 0) {
1191 BOOL retval;
1192 retval = nfs_quotas(mnts[i].f_mntfromname,euser_id,bsize,dfree,dsize);
1193 unbecome_root();
1194 return retval;
1196 #endif
1198 egrp_id = getegid();
1199 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1201 /* As FreeBSD has group quotas, if getting the user
1202 quota fails, try getting the group instead. */
1203 if (r) {
1204 r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
1207 unbecome_root();
1209 #elif defined(AIX)
1210 /* AIX has both USER and GROUP quotas:
1211 Get the USER quota (ohnielse@fysik.dtu.dk) */
1212 #ifdef _AIXVERSION_530
1214 struct statfs statbuf;
1215 quota64_t user_quota;
1216 if (statfs(path,&statbuf) != 0)
1217 return False;
1218 if(statbuf.f_vfstype == MNT_J2)
1220 /* For some reason we need to be root for jfs2 */
1221 become_root();
1222 r = quotactl(path,QCMD(Q_J2GETQUOTA,USRQUOTA),euser_id,(char *) &user_quota);
1223 unbecome_root();
1224 /* Copy results to old struct to let the following code work as before */
1225 D.dqb_curblocks = user_quota.bused;
1226 D.dqb_bsoftlimit = user_quota.bsoft;
1227 D.dqb_bhardlimit = user_quota.bhard;
1228 D.dqb_curfiles = user_quota.iused;
1229 D.dqb_fsoftlimit = user_quota.isoft;
1230 D.dqb_fhardlimit = user_quota.ihard;
1232 else if(statbuf.f_vfstype == MNT_JFS)
1234 #endif /* AIX 5.3 */
1235 save_re_uid();
1236 if (set_re_uid() != 0)
1237 return False;
1238 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1239 restore_re_uid();
1240 #ifdef _AIXVERSION_530
1242 else
1243 r = 1; /* Fail for other FS-types */
1245 #endif /* AIX 5.3 */
1246 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1247 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1248 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1249 #endif /* HPUX */
1251 /* Use softlimit to determine disk space, except when it has been exceeded */
1252 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1253 *bsize = DEV_BSIZE;
1254 #else /* !__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1255 *bsize = 1024;
1256 #endif /*!__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1258 if (r)
1260 if (errno == EDQUOT)
1262 *dfree =0;
1263 *dsize =D.dqb_curblocks;
1264 return (True);
1266 else return(False);
1269 /* If softlimit is zero, set it equal to hardlimit.
1272 if (D.dqb_bsoftlimit==0)
1273 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1275 if (D.dqb_bsoftlimit==0)
1276 return(False);
1277 /* Use softlimit to determine disk space, except when it has been exceeded */
1278 if ((D.dqb_curblocks>D.dqb_bsoftlimit)
1279 #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1280 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
1281 #endif
1283 *dfree = 0;
1284 *dsize = D.dqb_curblocks;
1286 else {
1287 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1288 *dsize = D.dqb_bsoftlimit;
1290 return (True);
1293 #endif
1295 #if defined(VXFS_QUOTA)
1297 /****************************************************************************
1298 Try to get the disk space from Veritas disk quotas.
1299 David Lee <T.D.Lee@durham.ac.uk> August 1999.
1301 Background assumptions:
1302 Potentially under many Operating Systems. Initially Solaris 2.
1304 My guess is that Veritas is largely, though not entirely,
1305 independent of OS. So I have separated it out.
1307 There may be some details. For example, OS-specific "include" files.
1309 It is understood that HPUX 10 somehow gets Veritas quotas without
1310 any special effort; if so, this routine need not be compiled in.
1311 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1313 Warning:
1314 It is understood that Veritas do not publicly support this ioctl interface.
1315 Rather their preference would be for the user (us) to call the native
1316 OS and then for the OS itself to call through to the VxFS filesystem.
1317 Presumably HPUX 10, see above, does this.
1319 Hints for porting:
1320 Add your OS to "IFLIST" below.
1321 Get it to compile successfully:
1322 Almost certainly "include"s require attention: see SUNOS5.
1323 In the main code above, arrange for it to be called: see SUNOS5.
1324 Test!
1326 ****************************************************************************/
1328 /* "IFLIST"
1329 * This "if" is a list of ports:
1330 * if defined(OS1) || defined(OS2) || ...
1332 #if defined(SUNOS5)
1334 #if defined(SUNOS5)
1335 #include <sys/fs/vx_solaris.h>
1336 #endif
1337 #include <sys/fs/vx_machdep.h>
1338 #include <sys/fs/vx_layout.h>
1339 #include <sys/fs/vx_quota.h>
1340 #include <sys/fs/vx_aioctl.h>
1341 #include <sys/fs/vx_ioctl.h>
1343 BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
1345 uid_t user_id, euser_id;
1346 int ret;
1347 struct vx_dqblk D;
1348 struct vx_quotctl quotabuf;
1349 struct vx_genioctl genbuf;
1350 pstring qfname;
1351 int file;
1354 * "name" may or may not include a trailing "/quotas".
1355 * Arranging consistency of calling here in "quotas.c" may not be easy and
1356 * it might be easier to examine and adjust it here.
1357 * Fortunately, VxFS seems not to mind at present.
1359 pstrcpy(qfname, name) ;
1360 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
1362 euser_id = geteuid();
1363 set_effective_uid(0);
1365 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
1366 if((file=sys_open(qfname, O_RDONLY,0))<0) {
1367 set_effective_uid(euser_id);
1368 return(False);
1370 genbuf.ioc_cmd = VX_QUOTACTL;
1371 genbuf.ioc_up = (void *) &quotabuf;
1373 quotabuf.cmd = VX_GETQUOTA;
1374 quotabuf.uid = euser_id;
1375 quotabuf.addr = (caddr_t) &D;
1376 ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
1377 close(file);
1379 set_effective_uid(euser_id);
1381 if (ret < 0) {
1382 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
1383 return(False);
1386 /* If softlimit is zero, set it equal to hardlimit.
1389 if (D.dqb_bsoftlimit==0)
1390 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1392 /* Use softlimit to determine disk space. A user exceeding the quota is told
1393 * that there's no space left. Writes might actually work for a bit if the
1394 * hardlimit is set higher than softlimit. Effectively the disk becomes
1395 * made of rubber latex and begins to expand to accommodate the user :-)
1397 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1398 path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
1399 D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
1401 if (D.dqb_bsoftlimit==0)
1402 return(False);
1403 *bsize = DEV_BSIZE;
1404 *dsize = D.dqb_bsoftlimit;
1406 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1407 *dfree = 0;
1408 *dsize = D.dqb_curblocks;
1409 } else
1410 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1412 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
1413 path,(double)*bsize,(double)*dfree,(double)*dsize));
1415 return(True);
1418 #endif /* SUNOS5 || ... */
1420 #endif /* VXFS_QUOTA */
1422 #else /* WITH_QUOTAS */
1424 BOOL disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
1426 (*bsize) = 512; /* This value should be ignored */
1428 /* And just to be sure we set some values that hopefully */
1429 /* will be larger that any possible real-world value */
1430 (*dfree) = (SMB_BIG_UINT)-1;
1431 (*dsize) = (SMB_BIG_UINT)-1;
1433 /* As we have select not to use quotas, allways fail */
1434 return False;
1436 #endif /* WITH_QUOTAS */
1438 #else /* HAVE_SYS_QUOTAS */
1439 /* wrapper to the new sys_quota interface
1440 this file should be removed later
1442 BOOL disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
1444 int r;
1445 SMB_DISK_QUOTA D;
1446 unid_t id;
1448 id.uid = geteuid();
1450 ZERO_STRUCT(D);
1451 r=sys_get_quota(path, SMB_USER_QUOTA_TYPE, id, &D);
1453 /* Use softlimit to determine disk space, except when it has been exceeded */
1454 *bsize = D.bsize;
1455 if (r == -1) {
1456 if (errno == EDQUOT) {
1457 *dfree =0;
1458 *dsize =D.curblocks;
1459 return (True);
1460 } else {
1461 goto try_group_quota;
1465 /* Use softlimit to determine disk space, except when it has been exceeded */
1466 if (
1467 (D.softlimit && D.curblocks >= D.softlimit) ||
1468 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1469 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1470 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1472 *dfree = 0;
1473 *dsize = D.curblocks;
1474 } else if (D.softlimit==0 && D.hardlimit==0) {
1475 goto try_group_quota;
1476 } else {
1477 if (D.softlimit == 0)
1478 D.softlimit = D.hardlimit;
1479 *dfree = D.softlimit - D.curblocks;
1480 *dsize = D.softlimit;
1483 return True;
1485 try_group_quota:
1486 id.gid = getegid();
1488 ZERO_STRUCT(D);
1489 r=sys_get_quota(path, SMB_GROUP_QUOTA_TYPE, id, &D);
1491 /* Use softlimit to determine disk space, except when it has been exceeded */
1492 *bsize = D.bsize;
1493 if (r == -1) {
1494 if (errno == EDQUOT) {
1495 *dfree =0;
1496 *dsize =D.curblocks;
1497 return (True);
1498 } else {
1499 return False;
1503 /* Use softlimit to determine disk space, except when it has been exceeded */
1504 if (
1505 (D.softlimit && D.curblocks >= D.softlimit) ||
1506 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1507 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1508 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1510 *dfree = 0;
1511 *dsize = D.curblocks;
1512 } else if (D.softlimit==0 && D.hardlimit==0) {
1513 return False;
1514 } else {
1515 if (D.softlimit == 0)
1516 D.softlimit = D.hardlimit;
1517 *dfree = D.softlimit - D.curblocks;
1518 *dsize = D.softlimit;
1521 return (True);
1523 #endif /* HAVE_SYS_QUOTAS */