Minor comment updates ...
[Samba/gebeck_regimport.git] / source3 / smbd / quotas.c
blob91c952aa902bb684b6c9ae08fb2d74db09321eb3
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 #ifndef HAVE_SYS_QUOTAS
32 /* just a quick hack because sysquotas.h is included before linux/quota.h */
33 #ifdef QUOTABLOCK_SIZE
34 #undef QUOTABLOCK_SIZE
35 #endif
37 #ifdef WITH_QUOTAS
39 #if defined(VXFS_QUOTA)
42 * In addition to their native filesystems, some systems have Veritas VxFS.
43 * Declare here, define at end: reduces likely "include" interaction problems.
44 * David Lee <T.D.Lee@durham.ac.uk>
46 BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize);
48 #endif /* VXFS_QUOTA */
50 #ifdef LINUX
52 #include <sys/types.h>
53 #include <asm/types.h>
56 * This shouldn't be neccessary - it should be /usr/include/sys/quota.h
57 * Unfortunately, RH7.1 ships with a different quota system using struct mem_dqblk
58 * rather than the struct dqblk defined in /usr/include/sys/quota.h.
59 * This means we must include linux/quota.h to have a hope of working on
60 * RH7.1 systems. And it also means this breaks if the kernel is upgraded
61 * to a Linus 2.4.x (where x > the minor number shipped with RH7.1) until
62 * Linus synchronises with the AC patches. Sometimes I *hate* Linux :-). JRA.
65 #include <linux/quota.h>
66 #ifdef HAVE_LINUX_XQM_H
67 #include <linux/xqm.h>
68 #else
69 #ifdef HAVE_XFS_XQM_H
70 #include <xfs/xqm.h>
71 #define HAVE_LINUX_XQM_H
72 #endif
73 #endif
75 #include <mntent.h>
76 #include <linux/unistd.h>
79 #define LINUX_QUOTAS_2
81 typedef struct _LINUX_SMB_DISK_QUOTA {
82 SMB_BIG_UINT bsize;
83 SMB_BIG_UINT hardlimit; /* In bsize units. */
84 SMB_BIG_UINT softlimit; /* In bsize units. */
85 SMB_BIG_UINT curblocks; /* In bsize units. */
86 SMB_BIG_UINT ihardlimit; /* inode hard limit. */
87 SMB_BIG_UINT isoftlimit; /* inode soft limit. */
88 SMB_BIG_UINT curinodes; /* Current used inodes. */
89 } LINUX_SMB_DISK_QUOTA;
91 /****************************************************************************
92 Abstract out the XFS Quota Manager quota get call.
93 ****************************************************************************/
95 static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA *dp)
97 int ret = -1;
98 #ifdef HAVE_LINUX_XQM_H
99 struct fs_disk_quota D;
100 ZERO_STRUCT(D);
102 if ((ret = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D)))
103 return ret;
105 dp->bsize = (SMB_BIG_UINT)512;
106 dp->softlimit = (SMB_BIG_UINT)D.d_blk_softlimit;
107 dp->hardlimit = (SMB_BIG_UINT)D.d_blk_hardlimit;
108 dp->ihardlimit = (SMB_BIG_UINT)D.d_ino_hardlimit;
109 dp->isoftlimit = (SMB_BIG_UINT)D.d_ino_softlimit;
110 dp->curinodes = (SMB_BIG_UINT)D.d_icount;
111 dp->curblocks = (SMB_BIG_UINT)D.d_bcount;
112 #endif
113 return ret;
116 /****************************************************************************
117 Abstract out the old and new Linux quota get calls.
118 ****************************************************************************/
120 static int get_smb_linux_vfs_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA *dp)
122 int ret;
123 #ifdef LINUX_QUOTAS_1
124 struct dqblk D;
125 ZERO_STRUCT(D);
126 dp->bsize = (SMB_BIG_UINT)1024;
127 #else /* LINUX_QUOTAS_2 */
128 struct mem_dqblk D;
129 ZERO_STRUCT(D);
130 #ifndef QUOTABLOCK_SIZE
131 #define QUOTABLOCK_SIZE 1024
132 #endif
133 dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
134 #endif
136 if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D)))
137 return -1;
139 dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
140 dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
141 dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
142 dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
143 dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
145 #ifdef LINUX_QUOTAS_1
146 dp->curblocks = (SMB_BIG_UINT)D.dqb_curblocks;
147 #else /* LINUX_QUOTAS_2 */
148 dp->curblocks = ((SMB_BIG_UINT)D.dqb_curspace)/ dp->bsize;
149 #endif
151 return 0;
154 /****************************************************************************
155 try to get the disk space from disk quotas (LINUX version)
156 ****************************************************************************/
158 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
160 int r;
161 SMB_STRUCT_STAT S;
162 FILE *fp;
163 LINUX_SMB_DISK_QUOTA D;
164 struct mntent *mnt;
165 SMB_DEV_T devno;
166 int found;
167 uid_t euser_id;
169 euser_id = geteuid();
171 /* find the block device file */
173 if ( sys_stat(path, &S) == -1 )
174 return(False) ;
176 devno = S.st_dev ;
178 fp = setmntent(MOUNTED,"r");
179 found = False ;
181 while ((mnt = getmntent(fp))) {
182 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
183 continue ;
185 if (S.st_dev == devno) {
186 found = True ;
187 break;
191 endmntent(fp) ;
193 if (!found)
194 return(False);
196 save_re_uid();
197 set_effective_uid(0);
198 if (strcmp(mnt->mnt_type, "xfs") == 0)
199 r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, &D);
200 else
201 r=get_smb_linux_vfs_quota(mnt->mnt_fsname, euser_id, &D);
202 restore_re_uid();
204 /* Use softlimit to determine disk space, except when it has been exceeded */
205 *bsize = D.bsize;
206 if (r == -1) {
207 if (errno == EDQUOT) {
208 *dfree =0;
209 *dsize =D.curblocks;
210 return (True);
211 } else {
212 return(False);
216 /* Use softlimit to determine disk space, except when it has been exceeded */
217 if (
218 (D.softlimit && D.curblocks >= D.softlimit) ||
219 (D.hardlimit && D.curblocks >= D.hardlimit) ||
220 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
221 (D.ihardlimit && D.curinodes>=D.ihardlimit)
223 *dfree = 0;
224 *dsize = D.curblocks;
225 } else if (D.softlimit==0 && D.hardlimit==0) {
226 return(False);
227 } else {
228 if (D.softlimit == 0)
229 D.softlimit = D.hardlimit;
230 *dfree = D.softlimit - D.curblocks;
231 *dsize = D.softlimit;
234 return (True);
237 #elif defined(CRAY)
239 #include <sys/quota.h>
240 #include <mntent.h>
242 /****************************************************************************
243 try to get the disk space from disk quotas (CRAY VERSION)
244 ****************************************************************************/
246 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
248 struct mntent *mnt;
249 FILE *fd;
250 SMB_STRUCT_STAT sbuf;
251 SMB_DEV_T devno ;
252 static SMB_DEV_T devno_cached = 0 ;
253 static pstring name;
254 struct q_request request ;
255 struct qf_header header ;
256 static int quota_default = 0 ;
257 int found ;
259 if ( sys_stat(path,&sbuf) == -1 )
260 return(False) ;
262 devno = sbuf.st_dev ;
264 if ( devno != devno_cached ) {
266 devno_cached = devno ;
268 if ((fd = setmntent(KMTAB)) == NULL)
269 return(False) ;
271 found = False ;
273 while ((mnt = getmntent(fd)) != NULL) {
275 if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
276 continue ;
278 if (sbuf.st_dev == devno) {
280 found = True ;
281 break ;
287 pstrcpy(name,mnt->mnt_dir) ;
288 endmntent(fd) ;
290 if ( ! found )
291 return(False) ;
294 request.qf_magic = QF_MAGIC ;
295 request.qf_entry.id = geteuid() ;
297 if (quotactl(name, Q_GETQUOTA, &request) == -1)
298 return(False) ;
300 if ( ! request.user )
301 return(False) ;
303 if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) {
305 if ( ! quota_default ) {
307 if ( quotactl(name, Q_GETHEADER, &header) == -1 )
308 return(False) ;
309 else
310 quota_default = header.user_h.def_fq ;
313 *dfree = quota_default ;
315 }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) {
317 *dfree = 0 ;
319 }else{
321 *dfree = request.qf_entry.user_q.f_quota ;
325 *dsize = request.qf_entry.user_q.f_use ;
327 if ( *dfree < *dsize )
328 *dfree = 0 ;
329 else
330 *dfree -= *dsize ;
332 *bsize = 4096 ; /* Cray blocksize */
334 return(True) ;
339 #elif defined(SUNOS5) || defined(SUNOS4)
341 #include <fcntl.h>
342 #include <sys/param.h>
343 #if defined(SUNOS5)
344 #include <sys/fs/ufs_quota.h>
345 #include <sys/mnttab.h>
346 #include <sys/mntent.h>
347 #else /* defined(SUNOS4) */
348 #include <ufs/quota.h>
349 #include <mntent.h>
350 #endif
352 #if defined(SUNOS5)
354 /****************************************************************************
355 Allows querying of remote hosts for quotas on NFS mounted shares.
356 Supports normal NFS and AMD mounts.
357 Alan Romeril <a.romeril@ic.ac.uk> July 2K.
358 ****************************************************************************/
360 #include <rpc/rpc.h>
361 #include <rpc/types.h>
362 #include <rpcsvc/rquota.h>
363 #include <rpc/nettype.h>
364 #include <rpc/xdr.h>
366 static int quotastat;
368 static int xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
370 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
371 return(0);
372 if (!xdr_int(xdrsp, &args->gqa_uid))
373 return(0);
374 return (1);
377 static int xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
379 if (!xdr_int(xdrsp, &quotastat)) {
380 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
381 return 0;
383 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
384 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
385 return 0;
387 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
388 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
389 return 0;
391 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
392 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
393 return 0;
395 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
396 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
397 return 0;
399 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
400 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
401 return 0;
403 return (1);
406 /* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
407 static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
409 uid_t uid = euser_id;
410 struct dqblk D;
411 char *mnttype = nfspath;
412 CLIENT *clnt;
413 struct getquota_rslt gqr;
414 struct getquota_args args;
415 char *cutstr, *pathname, *host, *testpath;
416 int len;
417 static struct timeval timeout = {2,0};
418 enum clnt_stat clnt_stat;
419 BOOL ret = True;
421 *bsize = *dfree = *dsize = (SMB_BIG_UINT)0;
423 len=strcspn(mnttype, ":");
424 pathname=strstr(mnttype, ":");
425 cutstr = (char *) malloc(len+1);
426 if (!cutstr)
427 return False;
429 memset(cutstr, '\0', len+1);
430 host = strncat(cutstr,mnttype, sizeof(char) * len );
431 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
432 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
433 testpath=strchr_m(mnttype, ':');
434 args.gqa_pathp = testpath+1;
435 args.gqa_uid = uid;
437 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
439 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
440 ret = False;
441 goto out;
444 clnt->cl_auth = authunix_create_default();
445 DEBUG(9,("nfs_quotas: auth_success\n"));
447 clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, xdr_getquota_args, (caddr_t)&args, xdr_getquota_rslt, (caddr_t)&gqr, timeout);
449 if (clnt_stat != RPC_SUCCESS) {
450 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
451 ret = False;
452 goto out;
456 * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
457 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
458 * something sensible.
461 switch ( quotastat ) {
462 case 0:
463 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat ));
464 ret = False;
465 goto out;
467 case 1:
468 DEBUG(9,("nfs_quotas: Good quota data\n"));
469 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
470 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
471 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
472 break;
474 case 2:
475 case 3:
476 D.dqb_bsoftlimit = 1;
477 D.dqb_curblocks = 1;
478 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
479 break;
481 default:
482 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat ));
483 break;
486 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",
487 quotastat,
488 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
489 gqr.getquota_rslt_u.gqr_rquota.rq_active,
490 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
491 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
492 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
494 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
495 *dsize = D.dqb_bsoftlimit;
497 if (D.dqb_curblocks == D.dqb_curblocks == 1)
498 *bsize = 512;
500 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
501 *dfree = 0;
502 *dsize = D.dqb_curblocks;
503 } else
504 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
506 out:
508 if (clnt) {
509 if (clnt->cl_auth)
510 auth_destroy(clnt->cl_auth);
511 clnt_destroy(clnt);
514 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
516 SAFE_FREE(cutstr);
517 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
518 return ret;
520 #endif
522 /****************************************************************************
523 try to get the disk space from disk quotas (SunOS & Solaris2 version)
524 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
525 ****************************************************************************/
527 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
529 uid_t euser_id;
530 int ret;
531 struct dqblk D;
532 #if defined(SUNOS5)
533 struct quotctl command;
534 int file;
535 static struct mnttab mnt;
536 static pstring name;
537 pstring devopt;
538 #else /* SunOS4 */
539 struct mntent *mnt;
540 static pstring name;
541 #endif
542 FILE *fd;
543 SMB_STRUCT_STAT sbuf;
544 SMB_DEV_T devno ;
545 static SMB_DEV_T devno_cached = 0 ;
546 static int found ;
548 euser_id = geteuid();
550 if ( sys_stat(path,&sbuf) == -1 )
551 return(False) ;
553 devno = sbuf.st_dev ;
554 DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n", path,(unsigned int)devno));
555 if ( devno != devno_cached ) {
556 devno_cached = devno ;
557 #if defined(SUNOS5)
558 if ((fd = sys_fopen(MNTTAB, "r")) == NULL)
559 return(False) ;
561 found = False ;
562 slprintf(devopt, sizeof(devopt) - 1, "dev=%x", (unsigned int)devno);
563 while (getmntent(fd, &mnt) == 0) {
564 if( !hasmntopt(&mnt, devopt) )
565 continue;
567 DEBUG(5,("disk_quotas: testing \"%s\" %s\n", mnt.mnt_mountp,devopt));
569 /* quotas are only on vxfs, UFS or NFS */
570 if ( strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
571 strcmp( mnt.mnt_fstype, "nfs" ) == 0 ||
572 strcmp( mnt.mnt_fstype, "vxfs" ) == 0 ) {
573 found = True ;
574 break;
578 pstrcpy(name,mnt.mnt_mountp) ;
579 pstrcat(name,"/quotas") ;
580 fclose(fd) ;
581 #else /* SunOS4 */
582 if ((fd = setmntent(MOUNTED, "r")) == NULL)
583 return(False) ;
585 found = False ;
586 while ((mnt = getmntent(fd)) != NULL) {
587 if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
588 continue ;
589 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n", mnt->mnt_dir,(unsigned int)sbuf.st_dev));
590 if (sbuf.st_dev == devno) {
591 found = True ;
592 break;
596 pstrcpy(name,mnt->mnt_fsname) ;
597 endmntent(fd) ;
598 #endif
601 if ( ! found )
602 return(False) ;
604 save_re_uid();
605 set_effective_uid(0);
607 #if defined(SUNOS5)
608 if ( strcmp( mnt.mnt_fstype, "nfs" ) == 0) {
609 BOOL retval;
610 DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n", mnt.mnt_special));
611 retval = nfs_quotas(mnt.mnt_special, euser_id, bsize, dfree, dsize);
612 restore_re_uid();
613 return retval;
616 DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
617 if((file=sys_open(name, O_RDONLY,0))<0) {
618 restore_re_uid();
619 return(False);
621 command.op = Q_GETQUOTA;
622 command.uid = euser_id;
623 command.addr = (caddr_t) &D;
624 ret = ioctl(file, Q_QUOTACTL, &command);
625 close(file);
626 #else
627 DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
628 ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
629 #endif
631 restore_re_uid();
633 if (ret < 0) {
634 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n", strerror(errno) ));
636 #if defined(SUNOS5) && defined(VXFS_QUOTA)
637 /* If normal quotactl() fails, try vxfs private calls */
638 set_effective_uid(euser_id);
639 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype));
640 if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) {
641 BOOL retval;
642 retval = disk_quotas_vxfs(name, path, bsize, dfree, dsize);
643 return(retval);
645 #else
646 return(False);
647 #endif
650 /* If softlimit is zero, set it equal to hardlimit.
653 if (D.dqb_bsoftlimit==0)
654 D.dqb_bsoftlimit = D.dqb_bhardlimit;
656 /* Use softlimit to determine disk space. A user exceeding the quota is told
657 * that there's no space left. Writes might actually work for a bit if the
658 * hardlimit is set higher than softlimit. Effectively the disk becomes
659 * made of rubber latex and begins to expand to accommodate the user :-)
662 if (D.dqb_bsoftlimit==0)
663 return(False);
664 *bsize = DEV_BSIZE;
665 *dsize = D.dqb_bsoftlimit;
667 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
668 *dfree = 0;
669 *dsize = D.dqb_curblocks;
670 } else
671 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
673 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
674 path,(double)*bsize,(double)*dfree,(double)*dsize));
676 return(True);
680 #elif defined(OSF1)
681 #include <ufs/quota.h>
683 /****************************************************************************
684 try to get the disk space from disk quotas - OSF1 version
685 ****************************************************************************/
687 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
689 int r, save_errno;
690 struct dqblk D;
691 SMB_STRUCT_STAT S;
692 uid_t euser_id;
695 * This code presumes that OSF1 will only
696 * give out quota info when the real uid
697 * matches the effective uid. JRA.
699 euser_id = geteuid();
700 save_re_uid();
701 if (set_re_uid() != 0) return False;
703 r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
704 if (r) {
705 save_errno = errno;
708 restore_re_uid();
710 *bsize = DEV_BSIZE;
712 if (r)
714 if (save_errno == EDQUOT) /* disk quota exceeded */
716 *dfree = 0;
717 *dsize = D.dqb_curblocks;
718 return (True);
720 else
721 return (False);
724 /* If softlimit is zero, set it equal to hardlimit.
727 if (D.dqb_bsoftlimit==0)
728 D.dqb_bsoftlimit = D.dqb_bhardlimit;
730 /* Use softlimit to determine disk space, except when it has been exceeded */
732 if (D.dqb_bsoftlimit==0)
733 return(False);
735 if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
736 *dfree = 0;
737 *dsize = D.dqb_curblocks;
738 } else {
739 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
740 *dsize = D.dqb_bsoftlimit;
742 return (True);
745 #elif defined (IRIX6)
746 /****************************************************************************
747 try to get the disk space from disk quotas (IRIX 6.2 version)
748 ****************************************************************************/
750 #include <sys/quota.h>
751 #include <mntent.h>
753 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
755 uid_t euser_id;
756 int r;
757 struct dqblk D;
758 struct fs_disk_quota F;
759 SMB_STRUCT_STAT S;
760 FILE *fp;
761 struct mntent *mnt;
762 SMB_DEV_T devno;
763 int found;
765 /* find the block device file */
767 if ( sys_stat(path, &S) == -1 ) {
768 return(False) ;
771 devno = S.st_dev ;
773 fp = setmntent(MOUNTED,"r");
774 found = False ;
776 while ((mnt = getmntent(fp))) {
777 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
778 continue ;
779 if (S.st_dev == devno) {
780 found = True ;
781 break ;
784 endmntent(fp) ;
786 if (!found) {
787 return(False);
790 euser_id=geteuid();
791 save_re_uid();
792 set_effective_uid(0);
794 /* Use softlimit to determine disk space, except when it has been exceeded */
796 *bsize = 512;
798 if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
800 r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
802 restore_re_uid();
804 if (r==-1)
805 return(False);
807 /* Use softlimit to determine disk space, except when it has been exceeded */
808 if (
809 (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
810 (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
811 (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
812 (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
815 *dfree = 0;
816 *dsize = D.dqb_curblocks;
818 else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
820 return(False);
822 else
824 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
825 *dsize = D.dqb_bsoftlimit;
829 else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
831 r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
833 restore_re_uid();
835 if (r==-1)
836 return(False);
838 /* Use softlimit to determine disk space, except when it has been exceeded */
839 if (
840 (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
841 (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
842 (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
843 (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
846 *dfree = 0;
847 *dsize = F.d_bcount;
849 else if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
851 return(False);
853 else
855 *dfree = (F.d_blk_softlimit - F.d_bcount);
856 *dsize = F.d_blk_softlimit;
860 else
862 restore_re_uid();
863 return(False);
866 return (True);
870 #else
872 #if defined(__FreeBSD__) || defined(__OpenBSD__)
873 #include <ufs/ufs/quota.h>
874 #include <machine/param.h>
875 #elif AIX
876 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
877 #include <jfs/quota.h>
878 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
879 #define dqb_curfiles dqb_curinodes
880 #define dqb_fhardlimit dqb_ihardlimit
881 #define dqb_fsoftlimit dqb_isoftlimit
882 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
883 #include <sys/quota.h>
884 #include <devnm.h>
885 #endif
887 /****************************************************************************
888 try to get the disk space from disk quotas - default version
889 ****************************************************************************/
891 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
893 int r;
894 struct dqblk D;
895 uid_t euser_id;
896 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__)
897 char dev_disk[256];
898 SMB_STRUCT_STAT S;
900 /* find the block device file */
902 #ifdef HPUX
903 /* Need to set the cache flag to 1 for HPUX. Seems
904 * to have a significant performance boost when
905 * lstat calls on /dev access this function.
907 if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 1)<0))
908 #else
909 if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0))
910 #endif /* ifdef HPUX */
911 return (False);
913 #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) */
915 euser_id = geteuid();
917 #ifdef HPUX
918 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
919 save_re_uid();
920 if (set_re_uid() != 0) return False;
922 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
924 restore_re_uid();
925 #else
926 #if defined(__FreeBSD__) || defined(__OpenBSD__)
928 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
929 gid_t egrp_id;
931 save_re_uid();
932 set_effective_uid(0);
934 egrp_id = getegid();
935 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
937 /* As FreeBSD has group quotas, if getting the user
938 quota fails, try getting the group instead. */
939 if (r) {
940 r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
943 restore_re_uid();
945 #elif defined(AIX)
946 /* AIX has both USER and GROUP quotas:
947 Get the USER quota (ohnielse@fysik.dtu.dk) */
948 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
949 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
950 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
951 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
952 #endif /* HPUX */
954 /* Use softlimit to determine disk space, except when it has been exceeded */
955 #if defined(__FreeBSD__) || defined(__OpenBSD__)
956 *bsize = DEV_BSIZE;
957 #else /* !__FreeBSD__ && !__OpenBSD__ */
958 *bsize = 1024;
959 #endif /*!__FreeBSD__ && !__OpenBSD__ */
961 if (r)
963 if (errno == EDQUOT)
965 *dfree =0;
966 *dsize =D.dqb_curblocks;
967 return (True);
969 else return(False);
972 /* If softlimit is zero, set it equal to hardlimit.
975 if (D.dqb_bsoftlimit==0)
976 D.dqb_bsoftlimit = D.dqb_bhardlimit;
978 if (D.dqb_bsoftlimit==0)
979 return(False);
980 /* Use softlimit to determine disk space, except when it has been exceeded */
981 if ((D.dqb_curblocks>D.dqb_bsoftlimit)
982 #if !defined(__FreeBSD__) && !defined(__OpenBSD__)
983 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
984 #endif
986 *dfree = 0;
987 *dsize = D.dqb_curblocks;
989 else {
990 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
991 *dsize = D.dqb_bsoftlimit;
993 return (True);
996 #endif
998 #if defined(VXFS_QUOTA)
1000 /****************************************************************************
1001 Try to get the disk space from Veritas disk quotas.
1002 David Lee <T.D.Lee@durham.ac.uk> August 1999.
1004 Background assumptions:
1005 Potentially under many Operating Systems. Initially Solaris 2.
1007 My guess is that Veritas is largely, though not entirely,
1008 independent of OS. So I have separated it out.
1010 There may be some details. For example, OS-specific "include" files.
1012 It is understood that HPUX 10 somehow gets Veritas quotas without
1013 any special effort; if so, this routine need not be compiled in.
1014 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1016 Warning:
1017 It is understood that Veritas do not publicly support this ioctl interface.
1018 Rather their preference would be for the user (us) to call the native
1019 OS and then for the OS itself to call through to the VxFS filesystem.
1020 Presumably HPUX 10, see above, does this.
1022 Hints for porting:
1023 Add your OS to "IFLIST" below.
1024 Get it to compile successfully:
1025 Almost certainly "include"s require attention: see SUNOS5.
1026 In the main code above, arrange for it to be called: see SUNOS5.
1027 Test!
1029 ****************************************************************************/
1031 /* "IFLIST"
1032 * This "if" is a list of ports:
1033 * if defined(OS1) || defined(OS2) || ...
1035 #if defined(SUNOS5)
1037 #if defined(SUNOS5)
1038 #include <sys/fs/vx_solaris.h>
1039 #endif
1040 #include <sys/fs/vx_machdep.h>
1041 #include <sys/fs/vx_layout.h>
1042 #include <sys/fs/vx_quota.h>
1043 #include <sys/fs/vx_aioctl.h>
1044 #include <sys/fs/vx_ioctl.h>
1046 BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
1048 uid_t user_id, euser_id;
1049 int ret;
1050 struct vx_dqblk D;
1051 struct vx_quotctl quotabuf;
1052 struct vx_genioctl genbuf;
1053 pstring qfname;
1054 int file;
1057 * "name" may or may not include a trailing "/quotas".
1058 * Arranging consistency of calling here in "quotas.c" may not be easy and
1059 * it might be easier to examine and adjust it here.
1060 * Fortunately, VxFS seems not to mind at present.
1062 pstrcpy(qfname, name) ;
1063 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
1065 euser_id = geteuid();
1066 set_effective_uid(0);
1068 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
1069 if((file=sys_open(qfname, O_RDONLY,0))<0) {
1070 set_effective_uid(euser_id);
1071 return(False);
1073 genbuf.ioc_cmd = VX_QUOTACTL;
1074 genbuf.ioc_up = (void *) &quotabuf;
1076 quotabuf.cmd = VX_GETQUOTA;
1077 quotabuf.uid = euser_id;
1078 quotabuf.addr = (caddr_t) &D;
1079 ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
1080 close(file);
1082 set_effective_uid(euser_id);
1084 if (ret < 0) {
1085 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
1086 return(False);
1089 /* If softlimit is zero, set it equal to hardlimit.
1092 if (D.dqb_bsoftlimit==0)
1093 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1095 /* Use softlimit to determine disk space. A user exceeding the quota is told
1096 * that there's no space left. Writes might actually work for a bit if the
1097 * hardlimit is set higher than softlimit. Effectively the disk becomes
1098 * made of rubber latex and begins to expand to accommodate the user :-)
1100 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1101 path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
1102 D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
1104 if (D.dqb_bsoftlimit==0)
1105 return(False);
1106 *bsize = DEV_BSIZE;
1107 *dsize = D.dqb_bsoftlimit;
1109 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1110 *dfree = 0;
1111 *dsize = D.dqb_curblocks;
1112 } else
1113 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1115 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
1116 path,(double)*bsize,(double)*dfree,(double)*dsize));
1118 return(True);
1121 #endif /* SUNOS5 || ... */
1123 #endif /* VXFS_QUOTA */
1125 #else /* WITH_QUOTAS */
1127 BOOL disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
1129 (*bsize) = 512; /* This value should be ignored */
1131 /* And just to be sure we set some values that hopefully */
1132 /* will be larger that any possible real-world value */
1133 (*dfree) = (SMB_BIG_UINT)-1;
1134 (*dsize) = (SMB_BIG_UINT)-1;
1136 /* As we have select not to use quotas, allways fail */
1137 return False;
1139 #endif /* WITH_QUOTAS */
1141 #else /* HAVE_SYS_QUOTAS */
1142 /* wrapper to the new sys_quota interface
1143 this file should be removed later
1145 BOOL disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
1147 int r;
1148 SMB_DISK_QUOTA D;
1149 unid_t id;
1151 id.uid = geteuid();
1153 r=sys_get_quota(path, SMB_USER_QUOTA_TYPE, id, &D);
1155 /* Use softlimit to determine disk space, except when it has been exceeded */
1156 *bsize = D.bsize;
1157 if (r == -1) {
1158 if (errno == EDQUOT) {
1159 *dfree =0;
1160 *dsize =D.curblocks;
1161 return (True);
1162 } else {
1163 goto try_group_quota;
1167 /* Use softlimit to determine disk space, except when it has been exceeded */
1168 if (
1169 (D.softlimit && D.curblocks >= D.softlimit) ||
1170 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1171 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1172 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1174 *dfree = 0;
1175 *dsize = D.curblocks;
1176 } else if (D.softlimit==0 && D.hardlimit==0) {
1177 goto try_group_quota;
1178 } else {
1179 if (D.softlimit == 0)
1180 D.softlimit = D.hardlimit;
1181 *dfree = D.softlimit - D.curblocks;
1182 *dsize = D.softlimit;
1185 return True;
1187 try_group_quota:
1188 #ifdef HAVE_GROUP_QUOTA
1189 id.gid = getegid();
1191 r=sys_get_quota(path, SMB_GROUP_QUOTA_TYPE, id, &D);
1193 /* Use softlimit to determine disk space, except when it has been exceeded */
1194 *bsize = D.bsize;
1195 if (r == -1) {
1196 if (errno == EDQUOT) {
1197 *dfree =0;
1198 *dsize =D.curblocks;
1199 return (True);
1200 } else {
1201 return False;
1205 /* Use softlimit to determine disk space, except when it has been exceeded */
1206 if (
1207 (D.softlimit && D.curblocks >= D.softlimit) ||
1208 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1209 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1210 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1212 *dfree = 0;
1213 *dsize = D.curblocks;
1214 } else if (D.softlimit==0 && D.hardlimit==0) {
1215 return False;
1216 } else {
1217 if (D.softlimit == 0)
1218 D.softlimit = D.hardlimit;
1219 *dfree = D.softlimit - D.curblocks;
1220 *dsize = D.softlimit;
1223 return (True);
1224 #else /* HAVE_GROUP_QUOTA */
1225 return False;
1226 #endif /* HAVE_GROUP_QUOTA */
1228 #endif /* HAVE_SYS_QUOTAS */