Merger krb5-config and libtinfo to SAMBA_3_0
[Samba/gebeck_regimport.git] / source3 / smbd / quotas.c
blob9d3bfe2d64d0351af5494f962fe7c3fd0b8a9056
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(sizeof(char) * len );
417 if (!cutstr)
418 return False;
420 host = strncat(cutstr,mnttype, sizeof(char) * len );
421 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
422 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
423 testpath=strchr_m(mnttype, ':');
424 args.gqa_pathp = testpath+1;
425 args.gqa_uid = uid;
427 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
429 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
430 ret = False;
431 goto out;
434 clnt->cl_auth = authunix_create_default();
435 DEBUG(9,("nfs_quotas: auth_success\n"));
437 clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, xdr_getquota_args, (caddr_t)&args, xdr_getquota_rslt, (caddr_t)&gqr, timeout);
439 if (clnt_stat != RPC_SUCCESS) {
440 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
441 ret = False;
442 goto out;
446 * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
447 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
448 * something sensible.
451 switch ( quotastat ) {
452 case 0:
453 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat ));
454 ret = False;
455 goto out;
457 case 1:
458 DEBUG(9,("nfs_quotas: Good quota data\n"));
459 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
460 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
461 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
462 break;
464 case 2:
465 case 3:
466 D.dqb_bsoftlimit = 1;
467 D.dqb_curblocks = 1;
468 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
469 break;
471 default:
472 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat ));
473 break;
476 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",
477 quotastat,
478 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
479 gqr.getquota_rslt_u.gqr_rquota.rq_active,
480 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
481 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
482 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
484 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
485 *dsize = D.dqb_bsoftlimit;
487 if (D.dqb_curblocks == D.dqb_curblocks == 1)
488 *bsize = 512;
490 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
491 *dfree = 0;
492 *dsize = D.dqb_curblocks;
493 } else
494 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
496 out:
498 if (clnt) {
499 if (clnt->cl_auth)
500 auth_destroy(clnt->cl_auth);
501 clnt_destroy(clnt);
504 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
506 SAFE_FREE(cutstr);
507 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
508 return ret;
510 #endif
512 /****************************************************************************
513 try to get the disk space from disk quotas (SunOS & Solaris2 version)
514 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
515 ****************************************************************************/
517 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
519 uid_t euser_id;
520 int ret;
521 struct dqblk D;
522 #if defined(SUNOS5)
523 struct quotctl command;
524 int file;
525 static struct mnttab mnt;
526 static pstring name;
527 pstring devopt;
528 #else /* SunOS4 */
529 struct mntent *mnt;
530 static pstring name;
531 #endif
532 FILE *fd;
533 SMB_STRUCT_STAT sbuf;
534 SMB_DEV_T devno ;
535 static SMB_DEV_T devno_cached = 0 ;
536 static int found ;
538 euser_id = geteuid();
540 if ( sys_stat(path,&sbuf) == -1 )
541 return(False) ;
543 devno = sbuf.st_dev ;
544 DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n", path,(unsigned int)devno));
545 if ( devno != devno_cached ) {
546 devno_cached = devno ;
547 #if defined(SUNOS5)
548 if ((fd = sys_fopen(MNTTAB, "r")) == NULL)
549 return(False) ;
551 found = False ;
552 slprintf(devopt, sizeof(devopt) - 1, "dev=%x", (unsigned int)devno);
553 while (getmntent(fd, &mnt) == 0) {
554 if( !hasmntopt(&mnt, devopt) )
555 continue;
557 DEBUG(5,("disk_quotas: testing \"%s\" %s\n", mnt.mnt_mountp,devopt));
559 /* quotas are only on vxfs, UFS or NFS */
560 if ( strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
561 strcmp( mnt.mnt_fstype, "nfs" ) == 0 ||
562 strcmp( mnt.mnt_fstype, "vxfs" ) == 0 ) {
563 found = True ;
564 break;
568 pstrcpy(name,mnt.mnt_mountp) ;
569 pstrcat(name,"/quotas") ;
570 fclose(fd) ;
571 #else /* SunOS4 */
572 if ((fd = setmntent(MOUNTED, "r")) == NULL)
573 return(False) ;
575 found = False ;
576 while ((mnt = getmntent(fd)) != NULL) {
577 if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
578 continue ;
579 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n", mnt->mnt_dir,(unsigned int)sbuf.st_dev));
580 if (sbuf.st_dev == devno) {
581 found = True ;
582 break;
586 pstrcpy(name,mnt->mnt_fsname) ;
587 endmntent(fd) ;
588 #endif
591 if ( ! found )
592 return(False) ;
594 save_re_uid();
595 set_effective_uid(0);
597 #if defined(SUNOS5)
598 if ( strcmp( mnt.mnt_fstype, "nfs" ) == 0) {
599 BOOL retval;
600 DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n", mnt.mnt_special));
601 retval = nfs_quotas(mnt.mnt_special, euser_id, bsize, dfree, dsize);
602 restore_re_uid();
603 return retval;
606 DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
607 if((file=sys_open(name, O_RDONLY,0))<0) {
608 restore_re_uid();
609 return(False);
611 command.op = Q_GETQUOTA;
612 command.uid = euser_id;
613 command.addr = (caddr_t) &D;
614 ret = ioctl(file, Q_QUOTACTL, &command);
615 close(file);
616 #else
617 DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
618 ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
619 #endif
621 restore_re_uid();
623 if (ret < 0) {
624 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n", strerror(errno) ));
626 #if defined(SUNOS5) && defined(VXFS_QUOTA)
627 /* If normal quotactl() fails, try vxfs private calls */
628 set_effective_uid(euser_id);
629 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype));
630 if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) {
631 BOOL retval;
632 retval = disk_quotas_vxfs(name, path, bsize, dfree, dsize);
633 return(retval);
635 #else
636 return(False);
637 #endif
640 /* If softlimit is zero, set it equal to hardlimit.
643 if (D.dqb_bsoftlimit==0)
644 D.dqb_bsoftlimit = D.dqb_bhardlimit;
646 /* Use softlimit to determine disk space. A user exceeding the quota is told
647 * that there's no space left. Writes might actually work for a bit if the
648 * hardlimit is set higher than softlimit. Effectively the disk becomes
649 * made of rubber latex and begins to expand to accommodate the user :-)
652 if (D.dqb_bsoftlimit==0)
653 return(False);
654 *bsize = DEV_BSIZE;
655 *dsize = D.dqb_bsoftlimit;
657 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
658 *dfree = 0;
659 *dsize = D.dqb_curblocks;
660 } else
661 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
663 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
664 path,(double)*bsize,(double)*dfree,(double)*dsize));
666 return(True);
670 #elif defined(OSF1)
671 #include <ufs/quota.h>
673 /****************************************************************************
674 try to get the disk space from disk quotas - OSF1 version
675 ****************************************************************************/
677 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
679 int r, save_errno;
680 struct dqblk D;
681 SMB_STRUCT_STAT S;
682 uid_t euser_id;
685 * This code presumes that OSF1 will only
686 * give out quota info when the real uid
687 * matches the effective uid. JRA.
689 euser_id = geteuid();
690 save_re_uid();
691 if (set_re_uid() != 0) return False;
693 r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
694 if (r) {
695 save_errno = errno;
698 restore_re_uid();
700 *bsize = DEV_BSIZE;
702 if (r)
704 if (save_errno == EDQUOT) /* disk quota exceeded */
706 *dfree = 0;
707 *dsize = D.dqb_curblocks;
708 return (True);
710 else
711 return (False);
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, except when it has been exceeded */
722 if (D.dqb_bsoftlimit==0)
723 return(False);
725 if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
726 *dfree = 0;
727 *dsize = D.dqb_curblocks;
728 } else {
729 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
730 *dsize = D.dqb_bsoftlimit;
732 return (True);
735 #elif defined (IRIX6)
736 /****************************************************************************
737 try to get the disk space from disk quotas (IRIX 6.2 version)
738 ****************************************************************************/
740 #include <sys/quota.h>
741 #include <mntent.h>
743 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
745 uid_t euser_id;
746 int r;
747 struct dqblk D;
748 struct fs_disk_quota F;
749 SMB_STRUCT_STAT S;
750 FILE *fp;
751 struct mntent *mnt;
752 SMB_DEV_T devno;
753 int found;
755 /* find the block device file */
757 if ( sys_stat(path, &S) == -1 ) {
758 return(False) ;
761 devno = S.st_dev ;
763 fp = setmntent(MOUNTED,"r");
764 found = False ;
766 while ((mnt = getmntent(fp))) {
767 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
768 continue ;
769 if (S.st_dev == devno) {
770 found = True ;
771 break ;
774 endmntent(fp) ;
776 if (!found) {
777 return(False);
780 euser_id=geteuid();
781 save_re_uid();
782 set_effective_uid(0);
784 /* Use softlimit to determine disk space, except when it has been exceeded */
786 *bsize = 512;
788 if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
790 r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
792 restore_re_uid();
794 if (r==-1)
795 return(False);
797 /* Use softlimit to determine disk space, except when it has been exceeded */
798 if (
799 (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
800 (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
801 (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
802 (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
805 *dfree = 0;
806 *dsize = D.dqb_curblocks;
808 else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
810 return(False);
812 else
814 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
815 *dsize = D.dqb_bsoftlimit;
819 else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
821 r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
823 restore_re_uid();
825 if (r==-1)
826 return(False);
828 /* Use softlimit to determine disk space, except when it has been exceeded */
829 if (
830 (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
831 (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
832 (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
833 (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
836 *dfree = 0;
837 *dsize = F.d_bcount;
839 else if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
841 return(False);
843 else
845 *dfree = (F.d_blk_softlimit - F.d_bcount);
846 *dsize = F.d_blk_softlimit;
850 else
852 restore_re_uid();
853 return(False);
856 return (True);
860 #else
862 #if defined(__FreeBSD__) || defined(__OpenBSD__)
863 #include <ufs/ufs/quota.h>
864 #include <machine/param.h>
865 #elif AIX
866 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
867 #include <jfs/quota.h>
868 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
869 #define dqb_curfiles dqb_curinodes
870 #define dqb_fhardlimit dqb_ihardlimit
871 #define dqb_fsoftlimit dqb_isoftlimit
872 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
873 #include <sys/quota.h>
874 #include <devnm.h>
875 #endif
877 /****************************************************************************
878 try to get the disk space from disk quotas - default version
879 ****************************************************************************/
881 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
883 int r;
884 struct dqblk D;
885 uid_t euser_id;
886 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__)
887 char dev_disk[256];
888 SMB_STRUCT_STAT S;
890 /* find the block device file */
892 #ifdef HPUX
893 /* Need to set the cache flag to 1 for HPUX. Seems
894 * to have a significant performance boost when
895 * lstat calls on /dev access this function.
897 if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 1)<0))
898 #else
899 if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0))
900 return (False);
901 #endif /* ifdef HPUX */
903 #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) */
905 euser_id = geteuid();
907 #ifdef HPUX
908 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
909 save_re_uid();
910 if (set_re_uid() != 0) return False;
912 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
914 restore_re_uid();
915 #else
916 #if defined(__FreeBSD__) || defined(__OpenBSD__)
918 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
919 gid_t egrp_id;
921 save_re_uid();
922 set_effective_uid(0);
924 egrp_id = getegid();
925 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
927 /* As FreeBSD has group quotas, if getting the user
928 quota fails, try getting the group instead. */
929 if (r) {
930 r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
933 restore_re_uid();
935 #elif defined(AIX)
936 /* AIX has both USER and GROUP quotas:
937 Get the USER quota (ohnielse@fysik.dtu.dk) */
938 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
939 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
940 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
941 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
942 #endif /* HPUX */
944 /* Use softlimit to determine disk space, except when it has been exceeded */
945 #if defined(__FreeBSD__) || defined(__OpenBSD__)
946 *bsize = DEV_BSIZE;
947 #else /* !__FreeBSD__ && !__OpenBSD__ */
948 *bsize = 1024;
949 #endif /*!__FreeBSD__ && !__OpenBSD__ */
951 if (r)
953 if (errno == EDQUOT)
955 *dfree =0;
956 *dsize =D.dqb_curblocks;
957 return (True);
959 else return(False);
962 /* If softlimit is zero, set it equal to hardlimit.
965 if (D.dqb_bsoftlimit==0)
966 D.dqb_bsoftlimit = D.dqb_bhardlimit;
968 if (D.dqb_bsoftlimit==0)
969 return(False);
970 /* Use softlimit to determine disk space, except when it has been exceeded */
971 if ((D.dqb_curblocks>D.dqb_bsoftlimit)
972 #if !defined(__FreeBSD__) && !defined(__OpenBSD__)
973 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
974 #endif
976 *dfree = 0;
977 *dsize = D.dqb_curblocks;
979 else {
980 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
981 *dsize = D.dqb_bsoftlimit;
983 return (True);
986 #endif
988 #if defined(VXFS_QUOTA)
990 /****************************************************************************
991 Try to get the disk space from Veritas disk quotas.
992 David Lee <T.D.Lee@durham.ac.uk> August 1999.
994 Background assumptions:
995 Potentially under many Operating Systems. Initially Solaris 2.
997 My guess is that Veritas is largely, though not entirely,
998 independent of OS. So I have separated it out.
1000 There may be some details. For example, OS-specific "include" files.
1002 It is understood that HPUX 10 somehow gets Veritas quotas without
1003 any special effort; if so, this routine need not be compiled in.
1004 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1006 Warning:
1007 It is understood that Veritas do not publicly support this ioctl interface.
1008 Rather their preference would be for the user (us) to call the native
1009 OS and then for the OS itself to call through to the VxFS filesystem.
1010 Presumably HPUX 10, see above, does this.
1012 Hints for porting:
1013 Add your OS to "IFLIST" below.
1014 Get it to compile successfully:
1015 Almost certainly "include"s require attention: see SUNOS5.
1016 In the main code above, arrange for it to be called: see SUNOS5.
1017 Test!
1019 ****************************************************************************/
1021 /* "IFLIST"
1022 * This "if" is a list of ports:
1023 * if defined(OS1) || defined(OS2) || ...
1025 #if defined(SUNOS5)
1027 #if defined(SUNOS5)
1028 #include <sys/fs/vx_solaris.h>
1029 #endif
1030 #include <sys/fs/vx_machdep.h>
1031 #include <sys/fs/vx_layout.h>
1032 #include <sys/fs/vx_quota.h>
1033 #include <sys/fs/vx_aioctl.h>
1034 #include <sys/fs/vx_ioctl.h>
1036 BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
1038 uid_t user_id, euser_id;
1039 int ret;
1040 struct vx_dqblk D;
1041 struct vx_quotctl quotabuf;
1042 struct vx_genioctl genbuf;
1043 pstring qfname;
1044 int file;
1047 * "name" may or may not include a trailing "/quotas".
1048 * Arranging consistency of calling here in "quotas.c" may not be easy and
1049 * it might be easier to examine and adjust it here.
1050 * Fortunately, VxFS seems not to mind at present.
1052 pstrcpy(qfname, name) ;
1053 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
1055 euser_id = geteuid();
1056 set_effective_uid(0);
1058 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
1059 if((file=sys_open(qfname, O_RDONLY,0))<0) {
1060 set_effective_uid(euser_id);
1061 return(False);
1063 genbuf.ioc_cmd = VX_QUOTACTL;
1064 genbuf.ioc_up = (void *) &quotabuf;
1066 quotabuf.cmd = VX_GETQUOTA;
1067 quotabuf.uid = euser_id;
1068 quotabuf.addr = (caddr_t) &D;
1069 ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
1070 close(file);
1072 set_effective_uid(euser_id);
1074 if (ret < 0) {
1075 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
1076 return(False);
1079 /* If softlimit is zero, set it equal to hardlimit.
1082 if (D.dqb_bsoftlimit==0)
1083 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1085 /* Use softlimit to determine disk space. A user exceeding the quota is told
1086 * that there's no space left. Writes might actually work for a bit if the
1087 * hardlimit is set higher than softlimit. Effectively the disk becomes
1088 * made of rubber latex and begins to expand to accommodate the user :-)
1090 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1091 path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
1092 D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
1094 if (D.dqb_bsoftlimit==0)
1095 return(False);
1096 *bsize = DEV_BSIZE;
1097 *dsize = D.dqb_bsoftlimit;
1099 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1100 *dfree = 0;
1101 *dsize = D.dqb_curblocks;
1102 } else
1103 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1105 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
1106 path,(double)*bsize,(double)*dfree,(double)*dsize));
1108 return(True);
1111 #endif /* SUNOS5 || ... */
1113 #endif /* VXFS_QUOTA */