performance patch from HP-UX folks (cant remember who)
[Samba.git] / source / smbd / quotas.c
blobbe72d26058d3a9a251b204799ceb234fe2fcaf4f
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 support for quotas
5 Copyright (C) Andrew Tridgell 1992-1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 /*
24 * This is one of the most system dependent parts of Samba, and its
25 * done a litle differently. Each system has its own way of doing
26 * things :-(
29 #include "includes.h"
31 #if defined(VXFS_QUOTA)
34 * In addition to their native filesystems, some systems have Veritas VxFS.
35 * Declare here, define at end: reduces likely "include" interaction problems.
36 * David Lee <T.D.Lee@durham.ac.uk>
38 BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize);
40 #endif /* VXFS_QUOTA */
42 #ifdef LINUX
44 #include <sys/types.h>
45 #include <mntent.h>
48 * This shouldn't be neccessary - it should be /usr/include/sys/quota.h
49 * So we include all the files has *should* be in the system into a large,
50 * grungy samba_linux_quoatas.h Sometimes I *hate* Linux :-). JRA.
53 #include "samba_linux_quota.h"
55 typedef struct _LINUX_SMB_DISK_QUOTA {
56 SMB_BIG_UINT bsize;
57 SMB_BIG_UINT hardlimit; /* In bsize units. */
58 SMB_BIG_UINT softlimit; /* In bsize units. */
59 SMB_BIG_UINT curblocks; /* In bsize units. */
60 SMB_BIG_UINT ihardlimit; /* inode hard limit. */
61 SMB_BIG_UINT isoftlimit; /* inode soft limit. */
62 SMB_BIG_UINT curinodes; /* Current used inodes. */
63 } LINUX_SMB_DISK_QUOTA;
65 /****************************************************************************
66 Abstract out the XFS Quota Manager quota get call.
67 ****************************************************************************/
69 static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA *dp)
71 int ret = -1;
72 struct fs_disk_quota D;
73 ZERO_STRUCT(D);
75 if ((ret = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D)))
76 return ret;
78 dp->bsize = (SMB_BIG_UINT)512;
79 dp->softlimit = (SMB_BIG_UINT)D.d_blk_softlimit;
80 dp->hardlimit = (SMB_BIG_UINT)D.d_blk_hardlimit;
81 dp->ihardlimit = (SMB_BIG_UINT)D.d_ino_hardlimit;
82 dp->isoftlimit = (SMB_BIG_UINT)D.d_ino_softlimit;
83 dp->curinodes = (SMB_BIG_UINT)D.d_icount;
84 dp->curblocks = (SMB_BIG_UINT)D.d_bcount;
85 return ret;
88 /****************************************************************************
89 Abstract out the old and new Linux quota get calls.
90 ****************************************************************************/
92 static int get_smb_linux_v1_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA *dp)
94 struct v1_kern_dqblk D;
95 int ret;
97 ZERO_STRUCT(D);
98 dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
100 if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D)))
101 return -1;
103 dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
104 dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
105 dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
106 dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
107 dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
108 dp->curblocks = (SMB_BIG_UINT)D.dqb_curblocks;
110 return 0;
113 static int get_smb_linux_v2_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA *dp)
115 struct v2_kern_dqblk D;
116 int ret;
118 ZERO_STRUCT(D);
119 dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
121 if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D)))
122 return -1;
124 dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
125 dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
126 dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
127 dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
128 dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
129 dp->curblocks = ((SMB_BIG_UINT)D.dqb_curspace) / dp->bsize;
131 return 0;
134 /****************************************************************************
135 Brand-new generic quota interface.
136 ****************************************************************************/
138 static int get_smb_linux_gen_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA *dp)
140 struct if_dqblk D;
141 int ret;
143 ZERO_STRUCT(D);
144 dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
146 if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D)))
147 return -1;
149 dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
150 dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
151 dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
152 dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
153 dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
154 dp->curblocks = ((SMB_BIG_UINT)D.dqb_curspace) / dp->bsize;
156 return 0;
159 /****************************************************************************
160 Try to get the disk space from disk quotas (LINUX version).
161 ****************************************************************************/
163 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
165 int r;
166 SMB_STRUCT_STAT S;
167 FILE *fp;
168 LINUX_SMB_DISK_QUOTA D;
169 struct mntent *mnt;
170 SMB_DEV_T devno;
171 int found;
172 uid_t euser_id;
174 euser_id = geteuid();
176 /* find the block device file */
178 if ( sys_stat(path, &S) == -1 )
179 return(False) ;
181 devno = S.st_dev ;
183 fp = setmntent(MOUNTED,"r");
184 found = False ;
186 while ((mnt = getmntent(fp))) {
187 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
188 continue ;
190 if (S.st_dev == devno) {
191 found = True ;
192 break;
196 endmntent(fp) ;
198 if (!found)
199 return(False);
201 save_re_uid();
202 set_effective_uid(0);
204 if (strcmp(mnt->mnt_type, "xfs")) {
205 r=get_smb_linux_gen_quota(mnt->mnt_fsname, euser_id, &D);
206 if (r == -1) {
207 r=get_smb_linux_v2_quota(mnt->mnt_fsname, euser_id, &D);
208 if (r == -1)
209 r=get_smb_linux_v1_quota(mnt->mnt_fsname, euser_id, &D);
211 } else {
212 r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, &D);
215 restore_re_uid();
217 /* Use softlimit to determine disk space, except when it has been exceeded */
218 *bsize = D.bsize;
219 if (r == -1) {
220 if (errno == EDQUOT) {
221 *dfree =0;
222 *dsize =D.curblocks;
223 return (True);
224 } else {
225 return(False);
229 /* Use softlimit to determine disk space, except when it has been exceeded */
230 if (
231 (D.softlimit && D.curblocks >= D.softlimit) ||
232 (D.hardlimit && D.curblocks >= D.hardlimit) ||
233 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
234 (D.ihardlimit && D.curinodes>=D.ihardlimit)
236 *dfree = 0;
237 *dsize = D.curblocks;
238 } else if (D.softlimit==0 && D.hardlimit==0) {
239 return(False);
240 } else {
241 if (D.softlimit == 0)
242 D.softlimit = D.hardlimit;
243 *dfree = D.softlimit - D.curblocks;
244 *dsize = D.softlimit;
247 return (True);
250 #elif defined(CRAY)
252 #include <sys/quota.h>
253 #include <mntent.h>
255 /****************************************************************************
256 try to get the disk space from disk quotas (CRAY VERSION)
257 ****************************************************************************/
259 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
261 struct mntent *mnt;
262 FILE *fd;
263 SMB_STRUCT_STAT sbuf;
264 SMB_DEV_T devno ;
265 static SMB_DEV_T devno_cached = 0 ;
266 static pstring name;
267 struct q_request request ;
268 struct qf_header header ;
269 static int quota_default = 0 ;
270 int found ;
272 if ( sys_stat(path,&sbuf) == -1 )
273 return(False) ;
275 devno = sbuf.st_dev ;
277 if ( devno != devno_cached ) {
279 devno_cached = devno ;
281 if ((fd = setmntent(KMTAB)) == NULL)
282 return(False) ;
284 found = False ;
286 while ((mnt = getmntent(fd)) != NULL) {
288 if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
289 continue ;
291 if (sbuf.st_dev == devno) {
293 found = True ;
294 break ;
300 pstrcpy(name,mnt->mnt_dir) ;
301 endmntent(fd) ;
303 if ( ! found )
304 return(False) ;
307 request.qf_magic = QF_MAGIC ;
308 request.qf_entry.id = geteuid() ;
310 if (quotactl(name, Q_GETQUOTA, &request) == -1)
311 return(False) ;
313 if ( ! request.user )
314 return(False) ;
316 if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) {
318 if ( ! quota_default ) {
320 if ( quotactl(name, Q_GETHEADER, &header) == -1 )
321 return(False) ;
322 else
323 quota_default = header.user_h.def_fq ;
326 *dfree = quota_default ;
328 }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) {
330 *dfree = 0 ;
332 }else{
334 *dfree = request.qf_entry.user_q.f_quota ;
338 *dsize = request.qf_entry.user_q.f_use ;
340 if ( *dfree < *dsize )
341 *dfree = 0 ;
342 else
343 *dfree -= *dsize ;
345 *bsize = 4096 ; /* Cray blocksize */
347 return(True) ;
352 #elif defined(SUNOS5) || defined(SUNOS4)
354 #include <fcntl.h>
355 #include <sys/param.h>
356 #if defined(SUNOS5)
357 #include <sys/fs/ufs_quota.h>
358 #include <sys/mnttab.h>
359 #include <sys/mntent.h>
360 #else /* defined(SUNOS4) */
361 #include <ufs/quota.h>
362 #include <mntent.h>
363 #endif
365 #if defined(SUNOS5)
367 /****************************************************************************
368 Allows querying of remote hosts for quotas on NFS mounted shares.
369 Supports normal NFS and AMD mounts.
370 Alan Romeril <a.romeril@ic.ac.uk> July 2K.
371 ****************************************************************************/
373 #include <rpc/rpc.h>
374 #include <rpc/types.h>
375 #include <rpcsvc/rquota.h>
376 #include <rpc/nettype.h>
377 #include <rpc/xdr.h>
379 static int quotastat;
381 static int xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
383 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
384 return(0);
385 if (!xdr_int(xdrsp, &args->gqa_uid))
386 return(0);
387 return (1);
390 static int xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
392 if (!xdr_int(xdrsp, &quotastat)) {
393 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
394 return 0;
396 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
397 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
398 return 0;
400 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
401 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
402 return 0;
404 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
405 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
406 return 0;
408 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
409 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
410 return 0;
412 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
413 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
414 return 0;
416 return (1);
419 /* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
420 static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
422 uid_t uid = euser_id;
423 struct dqblk D;
424 char *mnttype = nfspath;
425 CLIENT *clnt;
426 struct getquota_rslt gqr;
427 struct getquota_args args;
428 char *cutstr, *pathname, *host, *testpath;
429 int len;
430 static struct timeval timeout = {2,0};
431 enum clnt_stat clnt_stat;
432 BOOL ret = True;
434 *bsize = *dfree = *dsize = (SMB_BIG_UINT)0;
436 len=strcspn(mnttype, ":");
437 pathname=strstr(mnttype, ":");
438 cutstr = (char *) malloc(sizeof(char) * len );
439 if (!cutstr)
440 return False;
442 host = strncat(cutstr,mnttype, sizeof(char) * len );
443 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
444 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
445 testpath=strchr(mnttype, ':');
446 args.gqa_pathp = testpath+1;
447 args.gqa_uid = uid;
449 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
451 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
452 ret = False;
453 goto out;
456 clnt->cl_auth = authunix_create_default();
457 DEBUG(9,("nfs_quotas: auth_success\n"));
459 clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, xdr_getquota_args, (caddr_t)&args, xdr_getquota_rslt, (caddr_t)&gqr, timeout);
461 if (clnt_stat != RPC_SUCCESS) {
462 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
463 ret = False;
464 goto out;
468 * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
469 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
470 * something sensible.
473 switch ( quotastat ) {
474 case 0:
475 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat ));
476 ret = False;
477 goto out;
479 case 1:
480 DEBUG(9,("nfs_quotas: Good quota data\n"));
481 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
482 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
483 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
484 break;
486 case 2:
487 case 3:
488 D.dqb_bsoftlimit = 1;
489 D.dqb_curblocks = 1;
490 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
491 break;
493 default:
494 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat ));
495 break;
498 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",
499 quotastat,
500 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
501 gqr.getquota_rslt_u.gqr_rquota.rq_active,
502 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
503 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
504 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
506 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
507 *dsize = D.dqb_bsoftlimit;
509 if (D.dqb_curblocks == D.dqb_curblocks == 1)
510 *bsize = 512;
512 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
513 *dfree = 0;
514 *dsize = D.dqb_curblocks;
515 } else
516 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
518 out:
520 if (clnt) {
521 if (clnt->cl_auth)
522 auth_destroy(clnt->cl_auth);
523 clnt_destroy(clnt);
526 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
528 safe_free(cutstr);
529 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
530 return ret;
532 #endif
534 /****************************************************************************
535 try to get the disk space from disk quotas (SunOS & Solaris2 version)
536 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
537 ****************************************************************************/
539 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
541 uid_t euser_id;
542 int ret;
543 struct dqblk D;
544 #if defined(SUNOS5)
545 struct quotctl command;
546 int file;
547 static struct mnttab mnt;
548 static pstring name;
549 pstring devopt;
550 #else /* SunOS4 */
551 struct mntent *mnt;
552 static pstring name;
553 #endif
554 FILE *fd;
555 SMB_STRUCT_STAT sbuf;
556 SMB_DEV_T devno ;
557 static SMB_DEV_T devno_cached = 0 ;
558 static int found ;
560 euser_id = geteuid();
562 if ( sys_stat(path,&sbuf) == -1 )
563 return(False) ;
565 devno = sbuf.st_dev ;
566 DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n", path,(unsigned int)devno));
567 if ( devno != devno_cached ) {
568 devno_cached = devno ;
569 #if defined(SUNOS5)
570 if ((fd = sys_fopen(MNTTAB, "r")) == NULL)
571 return(False) ;
573 found = False ;
574 slprintf(devopt, sizeof(devopt) - 1, "dev=%x", (unsigned int)devno);
575 while (getmntent(fd, &mnt) == 0) {
576 if( !hasmntopt(&mnt, devopt) )
577 continue;
579 DEBUG(5,("disk_quotas: testing \"%s\" %s\n", mnt.mnt_mountp,devopt));
581 /* quotas are only on vxfs, UFS or NFS */
582 if ( strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
583 strcmp( mnt.mnt_fstype, "nfs" ) == 0 ||
584 strcmp( mnt.mnt_fstype, "vxfs" ) == 0 ) {
585 found = True ;
586 break;
590 pstrcpy(name,mnt.mnt_mountp) ;
591 pstrcat(name,"/quotas") ;
592 fclose(fd) ;
593 #else /* SunOS4 */
594 if ((fd = setmntent(MOUNTED, "r")) == NULL)
595 return(False) ;
597 found = False ;
598 while ((mnt = getmntent(fd)) != NULL) {
599 if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
600 continue ;
601 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n", mnt->mnt_dir,(unsigned int)sbuf.st_dev));
602 if (sbuf.st_dev == devno) {
603 found = True ;
604 break;
608 pstrcpy(name,mnt->mnt_fsname) ;
609 endmntent(fd) ;
610 #endif
613 if ( ! found )
614 return(False) ;
616 save_re_uid();
617 set_effective_uid(0);
619 #if defined(SUNOS5)
620 if ( strcmp( mnt.mnt_fstype, "nfs" ) == 0) {
621 BOOL retval;
622 DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n", mnt.mnt_special));
623 retval = nfs_quotas(mnt.mnt_special, euser_id, bsize, dfree, dsize);
624 restore_re_uid();
625 return retval;
628 DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
629 if((file=sys_open(name, O_RDONLY,0))<0) {
630 restore_re_uid();
631 return(False);
633 command.op = Q_GETQUOTA;
634 command.uid = euser_id;
635 command.addr = (caddr_t) &D;
636 ret = ioctl(file, Q_QUOTACTL, &command);
637 close(file);
638 #else
639 DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
640 ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
641 #endif
643 restore_re_uid();
645 if (ret < 0) {
646 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n", strerror(errno) ));
648 #if defined(SUNOS5) && defined(VXFS_QUOTA)
649 /* If normal quotactl() fails, try vxfs private calls */
650 set_effective_uid(euser_id);
651 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype));
652 if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) {
653 BOOL retval;
654 retval = disk_quotas_vxfs(name, path, bsize, dfree, dsize);
655 return(retval);
657 #else
658 return(False);
659 #endif
662 /* If softlimit is zero, set it equal to hardlimit.
665 if (D.dqb_bsoftlimit==0)
666 D.dqb_bsoftlimit = D.dqb_bhardlimit;
668 /* Use softlimit to determine disk space. A user exceeding the quota is told
669 * that there's no space left. Writes might actually work for a bit if the
670 * hardlimit is set higher than softlimit. Effectively the disk becomes
671 * made of rubber latex and begins to expand to accommodate the user :-)
674 if (D.dqb_bsoftlimit==0)
675 return(False);
676 *bsize = DEV_BSIZE;
677 *dsize = D.dqb_bsoftlimit;
679 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
680 *dfree = 0;
681 *dsize = D.dqb_curblocks;
682 } else
683 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
685 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
686 path,(double)*bsize,(double)*dfree,(double)*dsize));
688 return(True);
692 #elif defined(OSF1)
693 #include <ufs/quota.h>
695 /****************************************************************************
696 try to get the disk space from disk quotas - OSF1 version
697 ****************************************************************************/
699 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
701 int r, save_errno;
702 struct dqblk D;
703 SMB_STRUCT_STAT S;
704 uid_t euser_id;
707 * This code presumes that OSF1 will only
708 * give out quota info when the real uid
709 * matches the effective uid. JRA.
711 euser_id = geteuid();
712 save_re_uid();
713 if (set_re_uid() != 0) return False;
715 r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
716 if (r) {
717 save_errno = errno;
720 restore_re_uid();
722 *bsize = DEV_BSIZE;
724 if (r)
726 if (save_errno == EDQUOT) /* disk quota exceeded */
728 *dfree = 0;
729 *dsize = D.dqb_curblocks;
730 return (True);
732 else
733 return (False);
736 /* If softlimit is zero, set it equal to hardlimit.
739 if (D.dqb_bsoftlimit==0)
740 D.dqb_bsoftlimit = D.dqb_bhardlimit;
742 /* Use softlimit to determine disk space, except when it has been exceeded */
744 if (D.dqb_bsoftlimit==0)
745 return(False);
747 if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
748 *dfree = 0;
749 *dsize = D.dqb_curblocks;
750 } else {
751 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
752 *dsize = D.dqb_bsoftlimit;
754 return (True);
757 #elif defined (IRIX6)
758 /****************************************************************************
759 try to get the disk space from disk quotas (IRIX 6.2 version)
760 ****************************************************************************/
762 #include <sys/quota.h>
763 #include <mntent.h>
765 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
767 uid_t euser_id;
768 int r;
769 struct dqblk D;
770 struct fs_disk_quota F;
771 SMB_STRUCT_STAT S;
772 FILE *fp;
773 struct mntent *mnt;
774 SMB_DEV_T devno;
775 int found;
777 /* find the block device file */
779 if ( sys_stat(path, &S) == -1 ) {
780 return(False) ;
783 devno = S.st_dev ;
785 fp = setmntent(MOUNTED,"r");
786 found = False ;
788 while ((mnt = getmntent(fp))) {
789 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
790 continue ;
791 if (S.st_dev == devno) {
792 found = True ;
793 break ;
796 endmntent(fp) ;
798 if (!found) {
799 return(False);
802 euser_id=geteuid();
803 save_re_uid();
804 set_effective_uid(0);
806 /* Use softlimit to determine disk space, except when it has been exceeded */
808 *bsize = 512;
810 if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
812 r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
814 restore_re_uid();
816 if (r==-1)
817 return(False);
819 /* Use softlimit to determine disk space, except when it has been exceeded */
820 if (
821 (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
822 (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
823 (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
824 (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
827 *dfree = 0;
828 *dsize = D.dqb_curblocks;
830 else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
832 return(False);
834 else
836 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
837 *dsize = D.dqb_bsoftlimit;
841 else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
843 r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
845 restore_re_uid();
847 if (r==-1)
848 return(False);
850 /* Use softlimit to determine disk space, except when it has been exceeded */
851 if (
852 (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
853 (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
854 (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
855 (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
858 *dfree = 0;
859 *dsize = F.d_bcount;
861 else if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
863 return(False);
865 else
867 *dfree = (F.d_blk_softlimit - F.d_bcount);
868 *dsize = F.d_blk_softlimit;
872 else
874 restore_re_uid();
875 return(False);
878 return (True);
882 #else
884 #if defined(__FreeBSD__) || defined(__OpenBSD__)
885 #include <ufs/ufs/quota.h>
886 #include <machine/param.h>
887 #elif AIX
888 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
889 #include <jfs/quota.h>
890 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
891 #define dqb_curfiles dqb_curinodes
892 #define dqb_fhardlimit dqb_ihardlimit
893 #define dqb_fsoftlimit dqb_isoftlimit
894 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
895 #include <sys/quota.h>
896 #include <devnm.h>
897 #endif
899 /****************************************************************************
900 try to get the disk space from disk quotas - default version
901 ****************************************************************************/
903 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
905 int r;
906 struct dqblk D;
907 uid_t euser_id;
908 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__)
909 char dev_disk[256];
910 SMB_STRUCT_STAT S;
912 /* find the block device file */
914 #ifdef HPUX
915 /* Need to set the cache flag to 1 for HPUX. Seems
916 * to have a significant performance boost when
917 * lstat calls on /dev access this function.
919 if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 1)<0))
920 #else
921 if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0))
922 return (False);
923 #endif /* ifdef HPUX */
925 #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) */
927 euser_id = geteuid();
929 #ifdef HPUX
930 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
931 save_re_uid();
932 if (set_re_uid() != 0) return False;
934 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
936 restore_re_uid();
937 #else
938 #if defined(__FreeBSD__) || defined(__OpenBSD__)
940 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
941 gid_t egrp_id;
943 save_re_uid();
944 set_effective_uid(0);
946 egrp_id = getegid();
947 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
949 /* As FreeBSD has group quotas, if getting the user
950 quota fails, try getting the group instead. */
951 if (r) {
952 r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
955 restore_re_uid();
957 #elif defined(AIX)
958 /* AIX has both USER and GROUP quotas:
959 Get the USER quota (ohnielse@fysik.dtu.dk) */
960 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
961 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
962 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
963 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
964 #endif /* HPUX */
966 /* Use softlimit to determine disk space, except when it has been exceeded */
967 #if defined(__FreeBSD__) || defined(__OpenBSD__)
968 *bsize = DEV_BSIZE;
969 #else /* !__FreeBSD__ && !__OpenBSD__ */
970 *bsize = 1024;
971 #endif /*!__FreeBSD__ && !__OpenBSD__ */
973 if (r)
975 if (errno == EDQUOT)
977 *dfree =0;
978 *dsize =D.dqb_curblocks;
979 return (True);
981 else return(False);
984 /* If softlimit is zero, set it equal to hardlimit.
987 if (D.dqb_bsoftlimit==0)
988 D.dqb_bsoftlimit = D.dqb_bhardlimit;
990 if (D.dqb_bsoftlimit==0)
991 return(False);
992 /* Use softlimit to determine disk space, except when it has been exceeded */
993 if ((D.dqb_curblocks>D.dqb_bsoftlimit)
994 #if !defined(__FreeBSD__) && !defined(__OpenBSD__)
995 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
996 #endif
998 *dfree = 0;
999 *dsize = D.dqb_curblocks;
1001 else {
1002 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1003 *dsize = D.dqb_bsoftlimit;
1005 return (True);
1008 #endif
1010 #if defined(VXFS_QUOTA)
1012 /****************************************************************************
1013 Try to get the disk space from Veritas disk quotas.
1014 David Lee <T.D.Lee@durham.ac.uk> August 1999.
1016 Background assumptions:
1017 Potentially under many Operating Systems. Initially Solaris 2.
1019 My guess is that Veritas is largely, though not entirely,
1020 independent of OS. So I have separated it out.
1022 There may be some details. For example, OS-specific "include" files.
1024 It is understood that HPUX 10 somehow gets Veritas quotas without
1025 any special effort; if so, this routine need not be compiled in.
1026 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1028 Warning:
1029 It is understood that Veritas do not publicly support this ioctl interface.
1030 Rather their preference would be for the user (us) to call the native
1031 OS and then for the OS itself to call through to the VxFS filesystem.
1032 Presumably HPUX 10, see above, does this.
1034 Hints for porting:
1035 Add your OS to "IFLIST" below.
1036 Get it to compile successfully:
1037 Almost certainly "include"s require attention: see SUNOS5.
1038 In the main code above, arrange for it to be called: see SUNOS5.
1039 Test!
1041 ****************************************************************************/
1043 /* "IFLIST"
1044 * This "if" is a list of ports:
1045 * if defined(OS1) || defined(OS2) || ...
1047 #if defined(SUNOS5)
1049 #if defined(SUNOS5)
1050 #include <sys/fs/vx_solaris.h>
1051 #endif
1052 #include <sys/fs/vx_machdep.h>
1053 #include <sys/fs/vx_layout.h>
1054 #include <sys/fs/vx_quota.h>
1055 #include <sys/fs/vx_aioctl.h>
1056 #include <sys/fs/vx_ioctl.h>
1058 BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
1060 uid_t user_id, euser_id;
1061 int ret;
1062 struct vx_dqblk D;
1063 struct vx_quotctl quotabuf;
1064 struct vx_genioctl genbuf;
1065 pstring qfname;
1066 int file;
1069 * "name" may or may not include a trailing "/quotas".
1070 * Arranging consistency of calling here in "quotas.c" may not be easy and
1071 * it might be easier to examine and adjust it here.
1072 * Fortunately, VxFS seems not to mind at present.
1074 pstrcpy(qfname, name) ;
1075 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
1077 euser_id = geteuid();
1078 set_effective_uid(0);
1080 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
1081 if((file=sys_open(qfname, O_RDONLY,0))<0) {
1082 set_effective_uid(euser_id);
1083 return(False);
1085 genbuf.ioc_cmd = VX_QUOTACTL;
1086 genbuf.ioc_up = (void *) &quotabuf;
1088 quotabuf.cmd = VX_GETQUOTA;
1089 quotabuf.uid = euser_id;
1090 quotabuf.addr = (caddr_t) &D;
1091 ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
1092 close(file);
1094 set_effective_uid(euser_id);
1096 if (ret < 0) {
1097 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
1098 return(False);
1101 /* If softlimit is zero, set it equal to hardlimit.
1104 if (D.dqb_bsoftlimit==0)
1105 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1107 /* Use softlimit to determine disk space. A user exceeding the quota is told
1108 * that there's no space left. Writes might actually work for a bit if the
1109 * hardlimit is set higher than softlimit. Effectively the disk becomes
1110 * made of rubber latex and begins to expand to accommodate the user :-)
1112 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1113 path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
1114 D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
1116 if (D.dqb_bsoftlimit==0)
1117 return(False);
1118 *bsize = DEV_BSIZE;
1119 *dsize = D.dqb_bsoftlimit;
1121 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1122 *dfree = 0;
1123 *dsize = D.dqb_curblocks;
1124 } else
1125 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1127 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
1128 path,(double)*bsize,(double)*dfree,(double)*dsize));
1130 return(True);
1133 #endif /* SUNOS5 || ... */
1135 #endif /* VXFS_QUOTA */