Sync to the changes in head ...
[Samba/gbeck.git] / source3 / smbd / quotas.c
blob5b843bd09a6e996eb6bd89a6bdf205ccd5a21e33
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 #if defined(VXFS_QUOTA)
33 * In addition to their native filesystems, some systems have Veritas VxFS.
34 * Declare here, define at end: reduces likely "include" interaction problems.
35 * David Lee <T.D.Lee@durham.ac.uk>
37 BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize);
39 #endif /* VXFS_QUOTA */
41 #ifdef LINUX
43 #include <sys/types.h>
44 #include <asm/types.h>
47 * This shouldn't be neccessary - it should be /usr/include/sys/quota.h
48 * Unfortunately, RH7.1 ships with a different quota system using struct mem_dqblk
49 * rather than the struct dqblk defined in /usr/include/sys/quota.h.
50 * This means we must include linux/quota.h to have a hope of working on
51 * RH7.1 systems. And it also means this breaks if the kernel is upgraded
52 * to a Linus 2.4.x (where x > the minor number shipped with RH7.1) until
53 * Linus synchronises with the AC patches. Sometimes I *hate* Linux :-). JRA.
56 #include <linux/quota.h>
57 #ifdef HAVE_LINUX_XQM_H
58 #include <linux/xqm.h>
59 #else
60 #ifdef HAVE_XFS_XQM_H
61 #include <xfs/xqm.h>
62 #define HAVE_LINUX_XQM_H
63 #endif
64 #endif
66 #include <mntent.h>
67 #include <linux/unistd.h>
70 #define LINUX_QUOTAS_2
72 typedef struct _LINUX_SMB_DISK_QUOTA {
73 SMB_BIG_UINT bsize;
74 SMB_BIG_UINT hardlimit; /* In bsize units. */
75 SMB_BIG_UINT softlimit; /* In bsize units. */
76 SMB_BIG_UINT curblocks; /* In bsize units. */
77 SMB_BIG_UINT ihardlimit; /* inode hard limit. */
78 SMB_BIG_UINT isoftlimit; /* inode soft limit. */
79 SMB_BIG_UINT curinodes; /* Current used inodes. */
80 } LINUX_SMB_DISK_QUOTA;
82 /****************************************************************************
83 Abstract out the XFS Quota Manager quota get call.
84 ****************************************************************************/
86 static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA *dp)
88 int ret = -1;
89 #ifdef HAVE_LINUX_XQM_H
90 struct fs_disk_quota D;
91 ZERO_STRUCT(D);
93 if ((ret = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D)))
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;
103 #endif
104 return ret;
107 /****************************************************************************
108 Abstract out the old and new Linux quota get calls.
109 ****************************************************************************/
111 static int get_smb_linux_vfs_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA *dp)
113 int ret;
114 #ifdef LINUX_QUOTAS_1
115 struct dqblk D;
116 ZERO_STRUCT(D);
117 dp->bsize = (SMB_BIG_UINT)1024;
118 #else /* LINUX_QUOTAS_2 */
119 struct mem_dqblk D;
120 ZERO_STRUCT(D);
121 #ifndef QUOTABLOCK_SIZE
122 #define QUOTABLOCK_SIZE 1024
123 #endif
124 dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
125 #endif
127 if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D)))
128 return -1;
130 dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
131 dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
132 dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
133 dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
134 dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
136 #ifdef LINUX_QUOTAS_1
137 dp->curblocks = (SMB_BIG_UINT)D.dqb_curblocks;
138 #else /* LINUX_QUOTAS_2 */
139 dp->curblocks = ((SMB_BIG_UINT)D.dqb_curspace)/ dp->bsize;
140 #endif
142 return 0;
145 /****************************************************************************
146 try to get the disk space from disk quotas (LINUX version)
147 ****************************************************************************/
149 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
151 int r;
152 SMB_STRUCT_STAT S;
153 FILE *fp;
154 LINUX_SMB_DISK_QUOTA D;
155 struct mntent *mnt;
156 SMB_DEV_T devno;
157 int found;
158 uid_t euser_id;
160 euser_id = geteuid();
162 /* find the block device file */
164 if ( sys_stat(path, &S) == -1 )
165 return(False) ;
167 devno = S.st_dev ;
169 fp = setmntent(MOUNTED,"r");
170 found = False ;
172 while ((mnt = getmntent(fp))) {
173 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
174 continue ;
176 if (S.st_dev == devno) {
177 found = True ;
178 break;
182 endmntent(fp) ;
184 if (!found)
185 return(False);
187 save_re_uid();
188 set_effective_uid(0);
189 if (strcmp(mnt->mnt_type, "xfs") == 0)
190 r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, &D);
191 else
192 r=get_smb_linux_vfs_quota(mnt->mnt_fsname, euser_id, &D);
193 restore_re_uid();
195 /* Use softlimit to determine disk space, except when it has been exceeded */
196 *bsize = D.bsize;
197 if (r == -1) {
198 if (errno == EDQUOT) {
199 *dfree =0;
200 *dsize =D.curblocks;
201 return (True);
202 } else {
203 return(False);
207 /* Use softlimit to determine disk space, except when it has been exceeded */
208 if (
209 (D.softlimit && D.curblocks >= D.softlimit) ||
210 (D.hardlimit && D.curblocks >= D.hardlimit) ||
211 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
212 (D.ihardlimit && D.curinodes>=D.ihardlimit)
214 *dfree = 0;
215 *dsize = D.curblocks;
216 } else if (D.softlimit==0 && D.hardlimit==0) {
217 return(False);
218 } else {
219 if (D.softlimit == 0)
220 D.softlimit = D.hardlimit;
221 *dfree = D.softlimit - D.curblocks;
222 *dsize = D.softlimit;
225 return (True);
228 #elif defined(CRAY)
230 #include <sys/quota.h>
231 #include <mntent.h>
233 /****************************************************************************
234 try to get the disk space from disk quotas (CRAY VERSION)
235 ****************************************************************************/
237 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
239 struct mntent *mnt;
240 FILE *fd;
241 SMB_STRUCT_STAT sbuf;
242 SMB_DEV_T devno ;
243 static SMB_DEV_T devno_cached = 0 ;
244 static pstring name;
245 struct q_request request ;
246 struct qf_header header ;
247 static int quota_default = 0 ;
248 int found ;
250 if ( sys_stat(path,&sbuf) == -1 )
251 return(False) ;
253 devno = sbuf.st_dev ;
255 if ( devno != devno_cached ) {
257 devno_cached = devno ;
259 if ((fd = setmntent(KMTAB)) == NULL)
260 return(False) ;
262 found = False ;
264 while ((mnt = getmntent(fd)) != NULL) {
266 if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
267 continue ;
269 if (sbuf.st_dev == devno) {
271 found = True ;
272 break ;
278 pstrcpy(name,mnt->mnt_dir) ;
279 endmntent(fd) ;
281 if ( ! found )
282 return(False) ;
285 request.qf_magic = QF_MAGIC ;
286 request.qf_entry.id = geteuid() ;
288 if (quotactl(name, Q_GETQUOTA, &request) == -1)
289 return(False) ;
291 if ( ! request.user )
292 return(False) ;
294 if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) {
296 if ( ! quota_default ) {
298 if ( quotactl(name, Q_GETHEADER, &header) == -1 )
299 return(False) ;
300 else
301 quota_default = header.user_h.def_fq ;
304 *dfree = quota_default ;
306 }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) {
308 *dfree = 0 ;
310 }else{
312 *dfree = request.qf_entry.user_q.f_quota ;
316 *dsize = request.qf_entry.user_q.f_use ;
318 if ( *dfree < *dsize )
319 *dfree = 0 ;
320 else
321 *dfree -= *dsize ;
323 *bsize = 4096 ; /* Cray blocksize */
325 return(True) ;
330 #elif defined(SUNOS5) || defined(SUNOS4)
332 #include <fcntl.h>
333 #include <sys/param.h>
334 #if defined(SUNOS5)
335 #include <sys/fs/ufs_quota.h>
336 #include <sys/mnttab.h>
337 #include <sys/mntent.h>
338 #else /* defined(SUNOS4) */
339 #include <ufs/quota.h>
340 #include <mntent.h>
341 #endif
343 #if defined(SUNOS5)
345 /****************************************************************************
346 Allows querying of remote hosts for quotas on NFS mounted shares.
347 Supports normal NFS and AMD mounts.
348 Alan Romeril <a.romeril@ic.ac.uk> July 2K.
349 ****************************************************************************/
351 #include <rpc/rpc.h>
352 #include <rpc/types.h>
353 #include <rpcsvc/rquota.h>
354 #include <rpc/nettype.h>
355 #include <rpc/xdr.h>
357 static int quotastat;
359 static int xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
361 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
362 return(0);
363 if (!xdr_int(xdrsp, &args->gqa_uid))
364 return(0);
365 return (1);
368 static int xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
370 if (!xdr_int(xdrsp, &quotastat)) {
371 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
372 return 0;
374 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
375 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
376 return 0;
378 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
379 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
380 return 0;
382 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
383 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
384 return 0;
386 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
387 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
388 return 0;
390 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
391 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
392 return 0;
394 return (1);
397 /* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
398 static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
400 uid_t uid = euser_id;
401 struct dqblk D;
402 char *mnttype = nfspath;
403 CLIENT *clnt;
404 struct getquota_rslt gqr;
405 struct getquota_args args;
406 char *cutstr, *pathname, *host, *testpath;
407 int len;
408 static struct timeval timeout = {2,0};
409 enum clnt_stat clnt_stat;
410 BOOL ret = True;
412 *bsize = *dfree = *dsize = (SMB_BIG_UINT)0;
414 len=strcspn(mnttype, ":");
415 pathname=strstr(mnttype, ":");
416 cutstr = (char *) malloc(len+1);
417 if (!cutstr)
418 return False;
420 memset(cutstr, '\0', len+1);
421 host = strncat(cutstr,mnttype, sizeof(char) * len );
422 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
423 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
424 testpath=strchr_m(mnttype, ':');
425 args.gqa_pathp = testpath+1;
426 args.gqa_uid = uid;
428 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
430 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
431 ret = False;
432 goto out;
435 clnt->cl_auth = authunix_create_default();
436 DEBUG(9,("nfs_quotas: auth_success\n"));
438 clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, xdr_getquota_args, (caddr_t)&args, xdr_getquota_rslt, (caddr_t)&gqr, timeout);
440 if (clnt_stat != RPC_SUCCESS) {
441 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
442 ret = False;
443 goto out;
447 * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
448 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
449 * something sensible.
452 switch ( quotastat ) {
453 case 0:
454 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat ));
455 ret = False;
456 goto out;
458 case 1:
459 DEBUG(9,("nfs_quotas: Good quota data\n"));
460 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
461 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
462 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
463 break;
465 case 2:
466 case 3:
467 D.dqb_bsoftlimit = 1;
468 D.dqb_curblocks = 1;
469 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
470 break;
472 default:
473 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat ));
474 break;
477 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",
478 quotastat,
479 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
480 gqr.getquota_rslt_u.gqr_rquota.rq_active,
481 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
482 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
483 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
485 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
486 *dsize = D.dqb_bsoftlimit;
488 if (D.dqb_curblocks == D.dqb_curblocks == 1)
489 *bsize = 512;
491 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
492 *dfree = 0;
493 *dsize = D.dqb_curblocks;
494 } else
495 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
497 out:
499 if (clnt) {
500 if (clnt->cl_auth)
501 auth_destroy(clnt->cl_auth);
502 clnt_destroy(clnt);
505 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
507 SAFE_FREE(cutstr);
508 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
509 return ret;
511 #endif
513 /****************************************************************************
514 try to get the disk space from disk quotas (SunOS & Solaris2 version)
515 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
516 ****************************************************************************/
518 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
520 uid_t euser_id;
521 int ret;
522 struct dqblk D;
523 #if defined(SUNOS5)
524 struct quotctl command;
525 int file;
526 static struct mnttab mnt;
527 static pstring name;
528 pstring devopt;
529 #else /* SunOS4 */
530 struct mntent *mnt;
531 static pstring name;
532 #endif
533 FILE *fd;
534 SMB_STRUCT_STAT sbuf;
535 SMB_DEV_T devno ;
536 static SMB_DEV_T devno_cached = 0 ;
537 static int found ;
539 euser_id = geteuid();
541 if ( sys_stat(path,&sbuf) == -1 )
542 return(False) ;
544 devno = sbuf.st_dev ;
545 DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n", path,(unsigned int)devno));
546 if ( devno != devno_cached ) {
547 devno_cached = devno ;
548 #if defined(SUNOS5)
549 if ((fd = sys_fopen(MNTTAB, "r")) == NULL)
550 return(False) ;
552 found = False ;
553 slprintf(devopt, sizeof(devopt) - 1, "dev=%x", (unsigned int)devno);
554 while (getmntent(fd, &mnt) == 0) {
555 if( !hasmntopt(&mnt, devopt) )
556 continue;
558 DEBUG(5,("disk_quotas: testing \"%s\" %s\n", mnt.mnt_mountp,devopt));
560 /* quotas are only on vxfs, UFS or NFS */
561 if ( strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
562 strcmp( mnt.mnt_fstype, "nfs" ) == 0 ||
563 strcmp( mnt.mnt_fstype, "vxfs" ) == 0 ) {
564 found = True ;
565 break;
569 pstrcpy(name,mnt.mnt_mountp) ;
570 pstrcat(name,"/quotas") ;
571 fclose(fd) ;
572 #else /* SunOS4 */
573 if ((fd = setmntent(MOUNTED, "r")) == NULL)
574 return(False) ;
576 found = False ;
577 while ((mnt = getmntent(fd)) != NULL) {
578 if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
579 continue ;
580 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n", mnt->mnt_dir,(unsigned int)sbuf.st_dev));
581 if (sbuf.st_dev == devno) {
582 found = True ;
583 break;
587 pstrcpy(name,mnt->mnt_fsname) ;
588 endmntent(fd) ;
589 #endif
592 if ( ! found )
593 return(False) ;
595 save_re_uid();
596 set_effective_uid(0);
598 #if defined(SUNOS5)
599 if ( strcmp( mnt.mnt_fstype, "nfs" ) == 0) {
600 BOOL retval;
601 DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n", mnt.mnt_special));
602 retval = nfs_quotas(mnt.mnt_special, euser_id, bsize, dfree, dsize);
603 restore_re_uid();
604 return retval;
607 DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
608 if((file=sys_open(name, O_RDONLY,0))<0) {
609 restore_re_uid();
610 return(False);
612 command.op = Q_GETQUOTA;
613 command.uid = euser_id;
614 command.addr = (caddr_t) &D;
615 ret = ioctl(file, Q_QUOTACTL, &command);
616 close(file);
617 #else
618 DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
619 ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
620 #endif
622 restore_re_uid();
624 if (ret < 0) {
625 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n", strerror(errno) ));
627 #if defined(SUNOS5) && defined(VXFS_QUOTA)
628 /* If normal quotactl() fails, try vxfs private calls */
629 set_effective_uid(euser_id);
630 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype));
631 if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) {
632 BOOL retval;
633 retval = disk_quotas_vxfs(name, path, bsize, dfree, dsize);
634 return(retval);
636 #else
637 return(False);
638 #endif
641 /* If softlimit is zero, set it equal to hardlimit.
644 if (D.dqb_bsoftlimit==0)
645 D.dqb_bsoftlimit = D.dqb_bhardlimit;
647 /* Use softlimit to determine disk space. A user exceeding the quota is told
648 * that there's no space left. Writes might actually work for a bit if the
649 * hardlimit is set higher than softlimit. Effectively the disk becomes
650 * made of rubber latex and begins to expand to accommodate the user :-)
653 if (D.dqb_bsoftlimit==0)
654 return(False);
655 *bsize = DEV_BSIZE;
656 *dsize = D.dqb_bsoftlimit;
658 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
659 *dfree = 0;
660 *dsize = D.dqb_curblocks;
661 } else
662 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
664 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
665 path,(double)*bsize,(double)*dfree,(double)*dsize));
667 return(True);
671 #elif defined(OSF1)
672 #include <ufs/quota.h>
674 /****************************************************************************
675 try to get the disk space from disk quotas - OSF1 version
676 ****************************************************************************/
678 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
680 int r, save_errno;
681 struct dqblk D;
682 SMB_STRUCT_STAT S;
683 uid_t euser_id;
686 * This code presumes that OSF1 will only
687 * give out quota info when the real uid
688 * matches the effective uid. JRA.
690 euser_id = geteuid();
691 save_re_uid();
692 if (set_re_uid() != 0) return False;
694 r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
695 if (r) {
696 save_errno = errno;
699 restore_re_uid();
701 *bsize = DEV_BSIZE;
703 if (r)
705 if (save_errno == EDQUOT) /* disk quota exceeded */
707 *dfree = 0;
708 *dsize = D.dqb_curblocks;
709 return (True);
711 else
712 return (False);
715 /* If softlimit is zero, set it equal to hardlimit.
718 if (D.dqb_bsoftlimit==0)
719 D.dqb_bsoftlimit = D.dqb_bhardlimit;
721 /* Use softlimit to determine disk space, except when it has been exceeded */
723 if (D.dqb_bsoftlimit==0)
724 return(False);
726 if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
727 *dfree = 0;
728 *dsize = D.dqb_curblocks;
729 } else {
730 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
731 *dsize = D.dqb_bsoftlimit;
733 return (True);
736 #elif defined (IRIX6)
737 /****************************************************************************
738 try to get the disk space from disk quotas (IRIX 6.2 version)
739 ****************************************************************************/
741 #include <sys/quota.h>
742 #include <mntent.h>
744 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
746 uid_t euser_id;
747 int r;
748 struct dqblk D;
749 struct fs_disk_quota F;
750 SMB_STRUCT_STAT S;
751 FILE *fp;
752 struct mntent *mnt;
753 SMB_DEV_T devno;
754 int found;
756 /* find the block device file */
758 if ( sys_stat(path, &S) == -1 ) {
759 return(False) ;
762 devno = S.st_dev ;
764 fp = setmntent(MOUNTED,"r");
765 found = False ;
767 while ((mnt = getmntent(fp))) {
768 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
769 continue ;
770 if (S.st_dev == devno) {
771 found = True ;
772 break ;
775 endmntent(fp) ;
777 if (!found) {
778 return(False);
781 euser_id=geteuid();
782 save_re_uid();
783 set_effective_uid(0);
785 /* Use softlimit to determine disk space, except when it has been exceeded */
787 *bsize = 512;
789 if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
791 r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
793 restore_re_uid();
795 if (r==-1)
796 return(False);
798 /* Use softlimit to determine disk space, except when it has been exceeded */
799 if (
800 (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
801 (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
802 (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
803 (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
806 *dfree = 0;
807 *dsize = D.dqb_curblocks;
809 else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
811 return(False);
813 else
815 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
816 *dsize = D.dqb_bsoftlimit;
820 else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
822 r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
824 restore_re_uid();
826 if (r==-1)
827 return(False);
829 /* Use softlimit to determine disk space, except when it has been exceeded */
830 if (
831 (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
832 (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
833 (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
834 (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
837 *dfree = 0;
838 *dsize = F.d_bcount;
840 else if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
842 return(False);
844 else
846 *dfree = (F.d_blk_softlimit - F.d_bcount);
847 *dsize = F.d_blk_softlimit;
851 else
853 restore_re_uid();
854 return(False);
857 return (True);
861 #else
863 #if defined(__FreeBSD__) || defined(__OpenBSD__)
864 #include <ufs/ufs/quota.h>
865 #include <machine/param.h>
866 #elif AIX
867 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
868 #include <jfs/quota.h>
869 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
870 #define dqb_curfiles dqb_curinodes
871 #define dqb_fhardlimit dqb_ihardlimit
872 #define dqb_fsoftlimit dqb_isoftlimit
873 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
874 #include <sys/quota.h>
875 #include <devnm.h>
876 #endif
878 /****************************************************************************
879 try to get the disk space from disk quotas - default version
880 ****************************************************************************/
882 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
884 int r;
885 struct dqblk D;
886 uid_t euser_id;
887 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__)
888 char dev_disk[256];
889 SMB_STRUCT_STAT S;
891 /* find the block device file */
893 #ifdef HPUX
894 /* Need to set the cache flag to 1 for HPUX. Seems
895 * to have a significant performance boost when
896 * lstat calls on /dev access this function.
898 if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 1)<0))
899 #else
900 if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0))
901 #endif /* ifdef HPUX */
902 return (False);
904 #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) */
906 euser_id = geteuid();
908 #ifdef HPUX
909 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
910 save_re_uid();
911 if (set_re_uid() != 0) return False;
913 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
915 restore_re_uid();
916 #else
917 #if defined(__FreeBSD__) || defined(__OpenBSD__)
919 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
920 gid_t egrp_id;
922 save_re_uid();
923 set_effective_uid(0);
925 egrp_id = getegid();
926 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
928 /* As FreeBSD has group quotas, if getting the user
929 quota fails, try getting the group instead. */
930 if (r) {
931 r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
934 restore_re_uid();
936 #elif defined(AIX)
937 /* AIX has both USER and GROUP quotas:
938 Get the USER quota (ohnielse@fysik.dtu.dk) */
939 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
940 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
941 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
942 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
943 #endif /* HPUX */
945 /* Use softlimit to determine disk space, except when it has been exceeded */
946 #if defined(__FreeBSD__) || defined(__OpenBSD__)
947 *bsize = DEV_BSIZE;
948 #else /* !__FreeBSD__ && !__OpenBSD__ */
949 *bsize = 1024;
950 #endif /*!__FreeBSD__ && !__OpenBSD__ */
952 if (r)
954 if (errno == EDQUOT)
956 *dfree =0;
957 *dsize =D.dqb_curblocks;
958 return (True);
960 else return(False);
963 /* If softlimit is zero, set it equal to hardlimit.
966 if (D.dqb_bsoftlimit==0)
967 D.dqb_bsoftlimit = D.dqb_bhardlimit;
969 if (D.dqb_bsoftlimit==0)
970 return(False);
971 /* Use softlimit to determine disk space, except when it has been exceeded */
972 if ((D.dqb_curblocks>D.dqb_bsoftlimit)
973 #if !defined(__FreeBSD__) && !defined(__OpenBSD__)
974 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
975 #endif
977 *dfree = 0;
978 *dsize = D.dqb_curblocks;
980 else {
981 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
982 *dsize = D.dqb_bsoftlimit;
984 return (True);
987 #endif
989 #if defined(VXFS_QUOTA)
991 /****************************************************************************
992 Try to get the disk space from Veritas disk quotas.
993 David Lee <T.D.Lee@durham.ac.uk> August 1999.
995 Background assumptions:
996 Potentially under many Operating Systems. Initially Solaris 2.
998 My guess is that Veritas is largely, though not entirely,
999 independent of OS. So I have separated it out.
1001 There may be some details. For example, OS-specific "include" files.
1003 It is understood that HPUX 10 somehow gets Veritas quotas without
1004 any special effort; if so, this routine need not be compiled in.
1005 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1007 Warning:
1008 It is understood that Veritas do not publicly support this ioctl interface.
1009 Rather their preference would be for the user (us) to call the native
1010 OS and then for the OS itself to call through to the VxFS filesystem.
1011 Presumably HPUX 10, see above, does this.
1013 Hints for porting:
1014 Add your OS to "IFLIST" below.
1015 Get it to compile successfully:
1016 Almost certainly "include"s require attention: see SUNOS5.
1017 In the main code above, arrange for it to be called: see SUNOS5.
1018 Test!
1020 ****************************************************************************/
1022 /* "IFLIST"
1023 * This "if" is a list of ports:
1024 * if defined(OS1) || defined(OS2) || ...
1026 #if defined(SUNOS5)
1028 #if defined(SUNOS5)
1029 #include <sys/fs/vx_solaris.h>
1030 #endif
1031 #include <sys/fs/vx_machdep.h>
1032 #include <sys/fs/vx_layout.h>
1033 #include <sys/fs/vx_quota.h>
1034 #include <sys/fs/vx_aioctl.h>
1035 #include <sys/fs/vx_ioctl.h>
1037 BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
1039 uid_t user_id, euser_id;
1040 int ret;
1041 struct vx_dqblk D;
1042 struct vx_quotctl quotabuf;
1043 struct vx_genioctl genbuf;
1044 pstring qfname;
1045 int file;
1048 * "name" may or may not include a trailing "/quotas".
1049 * Arranging consistency of calling here in "quotas.c" may not be easy and
1050 * it might be easier to examine and adjust it here.
1051 * Fortunately, VxFS seems not to mind at present.
1053 pstrcpy(qfname, name) ;
1054 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
1056 euser_id = geteuid();
1057 set_effective_uid(0);
1059 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
1060 if((file=sys_open(qfname, O_RDONLY,0))<0) {
1061 set_effective_uid(euser_id);
1062 return(False);
1064 genbuf.ioc_cmd = VX_QUOTACTL;
1065 genbuf.ioc_up = (void *) &quotabuf;
1067 quotabuf.cmd = VX_GETQUOTA;
1068 quotabuf.uid = euser_id;
1069 quotabuf.addr = (caddr_t) &D;
1070 ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
1071 close(file);
1073 set_effective_uid(euser_id);
1075 if (ret < 0) {
1076 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
1077 return(False);
1080 /* If softlimit is zero, set it equal to hardlimit.
1083 if (D.dqb_bsoftlimit==0)
1084 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1086 /* Use softlimit to determine disk space. A user exceeding the quota is told
1087 * that there's no space left. Writes might actually work for a bit if the
1088 * hardlimit is set higher than softlimit. Effectively the disk becomes
1089 * made of rubber latex and begins to expand to accommodate the user :-)
1091 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1092 path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
1093 D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
1095 if (D.dqb_bsoftlimit==0)
1096 return(False);
1097 *bsize = DEV_BSIZE;
1098 *dsize = D.dqb_bsoftlimit;
1100 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1101 *dfree = 0;
1102 *dsize = D.dqb_curblocks;
1103 } else
1104 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1106 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
1107 path,(double)*bsize,(double)*dfree,(double)*dsize));
1109 return(True);
1112 #endif /* SUNOS5 || ... */
1114 #endif /* VXFS_QUOTA */