oops. Use -r, not -f
[Samba.git] / source / smbd / quotas.c
blob4cfa05b1997afe808952f5bf30e68b2843f33420
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;
911 /* find the block device file */
912 if ((sys_stat(path, &S)<0) ||
913 (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0)) return (False);
914 #endif
916 euser_id = geteuid();
918 #ifdef HPUX
919 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
920 save_re_uid();
921 if (set_re_uid() != 0) return False;
923 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
925 restore_re_uid();
926 #else
927 #if defined(__FreeBSD__) || defined(__OpenBSD__)
929 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
930 gid_t egrp_id;
932 save_re_uid();
933 set_effective_uid(0);
935 egrp_id = getegid();
936 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
938 /* As FreeBSD has group quotas, if getting the user
939 quota fails, try getting the group instead. */
940 if (r) {
941 r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
944 restore_re_uid();
946 #elif defined(AIX)
947 /* AIX has both USER and GROUP quotas:
948 Get the USER quota (ohnielse@fysik.dtu.dk) */
949 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
950 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
951 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
952 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
953 #endif /* HPUX */
955 /* Use softlimit to determine disk space, except when it has been exceeded */
956 #if defined(__FreeBSD__) || defined(__OpenBSD__)
957 *bsize = DEV_BSIZE;
958 #else /* !__FreeBSD__ && !__OpenBSD__ */
959 *bsize = 1024;
960 #endif /*!__FreeBSD__ && !__OpenBSD__ */
962 if (r)
964 if (errno == EDQUOT)
966 *dfree =0;
967 *dsize =D.dqb_curblocks;
968 return (True);
970 else return(False);
973 /* If softlimit is zero, set it equal to hardlimit.
976 if (D.dqb_bsoftlimit==0)
977 D.dqb_bsoftlimit = D.dqb_bhardlimit;
979 if (D.dqb_bsoftlimit==0)
980 return(False);
981 /* Use softlimit to determine disk space, except when it has been exceeded */
982 if ((D.dqb_curblocks>D.dqb_bsoftlimit)
983 #if !defined(__FreeBSD__) && !defined(__OpenBSD__)
984 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
985 #endif
987 *dfree = 0;
988 *dsize = D.dqb_curblocks;
990 else {
991 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
992 *dsize = D.dqb_bsoftlimit;
994 return (True);
997 #endif
999 #if defined(VXFS_QUOTA)
1001 /****************************************************************************
1002 Try to get the disk space from Veritas disk quotas.
1003 David Lee <T.D.Lee@durham.ac.uk> August 1999.
1005 Background assumptions:
1006 Potentially under many Operating Systems. Initially Solaris 2.
1008 My guess is that Veritas is largely, though not entirely,
1009 independent of OS. So I have separated it out.
1011 There may be some details. For example, OS-specific "include" files.
1013 It is understood that HPUX 10 somehow gets Veritas quotas without
1014 any special effort; if so, this routine need not be compiled in.
1015 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1017 Warning:
1018 It is understood that Veritas do not publicly support this ioctl interface.
1019 Rather their preference would be for the user (us) to call the native
1020 OS and then for the OS itself to call through to the VxFS filesystem.
1021 Presumably HPUX 10, see above, does this.
1023 Hints for porting:
1024 Add your OS to "IFLIST" below.
1025 Get it to compile successfully:
1026 Almost certainly "include"s require attention: see SUNOS5.
1027 In the main code above, arrange for it to be called: see SUNOS5.
1028 Test!
1030 ****************************************************************************/
1032 /* "IFLIST"
1033 * This "if" is a list of ports:
1034 * if defined(OS1) || defined(OS2) || ...
1036 #if defined(SUNOS5)
1038 #if defined(SUNOS5)
1039 #include <sys/fs/vx_solaris.h>
1040 #endif
1041 #include <sys/fs/vx_machdep.h>
1042 #include <sys/fs/vx_layout.h>
1043 #include <sys/fs/vx_quota.h>
1044 #include <sys/fs/vx_aioctl.h>
1045 #include <sys/fs/vx_ioctl.h>
1047 BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
1049 uid_t user_id, euser_id;
1050 int ret;
1051 struct vx_dqblk D;
1052 struct vx_quotctl quotabuf;
1053 struct vx_genioctl genbuf;
1054 pstring qfname;
1055 int file;
1058 * "name" may or may not include a trailing "/quotas".
1059 * Arranging consistency of calling here in "quotas.c" may not be easy and
1060 * it might be easier to examine and adjust it here.
1061 * Fortunately, VxFS seems not to mind at present.
1063 pstrcpy(qfname, name) ;
1064 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
1066 euser_id = geteuid();
1067 set_effective_uid(0);
1069 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
1070 if((file=sys_open(qfname, O_RDONLY,0))<0) {
1071 set_effective_uid(euser_id);
1072 return(False);
1074 genbuf.ioc_cmd = VX_QUOTACTL;
1075 genbuf.ioc_up = (void *) &quotabuf;
1077 quotabuf.cmd = VX_GETQUOTA;
1078 quotabuf.uid = euser_id;
1079 quotabuf.addr = (caddr_t) &D;
1080 ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
1081 close(file);
1083 set_effective_uid(euser_id);
1085 if (ret < 0) {
1086 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
1087 return(False);
1090 /* If softlimit is zero, set it equal to hardlimit.
1093 if (D.dqb_bsoftlimit==0)
1094 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1096 /* Use softlimit to determine disk space. A user exceeding the quota is told
1097 * that there's no space left. Writes might actually work for a bit if the
1098 * hardlimit is set higher than softlimit. Effectively the disk becomes
1099 * made of rubber latex and begins to expand to accommodate the user :-)
1101 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1102 path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
1103 D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
1105 if (D.dqb_bsoftlimit==0)
1106 return(False);
1107 *bsize = DEV_BSIZE;
1108 *dsize = D.dqb_bsoftlimit;
1110 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1111 *dfree = 0;
1112 *dsize = D.dqb_curblocks;
1113 } else
1114 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1116 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
1117 path,(double)*bsize,(double)*dfree,(double)*dsize));
1119 return(True);
1122 #endif /* SUNOS5 || ... */
1124 #endif /* VXFS_QUOTA */