move to SAFE_FREE()
[Samba.git] / source / smbd / quotas.c
blob3ef04b0692742f7c7d41e5c4cdde7baedbe3f31b
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 extern int DEBUGLEVEL;
33 #if defined(VXFS_QUOTA)
36 * In addition to their native filesystems, some systems have Veritas VxFS.
37 * Declare here, define at end: reduces likely "include" interaction problems.
38 * David Lee <T.D.Lee@durham.ac.uk>
40 BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize);
42 #endif /* VXFS_QUOTA */
44 #ifdef LINUX
46 #include <sys/types.h>
47 #include <asm/types.h>
48 #include <sys/quota.h>
50 #include <mntent.h>
51 #include <linux/unistd.h>
53 _syscall4(int, quotactl, int, cmd, const char *, special, int, id, caddr_t, addr);
55 /****************************************************************************
56 try to get the disk space from disk quotas (LINUX version)
57 ****************************************************************************/
59 BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
61 int r;
62 struct dqblk D;
63 SMB_STRUCT_STAT S;
64 FILE *fp;
65 struct mntent *mnt;
66 SMB_DEV_T devno;
67 int found;
68 uid_t euser_id;
70 euser_id = geteuid();
72 /* find the block device file */
74 if ( sys_stat(path, &S) == -1 ) {
75 return(False) ;
78 devno = S.st_dev ;
80 fp = setmntent(MOUNTED,"r");
81 found = False ;
83 while ((mnt = getmntent(fp))) {
84 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
85 continue ;
86 if (S.st_dev == devno) {
87 found = True ;
88 break ;
91 endmntent(fp) ;
93 if (!found) {
94 return(False);
97 save_re_uid();
98 set_effective_uid(0);
99 r=quotactl(QCMD(Q_GETQUOTA,USRQUOTA), mnt->mnt_fsname, euser_id, (caddr_t)&D);
100 restore_re_uid();
102 /* Use softlimit to determine disk space, except when it has been exceeded */
103 *bsize = 1024;
104 if (r)
106 if (errno == EDQUOT)
108 *dfree =0;
109 *dsize =D.dqb_curblocks;
110 return (True);
112 else return(False);
114 /* Use softlimit to determine disk space, except when it has been exceeded */
115 if (
116 (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
117 (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
118 (D.dqb_isoftlimit && D.dqb_curinodes>=D.dqb_isoftlimit) ||
119 (D.dqb_ihardlimit && D.dqb_curinodes>=D.dqb_ihardlimit)
122 *dfree = 0;
123 *dsize = D.dqb_curblocks;
125 else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
127 return(False);
129 else {
130 if (D.dqb_bsoftlimit == 0)
131 D.dqb_bsoftlimit = D.dqb_bhardlimit;
132 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
133 *dsize = D.dqb_bsoftlimit;
135 return (True);
138 #elif defined(CRAY)
140 #include <sys/quota.h>
141 #include <mntent.h>
143 /****************************************************************************
144 try to get the disk space from disk quotas (CRAY VERSION)
145 ****************************************************************************/
147 BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
149 struct mntent *mnt;
150 FILE *fd;
151 SMB_STRUCT_STAT sbuf;
152 SMB_DEV_T devno ;
153 static SMB_DEV_T devno_cached = 0 ;
154 static pstring name;
155 struct q_request request ;
156 struct qf_header header ;
157 static int quota_default = 0 ;
158 int found ;
160 if ( sys_stat(path,&sbuf) == -1 )
161 return(False) ;
163 devno = sbuf.st_dev ;
165 if ( devno != devno_cached ) {
167 devno_cached = devno ;
169 if ((fd = setmntent(KMTAB)) == NULL)
170 return(False) ;
172 found = False ;
174 while ((mnt = getmntent(fd)) != NULL) {
176 if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
177 continue ;
179 if (sbuf.st_dev == devno) {
181 found = True ;
182 break ;
188 pstrcpy(name,mnt->mnt_dir) ;
189 endmntent(fd) ;
191 if ( ! found )
192 return(False) ;
195 request.qf_magic = QF_MAGIC ;
196 request.qf_entry.id = geteuid() ;
198 if (quotactl(name, Q_GETQUOTA, &request) == -1)
199 return(False) ;
201 if ( ! request.user )
202 return(False) ;
204 if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) {
206 if ( ! quota_default ) {
208 if ( quotactl(name, Q_GETHEADER, &header) == -1 )
209 return(False) ;
210 else
211 quota_default = header.user_h.def_fq ;
214 *dfree = quota_default ;
216 }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) {
218 *dfree = 0 ;
220 }else{
222 *dfree = request.qf_entry.user_q.f_quota ;
226 *dsize = request.qf_entry.user_q.f_use ;
228 if ( *dfree < *dsize )
229 *dfree = 0 ;
230 else
231 *dfree -= *dsize ;
233 *bsize = 4096 ; /* Cray blocksize */
235 return(True) ;
240 #elif defined(SUNOS5) || defined(SUNOS4)
242 #include <fcntl.h>
243 #include <sys/param.h>
244 #if defined(SUNOS5)
245 #include <sys/fs/ufs_quota.h>
246 #include <sys/mnttab.h>
247 #include <sys/mntent.h>
248 #else /* defined(SUNOS4) */
249 #include <ufs/quota.h>
250 #include <mntent.h>
251 #endif
253 #if defined(SUNOS5)
255 /****************************************************************************
256 Allows querying of remote hosts for quotas on NFS mounted shares.
257 Supports normal NFS and AMD mounts.
258 Alan Romeril <a.romeril@ic.ac.uk> July 2K.
259 ****************************************************************************/
261 #include <rpc/rpc.h>
262 #include <rpc/types.h>
263 #include <rpcsvc/rquota.h>
264 #include <rpc/nettype.h>
265 #include <rpc/xdr.h>
267 static int quotastat;
269 static int xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
271 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
272 return(0);
273 if (!xdr_int(xdrsp, &args->gqa_uid))
274 return(0);
275 return (1);
278 static int xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
280 if (!xdr_int(xdrsp, &quotastat)) {
281 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
282 return 0;
284 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
285 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
286 return 0;
288 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
289 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
290 return 0;
292 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
293 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
294 return 0;
296 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
297 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
298 return 0;
300 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
301 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
302 return 0;
304 return (1);
307 /* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
308 static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
310 uid_t uid = euser_id;
311 struct dqblk D;
312 char *mnttype = nfspath;
313 CLIENT *clnt;
314 struct getquota_rslt gqr;
315 struct getquota_args args;
316 char *cutstr, *pathname, *host, *testpath;
317 int len;
318 static struct timeval timeout = {2,0};
319 enum clnt_stat clnt_stat;
320 BOOL ret = True;
322 *bsize = *dfree = *dsize = (SMB_BIG_UINT)0;
324 len=strcspn(mnttype, ":");
325 pathname=strstr(mnttype, ":");
326 cutstr = (char *) malloc(sizeof(char) * len );
327 if (!cutstr)
328 return False;
330 host = strncat(cutstr,mnttype, sizeof(char) * len );
331 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
332 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
333 testpath=strchr_m(mnttype, ':');
334 args.gqa_pathp = testpath+1;
335 args.gqa_uid = uid;
337 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
339 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
340 ret = False;
341 goto out;
344 clnt->cl_auth = authunix_create_default();
345 DEBUG(9,("nfs_quotas: auth_success\n"));
347 clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, xdr_getquota_args, (caddr_t)&args, xdr_getquota_rslt, (caddr_t)&gqr, timeout);
349 if (clnt_stat != RPC_SUCCESS) {
350 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
351 ret = False;
352 goto out;
356 * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
357 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
358 * something sensible.
361 switch ( quotastat ) {
362 case 0:
363 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat ));
364 ret = False;
365 goto out;
367 case 1:
368 DEBUG(9,("nfs_quotas: Good quota data\n"));
369 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
370 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
371 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
372 break;
374 case 2:
375 case 3:
376 D.dqb_bsoftlimit = 1;
377 D.dqb_curblocks = 1;
378 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
379 break;
381 default:
382 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat ));
383 break;
386 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",
387 quotastat,
388 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
389 gqr.getquota_rslt_u.gqr_rquota.rq_active,
390 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
391 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
392 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
394 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
395 *dsize = D.dqb_bsoftlimit;
397 if (D.dqb_curblocks == D.dqb_curblocks == 1)
398 *bsize = 512;
400 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
401 *dfree = 0;
402 *dsize = D.dqb_curblocks;
403 } else
404 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
406 out:
408 if (clnt) {
409 if (clnt->cl_auth)
410 auth_destroy(clnt->cl_auth);
411 clnt_destroy(clnt);
414 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
416 SAFE_FREE(cutstr);
417 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
418 return ret;
420 #endif
422 /****************************************************************************
423 try to get the disk space from disk quotas (SunOS & Solaris2 version)
424 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
425 ****************************************************************************/
427 BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
429 uid_t euser_id;
430 int ret;
431 struct dqblk D;
432 #if defined(SUNOS5)
433 struct quotctl command;
434 int file;
435 static struct mnttab mnt;
436 static pstring name;
437 pstring devopt;
438 #else /* SunOS4 */
439 struct mntent *mnt;
440 static pstring name;
441 #endif
442 FILE *fd;
443 SMB_STRUCT_STAT sbuf;
444 SMB_DEV_T devno ;
445 static SMB_DEV_T devno_cached = 0 ;
446 static int found ;
448 euser_id = geteuid();
450 if ( sys_stat(path,&sbuf) == -1 )
451 return(False) ;
453 devno = sbuf.st_dev ;
454 DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n", path,(unsigned int)devno));
455 if ( devno != devno_cached ) {
456 devno_cached = devno ;
457 #if defined(SUNOS5)
458 if ((fd = sys_fopen(MNTTAB, "r")) == NULL)
459 return(False) ;
461 found = False ;
462 slprintf(devopt, sizeof(devopt) - 1, "dev=%x", (unsigned int)devno);
463 while (getmntent(fd, &mnt) == 0) {
464 if( !hasmntopt(&mnt, devopt) )
465 continue;
467 DEBUG(5,("disk_quotas: testing \"%s\" %s\n", mnt.mnt_mountp,devopt));
469 /* quotas are only on vxfs, UFS or NFS */
470 if ( strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
471 strcmp( mnt.mnt_fstype, "nfs" ) == 0 ||
472 strcmp( mnt.mnt_fstype, "vxfs" ) == 0 ) {
473 found = True ;
474 break;
478 pstrcpy(name,mnt.mnt_mountp) ;
479 pstrcat(name,"/quotas") ;
480 fclose(fd) ;
481 #else /* SunOS4 */
482 if ((fd = setmntent(MOUNTED, "r")) == NULL)
483 return(False) ;
485 found = False ;
486 while ((mnt = getmntent(fd)) != NULL) {
487 if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
488 continue ;
489 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n", mnt->mnt_dir,(unsigned int)sbuf.st_dev));
490 if (sbuf.st_dev == devno) {
491 found = True ;
492 break;
496 pstrcpy(name,mnt->mnt_fsname) ;
497 endmntent(fd) ;
498 #endif
501 if ( ! found )
502 return(False) ;
504 save_re_uid();
505 set_effective_uid(0);
507 #if defined(SUNOS5)
508 if ( strcmp( mnt.mnt_fstype, "nfs" ) == 0) {
509 BOOL retval;
510 DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n", mnt.mnt_special));
511 retval = nfs_quotas(mnt.mnt_special, euser_id, bsize, dfree, dsize);
512 restore_re_uid();
513 return retval;
516 DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
517 if((file=sys_open(name, O_RDONLY,0))<0) {
518 restore_re_uid();
519 return(False);
521 command.op = Q_GETQUOTA;
522 command.uid = euser_id;
523 command.addr = (caddr_t) &D;
524 ret = ioctl(file, Q_QUOTACTL, &command);
525 close(file);
526 #else
527 DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
528 ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
529 #endif
531 restore_re_uid();
533 if (ret < 0) {
534 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n", strerror(errno) ));
536 #if defined(SUNOS5) && defined(VXFS_QUOTA)
537 /* If normal quotactl() fails, try vxfs private calls */
538 set_effective_uid(euser_id);
539 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype));
540 if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) {
541 BOOL retval;
542 retval = disk_quotas_vxfs(name, path, bsize, dfree, dsize);
543 return(retval);
545 #else
546 return(False);
547 #endif
550 /* If softlimit is zero, set it equal to hardlimit.
553 if (D.dqb_bsoftlimit==0)
554 D.dqb_bsoftlimit = D.dqb_bhardlimit;
556 /* Use softlimit to determine disk space. A user exceeding the quota is told
557 * that there's no space left. Writes might actually work for a bit if the
558 * hardlimit is set higher than softlimit. Effectively the disk becomes
559 * made of rubber latex and begins to expand to accommodate the user :-)
562 if (D.dqb_bsoftlimit==0)
563 return(False);
564 *bsize = DEV_BSIZE;
565 *dsize = D.dqb_bsoftlimit;
567 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
568 *dfree = 0;
569 *dsize = D.dqb_curblocks;
570 } else
571 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
573 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
574 path,(double)*bsize,(double)*dfree,(double)*dsize));
576 return(True);
580 #elif defined(OSF1)
581 #include <ufs/quota.h>
583 /****************************************************************************
584 try to get the disk space from disk quotas - OSF1 version
585 ****************************************************************************/
587 BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
589 int r, save_errno;
590 struct dqblk D;
591 SMB_STRUCT_STAT S;
592 uid_t euser_id;
595 * This code presumes that OSF1 will only
596 * give out quota info when the real uid
597 * matches the effective uid. JRA.
599 euser_id = geteuid();
600 save_re_uid();
601 if (set_re_uid() != 0) return False;
603 r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
604 if (r) {
605 save_errno = errno;
608 restore_re_uid();
610 *bsize = DEV_BSIZE;
612 if (r)
614 if (save_errno == EDQUOT) /* disk quota exceeded */
616 *dfree = 0;
617 *dsize = D.dqb_curblocks;
618 return (True);
620 else
621 return (False);
624 /* If softlimit is zero, set it equal to hardlimit.
627 if (D.dqb_bsoftlimit==0)
628 D.dqb_bsoftlimit = D.dqb_bhardlimit;
630 /* Use softlimit to determine disk space, except when it has been exceeded */
632 if (D.dqb_bsoftlimit==0)
633 return(False);
635 if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
636 *dfree = 0;
637 *dsize = D.dqb_curblocks;
638 } else {
639 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
640 *dsize = D.dqb_bsoftlimit;
642 return (True);
645 #elif defined (IRIX6)
646 /****************************************************************************
647 try to get the disk space from disk quotas (IRIX 6.2 version)
648 ****************************************************************************/
650 #include <sys/quota.h>
651 #include <mntent.h>
653 BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
655 uid_t euser_id;
656 int r;
657 struct dqblk D;
658 struct fs_disk_quota F;
659 SMB_STRUCT_STAT S;
660 FILE *fp;
661 struct mntent *mnt;
662 SMB_DEV_T devno;
663 int found;
665 /* find the block device file */
667 if ( sys_stat(path, &S) == -1 ) {
668 return(False) ;
671 devno = S.st_dev ;
673 fp = setmntent(MOUNTED,"r");
674 found = False ;
676 while ((mnt = getmntent(fp))) {
677 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
678 continue ;
679 if (S.st_dev == devno) {
680 found = True ;
681 break ;
684 endmntent(fp) ;
686 if (!found) {
687 return(False);
690 euser_id=geteuid();
691 save_re_uid();
692 set_effective_uid(0);
694 /* Use softlimit to determine disk space, except when it has been exceeded */
696 *bsize = 512;
698 if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
700 r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
702 restore_re_uid();
704 if (r==-1)
705 return(False);
707 /* Use softlimit to determine disk space, except when it has been exceeded */
708 if (
709 (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
710 (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
711 (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
712 (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
715 *dfree = 0;
716 *dsize = D.dqb_curblocks;
718 else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
720 return(False);
722 else
724 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
725 *dsize = D.dqb_bsoftlimit;
729 else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
731 r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
733 restore_re_uid();
735 if (r==-1)
736 return(False);
738 /* Use softlimit to determine disk space, except when it has been exceeded */
739 if (
740 (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
741 (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
742 (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
743 (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
746 *dfree = 0;
747 *dsize = F.d_bcount;
749 else if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
751 return(False);
753 else
755 *dfree = (F.d_blk_softlimit - F.d_bcount);
756 *dsize = F.d_blk_softlimit;
760 else
762 restore_re_uid();
763 return(False);
766 return (True);
770 #else
772 #if defined(__FreeBSD__) || defined(__OpenBSD__)
773 #include <ufs/ufs/quota.h>
774 #include <machine/param.h>
775 #elif AIX
776 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
777 #include <jfs/quota.h>
778 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
779 #define dqb_curfiles dqb_curinodes
780 #define dqb_fhardlimit dqb_ihardlimit
781 #define dqb_fsoftlimit dqb_isoftlimit
782 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
783 #include <sys/quota.h>
784 #include <devnm.h>
785 #endif
787 /****************************************************************************
788 try to get the disk space from disk quotas - default version
789 ****************************************************************************/
791 BOOL disk_quotas(char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
793 int r;
794 struct dqblk D;
795 uid_t euser_id;
796 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__)
797 char dev_disk[256];
798 SMB_STRUCT_STAT S;
799 /* find the block device file */
800 if ((sys_stat(path, &S)<0) ||
801 (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0)) return (False);
802 #endif
804 euser_id = geteuid();
806 #ifdef HPUX
807 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
808 save_re_uid();
809 if (set_re_uid() != 0) return False;
811 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
813 restore_re_uid();
814 #else
815 #if defined(__FreeBSD__) || defined(__OpenBSD__)
817 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
818 gid_t egrp_id;
820 save_re_uid();
821 set_effective_uid(0);
823 egrp_id = getegid();
824 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
826 /* As FreeBSD has group quotas, if getting the user
827 quota fails, try getting the group instead. */
828 if (r) {
829 r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
832 restore_re_uid();
834 #elif defined(AIX)
835 /* AIX has both USER and GROUP quotas:
836 Get the USER quota (ohnielse@fysik.dtu.dk) */
837 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
838 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
839 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
840 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
841 #endif /* HPUX */
843 /* Use softlimit to determine disk space, except when it has been exceeded */
844 #if defined(__FreeBSD__) || defined(__OpenBSD__)
845 *bsize = DEV_BSIZE;
846 #else /* !__FreeBSD__ && !__OpenBSD__ */
847 *bsize = 1024;
848 #endif /*!__FreeBSD__ && !__OpenBSD__ */
850 if (r)
852 if (errno == EDQUOT)
854 *dfree =0;
855 *dsize =D.dqb_curblocks;
856 return (True);
858 else return(False);
861 /* If softlimit is zero, set it equal to hardlimit.
864 if (D.dqb_bsoftlimit==0)
865 D.dqb_bsoftlimit = D.dqb_bhardlimit;
867 if (D.dqb_bsoftlimit==0)
868 return(False);
869 /* Use softlimit to determine disk space, except when it has been exceeded */
870 if ((D.dqb_curblocks>D.dqb_bsoftlimit)
871 #if !defined(__FreeBSD__) && !defined(__OpenBSD__)
872 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
873 #endif
875 *dfree = 0;
876 *dsize = D.dqb_curblocks;
878 else {
879 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
880 *dsize = D.dqb_bsoftlimit;
882 return (True);
885 #endif
887 #if defined(VXFS_QUOTA)
889 /****************************************************************************
890 Try to get the disk space from Veritas disk quotas.
891 David Lee <T.D.Lee@durham.ac.uk> August 1999.
893 Background assumptions:
894 Potentially under many Operating Systems. Initially Solaris 2.
896 My guess is that Veritas is largely, though not entirely,
897 independent of OS. So I have separated it out.
899 There may be some details. For example, OS-specific "include" files.
901 It is understood that HPUX 10 somehow gets Veritas quotas without
902 any special effort; if so, this routine need not be compiled in.
903 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
905 Warning:
906 It is understood that Veritas do not publicly support this ioctl interface.
907 Rather their preference would be for the user (us) to call the native
908 OS and then for the OS itself to call through to the VxFS filesystem.
909 Presumably HPUX 10, see above, does this.
911 Hints for porting:
912 Add your OS to "IFLIST" below.
913 Get it to compile successfully:
914 Almost certainly "include"s require attention: see SUNOS5.
915 In the main code above, arrange for it to be called: see SUNOS5.
916 Test!
918 ****************************************************************************/
920 /* "IFLIST"
921 * This "if" is a list of ports:
922 * if defined(OS1) || defined(OS2) || ...
924 #if defined(SUNOS5)
926 #if defined(SUNOS5)
927 #include <sys/fs/vx_solaris.h>
928 #endif
929 #include <sys/fs/vx_machdep.h>
930 #include <sys/fs/vx_layout.h>
931 #include <sys/fs/vx_quota.h>
932 #include <sys/fs/vx_aioctl.h>
933 #include <sys/fs/vx_ioctl.h>
935 BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
937 uid_t user_id, euser_id;
938 int ret;
939 struct vx_dqblk D;
940 struct vx_quotctl quotabuf;
941 struct vx_genioctl genbuf;
942 pstring qfname;
943 int file;
946 * "name" may or may not include a trailing "/quotas".
947 * Arranging consistency of calling here in "quotas.c" may not be easy and
948 * it might be easier to examine and adjust it here.
949 * Fortunately, VxFS seems not to mind at present.
951 pstrcpy(qfname, name) ;
952 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
954 euser_id = geteuid();
955 set_effective_uid(0);
957 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
958 if((file=sys_open(qfname, O_RDONLY,0))<0) {
959 set_effective_uid(euser_id);
960 return(False);
962 genbuf.ioc_cmd = VX_QUOTACTL;
963 genbuf.ioc_up = (void *) &quotabuf;
965 quotabuf.cmd = VX_GETQUOTA;
966 quotabuf.uid = euser_id;
967 quotabuf.addr = (caddr_t) &D;
968 ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
969 close(file);
971 set_effective_uid(euser_id);
973 if (ret < 0) {
974 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
975 return(False);
978 /* If softlimit is zero, set it equal to hardlimit.
981 if (D.dqb_bsoftlimit==0)
982 D.dqb_bsoftlimit = D.dqb_bhardlimit;
984 /* Use softlimit to determine disk space. A user exceeding the quota is told
985 * that there's no space left. Writes might actually work for a bit if the
986 * hardlimit is set higher than softlimit. Effectively the disk becomes
987 * made of rubber latex and begins to expand to accommodate the user :-)
989 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
990 path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
991 D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
993 if (D.dqb_bsoftlimit==0)
994 return(False);
995 *bsize = DEV_BSIZE;
996 *dsize = D.dqb_bsoftlimit;
998 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
999 *dfree = 0;
1000 *dsize = D.dqb_curblocks;
1001 } else
1002 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1004 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
1005 path,(double)*bsize,(double)*dfree,(double)*dsize));
1007 return(True);
1010 #endif /* SUNOS5 || ... */
1012 #endif /* VXFS_QUOTA */