r23786: Use linux/dqblk_xfs.h rather than a private copy of this header in the
[Samba/bb.git] / source / smbd / quotas.c
blob1f30acef33c3d7c1a912b5622cd7e7905dbcd365
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 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/>.
21 /*
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
24 * things :-(
27 #include "includes.h"
29 #undef DBGC_CLASS
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
37 #endif
39 #ifdef WITH_QUOTAS
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 */
52 #ifdef LINUX
54 #include <sys/types.h>
55 #include <mntent.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"
65 typedef struct _LINUX_SMB_DISK_QUOTA {
66 SMB_BIG_UINT bsize;
67 SMB_BIG_UINT hardlimit; /* In bsize units. */
68 SMB_BIG_UINT softlimit; /* In bsize units. */
69 SMB_BIG_UINT curblocks; /* In bsize units. */
70 SMB_BIG_UINT ihardlimit; /* inode hard limit. */
71 SMB_BIG_UINT isoftlimit; /* inode soft limit. */
72 SMB_BIG_UINT curinodes; /* Current used inodes. */
73 } LINUX_SMB_DISK_QUOTA;
76 #ifdef HAVE_LINUX_DQBLK_XFS_H
77 #include <linux/dqblk_xfs.h>
79 /****************************************************************************
80 Abstract out the XFS Quota Manager quota get call.
81 ****************************************************************************/
83 static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
85 struct fs_disk_quota D;
86 int ret;
88 ZERO_STRUCT(D);
90 ret = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
92 if (ret)
93 ret = quotactl(QCMD(Q_XGETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
95 if (ret)
96 return ret;
98 dp->bsize = (SMB_BIG_UINT)512;
99 dp->softlimit = (SMB_BIG_UINT)D.d_blk_softlimit;
100 dp->hardlimit = (SMB_BIG_UINT)D.d_blk_hardlimit;
101 dp->ihardlimit = (SMB_BIG_UINT)D.d_ino_hardlimit;
102 dp->isoftlimit = (SMB_BIG_UINT)D.d_ino_softlimit;
103 dp->curinodes = (SMB_BIG_UINT)D.d_icount;
104 dp->curblocks = (SMB_BIG_UINT)D.d_bcount;
106 return ret;
108 #else
109 static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
111 DEBUG(0,("XFS quota support not available\n"));
112 errno = ENOSYS;
113 return -1;
115 #endif
118 /****************************************************************************
119 Abstract out the old and new Linux quota get calls.
120 ****************************************************************************/
122 static int get_smb_linux_v1_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
124 struct v1_kern_dqblk D;
125 int ret;
127 ZERO_STRUCT(D);
129 ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
131 if (ret && errno != EDQUOT)
132 ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
134 if (ret && errno != EDQUOT)
135 return ret;
137 dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
138 dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
139 dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
140 dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
141 dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
142 dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
143 dp->curblocks = (SMB_BIG_UINT)D.dqb_curblocks;
145 return ret;
148 static int get_smb_linux_v2_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
150 struct v2_kern_dqblk D;
151 int ret;
153 ZERO_STRUCT(D);
155 ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
157 if (ret && errno != EDQUOT)
158 ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
160 if (ret && errno != EDQUOT)
161 return ret;
163 dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
164 dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
165 dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
166 dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
167 dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
168 dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
169 dp->curblocks = ((SMB_BIG_UINT)D.dqb_curspace) / dp->bsize;
171 return ret;
174 /****************************************************************************
175 Brand-new generic quota interface.
176 ****************************************************************************/
178 static int get_smb_linux_gen_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
180 struct if_dqblk D;
181 int ret;
183 ZERO_STRUCT(D);
185 ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
187 if (ret && errno != EDQUOT)
188 ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
190 if (ret && errno != EDQUOT)
191 return ret;
193 dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
194 dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
195 dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
196 dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
197 dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
198 dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
199 dp->curblocks = ((SMB_BIG_UINT)D.dqb_curspace) / dp->bsize;
201 return ret;
204 /****************************************************************************
205 Try to get the disk space from disk quotas (LINUX version).
206 ****************************************************************************/
208 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
210 int r;
211 SMB_STRUCT_STAT S;
212 FILE *fp;
213 LINUX_SMB_DISK_QUOTA D;
214 struct mntent *mnt;
215 SMB_DEV_T devno;
216 int found;
217 uid_t euser_id;
218 gid_t egrp_id;
220 ZERO_STRUCT(D);
222 euser_id = geteuid();
223 egrp_id = getegid();
225 /* find the block device file */
227 if ( sys_stat(path, &S) == -1 )
228 return(False) ;
230 devno = S.st_dev ;
232 if ((fp = setmntent(MOUNTED,"r")) == NULL)
233 return(False) ;
235 found = False ;
237 while ((mnt = getmntent(fp))) {
238 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
239 continue ;
241 if (S.st_dev == devno) {
242 found = True ;
243 break;
247 endmntent(fp) ;
249 if (!found)
250 return(False);
252 become_root();
254 if (strcmp(mnt->mnt_type, "xfs")==0) {
255 r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
256 } else {
257 r=get_smb_linux_gen_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
258 if (r == -1 && errno != EDQUOT) {
259 r=get_smb_linux_v2_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
260 if (r == -1 && errno != EDQUOT)
261 r=get_smb_linux_v1_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
265 unbecome_root();
267 /* Use softlimit to determine disk space, except when it has been exceeded */
268 *bsize = D.bsize;
269 if (r == -1) {
270 if (errno == EDQUOT) {
271 *dfree =0;
272 *dsize =D.curblocks;
273 return (True);
274 } else {
275 return(False);
279 /* Use softlimit to determine disk space, except when it has been exceeded */
280 if (
281 (D.softlimit && D.curblocks >= D.softlimit) ||
282 (D.hardlimit && D.curblocks >= D.hardlimit) ||
283 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
284 (D.ihardlimit && D.curinodes>=D.ihardlimit)
286 *dfree = 0;
287 *dsize = D.curblocks;
288 } else if (D.softlimit==0 && D.hardlimit==0) {
289 return(False);
290 } else {
291 if (D.softlimit == 0)
292 D.softlimit = D.hardlimit;
293 *dfree = D.softlimit - D.curblocks;
294 *dsize = D.softlimit;
297 return (True);
300 #elif defined(CRAY)
302 #include <sys/quota.h>
303 #include <mntent.h>
305 /****************************************************************************
306 try to get the disk space from disk quotas (CRAY VERSION)
307 ****************************************************************************/
309 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
311 struct mntent *mnt;
312 FILE *fd;
313 SMB_STRUCT_STAT sbuf;
314 SMB_DEV_T devno ;
315 static SMB_DEV_T devno_cached = 0 ;
316 static pstring name;
317 struct q_request request ;
318 struct qf_header header ;
319 static int quota_default = 0 ;
320 int found ;
322 if ( sys_stat(path,&sbuf) == -1 )
323 return(False) ;
325 devno = sbuf.st_dev ;
327 if ( devno != devno_cached ) {
329 devno_cached = devno ;
331 if ((fd = setmntent(KMTAB)) == NULL)
332 return(False) ;
334 found = False ;
336 while ((mnt = getmntent(fd)) != NULL) {
338 if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
339 continue ;
341 if (sbuf.st_dev == devno) {
343 found = True ;
344 break ;
350 pstrcpy(name,mnt->mnt_dir) ;
351 endmntent(fd) ;
353 if ( ! found )
354 return(False) ;
357 request.qf_magic = QF_MAGIC ;
358 request.qf_entry.id = geteuid() ;
360 if (quotactl(name, Q_GETQUOTA, &request) == -1)
361 return(False) ;
363 if ( ! request.user )
364 return(False) ;
366 if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) {
368 if ( ! quota_default ) {
370 if ( quotactl(name, Q_GETHEADER, &header) == -1 )
371 return(False) ;
372 else
373 quota_default = header.user_h.def_fq ;
376 *dfree = quota_default ;
378 }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) {
380 *dfree = 0 ;
382 }else{
384 *dfree = request.qf_entry.user_q.f_quota ;
388 *dsize = request.qf_entry.user_q.f_use ;
390 if ( *dfree < *dsize )
391 *dfree = 0 ;
392 else
393 *dfree -= *dsize ;
395 *bsize = 4096 ; /* Cray blocksize */
397 return(True) ;
402 #elif defined(SUNOS5) || defined(SUNOS4)
404 #include <fcntl.h>
405 #include <sys/param.h>
406 #if defined(SUNOS5)
407 #include <sys/fs/ufs_quota.h>
408 #include <sys/mnttab.h>
409 #include <sys/mntent.h>
410 #else /* defined(SUNOS4) */
411 #include <ufs/quota.h>
412 #include <mntent.h>
413 #endif
415 #if defined(SUNOS5)
417 /****************************************************************************
418 Allows querying of remote hosts for quotas on NFS mounted shares.
419 Supports normal NFS and AMD mounts.
420 Alan Romeril <a.romeril@ic.ac.uk> July 2K.
421 ****************************************************************************/
423 #include <rpc/rpc.h>
424 #include <rpc/types.h>
425 #include <rpcsvc/rquota.h>
426 #include <rpc/nettype.h>
427 #include <rpc/xdr.h>
429 static int quotastat;
431 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
433 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
434 return(0);
435 if (!xdr_int(xdrsp, &args->gqa_uid))
436 return(0);
437 return (1);
440 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
442 if (!xdr_int(xdrsp, &quotastat)) {
443 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
444 return 0;
446 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
447 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
448 return 0;
450 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
451 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
452 return 0;
454 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
455 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
456 return 0;
458 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
459 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
460 return 0;
462 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
463 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
464 return 0;
466 return (1);
469 /* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
470 static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
472 uid_t uid = euser_id;
473 struct dqblk D;
474 char *mnttype = nfspath;
475 CLIENT *clnt;
476 struct getquota_rslt gqr;
477 struct getquota_args args;
478 char *cutstr, *pathname, *host, *testpath;
479 int len;
480 static struct timeval timeout = {2,0};
481 enum clnt_stat clnt_stat;
482 BOOL ret = True;
484 *bsize = *dfree = *dsize = (SMB_BIG_UINT)0;
486 len=strcspn(mnttype, ":");
487 pathname=strstr(mnttype, ":");
488 cutstr = (char *) SMB_MALLOC(len+1);
489 if (!cutstr)
490 return False;
492 memset(cutstr, '\0', len+1);
493 host = strncat(cutstr,mnttype, sizeof(char) * len );
494 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
495 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
496 testpath=strchr_m(mnttype, ':');
497 args.gqa_pathp = testpath+1;
498 args.gqa_uid = uid;
500 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
502 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
503 ret = False;
504 goto out;
507 clnt->cl_auth = authunix_create_default();
508 DEBUG(9,("nfs_quotas: auth_success\n"));
510 clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, my_xdr_getquota_args, (caddr_t)&args, my_xdr_getquota_rslt, (caddr_t)&gqr, timeout);
512 if (clnt_stat != RPC_SUCCESS) {
513 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
514 ret = False;
515 goto out;
519 * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
520 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
521 * something sensible.
524 switch ( quotastat ) {
525 case 0:
526 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat ));
527 ret = False;
528 goto out;
530 case 1:
531 DEBUG(9,("nfs_quotas: Good quota data\n"));
532 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
533 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
534 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
535 break;
537 case 2:
538 case 3:
539 D.dqb_bsoftlimit = 1;
540 D.dqb_curblocks = 1;
541 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
542 break;
544 default:
545 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat ));
546 break;
549 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",
550 quotastat,
551 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
552 gqr.getquota_rslt_u.gqr_rquota.rq_active,
553 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
554 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
555 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
557 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
558 *dsize = D.dqb_bsoftlimit;
560 if (D.dqb_curblocks == D.dqb_curblocks == 1)
561 *bsize = 512;
563 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
564 *dfree = 0;
565 *dsize = D.dqb_curblocks;
566 } else
567 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
569 out:
571 if (clnt) {
572 if (clnt->cl_auth)
573 auth_destroy(clnt->cl_auth);
574 clnt_destroy(clnt);
577 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
579 SAFE_FREE(cutstr);
580 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
581 return ret;
583 #endif
585 /****************************************************************************
586 try to get the disk space from disk quotas (SunOS & Solaris2 version)
587 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
588 ****************************************************************************/
590 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
592 uid_t euser_id;
593 int ret;
594 struct dqblk D;
595 #if defined(SUNOS5)
596 struct quotctl command;
597 int file;
598 static struct mnttab mnt;
599 static pstring name;
600 #else /* SunOS4 */
601 struct mntent *mnt;
602 static pstring name;
603 #endif
604 FILE *fd;
605 SMB_STRUCT_STAT sbuf;
606 SMB_DEV_T devno ;
607 static SMB_DEV_T devno_cached = 0 ;
608 static int found ;
610 euser_id = geteuid();
612 if ( sys_stat(path,&sbuf) == -1 )
613 return(False) ;
615 devno = sbuf.st_dev ;
616 DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n",
617 path, (unsigned int)devno));
618 if ( devno != devno_cached ) {
619 devno_cached = devno ;
620 #if defined(SUNOS5)
621 if ((fd = sys_fopen(MNTTAB, "r")) == NULL)
622 return(False) ;
624 found = False ;
626 while (getmntent(fd, &mnt) == 0) {
627 if (sys_stat(mnt.mnt_mountp, &sbuf) == -1)
628 continue;
630 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
631 mnt.mnt_mountp, (unsigned int)devno));
633 /* quotas are only on vxfs, UFS or NFS */
634 if ( (sbuf.st_dev == devno) && (
635 strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
636 strcmp( mnt.mnt_fstype, "nfs" ) == 0 ||
637 strcmp( mnt.mnt_fstype, "vxfs" ) == 0 )) {
638 found = True ;
639 break;
643 pstrcpy(name,mnt.mnt_mountp) ;
644 pstrcat(name,"/quotas") ;
645 fclose(fd) ;
646 #else /* SunOS4 */
647 if ((fd = setmntent(MOUNTED, "r")) == NULL)
648 return(False) ;
650 found = False ;
651 while ((mnt = getmntent(fd)) != NULL) {
652 if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
653 continue ;
654 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n", mnt->mnt_dir,(unsigned int)sbuf.st_dev));
655 if (sbuf.st_dev == devno) {
656 found = True ;
657 break;
661 pstrcpy(name,mnt->mnt_fsname) ;
662 endmntent(fd) ;
663 #endif
666 if ( ! found )
667 return(False) ;
669 become_root();
671 #if defined(SUNOS5)
672 if ( strcmp( mnt.mnt_fstype, "nfs" ) == 0) {
673 BOOL retval;
674 DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n", mnt.mnt_special));
675 retval = nfs_quotas(mnt.mnt_special, euser_id, bsize, dfree, dsize);
676 unbecome_root();
677 return retval;
680 DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
681 if((file=sys_open(name, O_RDONLY,0))<0) {
682 unbecome_root();
683 return(False);
685 command.op = Q_GETQUOTA;
686 command.uid = euser_id;
687 command.addr = (caddr_t) &D;
688 ret = ioctl(file, Q_QUOTACTL, &command);
689 close(file);
690 #else
691 DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
692 ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
693 #endif
695 unbecome_root();
697 if (ret < 0) {
698 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n", strerror(errno) ));
700 #if defined(SUNOS5) && defined(VXFS_QUOTA)
701 /* If normal quotactl() fails, try vxfs private calls */
702 set_effective_uid(euser_id);
703 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype));
704 if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) {
705 BOOL retval;
706 retval = disk_quotas_vxfs(name, path, bsize, dfree, dsize);
707 return(retval);
709 #else
710 return(False);
711 #endif
714 /* If softlimit is zero, set it equal to hardlimit.
717 if (D.dqb_bsoftlimit==0)
718 D.dqb_bsoftlimit = D.dqb_bhardlimit;
720 /* Use softlimit to determine disk space. A user exceeding the quota is told
721 * that there's no space left. Writes might actually work for a bit if the
722 * hardlimit is set higher than softlimit. Effectively the disk becomes
723 * made of rubber latex and begins to expand to accommodate the user :-)
726 if (D.dqb_bsoftlimit==0)
727 return(False);
728 *bsize = DEV_BSIZE;
729 *dsize = D.dqb_bsoftlimit;
731 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
732 *dfree = 0;
733 *dsize = D.dqb_curblocks;
734 } else
735 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
737 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
738 path,(double)*bsize,(double)*dfree,(double)*dsize));
740 return(True);
744 #elif defined(OSF1)
745 #include <ufs/quota.h>
747 /****************************************************************************
748 try to get the disk space from disk quotas - OSF1 version
749 ****************************************************************************/
751 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
753 int r, save_errno;
754 struct dqblk D;
755 SMB_STRUCT_STAT S;
756 uid_t euser_id;
759 * This code presumes that OSF1 will only
760 * give out quota info when the real uid
761 * matches the effective uid. JRA.
763 euser_id = geteuid();
764 save_re_uid();
765 if (set_re_uid() != 0) return False;
767 r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
768 if (r) {
769 save_errno = errno;
772 restore_re_uid();
774 *bsize = DEV_BSIZE;
776 if (r)
778 if (save_errno == EDQUOT) /* disk quota exceeded */
780 *dfree = 0;
781 *dsize = D.dqb_curblocks;
782 return (True);
784 else
785 return (False);
788 /* If softlimit is zero, set it equal to hardlimit.
791 if (D.dqb_bsoftlimit==0)
792 D.dqb_bsoftlimit = D.dqb_bhardlimit;
794 /* Use softlimit to determine disk space, except when it has been exceeded */
796 if (D.dqb_bsoftlimit==0)
797 return(False);
799 if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
800 *dfree = 0;
801 *dsize = D.dqb_curblocks;
802 } else {
803 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
804 *dsize = D.dqb_bsoftlimit;
806 return (True);
809 #elif defined (IRIX6)
810 /****************************************************************************
811 try to get the disk space from disk quotas (IRIX 6.2 version)
812 ****************************************************************************/
814 #include <sys/quota.h>
815 #include <mntent.h>
817 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
819 uid_t euser_id;
820 int r;
821 struct dqblk D;
822 struct fs_disk_quota F;
823 SMB_STRUCT_STAT S;
824 FILE *fp;
825 struct mntent *mnt;
826 SMB_DEV_T devno;
827 int found;
829 /* find the block device file */
831 if ( sys_stat(path, &S) == -1 ) {
832 return(False) ;
835 devno = S.st_dev ;
837 fp = setmntent(MOUNTED,"r");
838 found = False ;
840 while ((mnt = getmntent(fp))) {
841 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
842 continue ;
843 if (S.st_dev == devno) {
844 found = True ;
845 break ;
848 endmntent(fp) ;
850 if (!found) {
851 return(False);
854 euser_id=geteuid();
855 become_root();
857 /* Use softlimit to determine disk space, except when it has been exceeded */
859 *bsize = 512;
861 if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
863 r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
865 unbecome_root();
867 if (r==-1)
868 return(False);
870 /* Use softlimit to determine disk space, except when it has been exceeded */
871 if (
872 (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
873 (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
874 (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
875 (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
878 *dfree = 0;
879 *dsize = D.dqb_curblocks;
881 else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
883 return(False);
885 else
887 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
888 *dsize = D.dqb_bsoftlimit;
892 else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
894 r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
896 unbecome_root();
898 if (r==-1)
900 DEBUG(5, ("quotactl for uid=%u: %s", euser_id, strerror(errno)));
901 return(False);
904 /* No quota for this user. */
905 if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
907 return(False);
910 /* Use softlimit to determine disk space, except when it has been exceeded */
911 if (
912 (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
913 (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
914 (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
915 (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
918 *dfree = 0;
919 *dsize = F.d_bcount;
921 else
923 *dfree = (F.d_blk_softlimit - F.d_bcount);
924 *dsize = F.d_blk_softlimit ? F.d_blk_softlimit : F.d_blk_hardlimit;
928 else
930 unbecome_root();
931 return(False);
934 return (True);
938 #else
940 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
941 #include <ufs/ufs/quota.h>
942 #include <machine/param.h>
943 #elif AIX
944 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
945 #include <jfs/quota.h>
946 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
947 #define dqb_curfiles dqb_curinodes
948 #define dqb_fhardlimit dqb_ihardlimit
949 #define dqb_fsoftlimit dqb_isoftlimit
950 #ifdef _AIXVERSION_530
951 #include <sys/statfs.h>
952 #include <sys/vmount.h>
953 #endif /* AIX 5.3 */
954 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
955 #include <sys/quota.h>
956 #include <devnm.h>
957 #endif
959 #if defined(__FreeBSD__) || defined(__DragonFly__)
961 #include <rpc/rpc.h>
962 #include <rpc/types.h>
963 #include <rpcsvc/rquota.h>
964 #ifdef HAVE_RPC_NETTYPE_H
965 #include <rpc/nettype.h>
966 #endif
967 #include <rpc/xdr.h>
969 static int quotastat;
971 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
973 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
974 return(0);
975 if (!xdr_int(xdrsp, &args->gqa_uid))
976 return(0);
977 return (1);
980 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
982 if (!xdr_int(xdrsp, &quotastat)) {
983 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
984 return 0;
986 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
987 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
988 return 0;
990 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
991 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
992 return 0;
994 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
995 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
996 return 0;
998 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
999 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
1000 return 0;
1002 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
1003 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
1004 return 0;
1006 return (1);
1009 /* Works on FreeBSD, too. :-) */
1010 static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
1012 uid_t uid = euser_id;
1013 struct dqblk D;
1014 char *mnttype = nfspath;
1015 CLIENT *clnt;
1016 struct getquota_rslt gqr;
1017 struct getquota_args args;
1018 char *cutstr, *pathname, *host, *testpath;
1019 int len;
1020 static struct timeval timeout = {2,0};
1021 enum clnt_stat clnt_stat;
1022 BOOL ret = True;
1024 *bsize = *dfree = *dsize = (SMB_BIG_UINT)0;
1026 len=strcspn(mnttype, ":");
1027 pathname=strstr(mnttype, ":");
1028 cutstr = (char *) SMB_MALLOC(len+1);
1029 if (!cutstr)
1030 return False;
1032 memset(cutstr, '\0', len+1);
1033 host = strncat(cutstr,mnttype, sizeof(char) * len );
1034 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
1035 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
1036 testpath=strchr_m(mnttype, ':');
1037 args.gqa_pathp = testpath+1;
1038 args.gqa_uid = uid;
1040 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
1042 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
1043 ret = False;
1044 goto out;
1047 clnt->cl_auth = authunix_create_default();
1048 DEBUG(9,("nfs_quotas: auth_success\n"));
1050 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);
1052 if (clnt_stat != RPC_SUCCESS) {
1053 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
1054 ret = False;
1055 goto out;
1059 * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
1060 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
1061 * something sensible.
1064 switch ( quotastat ) {
1065 case 0:
1066 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat ));
1067 ret = False;
1068 goto out;
1070 case 1:
1071 DEBUG(9,("nfs_quotas: Good quota data\n"));
1072 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
1073 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
1074 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
1075 break;
1077 case 2:
1078 case 3:
1079 D.dqb_bsoftlimit = 1;
1080 D.dqb_curblocks = 1;
1081 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
1082 break;
1084 default:
1085 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat ));
1086 break;
1089 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",
1090 quotastat,
1091 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
1092 gqr.getquota_rslt_u.gqr_rquota.rq_active,
1093 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
1094 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
1095 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
1097 if (D.dqb_bsoftlimit == 0)
1098 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1099 if (D.dqb_bsoftlimit == 0)
1100 return False;
1102 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
1103 *dsize = D.dqb_bsoftlimit;
1105 if (D.dqb_curblocks == D.dqb_curblocks == 1)
1106 *bsize = DEV_BSIZE;
1108 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1109 *dfree = 0;
1110 *dsize = D.dqb_curblocks;
1111 } else
1112 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1114 out:
1116 if (clnt) {
1117 if (clnt->cl_auth)
1118 auth_destroy(clnt->cl_auth);
1119 clnt_destroy(clnt);
1122 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
1124 SAFE_FREE(cutstr);
1125 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
1126 return ret;
1129 #endif
1131 /****************************************************************************
1132 try to get the disk space from disk quotas - default version
1133 ****************************************************************************/
1135 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
1137 int r;
1138 struct dqblk D;
1139 uid_t euser_id;
1140 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1141 char dev_disk[256];
1142 SMB_STRUCT_STAT S;
1144 /* find the block device file */
1146 #ifdef HPUX
1147 /* Need to set the cache flag to 1 for HPUX. Seems
1148 * to have a significant performance boost when
1149 * lstat calls on /dev access this function.
1151 if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 1)<0))
1152 #else
1153 if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0))
1154 return (False);
1155 #endif /* ifdef HPUX */
1157 #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__) */
1159 euser_id = geteuid();
1161 #ifdef HPUX
1162 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
1163 save_re_uid();
1164 if (set_re_uid() != 0) return False;
1166 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1168 restore_re_uid();
1169 #else
1170 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1172 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
1173 gid_t egrp_id;
1174 #if defined(__FreeBSD__) || defined(__DragonFly__)
1175 SMB_DEV_T devno;
1176 struct statfs *mnts;
1177 SMB_STRUCT_STAT st;
1178 int mntsize, i;
1180 if (sys_stat(path,&st) < 0)
1181 return False;
1182 devno = st.st_dev;
1184 mntsize = getmntinfo(&mnts,MNT_NOWAIT);
1185 if (mntsize <= 0)
1186 return False;
1188 for (i = 0; i < mntsize; i++) {
1189 if (sys_stat(mnts[i].f_mntonname,&st) < 0)
1190 return False;
1191 if (st.st_dev == devno)
1192 break;
1194 if (i == mntsize)
1195 return False;
1196 #endif
1198 become_root();
1200 #if defined(__FreeBSD__) || defined(__DragonFly__)
1201 if (strcmp(mnts[i].f_fstypename,"nfs") == 0) {
1202 BOOL retval;
1203 retval = nfs_quotas(mnts[i].f_mntfromname,euser_id,bsize,dfree,dsize);
1204 unbecome_root();
1205 return retval;
1207 #endif
1209 egrp_id = getegid();
1210 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1212 /* As FreeBSD has group quotas, if getting the user
1213 quota fails, try getting the group instead. */
1214 if (r) {
1215 r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
1218 unbecome_root();
1220 #elif defined(AIX)
1221 /* AIX has both USER and GROUP quotas:
1222 Get the USER quota (ohnielse@fysik.dtu.dk) */
1223 #ifdef _AIXVERSION_530
1225 struct statfs statbuf;
1226 quota64_t user_quota;
1227 if (statfs(path,&statbuf) != 0)
1228 return False;
1229 if(statbuf.f_vfstype == MNT_J2)
1231 /* For some reason we need to be root for jfs2 */
1232 become_root();
1233 r = quotactl(path,QCMD(Q_J2GETQUOTA,USRQUOTA),euser_id,(char *) &user_quota);
1234 unbecome_root();
1235 /* Copy results to old struct to let the following code work as before */
1236 D.dqb_curblocks = user_quota.bused;
1237 D.dqb_bsoftlimit = user_quota.bsoft;
1238 D.dqb_bhardlimit = user_quota.bhard;
1240 else if(statbuf.f_vfstype == MNT_JFS)
1242 #endif /* AIX 5.3 */
1243 save_re_uid();
1244 if (set_re_uid() != 0)
1245 return False;
1246 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1247 restore_re_uid();
1248 #ifdef _AIXVERSION_530
1250 else
1251 r = 1; /* Fail for other FS-types */
1253 #endif /* AIX 5.3 */
1254 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1255 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1256 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1257 #endif /* HPUX */
1259 /* Use softlimit to determine disk space, except when it has been exceeded */
1260 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1261 *bsize = DEV_BSIZE;
1262 #else /* !__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1263 *bsize = 1024;
1264 #endif /*!__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1266 if (r)
1268 if (errno == EDQUOT)
1270 *dfree =0;
1271 *dsize =D.dqb_curblocks;
1272 return (True);
1274 else return(False);
1277 /* If softlimit is zero, set it equal to hardlimit.
1280 if (D.dqb_bsoftlimit==0)
1281 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1283 if (D.dqb_bsoftlimit==0)
1284 return(False);
1285 /* Use softlimit to determine disk space, except when it has been exceeded */
1286 if ((D.dqb_curblocks>D.dqb_bsoftlimit)
1287 #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1288 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
1289 #endif
1291 *dfree = 0;
1292 *dsize = D.dqb_curblocks;
1294 else {
1295 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1296 *dsize = D.dqb_bsoftlimit;
1298 return (True);
1301 #endif
1303 #if defined(VXFS_QUOTA)
1305 /****************************************************************************
1306 Try to get the disk space from Veritas disk quotas.
1307 David Lee <T.D.Lee@durham.ac.uk> August 1999.
1309 Background assumptions:
1310 Potentially under many Operating Systems. Initially Solaris 2.
1312 My guess is that Veritas is largely, though not entirely,
1313 independent of OS. So I have separated it out.
1315 There may be some details. For example, OS-specific "include" files.
1317 It is understood that HPUX 10 somehow gets Veritas quotas without
1318 any special effort; if so, this routine need not be compiled in.
1319 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1321 Warning:
1322 It is understood that Veritas do not publicly support this ioctl interface.
1323 Rather their preference would be for the user (us) to call the native
1324 OS and then for the OS itself to call through to the VxFS filesystem.
1325 Presumably HPUX 10, see above, does this.
1327 Hints for porting:
1328 Add your OS to "IFLIST" below.
1329 Get it to compile successfully:
1330 Almost certainly "include"s require attention: see SUNOS5.
1331 In the main code above, arrange for it to be called: see SUNOS5.
1332 Test!
1334 ****************************************************************************/
1336 /* "IFLIST"
1337 * This "if" is a list of ports:
1338 * if defined(OS1) || defined(OS2) || ...
1340 #if defined(SUNOS5)
1342 #if defined(SUNOS5)
1343 #include <sys/fs/vx_solaris.h>
1344 #endif
1345 #include <sys/fs/vx_machdep.h>
1346 #include <sys/fs/vx_layout.h>
1347 #include <sys/fs/vx_quota.h>
1348 #include <sys/fs/vx_aioctl.h>
1349 #include <sys/fs/vx_ioctl.h>
1351 BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
1353 uid_t user_id, euser_id;
1354 int ret;
1355 struct vx_dqblk D;
1356 struct vx_quotctl quotabuf;
1357 struct vx_genioctl genbuf;
1358 pstring qfname;
1359 int file;
1362 * "name" may or may not include a trailing "/quotas".
1363 * Arranging consistency of calling here in "quotas.c" may not be easy and
1364 * it might be easier to examine and adjust it here.
1365 * Fortunately, VxFS seems not to mind at present.
1367 pstrcpy(qfname, name) ;
1368 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
1370 euser_id = geteuid();
1371 set_effective_uid(0);
1373 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
1374 if((file=sys_open(qfname, O_RDONLY,0))<0) {
1375 set_effective_uid(euser_id);
1376 return(False);
1378 genbuf.ioc_cmd = VX_QUOTACTL;
1379 genbuf.ioc_up = (void *) &quotabuf;
1381 quotabuf.cmd = VX_GETQUOTA;
1382 quotabuf.uid = euser_id;
1383 quotabuf.addr = (caddr_t) &D;
1384 ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
1385 close(file);
1387 set_effective_uid(euser_id);
1389 if (ret < 0) {
1390 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
1391 return(False);
1394 /* If softlimit is zero, set it equal to hardlimit.
1397 if (D.dqb_bsoftlimit==0)
1398 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1400 /* Use softlimit to determine disk space. A user exceeding the quota is told
1401 * that there's no space left. Writes might actually work for a bit if the
1402 * hardlimit is set higher than softlimit. Effectively the disk becomes
1403 * made of rubber latex and begins to expand to accommodate the user :-)
1405 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1406 path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
1407 D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
1409 if (D.dqb_bsoftlimit==0)
1410 return(False);
1411 *bsize = DEV_BSIZE;
1412 *dsize = D.dqb_bsoftlimit;
1414 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1415 *dfree = 0;
1416 *dsize = D.dqb_curblocks;
1417 } else
1418 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1420 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
1421 path,(double)*bsize,(double)*dfree,(double)*dsize));
1423 return(True);
1426 #endif /* SUNOS5 || ... */
1428 #endif /* VXFS_QUOTA */
1430 #else /* WITH_QUOTAS */
1432 BOOL disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
1434 (*bsize) = 512; /* This value should be ignored */
1436 /* And just to be sure we set some values that hopefully */
1437 /* will be larger that any possible real-world value */
1438 (*dfree) = (SMB_BIG_UINT)-1;
1439 (*dsize) = (SMB_BIG_UINT)-1;
1441 /* As we have select not to use quotas, allways fail */
1442 return False;
1444 #endif /* WITH_QUOTAS */
1446 #else /* HAVE_SYS_QUOTAS */
1447 /* wrapper to the new sys_quota interface
1448 this file should be removed later
1450 BOOL disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
1452 int r;
1453 SMB_DISK_QUOTA D;
1454 unid_t id;
1456 id.uid = geteuid();
1458 ZERO_STRUCT(D);
1459 r=sys_get_quota(path, SMB_USER_QUOTA_TYPE, id, &D);
1461 /* Use softlimit to determine disk space, except when it has been exceeded */
1462 *bsize = D.bsize;
1463 if (r == -1) {
1464 if (errno == EDQUOT) {
1465 *dfree =0;
1466 *dsize =D.curblocks;
1467 return (True);
1468 } else {
1469 goto try_group_quota;
1473 /* Use softlimit to determine disk space, except when it has been exceeded */
1474 if (
1475 (D.softlimit && D.curblocks >= D.softlimit) ||
1476 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1477 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1478 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1480 *dfree = 0;
1481 *dsize = D.curblocks;
1482 } else if (D.softlimit==0 && D.hardlimit==0) {
1483 goto try_group_quota;
1484 } else {
1485 if (D.softlimit == 0)
1486 D.softlimit = D.hardlimit;
1487 *dfree = D.softlimit - D.curblocks;
1488 *dsize = D.softlimit;
1491 return True;
1493 try_group_quota:
1494 id.gid = getegid();
1496 ZERO_STRUCT(D);
1497 r=sys_get_quota(path, SMB_GROUP_QUOTA_TYPE, id, &D);
1499 /* Use softlimit to determine disk space, except when it has been exceeded */
1500 *bsize = D.bsize;
1501 if (r == -1) {
1502 if (errno == EDQUOT) {
1503 *dfree =0;
1504 *dsize =D.curblocks;
1505 return (True);
1506 } else {
1507 return False;
1511 /* Use softlimit to determine disk space, except when it has been exceeded */
1512 if (
1513 (D.softlimit && D.curblocks >= D.softlimit) ||
1514 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1515 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1516 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1518 *dfree = 0;
1519 *dsize = D.curblocks;
1520 } else if (D.softlimit==0 && D.hardlimit==0) {
1521 return False;
1522 } else {
1523 if (D.softlimit == 0)
1524 D.softlimit = D.hardlimit;
1525 *dfree = D.softlimit - D.curblocks;
1526 *dsize = D.softlimit;
1529 return (True);
1531 #endif /* HAVE_SYS_QUOTAS */